16#include <libavutil/pixdesc.h>
17#include <libavutil/samplefmt.h>
20#include <libavutil/hwcontext_videotoolbox.h>
32enum CodecStorageType {
38 CODEC_STORAGE_TYPE_COUNT
41using CodecsStorage = std::vector<const AVCodec *>;
43struct CodecsComparator
45 bool operator()(
const AVCodec *
a,
const AVCodec *
b)
const {
return a->id <
b->id; }
47 bool operator()(
const AVCodec *
a, AVCodecID
id)
const {
return a->id <
id; }
50static void dumpCodecInfo(
const AVCodec *
codec)
52 const auto mediaType =
codec->type == AVMEDIA_TYPE_VIDEO ?
"video"
53 :
codec->type == AVMEDIA_TYPE_AUDIO ?
"audio"
54 :
codec->type == AVMEDIA_TYPE_SUBTITLE ?
"subtitle"
56 qCDebug(qLcFFmpegUtils) << mediaType << (av_codec_is_encoder(
codec) ?
"encoder:" :
"decoder:")
58 <<
"capabilities:" <<
codec->capabilities;
59 if (
codec->pix_fmts) {
60 qCDebug(qLcFFmpegUtils) <<
" pix_fmts:";
61 for (
auto f =
codec->pix_fmts; *
f != AV_PIX_FMT_NONE; ++
f) {
62 auto desc = av_pix_fmt_desc_get(*
f);
64 << ((
desc->flags & AV_PIX_FMT_FLAG_HWACCEL) ?
"hw" :
"sw")
69 if (
codec->sample_fmts) {
70 qCDebug(qLcFFmpegUtils) <<
" sample_fmts:";
71 for (
auto f =
codec->sample_fmts; *
f != AV_SAMPLE_FMT_NONE; ++
f) {
72 const auto name = av_get_sample_fmt_name(*
f);
74 <<
"bytes_per_sample:" << av_get_bytes_per_sample(*
f)
75 <<
"is_planar:" << av_sample_fmt_is_planar(*
f);
79 if (avcodec_get_hw_config(
codec, 0)) {
80 qCDebug(qLcFFmpegUtils) <<
" hw config:";
83 auto pixFmtDesc = av_pix_fmt_desc_get(
config->pix_fmt);
84 auto pixFmtForDeviceDesc = av_pix_fmt_desc_get(pixFmtForDevice);
86 <<
" device_type:" <<
config->device_type <<
"pix_fmt:" <<
config->pix_fmt
87 << (pixFmtDesc ? pixFmtDesc->name :
"unknown")
89 << (pixFmtForDeviceDesc ? pixFmtForDeviceDesc->name :
"unknown");
94static bool isCodecValid(
const AVCodec *encoder,
95 const std::vector<AVHWDeviceType> &availableHwDeviceTypes)
97 if (encoder->type != AVMEDIA_TYPE_VIDEO)
100 if (!encoder->pix_fmts)
104 auto checkFormat = [&](AVPixelFormat pixelFormat) {
108 return std::any_of(availableHwDeviceTypes.begin(), availableHwDeviceTypes.end(),
109 [&pixelFormat](AVHWDeviceType
type) {
110 return pixelFormatForHwDevice(type) == pixelFormat;
114 return findAVFormat(encoder->pix_fmts, checkFormat) != AV_PIX_FMT_NONE;
117const CodecsStorage &codecsStorage(CodecStorageType codecsType)
119 static const auto &storages = []() {
120 std::array<CodecsStorage, CODEC_STORAGE_TYPE_COUNT>
result;
121 void *opaque =
nullptr;
123 while (
auto codec = av_codec_iterate(&opaque)) {
129 if (
codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) {
130 qCDebug(qLcFFmpegUtils) <<
"Skip experimental codec" <<
codec->name;
134 if (av_codec_is_decoder(
codec)) {
138 qCDebug(qLcFFmpegUtils) <<
"Skip decoder" <<
codec->name
139 <<
"due to disabled matching hw acceleration";
142 if (av_codec_is_encoder(
codec)) {
146 qCDebug(qLcFFmpegUtils) <<
"Skip encoder" <<
codec->name
147 <<
"due to disabled matching hw acceleration";
155 std::stable_sort(
storage.begin(),
storage.end(), CodecsComparator{});
159 const bool shouldDumpCodecsInfo = qLcFFmpegUtils().isEnabled(
QtDebugMsg)
162 if (shouldDumpCodecsInfo) {
163 qCDebug(qLcFFmpegUtils) <<
"Advanced ffmpeg codecs info:";
166 qCDebug(qLcFFmpegUtils) <<
"---------------------------";
173 return storages[codecsType];
176static const char *preferredHwCodecNameSuffix(
bool isEncoder, AVHWDeviceType
deviceType)
179 case AV_HWDEVICE_TYPE_VAAPI:
181 case AV_HWDEVICE_TYPE_MEDIACODEC:
182 return "_mediacodec";
183 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
184 return "_videotoolbox";
185 case AV_HWDEVICE_TYPE_D3D11VA:
186 case AV_HWDEVICE_TYPE_DXVA2:
188 case AV_HWDEVICE_TYPE_CUDA:
189 case AV_HWDEVICE_TYPE_VDPAU:
190 return isEncoder ?
"_nvenc" :
"_cuvid";
196template<
typename CodecScoreGetter>
197const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID
codecId,
198 const CodecScoreGetter &scoreGetter)
200 const auto &
storage = codecsStorage(codecsType);
203 const AVCodec *
result =
nullptr;
207 const auto score = scoreGetter(*
it);
209 if (score > resultScore) {
220 if (
auto suffix = preferredHwCodecNameSuffix(av_codec_is_encoder(
codec),
deviceType)) {
221 const auto substr = strstr(
codec->name, suffix);
222 if (substr && !substr[strlen(suffix)])
231const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID
codecId,
232 const std::optional<AVHWDeviceType> &
deviceType,
233 const std::optional<PixelOrSampleFormat> &
format)
235 return findAVCodec(codecsType,
codecId, [&](
const AVCodec *
codec) {
271 const std::optional<PixelOrSampleFormat> &
format)
277 const std::optional<PixelOrSampleFormat> &
format)
283 const std::function<
AVScore(
const AVCodec *)> &scoresGetter)
285 return findAVCodec(ENCODERS,
codecId, scoresGetter);
290 if (
codec->type == AVMEDIA_TYPE_VIDEO)
293 if (
codec->type == AVMEDIA_TYPE_AUDIO)
301 const auto desc = av_pix_fmt_desc_get(
format);
302 return desc && (
desc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
308 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
309 return AV_PIX_FMT_VIDEOTOOLBOX;
310 case AV_HWDEVICE_TYPE_VAAPI:
311 return AV_PIX_FMT_VAAPI;
312 case AV_HWDEVICE_TYPE_MEDIACODEC:
313 return AV_PIX_FMT_MEDIACODEC;
314 case AV_HWDEVICE_TYPE_CUDA:
315 return AV_PIX_FMT_CUDA;
316 case AV_HWDEVICE_TYPE_VDPAU:
317 return AV_PIX_FMT_VDPAU;
318 case AV_HWDEVICE_TYPE_OPENCL:
319 return AV_PIX_FMT_OPENCL;
320 case AV_HWDEVICE_TYPE_QSV:
321 return AV_PIX_FMT_QSV;
322 case AV_HWDEVICE_TYPE_D3D11VA:
323 return AV_PIX_FMT_D3D11;
324 case AV_HWDEVICE_TYPE_DXVA2:
325 return AV_PIX_FMT_DXVA2_VLD;
326 case AV_HWDEVICE_TYPE_DRM:
327 return AV_PIX_FMT_DRM_PRIME;
328#if QT_FFMPEG_HAS_VULKAN
329 case AV_HWDEVICE_TYPE_VULKAN:
330 return AV_PIX_FMT_VULKAN;
333 return AV_PIX_FMT_NONE;
338bool isCVFormatSupported(uint32_t cvFormat)
340 return av_map_videotoolbox_format_to_pixfmt(cvFormat) != AV_PIX_FMT_NONE;
343std::string cvFormatToString(uint32_t cvFormat)
345 auto formatDescIt = std::make_reverse_iterator(
reinterpret_cast<const char *
>(&cvFormat));
346 return std::string(formatDescIt - 4, formatDescIt);
static const std::vector< AVHWDeviceType > & decodingDeviceTypes()
static const std::vector< AVHWDeviceType > & encodingDeviceTypes()
QSet< QString >::iterator it
constexpr AVScore BestAVScore
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
bool isHwPixelFormat(AVPixelFormat format)
bool isAVFormatSupported(const AVCodec *codec, PixelOrSampleFormat format)
const AVCodec * findAVDecoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
bool isSwPixelFormat(AVPixelFormat format)
constexpr AVScore DefaultAVScore
bool hasAVFormat(const Format *fmts, Format format)
Format findAVFormat(const Format *fmts, const Predicate &predicate)
constexpr AVScore NotSuitableAVScore
AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLint GLenum GLsizei GLsizei GLsizei depth
GLboolean GLboolean GLboolean GLboolean a
[7]
GLint GLsizei GLsizei GLenum format
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
static QInputDevice::DeviceType deviceType(const UINT cursorType)