4#include "libavutil/version.h"
15#include <QtCore/private/qsystemlibrary_p.h>
24#include "QtCore/qfile.h"
28#include <unordered_set>
43#if defined(Q_OS_ANDROID)
44 AV_HWDEVICE_TYPE_MEDIACODEC,
45#elif defined(Q_OS_LINUX)
46 AV_HWDEVICE_TYPE_CUDA,
47 AV_HWDEVICE_TYPE_VAAPI,
53#elif defined (Q_OS_WIN)
54 AV_HWDEVICE_TYPE_D3D11VA,
55#elif defined (Q_OS_DARWIN)
56 AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
62 AVBufferRef *hwContext =
nullptr;
63 qCDebug(qLHWAccel) <<
" Checking HW context:" << av_hwdevice_get_type_name(
type);
64 int ret = av_hwdevice_ctx_create(&hwContext,
type,
nullptr,
nullptr, 0);
67 qCDebug(qLHWAccel) <<
" Using above hw context.";
70 qCDebug(qLHWAccel) <<
" Could not create hw context:" <<
ret << strerror(-
ret);
79#if defined(Q_OS_LINUX)
80 if (
type == AV_HWDEVICE_TYPE_CUDA) {
92#elif defined(Q_OS_WINDOWS)
93 if (
type == AV_HWDEVICE_TYPE_D3D11VA)
96#if QT_FFMPEG_HAS_D3D12VA
97 if (
type == AV_HWDEVICE_TYPE_D3D12VA)
101 if (
type == AV_HWDEVICE_TYPE_DXVA2)
105 if (
type == AV_HWDEVICE_TYPE_CUDA)
116 const auto deviceName = av_hwdevice_get_type_name(
type);
118 qWarning() <<
"Internal FFmpeg error, unknow hw type:" <<
type;
123 qCDebug(qLHWAccel) <<
"Drivers for hw device" << deviceName <<
"is not installed";
127 if (
type == AV_HWDEVICE_TYPE_MEDIACODEC ||
128 type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX ||
129 type == AV_HWDEVICE_TYPE_D3D11VA ||
131 type == AV_HWDEVICE_TYPE_D3D12VA ||
133 type == AV_HWDEVICE_TYPE_DXVA2)
145 static const auto types = []() {
146 qCDebug(qLHWAccel) <<
"Check device types";
151 std::unordered_set<AVPixelFormat> hwPixFormats;
152 void *opaque =
nullptr;
153 while (
auto codec = av_codec_iterate(&opaque)) {
156 hwPixFormats.insert(
format);
162 std::vector<AVHWDeviceType>
result;
163 AVHWDeviceType
type = AV_HWDEVICE_TYPE_NONE;
164 while ((
type = av_hwdevice_iterate_types(
type)) != AV_HWDEVICE_TYPE_NONE)
172 auto found = std::find(
it,
result.
end(), preffered);
173 if (found !=
result.end())
174 std::rotate(
it++, found, std::next(found));
177 using namespace std::chrono;
178 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(
timer.durationElapsed());
186static std::vector<AVHWDeviceType>
deviceTypes(
const char *envVarName)
188 const auto definedDeviceTypes =
qgetenv(envVarName);
190 if (definedDeviceTypes.isNull())
193 std::vector<AVHWDeviceType>
result;
194 const auto definedDeviceTypesString =
QString::fromUtf8(definedDeviceTypes).toLower();
195 for (
const auto &
deviceType : definedDeviceTypesString.split(
',')) {
197 const auto foundType = av_hwdevice_find_type_by_name(
deviceType.toUtf8().data());
198 if (foundType == AV_HWDEVICE_TYPE_NONE)
201 result.emplace_back(foundType);
209template<
typename CodecFinder>
210std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
212 CodecFinder codecFinder,
213 const std::function<
bool(
const HWAccel &)> &hwAccelPredicate)
216 const auto codec = codecFinder(
id,
type, {});
221 qCDebug(qLHWAccel) <<
"Found potential codec" <<
codec->name <<
"for hw accel" <<
type
222 <<
"; Checking the hw device...";
229 if (hwAccelPredicate && !hwAccelPredicate(*hwAccel)) {
230 qCDebug(qLHWAccel) <<
"HW device is available but doesn't suit due to restrictions";
234 qCDebug(qLHWAccel) <<
"HW device is OK";
236 return {
codec, std::move(hwAccel) };
239 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" <<
id;
241 return {
nullptr,
nullptr };
246 bool needsConversion =
true;
248 return !needsConversion;
253bool hwTextureConversionEnabled()
258 static const int disableHwConversion =
261 return !disableHwConversion;
264void setupDecoder(
const AVPixelFormat
format, AVCodecContext *
const codecContext)
266 if (!hwTextureConversionEnabled())
270 if (
format == AV_PIX_FMT_D3D11)
271 QFFmpeg::D3D11TextureConverter::SetupDecoderTextures(codecContext);
272#elif defined Q_OS_ANDROID
273 if (
format == AV_PIX_FMT_MEDIACODEC)
284AVPixelFormat
getFormat(AVCodecContext *codecContext,
const AVPixelFormat *suggestedFormats)
287 if (codecContext->hw_device_ctx) {
288 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
293 const AVCodecHWConfig *
config = avcodec_get_hw_config(codecContext->codec,
i);
i++) {
294 if (!(
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
297 if (device_ctx->type !=
config->device_type)
300 const bool isDeprecated = (
config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
301 const bool shouldCheckCodecFormats =
config->pix_fmt == AV_PIX_FMT_NONE;
303 auto scoresGettor = [&](AVPixelFormat
format) {
306 if (shouldCheckCodecFormats && !
hasAVFormat(codecContext->codec->pix_fmts,
format))
309 if (!shouldCheckCodecFormats &&
config->pix_fmt !=
format)
324 if (found.second > formatAndScore.second)
325 formatAndScore = found;
328 const auto &
format = formatAndScore.first;
329 if (
format != AV_PIX_FMT_NONE) {
330 setupDecoder(
format, codecContext);
331 qCDebug(qLHWAccel) <<
"Selected format" <<
format <<
"for hw" << device_ctx->type;
338 if (noConversionFormat != AV_PIX_FMT_NONE) {
339 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << noConversionFormat;
340 return noConversionFormat;
343 qCDebug(qLHWAccel) <<
"Selected format with conversion" << *suggestedFormats;
346 return *suggestedFormats;
354 return std::unique_ptr<HWAccel>(
new HWAccel(std::move(
ctx)));
361 if (!
frame->hw_frames_ctx)
362 return AVPixelFormat(
frame->format);
383 return m_hwDeviceContext ? (AVHWDeviceContext *)m_hwDeviceContext->data :
nullptr;
393 std::call_once(m_constraintsOnceFlag, [
this]() {
395 m_constraints.reset(av_hwdevice_get_hwframe_constraints(context,
nullptr));
398 return m_constraints.get();
401std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
404 auto finder = qOverload<AVCodecID, const std::optional<AVHWDeviceType> &,
409std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
418 return m_hwDeviceContext ?
hwDeviceContext()->type : AV_HWDEVICE_TYPE_NONE;
423 if (m_hwFramesContext) {
424 qWarning() <<
"Frames context has been already created!";
428 if (!m_hwDeviceContext)
431 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
432 auto *
c = (AVHWFramesContext *)m_hwFramesContext->data;
434 c->sw_format = swFormat;
435 c->width =
size.width();
436 c->height =
size.height();
437 qCDebug(qLHWAccel) <<
"init frames context";
438 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
440 qWarning() <<
"failed to init HW frame context" << err <<
err2str(err);
442 qCDebug(qLHWAccel) <<
"Initialized frames context" <<
size <<
c->format <<
c->sw_format;
447 return m_hwFramesContext ? (AVHWFramesContext *)m_hwFramesContext->data :
nullptr;
463 return d->backend->getTextures(
frame);
466void TextureConverter::updateBackend(AVPixelFormat
fmt)
468 d->backend =
nullptr;
472 if (!hwTextureConversionEnabled())
477 case AV_PIX_FMT_VAAPI:
478 d->backend = std::make_unique<VAAPITextureConverter>(d->rhi);
482 case AV_PIX_FMT_VIDEOTOOLBOX:
483 d->backend = std::make_unique<VideoToolBoxTextureConverter>(d->rhi);
487 case AV_PIX_FMT_D3D11:
488 d->backend = std::make_unique<D3D11TextureConverter>(d->rhi);
492 case AV_PIX_FMT_MEDIACODEC:
493 d->backend = std::make_unique<MediaCodecTextureConverter>(d->rhi);
static QVideoFrameFormat::PixelFormat toQtPixelFormat(AVPixelFormat avPixelFormat, bool *needsConversion=nullptr)
static std::pair< const AVCodec *, std::unique_ptr< HWAccel > > findDecoderWithHwAccel(AVCodecID id, const std::function< bool(const HWAccel &)> &hwAccelPredicate=nullptr)
AVHWFramesContext * hwFramesContext() const
static const std::vector< AVHWDeviceType > & decodingDeviceTypes()
static const std::vector< AVHWDeviceType > & encodingDeviceTypes()
void createFramesContext(AVPixelFormat swFormat, const QSize &size)
static AVPixelFormat format(AVFrame *frame)
static std::pair< const AVCodec *, std::unique_ptr< HWAccel > > findEncoderWithHwAccel(AVCodecID id, const std::function< bool(const HWAccel &)> &hwAccelPredicate=nullptr)
AVBufferRef * hwDeviceContextAsBuffer() const
const AVHWFramesConstraints * constraints() const
AVHWDeviceContext * hwDeviceContext() const
AVPixelFormat hwFormat() const
static std::unique_ptr< HWAccel > create(AVHWDeviceType deviceType)
AVHWDeviceType deviceType() const
static void setupDecoderSurface(AVCodecContext *s)
TextureSet * getTextures(AVFrame *frame)
TextureConverter(QRhi *rhi=nullptr)
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore \reentrant
bool load()
Loads the library and returns true if the library was loaded successfully; otherwise returns false.
bool unload()
Unloads the library and returns true if the library could be unloaded; otherwise returns false.
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
QSet< QString >::iterator it
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
AVFrameUPtr copyFromHwPoolD3D11(AVFrameUPtr src)
AVPixelFormat getFormat(AVCodecContext *codecContext, const AVPixelFormat *suggestedFormats)
bool isHwPixelFormat(AVPixelFormat format)
static const std::initializer_list< AVHWDeviceType > preferredHardwareAccelerators
QString err2str(int errnum)
static bool isNoConversionFormat(AVPixelFormat f)
const AVCodec * findAVDecoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
AVFrameUPtr copyFromHwPool(AVFrameUPtr frame)
constexpr AVScore DefaultAVScore
bool hasAVFormat(const Format *fmts, Format format)
std::unique_ptr< AVFrame, AVDeleter< decltype(&av_frame_free), &av_frame_free > > AVFrameUPtr
static const std::vector< AVHWDeviceType > & deviceTypes()
std::unique_ptr< AVBufferRef, AVDeleter< decltype(&av_buffer_unref), &av_buffer_unref > > AVBufferUPtr
static AVBufferUPtr loadHWContext(AVHWDeviceType type)
static bool checkHwType(AVHWDeviceType type)
Format findAVFormat(const Format *fmts, const Predicate &predicate)
std::pair< const AVCodec *, std::unique_ptr< HWAccel > > findCodecWithHwAccel(AVCodecID id, const std::vector< AVHWDeviceType > &deviceTypes, CodecFinder codecFinder, const std::function< bool(const HWAccel &)> &hwAccelPredicate)
constexpr AVScore NotSuitableAVScore
AVPixelFormat findAVPixelFormat(const AVCodec *codec, const Predicate &predicate)
AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
auto findBestAVValue(const Value *values, const CalculateScore &calculateScore)
static bool precheckDriver(AVHWDeviceType type)
Combined button and popup list for selecting options.
#define QT_FFMPEG_HAS_D3D12VA
bool thread_local FFmpegLogsEnabledInThread
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLenum GLenum * types
GLint GLsizei GLsizei GLenum format
QLatin1StringView QLatin1String
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QVideoFrameFormat::PixelFormat fmt
static QInputDevice::DeviceType deviceType(const UINT cursorType)