77#if defined(Q_OS_LINUX)
78 if (type == AV_HWDEVICE_TYPE_CUDA) {
79 if (!QFile::exists(QLatin1String(
"/proc/driver/nvidia/version")))
84 QLibrary lib(u"libnvcuvid.so"_s);
90#elif defined(Q_OS_WINDOWS)
91 if (type == AV_HWDEVICE_TYPE_D3D11VA)
92 return QSystemLibrary(QLatin1String(
"d3d11.dll")).load();
94#if QT_FFMPEG_HAS_D3D12VA
95 if (type == AV_HWDEVICE_TYPE_D3D12VA)
96 return QSystemLibrary(QLatin1String(
"d3d12.dll")).load();
99 if (type == AV_HWDEVICE_TYPE_DXVA2)
100 return QSystemLibrary(QLatin1String(
"d3d9.dll")).load();
103 if (type == AV_HWDEVICE_TYPE_CUDA)
104 return QSystemLibrary(QLatin1String(
"nvml.dll")).load();
114 const auto deviceName = av_hwdevice_get_type_name(type);
116 qWarning() <<
"Internal FFmpeg error, unknow hw type:" << type;
120 if (!precheckDriver(type)) {
121 qCDebug(qLHWAccel) <<
"Drivers for hw device" << deviceName <<
"is not installed";
125 if (type == AV_HWDEVICE_TYPE_MEDIACODEC ||
126 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
127 type == AV_HWDEVICE_TYPE_D3D11VA ||
128#if QT_FFMPEG_HAS_D3D12VA
129 type == AV_HWDEVICE_TYPE_D3D12VA ||
131 type == AV_HWDEVICE_TYPE_DXVA2)
138 return loadHWContext(type) !=
nullptr;
143 static const auto types = []() {
144 qCDebug(qLHWAccel) <<
"Check device types";
149 std::unordered_set<AVPixelFormat> hwPixFormats;
150 for (
const Codec codec : CodecEnumerator()) {
151 forEachAVPixelFormat(codec, [&](AVPixelFormat format) {
152 if (isHwPixelFormat(format))
153 hwPixFormats.insert(format);
158 std::vector<AVHWDeviceType> result;
159 AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
160 while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
161 if (hwPixFormats.count(pixelFormatForHwDevice(type)) && checkHwType(type))
162 result.push_back(type);
163 result.shrink_to_fit();
166 auto it = result.begin();
167 for (
const auto preffered : preferredHardwareAccelerators) {
168 auto found = std::find(it, result.end(), preffered);
169 if (found != result.end())
170 std::rotate(it++, found, std::next(found));
173 using namespace std::chrono;
174 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(timer.durationElapsed());
184 const auto definedDeviceTypes = qgetenv(envVarName);
186 if (definedDeviceTypes.isNull())
187 return deviceTypes();
189 std::vector<AVHWDeviceType> result;
190 const auto definedDeviceTypesString = QString::fromUtf8(definedDeviceTypes).toLower();
191 for (
const auto &deviceType : definedDeviceTypesString.split(u',')) {
192 if (!deviceType.isEmpty()) {
193 const auto foundType = av_hwdevice_find_type_by_name(deviceType.toUtf8().data());
194 if (foundType == AV_HWDEVICE_TYPE_NONE)
195 qWarning() <<
"Unknown hw device type" << deviceType;
197 result.emplace_back(foundType);
201 result.shrink_to_fit();
205std::pair<std::optional<Codec>, HWAccelUPtr>
HWAccel::findDecoderWithHwAccel(AVCodecID id)
207 for (
auto type : decodingDeviceTypes()) {
208 const std::optional<Codec> codec = findAVDecoder(id, pixelFormatForHwDevice(type));
213 qCDebug(qLHWAccel) <<
"Found potential codec" << codec->name() <<
"for hw accel" << type
214 <<
"; Checking the hw device...";
216 HWAccelUPtr hwAccel = create(type);
221 qCDebug(qLHWAccel) <<
"HW device is OK";
223 return { codec, std::move(hwAccel) };
226 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" << id;
228 return {
std::nullopt,
nullptr };
241 QSpan<
const AVPixelFormat> suggestedFormats = makeSpan(fmt);
243 if (codecContext->hw_device_ctx) {
244 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
245 ValueAndScore<AVPixelFormat> formatAndScore;
248 const Codec codec{ codecContext->codec };
249 for (
const AVCodecHWConfig *config : codec.hwConfigs()) {
250 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
253 if (device_ctx->type != config->device_type)
256 const bool isDeprecated = (config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
257 const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
259 auto scoresGettor = [&](AVPixelFormat format) {
263 const auto pixelFormats = codec.pixelFormats();
264 if (shouldCheckCodecFormats && !hasValue(pixelFormats, format))
265 return NotSuitableAVScore;
267 if (!shouldCheckCodecFormats && config->pix_fmt != format)
268 return NotSuitableAVScore;
270 auto result = DefaultAVScore;
274 if (isHwPixelFormat(format))
280 const auto found = findBestAVValueWithScore(suggestedFormats, scoresGettor);
282 if (found.score > formatAndScore.score)
283 formatAndScore = found;
286 const auto format = formatAndScore.value;
288 TextureConverter::applyDecoderPreset(*format, *codecContext);
289 qCDebug(qLHWAccel) <<
"Selected format" << *format <<
"for hw" << device_ctx->type;
295 const auto noConversionFormat = findIf(suggestedFormats, &isNoConversionFormat);
296 if (noConversionFormat) {
297 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << *noConversionFormat;
298 return *noConversionFormat;
301 const AVPixelFormat format = !suggestedFormats.empty() ? suggestedFormats[0] : AV_PIX_FMT_NONE;
302 qCDebug(qLHWAccel) <<
"Selected format with conversion" << format;
379 if (m_hwFramesContext) {
380 qWarning() <<
"Frames context has been already created!";
384 if (!m_hwDeviceContext)
387 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
388 auto *c = (AVHWFramesContext *)m_hwFramesContext->data;
389 c->format = hwFormat();
390 c->sw_format = swFormat;
391 c->width = size.width();
392 c->height = size.height();
393 qCDebug(qLHWAccel) <<
"init frames context";
394 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
396 qWarning() <<
"failed to init HW frame context" << err <<
AVError(err);
398 qCDebug(qLHWAccel) <<
"Initialized frames context" << size << c->format << c->sw_format;
413 Q_ASSERT(hwFrame.hw_frames_ctx && hwFrame.hw_frames_ctx->data);
415 auto context =
reinterpret_cast<AVHWFramesContext *>(hwFrame.hw_frames_ctx->data);
416 if (!context->user_opaque) {
418 Q_ASSERT(!context->free);
419 context->free = deleteHwFrameContextData;
421 Q_ASSERT(context->free == deleteHwFrameContextData);
The HwFrameContextData class contains custom belongings of hw frames context.