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 if (!precheckDriver(type)) {
113 qCDebug(qLHWAccel) <<
"Drivers for hw device" << type <<
"is not installed";
117#if QT_FFMPEG_HAS_D3D12VA
118 if (type == AV_HWDEVICE_TYPE_D3D12VA)
122 if (type == AV_HWDEVICE_TYPE_MEDIACODEC ||
123 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
124 type == AV_HWDEVICE_TYPE_D3D11VA ||
125#if QT_FFMPEG_HAS_D3D12VA
126 type == AV_HWDEVICE_TYPE_D3D12VA ||
128 type == AV_HWDEVICE_TYPE_DXVA2)
134 return loadHWContext(type) !=
nullptr;
139 static const auto types = []() {
140 qCDebug(qLHWAccel) <<
"Check device types";
145 std::unordered_set<AVPixelFormat> hwPixFormats;
146 for (
const Codec codec : CodecEnumerator()) {
147 forEachAVPixelFormat(codec, [&](AVPixelFormat format) {
148 if (isHwPixelFormat(format))
149 hwPixFormats.insert(format);
154 std::vector<AVHWDeviceType> result;
155 AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
156 while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
157 if (hwPixFormats.count(pixelFormatForHwDevice(type)) && checkHwType(type))
158 result.push_back(type);
159 result.shrink_to_fit();
162 auto it = result.begin();
163 for (
const auto preffered : preferredHardwareAccelerators) {
164 auto found = std::find(it, result.end(), preffered);
165 if (found != result.end())
166 std::rotate(it++, found, std::next(found));
169 using namespace std::chrono;
170 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(timer.durationElapsed());
180 const auto definedDeviceTypes = qgetenv(envVarName);
182 if (definedDeviceTypes.isNull())
183 return deviceTypes();
185 std::vector<AVHWDeviceType> result;
186 const auto definedDeviceTypesString = QString::fromUtf8(definedDeviceTypes).toLower();
187 for (
const auto &deviceType : definedDeviceTypesString.split(u',')) {
188 if (!deviceType.isEmpty()) {
189 const auto foundType = av_hwdevice_find_type_by_name(deviceType.toUtf8().data());
190 if (foundType == AV_HWDEVICE_TYPE_NONE)
191 qWarning() <<
"Unknown hw device type" << deviceType;
193 result.emplace_back(foundType);
197 result.shrink_to_fit();
201std::pair<std::optional<Codec>, HWAccelUPtr>
HWAccel::findDecoderWithHwAccel(AVCodecID id)
203 for (
auto type : decodingDeviceTypes()) {
204 const std::optional<Codec> codec = findAVDecoder(id, pixelFormatForHwDevice(type));
209 qCDebug(qLHWAccel) <<
"Found potential codec" << codec->name() <<
"for hw accel" << type
210 <<
"; Checking the hw device...";
212 HWAccelUPtr hwAccel = create(type);
217 qCDebug(qLHWAccel) <<
"HW device is OK";
219 return { codec, std::move(hwAccel) };
222 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" << id;
224 return {
std::nullopt,
nullptr };
237 QSpan<
const AVPixelFormat> suggestedFormats = makeSpan(fmt);
239 if (codecContext->hw_device_ctx) {
240 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
241 ValueAndScore<AVPixelFormat> formatAndScore;
244 const Codec codec{ codecContext->codec };
245 for (
const AVCodecHWConfig *config : codec.hwConfigs()) {
246 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
249 if (device_ctx->type != config->device_type)
252 const bool isDeprecated = (config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
253 const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
255 auto scoresGettor = [&](AVPixelFormat format) {
259 const auto pixelFormats = codec.pixelFormats();
260 if (shouldCheckCodecFormats && !ranges::contains(pixelFormats, format))
261 return NotSuitableAVScore;
263 if (!shouldCheckCodecFormats && config->pix_fmt != format)
264 return NotSuitableAVScore;
266 auto result = DefaultAVScore;
270 if (isHwPixelFormat(format))
276 const auto found = findBestAVValueWithScore(suggestedFormats, scoresGettor);
278 if (found.score > formatAndScore.score)
279 formatAndScore = found;
282 const auto format = formatAndScore.value;
284 TextureConverter::applyDecoderPreset(*format, *codecContext);
285 qCDebug(qLHWAccel) <<
"Selected format" << *format <<
"for hw" << device_ctx->type;
291 const auto noConversionFormat = findIf(suggestedFormats, &isNoConversionFormat);
292 if (noConversionFormat) {
293 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << *noConversionFormat;
294 return *noConversionFormat;
297 const AVPixelFormat format = !suggestedFormats.empty() ? suggestedFormats[0] : AV_PIX_FMT_NONE;
298 qCDebug(qLHWAccel) <<
"Selected format with conversion" << format;
375 if (m_hwFramesContext) {
376 qWarning() <<
"Frames context has been already created!";
380 if (!m_hwDeviceContext)
383 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
384 auto *c = (AVHWFramesContext *)m_hwFramesContext->data;
385 c->format = hwFormat();
386 c->sw_format = swFormat;
387 c->width = size.width();
388 c->height = size.height();
389 qCDebug(qLHWAccel) <<
"init frames context";
390 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
392 qWarning() <<
"failed to init HW frame context" << err <<
AVError(err);
394 qCDebug(qLHWAccel) <<
"Initialized frames context" << size << c->format << c->sw_format;
417 std::unique_ptr<HwFrameContextData> contextData(
419 Q_ASSERT(contextData);
421 if (contextData->avDeleter) {
422 context->user_opaque = contextData->avUserOpaque;
423 context->free = contextData->avDeleter;
425 context->free(context);
The HwFrameContextData class contains custom belongings of hw frames context.