75#if defined(Q_OS_LINUX)
76 if (type == AV_HWDEVICE_TYPE_CUDA) {
77 if (!QFile::exists(QLatin1String(
"/proc/driver/nvidia/version")))
82 QLibrary lib(u"libnvcuvid.so"_s);
88#elif defined(Q_OS_WINDOWS)
89 if (type == AV_HWDEVICE_TYPE_D3D11VA)
90 return QSystemLibrary(QLatin1String(
"d3d11.dll")).load();
92#if QT_FFMPEG_HAS_D3D12VA
93 if (type == AV_HWDEVICE_TYPE_D3D12VA)
94 return QSystemLibrary(QLatin1String(
"d3d12.dll")).load();
97 if (type == AV_HWDEVICE_TYPE_DXVA2)
98 return QSystemLibrary(QLatin1String(
"d3d9.dll")).load();
101 if (type == AV_HWDEVICE_TYPE_CUDA)
102 return QSystemLibrary(QLatin1String(
"nvml.dll")).load();
112 const auto deviceName = av_hwdevice_get_type_name(type);
114 qWarning() <<
"Internal FFmpeg error, unknow hw type:" << type;
118 if (!precheckDriver(type)) {
119 qCDebug(qLHWAccel) <<
"Drivers for hw device" << deviceName <<
"is not installed";
123#if QT_FFMPEG_HAS_D3D12VA
124 if (type == AV_HWDEVICE_TYPE_D3D12VA)
128 if (type == AV_HWDEVICE_TYPE_MEDIACODEC ||
129 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
130 type == AV_HWDEVICE_TYPE_D3D11VA ||
131#if QT_FFMPEG_HAS_D3D12VA
132 type == AV_HWDEVICE_TYPE_D3D12VA ||
134 type == AV_HWDEVICE_TYPE_DXVA2)
140 return loadHWContext(type) !=
nullptr;
145 static const auto types = []() {
146 qCDebug(qLHWAccel) <<
"Check device types";
151 std::unordered_set<AVPixelFormat> hwPixFormats;
152 for (
const Codec codec : CodecEnumerator()) {
153 forEachAVPixelFormat(codec, [&](AVPixelFormat format) {
154 if (isHwPixelFormat(format))
155 hwPixFormats.insert(format);
160 std::vector<AVHWDeviceType> result;
161 AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
162 while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
163 if (hwPixFormats.count(pixelFormatForHwDevice(type)) && checkHwType(type))
164 result.push_back(type);
165 result.shrink_to_fit();
168 auto it = result.begin();
169 for (
const auto preffered : preferredHardwareAccelerators) {
170 auto found = std::find(it, result.end(), preffered);
171 if (found != result.end())
172 std::rotate(it++, found, std::next(found));
175 using namespace std::chrono;
176 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(timer.durationElapsed());
186 const auto definedDeviceTypes = qgetenv(envVarName);
188 if (definedDeviceTypes.isNull())
189 return deviceTypes();
191 std::vector<AVHWDeviceType> result;
192 const auto definedDeviceTypesString = QString::fromUtf8(definedDeviceTypes).toLower();
193 for (
const auto &deviceType : definedDeviceTypesString.split(u',')) {
194 if (!deviceType.isEmpty()) {
195 const auto foundType = av_hwdevice_find_type_by_name(deviceType.toUtf8().data());
196 if (foundType == AV_HWDEVICE_TYPE_NONE)
197 qWarning() <<
"Unknown hw device type" << deviceType;
199 result.emplace_back(foundType);
203 result.shrink_to_fit();
207std::pair<std::optional<Codec>, HWAccelUPtr>
HWAccel::findDecoderWithHwAccel(AVCodecID id)
209 for (
auto type : decodingDeviceTypes()) {
210 const std::optional<Codec> codec = findAVDecoder(id, pixelFormatForHwDevice(type));
215 qCDebug(qLHWAccel) <<
"Found potential codec" << codec->name() <<
"for hw accel" << type
216 <<
"; Checking the hw device...";
218 HWAccelUPtr hwAccel = create(type);
223 qCDebug(qLHWAccel) <<
"HW device is OK";
225 return { codec, std::move(hwAccel) };
228 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" << id;
230 return {
std::nullopt,
nullptr };
243 QSpan<
const AVPixelFormat> suggestedFormats = makeSpan(fmt);
245 if (codecContext->hw_device_ctx) {
246 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
247 ValueAndScore<AVPixelFormat> formatAndScore;
250 const Codec codec{ codecContext->codec };
251 for (
const AVCodecHWConfig *config : codec.hwConfigs()) {
252 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
255 if (device_ctx->type != config->device_type)
258 const bool isDeprecated = (config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
259 const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
261 auto scoresGettor = [&](AVPixelFormat format) {
265 const auto pixelFormats = codec.pixelFormats();
266 if (shouldCheckCodecFormats && !hasValue(pixelFormats, format))
267 return NotSuitableAVScore;
269 if (!shouldCheckCodecFormats && config->pix_fmt != format)
270 return NotSuitableAVScore;
272 auto result = DefaultAVScore;
276 if (isHwPixelFormat(format))
282 const auto found = findBestAVValueWithScore(suggestedFormats, scoresGettor);
284 if (found.score > formatAndScore.score)
285 formatAndScore = found;
288 const auto format = formatAndScore.value;
290 TextureConverter::applyDecoderPreset(*format, *codecContext);
291 qCDebug(qLHWAccel) <<
"Selected format" << *format <<
"for hw" << device_ctx->type;
297 const auto noConversionFormat = findIf(suggestedFormats, &isNoConversionFormat);
298 if (noConversionFormat) {
299 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << *noConversionFormat;
300 return *noConversionFormat;
303 const AVPixelFormat format = !suggestedFormats.empty() ? suggestedFormats[0] : AV_PIX_FMT_NONE;
304 qCDebug(qLHWAccel) <<
"Selected format with conversion" << format;
381 if (m_hwFramesContext) {
382 qWarning() <<
"Frames context has been already created!";
386 if (!m_hwDeviceContext)
389 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
390 auto *c = (AVHWFramesContext *)m_hwFramesContext->data;
391 c->format = hwFormat();
392 c->sw_format = swFormat;
393 c->width = size.width();
394 c->height = size.height();
395 qCDebug(qLHWAccel) <<
"init frames context";
396 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
398 qWarning() <<
"failed to init HW frame context" << err <<
AVError(err);
400 qCDebug(qLHWAccel) <<
"Initialized frames context" << size << c->format << c->sw_format;
423 std::unique_ptr<HwFrameContextData> contextData(
425 Q_ASSERT(contextData);
427 if (contextData->avDeleter) {
428 context->user_opaque = contextData->avUserOpaque;
429 context->free = contextData->avDeleter;
431 context->free(context);
The HwFrameContextData class contains custom belongings of hw frames context.