136#if defined(Q_OS_LINUX)
137 if (type == AV_HWDEVICE_TYPE_CUDA) {
138 if (!QFile::exists(QLatin1String(
"/proc/driver/nvidia/version")))
143 QLibrary lib(u"libnvcuvid.so"_s);
150 if (type == AV_HWDEVICE_TYPE_VULKAN && hasSoftwareVulkanIcdRegistered()) {
151 qCDebug(qLHWAccel) <<
"A software Vulkan ICD (llvmpipe/SwiftShader) is registered on this "
152 "system; skipping Vulkan hwaccel, as it offers no real acceleration "
153 "benefit over native CPU codecs";
156#elif defined(Q_OS_WINDOWS)
157 if (type == AV_HWDEVICE_TYPE_D3D11VA)
158 return QSystemLibrary(QLatin1String(
"d3d11.dll")).load();
160#if QT_FFMPEG_HAS_D3D12VA
161 if (type == AV_HWDEVICE_TYPE_D3D12VA)
162 return QSystemLibrary(QLatin1String(
"d3d12.dll")).load();
165 if (type == AV_HWDEVICE_TYPE_DXVA2)
166 return QSystemLibrary(QLatin1String(
"d3d9.dll")).load();
169 if (type == AV_HWDEVICE_TYPE_CUDA)
170 return QSystemLibrary(QLatin1String(
"nvml.dll")).load();
180 if (!precheckDriver(type)) {
181 qCDebug(qLHWAccel) <<
"Drivers for hw device" << type <<
"is not installed";
185#if QT_FFMPEG_HAS_D3D12VA
186 if (type == AV_HWDEVICE_TYPE_D3D12VA)
190 if (type == AV_HWDEVICE_TYPE_MEDIACODEC ||
191 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
192 type == AV_HWDEVICE_TYPE_D3D11VA ||
193#if QT_FFMPEG_HAS_D3D12VA
194 type == AV_HWDEVICE_TYPE_D3D12VA ||
196 type == AV_HWDEVICE_TYPE_DXVA2)
202 return loadHWContext(type) !=
nullptr;
209 static const auto types = []() {
210 qCDebug(qLHWAccel) <<
"Check device types";
215 std::unordered_set<AVPixelFormat> hwPixFormats;
216 for (
const Codec codec : allCodecs) {
217 forEachAVPixelFormat(codec, [&](AVPixelFormat format) {
218 if (isHwPixelFormat(format))
219 hwPixFormats.insert(format);
224 std::vector<AVHWDeviceType> result;
225 for (
const AVHWDeviceType type : HWDeviceTypesRange())
226 if (hwPixFormats.count(pixelFormatForHwDevice(type)) && checkHwType(type))
227 result.push_back(type);
228 result.shrink_to_fit();
231 auto it = result.begin();
232 for (
const auto preffered : preferredHardwareAccelerators) {
233 auto found = std::find(it, result.end(), preffered);
234 if (found != result.end())
235 std::rotate(it++, found, std::next(found));
238 using namespace std::chrono;
239 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(timer.durationElapsed());
249 const auto definedDeviceTypes = qgetenv(envVarName);
251 if (definedDeviceTypes.isNull())
252 return deviceTypes();
254 std::vector<AVHWDeviceType> result;
255 const auto definedDeviceTypesString = QString::fromUtf8(definedDeviceTypes).toLower();
256 for (
const auto &deviceType : definedDeviceTypesString.split(u',')) {
257 if (!deviceType.isEmpty()) {
258 const auto foundType = av_hwdevice_find_type_by_name(deviceType.toUtf8().data());
259 if (foundType == AV_HWDEVICE_TYPE_NONE)
260 qWarning() <<
"Unknown hw device type" << deviceType;
262 result.emplace_back(foundType);
266 result.shrink_to_fit();
270std::pair<std::optional<Codec>, HWAccelUPtr>
HWAccel::findDecoderWithHwAccel(AVCodecID id)
272 for (
auto type : decodingDeviceTypes()) {
273 const std::optional<Codec> codec = findAVDecoder(id, pixelFormatForHwDevice(type));
278 qCDebug(qLHWAccel) <<
"Found potential codec" << codec->name() <<
"for hw accel" << type
279 <<
"; Checking the hw device...";
281 HWAccelUPtr hwAccel = create(type);
286 qCDebug(qLHWAccel) <<
"HW device is OK";
288 return { codec, std::move(hwAccel) };
291 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" << id;
293 return {
std::nullopt,
nullptr };
306 QSpan<
const AVPixelFormat> suggestedFormats = makeSpan(fmt);
308 if (codecContext->hw_device_ctx) {
309 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
310 std::optional<ValueAndScore<AVPixelFormat>> formatAndScore;
313 const Codec codec{ codecContext->codec };
314 for (
const AVCodecHWConfig *config : codec.hwConfigs()) {
315 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
318 if (device_ctx->type != config->device_type)
321 const bool isDeprecated = (config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
322 const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
324 auto scoresGettor = [&](AVPixelFormat format) {
328 const auto pixelFormats = codec.pixelFormats();
329 if (shouldCheckCodecFormats && !ranges::contains(pixelFormats, format))
330 return NotSuitableAVScore;
332 if (!shouldCheckCodecFormats && config->pix_fmt != format)
333 return NotSuitableAVScore;
335 auto result = DefaultAVScore;
339 if (isHwPixelFormat(format))
345 const auto found = findBestAVValueWithScore(suggestedFormats, scoresGettor);
347 if (!formatAndScore || found->score > formatAndScore->score)
348 formatAndScore = found;
352 if (formatAndScore) {
353 AVPixelFormat format = formatAndScore->value;
354 TextureConverter::applyDecoderPreset(format, *codecContext);
355 qCDebug(qLHWAccel) <<
"Selected format" << format <<
"for hw" << device_ctx->type;
361 const auto noConversionFormat = findIf(suggestedFormats, &isNoConversionFormat);
362 if (noConversionFormat) {
363 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << *noConversionFormat;
364 return *noConversionFormat;
367 const AVPixelFormat format = !suggestedFormats.empty() ? suggestedFormats[0] : AV_PIX_FMT_NONE;
368 qCDebug(qLHWAccel) <<
"Selected format with conversion" << format;
445 if (m_hwFramesContext) {
446 qWarning() <<
"Frames context has been already created!";
450 if (!m_hwDeviceContext)
453 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
454 auto *c = (AVHWFramesContext *)m_hwFramesContext->data;
455 c->format = hwFormat();
456 c->sw_format = swFormat;
457 c->width = size.width();
458 c->height = size.height();
459 qCDebug(qLHWAccel) <<
"init frames context";
460 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
462 qWarning() <<
"failed to init HW frame context" << err <<
AVError(err);
464 qCDebug(qLHWAccel) <<
"Initialized frames context" << size << c->format << c->sw_format;
492 std::unique_ptr<HwFrameContextData> contextData(
494 Q_ASSERT(contextData);
496 if (contextData->avDeleter) {
497 context->user_opaque = contextData->avUserOpaque;
498 context->free = contextData->avDeleter;
500 context->free(context);
The HwFrameContextData class contains custom belongings of hw frames context.