76#if defined(Q_OS_LINUX)
77 if (type == AV_HWDEVICE_TYPE_CUDA) {
78 if (!QFile::exists(QLatin1String(
"/proc/driver/nvidia/version")))
83 QLibrary lib(u"libnvcuvid.so"_s);
89#elif defined(Q_OS_WINDOWS)
90 if (type == AV_HWDEVICE_TYPE_D3D11VA)
91 return QSystemLibrary(QLatin1String(
"d3d11.dll")).load();
93#if QT_FFMPEG_HAS_D3D12VA
94 if (type == AV_HWDEVICE_TYPE_D3D12VA)
95 return QSystemLibrary(QLatin1String(
"d3d12.dll")).load();
98 if (type == AV_HWDEVICE_TYPE_DXVA2)
99 return QSystemLibrary(QLatin1String(
"d3d9.dll")).load();
102 if (type == AV_HWDEVICE_TYPE_CUDA)
103 return QSystemLibrary(QLatin1String(
"nvml.dll")).load();
113 if (!precheckDriver(type)) {
114 qCDebug(qLHWAccel) <<
"Drivers for hw device" << type <<
"is not installed";
118#if QT_FFMPEG_HAS_D3D12VA
119 if (type == AV_HWDEVICE_TYPE_D3D12VA)
123 if (type == AV_HWDEVICE_TYPE_MEDIACODEC ||
124 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
125 type == AV_HWDEVICE_TYPE_D3D11VA ||
126#if QT_FFMPEG_HAS_D3D12VA
127 type == AV_HWDEVICE_TYPE_D3D12VA ||
129 type == AV_HWDEVICE_TYPE_DXVA2)
135 return loadHWContext(type) !=
nullptr;
142 static const auto types = []() {
143 qCDebug(qLHWAccel) <<
"Check device types";
148 std::unordered_set<AVPixelFormat> hwPixFormats;
149 for (
const Codec codec : allCodecs) {
150 forEachAVPixelFormat(codec, [&](AVPixelFormat format) {
151 if (isHwPixelFormat(format))
152 hwPixFormats.insert(format);
157 std::vector<AVHWDeviceType> result;
158 for (
const AVHWDeviceType type : HWDeviceTypesRange())
159 if (hwPixFormats.count(pixelFormatForHwDevice(type)) && checkHwType(type))
160 result.push_back(type);
161 result.shrink_to_fit();
164 auto it = result.begin();
165 for (
const auto preffered : preferredHardwareAccelerators) {
166 auto found = std::find(it, result.end(), preffered);
167 if (found != result.end())
168 std::rotate(it++, found, std::next(found));
171 using namespace std::chrono;
172 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(timer.durationElapsed());
182 const auto definedDeviceTypes = qgetenv(envVarName);
184 if (definedDeviceTypes.isNull())
185 return deviceTypes();
187 std::vector<AVHWDeviceType> result;
188 const auto definedDeviceTypesString = QString::fromUtf8(definedDeviceTypes).toLower();
189 for (
const auto &deviceType : definedDeviceTypesString.split(u',')) {
190 if (!deviceType.isEmpty()) {
191 const auto foundType = av_hwdevice_find_type_by_name(deviceType.toUtf8().data());
192 if (foundType == AV_HWDEVICE_TYPE_NONE)
193 qWarning() <<
"Unknown hw device type" << deviceType;
195 result.emplace_back(foundType);
199 result.shrink_to_fit();
203std::pair<std::optional<Codec>, HWAccelUPtr>
HWAccel::findDecoderWithHwAccel(AVCodecID id)
205 for (
auto type : decodingDeviceTypes()) {
206 const std::optional<Codec> codec = findAVDecoder(id, pixelFormatForHwDevice(type));
211 qCDebug(qLHWAccel) <<
"Found potential codec" << codec->name() <<
"for hw accel" << type
212 <<
"; Checking the hw device...";
214 HWAccelUPtr hwAccel = create(type);
219 qCDebug(qLHWAccel) <<
"HW device is OK";
221 return { codec, std::move(hwAccel) };
224 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" << id;
226 return {
std::nullopt,
nullptr };
239 QSpan<
const AVPixelFormat> suggestedFormats = makeSpan(fmt);
241 if (codecContext->hw_device_ctx) {
242 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
243 std::optional<ValueAndScore<AVPixelFormat>> formatAndScore;
246 const Codec codec{ codecContext->codec };
247 for (
const AVCodecHWConfig *config : codec.hwConfigs()) {
248 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
251 if (device_ctx->type != config->device_type)
254 const bool isDeprecated = (config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
255 const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
257 auto scoresGettor = [&](AVPixelFormat format) {
261 const auto pixelFormats = codec.pixelFormats();
262 if (shouldCheckCodecFormats && !ranges::contains(pixelFormats, format))
263 return NotSuitableAVScore;
265 if (!shouldCheckCodecFormats && config->pix_fmt != format)
266 return NotSuitableAVScore;
268 auto result = DefaultAVScore;
272 if (isHwPixelFormat(format))
278 const auto found = findBestAVValueWithScore(suggestedFormats, scoresGettor);
280 if (!formatAndScore || found->score > formatAndScore->score)
281 formatAndScore = found;
285 if (formatAndScore) {
286 AVPixelFormat format = formatAndScore->value;
287 TextureConverter::applyDecoderPreset(format, *codecContext);
288 qCDebug(qLHWAccel) <<
"Selected format" << format <<
"for hw" << device_ctx->type;
294 const auto noConversionFormat = findIf(suggestedFormats, &isNoConversionFormat);
295 if (noConversionFormat) {
296 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << *noConversionFormat;
297 return *noConversionFormat;
300 const AVPixelFormat format = !suggestedFormats.empty() ? suggestedFormats[0] : AV_PIX_FMT_NONE;
301 qCDebug(qLHWAccel) <<
"Selected format with conversion" << format;
378 if (m_hwFramesContext) {
379 qWarning() <<
"Frames context has been already created!";
383 if (!m_hwDeviceContext)
386 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
387 auto *c = (AVHWFramesContext *)m_hwFramesContext->data;
388 c->format = hwFormat();
389 c->sw_format = swFormat;
390 c->width = size.width();
391 c->height = size.height();
392 qCDebug(qLHWAccel) <<
"init frames context";
393 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
395 qWarning() <<
"failed to init HW frame context" << err <<
AVError(err);
397 qCDebug(qLHWAccel) <<
"Initialized frames context" << size << c->format << c->sw_format;
420 std::unique_ptr<HwFrameContextData> contextData(
422 Q_ASSERT(contextData);
424 if (contextData->avDeleter) {
425 context->user_opaque = contextData->avUserOpaque;
426 context->free = contextData->avDeleter;
428 context->free(context);
The HwFrameContextData class contains custom belongings of hw frames context.