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)) {
154 if (
auto pixFmt =
codec->pix_fmts)
155 for (; *pixFmt != AV_PIX_FMT_NONE; ++pixFmt)
157 hwPixFormats.insert(*pixFmt);
161 std::vector<AVHWDeviceType>
result;
162 AVHWDeviceType
type = AV_HWDEVICE_TYPE_NONE;
163 while ((
type = av_hwdevice_iterate_types(
type)) != AV_HWDEVICE_TYPE_NONE)
171 auto found = std::find(
it,
result.
end(), preffered);
172 if (found !=
result.end())
173 std::rotate(
it++, found, std::next(found));
176 using namespace std::chrono;
177 qCDebug(qLHWAccel) <<
"Device types checked. Spent time:" << duration_cast<microseconds>(
timer.durationElapsed());
185static std::vector<AVHWDeviceType>
deviceTypes(
const char *envVarName)
187 const auto definedDeviceTypes =
qgetenv(envVarName);
189 if (definedDeviceTypes.isNull())
192 std::vector<AVHWDeviceType>
result;
193 const auto definedDeviceTypesString =
QString::fromUtf8(definedDeviceTypes).toLower();
194 for (
const auto &
deviceType : definedDeviceTypesString.split(
',')) {
196 const auto foundType = av_hwdevice_find_type_by_name(
deviceType.toUtf8().data());
197 if (foundType == AV_HWDEVICE_TYPE_NONE)
200 result.emplace_back(foundType);
208template<
typename CodecFinder>
209std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
211 CodecFinder codecFinder,
212 const std::function<
bool(
const HWAccel &)> &hwAccelPredicate)
215 const auto codec = codecFinder(
id,
type, {});
220 qCDebug(qLHWAccel) <<
"Found potential codec" <<
codec->name <<
"for hw accel" <<
type
221 <<
"; Checking the hw device...";
228 if (hwAccelPredicate && !hwAccelPredicate(*hwAccel)) {
229 qCDebug(qLHWAccel) <<
"HW device is available but doesn't suit due to restrictions";
233 qCDebug(qLHWAccel) <<
"HW device is OK";
235 return {
codec, std::move(hwAccel) };
238 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" <<
id;
240 return {
nullptr,
nullptr };
245 bool needsConversion =
true;
247 return !needsConversion;
252bool hwTextureConversionEnabled()
257 static const int disableHwConversion =
260 return !disableHwConversion;
263void setupDecoder(
const AVPixelFormat
format, AVCodecContext *
const codecContext)
265 if (!hwTextureConversionEnabled())
269 if (
format == AV_PIX_FMT_D3D11)
270 QFFmpeg::D3D11TextureConverter::SetupDecoderTextures(codecContext);
271#elif defined Q_OS_ANDROID
272 if (
format == AV_PIX_FMT_MEDIACODEC)
283AVPixelFormat
getFormat(AVCodecContext *codecContext,
const AVPixelFormat *suggestedFormats)
286 if (codecContext->hw_device_ctx) {
287 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
292 const AVCodecHWConfig *
config = avcodec_get_hw_config(codecContext->codec,
i);
i++) {
293 if (!(
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
296 if (device_ctx->type !=
config->device_type)
299 const bool isDeprecated = (
config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
300 const bool shouldCheckCodecFormats =
config->pix_fmt == AV_PIX_FMT_NONE;
302 auto scoresGettor = [&](AVPixelFormat
format) {
306 if (!shouldCheckCodecFormats &&
config->pix_fmt !=
format)
321 if (found.second > formatAndScore.second)
322 formatAndScore = found;
325 const auto &
format = formatAndScore.first;
326 if (
format != AV_PIX_FMT_NONE) {
327 setupDecoder(
format, codecContext);
328 qCDebug(qLHWAccel) <<
"Selected format" <<
format <<
"for hw" << device_ctx->type;
335 if (noConversionFormat != AV_PIX_FMT_NONE) {
336 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << noConversionFormat;
337 return noConversionFormat;
340 qCDebug(qLHWAccel) <<
"Selected format with conversion" << *suggestedFormats;
343 return *suggestedFormats;
351 return std::unique_ptr<HWAccel>(
new HWAccel(std::move(
ctx)));
358 if (!
frame->hw_frames_ctx)
359 return AVPixelFormat(
frame->format);
380 return m_hwDeviceContext ? (AVHWDeviceContext *)m_hwDeviceContext->data :
nullptr;
390 std::call_once(m_constraintsOnceFlag, [
this]() {
392 m_constraints.reset(av_hwdevice_get_hwframe_constraints(
context,
nullptr));
395 return m_constraints.get();
398std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
401 auto finder = qOverload<AVCodecID, const std::optional<AVHWDeviceType> &,
406std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
415 return m_hwDeviceContext ?
hwDeviceContext()->type : AV_HWDEVICE_TYPE_NONE;
420 if (m_hwFramesContext) {
421 qWarning() <<
"Frames context has been already created!";
425 if (!m_hwDeviceContext)
428 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
429 auto *
c = (AVHWFramesContext *)m_hwFramesContext->data;
431 c->sw_format = swFormat;
432 c->width =
size.width();
433 c->height =
size.height();
434 qCDebug(qLHWAccel) <<
"init frames context";
435 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
437 qWarning() <<
"failed to init HW frame context" << err <<
err2str(err);
439 qCDebug(qLHWAccel) <<
"Initialized frames context" <<
size <<
c->format <<
c->sw_format;
444 return m_hwFramesContext ? (AVHWFramesContext *)m_hwFramesContext->data :
nullptr;
460 return d->backend->getTextures(
frame);
463void TextureConverter::updateBackend(AVPixelFormat
fmt)
465 d->backend =
nullptr;
469 if (!hwTextureConversionEnabled())
474 case AV_PIX_FMT_VAAPI:
475 d->backend = std::make_unique<VAAPITextureConverter>(d->rhi);
479 case AV_PIX_FMT_VIDEOTOOLBOX:
480 d->backend = std::make_unique<VideoToolBoxTextureConverter>(d->rhi);
484 case AV_PIX_FMT_D3D11:
485 d->backend = std::make_unique<D3D11TextureConverter>(d->rhi);
489 case AV_PIX_FMT_MEDIACODEC:
490 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)
std::pair< Format, AVScore > findBestAVFormat(const Format *fmts, const CalculateScore &calculateScore)
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)
bool isAVFormatSupported(const AVCodec *codec, PixelOrSampleFormat format)
const AVCodec * findAVDecoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
constexpr AVScore DefaultAVScore
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 pixelFormatForHwDevice(AVHWDeviceType deviceType)
static bool precheckDriver(AVHWDeviceType type)
Combined button and popup list for selecting options.
#define QT_FFMPEG_HAS_D3D12VA
bool thread_local FFmpegLogsEnabledInThread
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
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)