4#include "libavutil/version.h"
35#if defined(Q_OS_ANDROID)
36 AV_HWDEVICE_TYPE_MEDIACODEC,
37#elif defined(Q_OS_LINUX)
38 AV_HWDEVICE_TYPE_VAAPI,
39 AV_HWDEVICE_TYPE_VDPAU,
40 AV_HWDEVICE_TYPE_CUDA,
41#elif defined (Q_OS_WIN)
42 AV_HWDEVICE_TYPE_D3D11VA,
43#elif defined (Q_OS_DARWIN)
44 AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
48static std::vector<AVHWDeviceType>
deviceTypes(
const char *envVarName)
50 std::vector<AVHWDeviceType>
result;
52 const auto definedDeviceTypes =
qgetenv(envVarName);
53 if (!definedDeviceTypes.isNull()) {
55 for (
const auto &
deviceType : definedDeviceTypesString.split(
',')) {
57 const auto foundType = av_hwdevice_find_type_by_name(
deviceType.toUtf8().data());
58 if (foundType == AV_HWDEVICE_TYPE_NONE)
61 result.emplace_back(foundType);
67 std::set<AVHWDeviceType> deviceTypesSet;
68 AVHWDeviceType
type = AV_HWDEVICE_TYPE_NONE;
69 while ((
type = av_hwdevice_iterate_types(
type)) != AV_HWDEVICE_TYPE_NONE)
70 deviceTypesSet.insert(
type);
73 if (deviceTypesSet.erase(preffered))
74 result.push_back(preffered);
76 result.insert(
result.end(), deviceTypesSet.begin(), deviceTypesSet.end());
85 AVBufferRef *hwContext =
nullptr;
86 int ret = av_hwdevice_ctx_create(&hwContext,
type,
nullptr,
nullptr, 0);
87 qCDebug(qLHWAccel) <<
" Checking HW context:" << av_hwdevice_get_type_name(
type);
89 qCDebug(qLHWAccel) <<
" Using above hw context.";
92 qCDebug(qLHWAccel) <<
" Could not create hw context:" <<
ret << strerror(-
ret);
96template<
typename CodecFinder>
97std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
99 CodecFinder codecFinder,
100 const std::function<
bool(
const HWAccel &)> &hwAccelPredicate)
103 const auto codec = codecFinder(
id,
type, {});
108 qCDebug(qLHWAccel) <<
"Found potential codec" <<
codec->name <<
"for hw accel" <<
type
109 <<
"; Checking the hw device...";
116 if (hwAccelPredicate && !hwAccelPredicate(*hwAccel)) {
117 qCDebug(qLHWAccel) <<
"HW device is available but doesn't suit due to restrictions";
121 qCDebug(qLHWAccel) <<
"HW device is OK";
123 return {
codec, std::move(hwAccel) };
126 qCDebug(qLHWAccel) <<
"No hw acceleration found for codec id" <<
id;
128 return {
nullptr,
nullptr };
133 bool needsConversion =
true;
135 return !needsConversion;
139AVPixelFormat
getFormat(AVCodecContext *codecContext,
const AVPixelFormat *suggestedFormats)
142 if (codecContext->hw_device_ctx) {
143 auto *device_ctx = (AVHWDeviceContext *)codecContext->hw_device_ctx->data;
148 const AVCodecHWConfig *
config = avcodec_get_hw_config(codecContext->codec,
i);
i++) {
149 if (!(
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
152 if (device_ctx->type !=
config->device_type)
155 const bool isDeprecated = (
config->methods & AV_CODEC_HW_CONFIG_METHOD_AD_HOC) != 0;
156 const bool shouldCheckCodecFormats =
config->pix_fmt == AV_PIX_FMT_NONE;
158 auto scoresGettor = [&](AVPixelFormat
format) {
162 if (!shouldCheckCodecFormats &&
config->pix_fmt !=
format)
177 if (found.second > formatAndScore.second)
178 formatAndScore = found;
181 const auto &
format = formatAndScore.first;
182 if (
format != AV_PIX_FMT_NONE) {
184 if (
format == AV_PIX_FMT_D3D11)
185 QFFmpeg::D3D11TextureConverter::SetupDecoderTextures(codecContext);
188 if (
format == AV_PIX_FMT_MEDIACODEC)
191 qCDebug(qLHWAccel) <<
"Selected format" <<
format <<
"for hw" << device_ctx->type;
198 if (noConversionFormat != AV_PIX_FMT_NONE) {
199 qCDebug(qLHWAccel) <<
"Selected format with no conversion" << noConversionFormat;
200 return noConversionFormat;
203 qCDebug(qLHWAccel) <<
"Selected format with conversion" << *suggestedFormats;
206 return *suggestedFormats;
209TextureConverter::Data::~Data()
219 return std::unique_ptr<HWAccel>(
new HWAccel(
ctx));
226 if (!
frame->hw_frames_ctx)
227 return AVPixelFormat(
frame->format);
248 return m_hwDeviceContext ? (AVHWDeviceContext *)m_hwDeviceContext->data :
nullptr;
262std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
265 auto finder = qOverload<AVCodecID, const std::optional<AVHWDeviceType> &,
270std::pair<const AVCodec *, std::unique_ptr<HWAccel>>
279 return m_hwDeviceContext ?
hwDeviceContext()->type : AV_HWDEVICE_TYPE_NONE;
284 if (m_hwFramesContext) {
285 qWarning() <<
"Frames context has been already created!";
289 if (!m_hwDeviceContext)
292 m_hwFramesContext.reset(av_hwframe_ctx_alloc(m_hwDeviceContext.get()));
293 auto *
c = (AVHWFramesContext *)m_hwFramesContext->data;
295 c->sw_format = swFormat;
296 c->width =
size.width();
297 c->height =
size.height();
298 qCDebug(qLHWAccel) <<
"init frames context";
299 int err = av_hwframe_ctx_init(m_hwFramesContext.get());
301 qWarning() <<
"failed to init HW frame context" << err <<
err2str(err);
303 qCDebug(qLHWAccel) <<
"Initialized frames context" <<
size <<
c->format <<
c->sw_format;
308 return m_hwFramesContext ? (AVHWFramesContext *)m_hwFramesContext->data :
nullptr;
324 return d->backend->getTextures(
frame);
327void TextureConverter::updateBackend(AVPixelFormat
fmt)
329 d->backend =
nullptr;
335 static const bool disableConversion =
338 if (disableConversion)
343 case AV_PIX_FMT_VAAPI:
344 d->backend =
new VAAPITextureConverter(d->rhi);
348 case AV_PIX_FMT_VIDEOTOOLBOX:
349 d->backend =
new VideoToolBoxTextureConverter(d->rhi);
353 case AV_PIX_FMT_D3D11:
354 d->backend =
new D3D11TextureConverter(d->rhi);
358 case AV_PIX_FMT_MEDIACODEC:
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
AVHWFramesConstraintsUPtr constraints() 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
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)
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString toLower() const &
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)
std::unique_ptr< AVHWFramesConstraints, AVDeleter< decltype(&av_hwframe_constraints_free), &av_hwframe_constraints_free > > AVHWFramesConstraintsUPtr
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
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
static AVBufferRef * loadHWContext(const AVHWDeviceType type)
AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
static std::vector< AVHWDeviceType > deviceTypes(const char *envVarName)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum format
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
QVideoFrameFormat::PixelFormat fmt
static QInputDevice::DeviceType deviceType(const UINT cursorType)