6#include <QtCore/qdebug.h>
7#include <QtCore/qloggingcategory.h>
8#include <QtCore/qscopeguard.h>
11#include <libavutil/pixdesc.h>
12#include <libavutil/samplefmt.h>
13#include <libavutil/error.h>
16#include <libavutil/hwcontext_videotoolbox.h>
27bool isAVFormatSupported(
const Codec &codec, AVPixelFormat format)
29 if (codec.type() == AVMEDIA_TYPE_VIDEO) {
30 auto checkFormat = [format](AVPixelFormat f) {
33 return findAVPixelFormat(codec, checkFormat).has_value();
38bool isAVFormatSupported(
const Codec &codec, AVSampleFormat format)
40 if (codec.type() == AVMEDIA_TYPE_AUDIO) {
41 const auto sampleFormats = codec.sampleFormats();
42 return ranges::contains(sampleFormats, format);
50 return std::visit([&](
auto fmt) {
51 return isAVFormatSupported(codec, fmt);
57 const auto desc = av_pix_fmt_desc_get(format);
58 return desc && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
63 if (codec.isExperimental()) {
64 qCWarning(qLcFFmpegUtils) <<
"Applying the option 'strict -2' for the experimental codec"
65 << codec.name() <<
". it's unlikely to work properly";
66 av_dict_set(opts,
"strict",
"-2", 0);
73 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
74 return AV_PIX_FMT_VIDEOTOOLBOX;
75 case AV_HWDEVICE_TYPE_VAAPI:
76 return AV_PIX_FMT_VAAPI;
77 case AV_HWDEVICE_TYPE_MEDIACODEC:
78 return AV_PIX_FMT_MEDIACODEC;
79 case AV_HWDEVICE_TYPE_CUDA:
80 return AV_PIX_FMT_CUDA;
81 case AV_HWDEVICE_TYPE_VDPAU:
82 return AV_PIX_FMT_VDPAU;
83 case AV_HWDEVICE_TYPE_OPENCL:
84 return AV_PIX_FMT_OPENCL;
85 case AV_HWDEVICE_TYPE_QSV:
86 return AV_PIX_FMT_QSV;
87 case AV_HWDEVICE_TYPE_D3D11VA:
88 return AV_PIX_FMT_D3D11;
89#if QT_FFMPEG_HAS_D3D12VA
90 case AV_HWDEVICE_TYPE_D3D12VA:
91 return AV_PIX_FMT_D3D12;
93 case AV_HWDEVICE_TYPE_DXVA2:
94 return AV_PIX_FMT_DXVA2_VLD;
95 case AV_HWDEVICE_TYPE_DRM:
96 return AV_PIX_FMT_DRM_PRIME;
97 case AV_HWDEVICE_TYPE_VULKAN:
98 return AV_PIX_FMT_VULKAN;
100 return AV_PIX_FMT_NONE;
106 QScopeGuard freeData([&sideData]() { av_free(sideData.data); });
107#if QT_FFMPEG_STREAM_SIDE_DATA_DEPRECATED
108 AVPacketSideData *result = av_packet_side_data_add(
109 &stream->codecpar->coded_side_data,
110 &stream->codecpar->nb_coded_side_data,
124 qWarning() <<
"Adding stream side data is not supported for FFmpeg < 6.1";
134#if QT_FFMPEG_STREAM_SIDE_DATA_DEPRECATED
135 return av_packet_side_data_get(stream->codecpar->coded_side_data,
136 stream->codecpar->nb_coded_side_data, type);
138 const auto end = stream->side_data + stream->nb_side_data;
139 const auto found = std::find_if(stream->side_data, end, [&](
const auto &item) {
140 return item.type == type;
142 return found == end ?
nullptr : found;
147 const AVAudioFormat &outputFormat)
149 SwrContext *resampler =
nullptr;
150#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
152#if QT_FFMPEG_SWR_CONST_CH_LAYOUT
153 using AVChannelLayoutPrm =
const AVChannelLayout*;
155 using AVChannelLayoutPrm = AVChannelLayout*;
158 swr_alloc_set_opts2(&resampler,
159 const_cast<AVChannelLayoutPrm>(&outputFormat.channelLayout),
160 outputFormat.sampleFormat,
161 outputFormat.sampleRate,
162 const_cast<AVChannelLayoutPrm>(&inputFormat.channelLayout),
163 inputFormat.sampleFormat,
164 inputFormat.sampleRate,
170 resampler = swr_alloc_set_opts(
nullptr,
171 outputFormat.channelLayoutMask,
172 outputFormat.sampleFormat,
173 outputFormat.sampleRate,
174 inputFormat.channelLayoutMask,
175 inputFormat.sampleFormat,
176 inputFormat.sampleRate,
186 qCWarning(qLcFFmpegUtils) <<
"Failed to initialize audio resampler:" << error;
189 return SwrContextUPtr(resampler);
194 case AVCOL_TRC_BT709:
196 case AVCOL_TRC_BT1361_ECG:
197 case AVCOL_TRC_BT2020_10:
198 case AVCOL_TRC_BT2020_12:
199 case AVCOL_TRC_SMPTE240M:
200 return QVideoFrameFormat::ColorTransfer_BT709;
201 case AVCOL_TRC_GAMMA22:
202 case AVCOL_TRC_SMPTE428:
203 case AVCOL_TRC_IEC61966_2_1:
204 case AVCOL_TRC_IEC61966_2_4:
205 return QVideoFrameFormat::ColorTransfer_Gamma22;
206 case AVCOL_TRC_GAMMA28:
207 return QVideoFrameFormat::ColorTransfer_Gamma28;
208 case AVCOL_TRC_SMPTE170M:
209 return QVideoFrameFormat::ColorTransfer_BT601;
210 case AVCOL_TRC_LINEAR:
211 return QVideoFrameFormat::ColorTransfer_Linear;
212 case AVCOL_TRC_SMPTE2084:
213 return QVideoFrameFormat::ColorTransfer_ST2084;
214 case AVCOL_TRC_ARIB_STD_B67:
215 return QVideoFrameFormat::ColorTransfer_STD_B67;
219 return QVideoFrameFormat::ColorTransfer_Unknown;
225 case QVideoFrameFormat::ColorTransfer_BT709:
226 return AVCOL_TRC_BT709;
227 case QVideoFrameFormat::ColorTransfer_BT601:
228 return AVCOL_TRC_BT709;
229 case QVideoFrameFormat::ColorTransfer_Linear:
230 return AVCOL_TRC_SMPTE2084;
231 case QVideoFrameFormat::ColorTransfer_Gamma22:
232 return AVCOL_TRC_GAMMA22;
233 case QVideoFrameFormat::ColorTransfer_Gamma28:
234 return AVCOL_TRC_GAMMA28;
235 case QVideoFrameFormat::ColorTransfer_ST2084:
236 return AVCOL_TRC_SMPTE2084;
237 case QVideoFrameFormat::ColorTransfer_STD_B67:
238 return AVCOL_TRC_ARIB_STD_B67;
240 return AVCOL_TRC_UNSPECIFIED;
246 switch (colorSpace) {
248 case AVCOL_SPC_UNSPECIFIED:
249 case AVCOL_SPC_RESERVED:
251 case AVCOL_SPC_SMPTE240M:
252 case AVCOL_SPC_YCGCO:
253 case AVCOL_SPC_SMPTE2085:
254 case AVCOL_SPC_CHROMA_DERIVED_NCL:
255 case AVCOL_SPC_CHROMA_DERIVED_CL:
256 case AVCOL_SPC_ICTCP:
257 return QVideoFrameFormat::ColorSpace_Undefined;
259 return QVideoFrameFormat::ColorSpace_AdobeRgb;
260 case AVCOL_SPC_BT709:
261 return QVideoFrameFormat::ColorSpace_BT709;
262 case AVCOL_SPC_BT470BG:
263 case AVCOL_SPC_SMPTE170M:
264 return QVideoFrameFormat::ColorSpace_BT601;
265 case AVCOL_SPC_BT2020_NCL:
266 case AVCOL_SPC_BT2020_CL:
267 return QVideoFrameFormat::ColorSpace_BT2020;
273 switch (colorSpace) {
274 case QVideoFrameFormat::ColorSpace_BT601:
275 return AVCOL_SPC_BT470BG;
276 case QVideoFrameFormat::ColorSpace_BT709:
277 return AVCOL_SPC_BT709;
278 case QVideoFrameFormat::ColorSpace_AdobeRgb:
279 return AVCOL_SPC_RGB;
280 case QVideoFrameFormat::ColorSpace_BT2020:
281 return AVCOL_SPC_BT2020_CL;
283 return AVCOL_SPC_UNSPECIFIED;
289 switch (colorRange) {
290 case AVCOL_RANGE_MPEG:
291 return QVideoFrameFormat::ColorRange_Video;
292 case AVCOL_RANGE_JPEG:
293 return QVideoFrameFormat::ColorRange_Full;
295 return QVideoFrameFormat::ColorRange_Unknown;
301 switch (colorRange) {
302 case QVideoFrameFormat::ColorRange_Video:
303 return AVCOL_RANGE_MPEG;
304 case QVideoFrameFormat::ColorRange_Full:
305 return AVCOL_RANGE_JPEG;
307 return AVCOL_RANGE_UNSPECIFIED;
314 if (!frame->hw_frames_ctx)
317 const auto *frameCtx =
reinterpret_cast<AVHWFramesContext *>(frame->hw_frames_ctx->data);
321 return frameCtx->device_ctx;
325 AVPixelFormat dstPixFmt, SwsFlags conversionType)
329 sws_getContext(srcSize.width(), srcSize.height(), srcPixFmt, dstSize.width(),
330 dstSize.height(), dstPixFmt, conversionType,
nullptr,
nullptr,
nullptr);
333 qCWarning(qLcFFmpegUtils) <<
"Cannot create sws context for:\n"
334 <<
"srcSize:" << srcSize
335 <<
"srcPixFmt:" << srcPixFmt
336 <<
"dstSize:" << dstSize
337 <<
"dstPixFmt:" << dstPixFmt
338 <<
"conversionType:" << conversionType;
340 return SwsContextUPtr(result);
361 dbg << value.num <<
"/" << value.den;
368 auto freeBuffer = QScopeGuard([&] {
372 int status = av_dict_get_string(&dict, &buffer,
'=',
',');
373 if (status < 0 || !buffer)
374 return dbg <<
"Failed to print AVDictionary";
382 const AVDictionary *rawDict = dict.opts;
384 return dbg << *rawDict;
386 return dbg <<
"Empty AVDictionaryHolder";
396 char errBuf[AV_ERROR_MAX_STRING_SIZE];
397 dbg << av_make_error_string(errBuf, AV_ERROR_MAX_STRING_SIZE, qToUnderlying(error));
403 const char *str = av_get_pix_fmt_name(fmt);
407 dbg <<
"<unknown pixel format>";
413 const char *str = av_hwdevice_get_type_name(type);
417 dbg <<
"<unknown hw device type>";
423 const char *str = av_get_media_type_string(type);
427 dbg <<
"<unknown hw media type>";
433 const char *str = avcodec_get_name(id);
437 dbg <<
"<unknown codec id>";
443 if (fmt ==
nullptr) {
448 const char *str = fmt->name;
452 dbg <<
"<unknown output format>";
458 if (fmt ==
nullptr) {
463 const char *str = fmt->name;
467 dbg <<
"<unknown input format>";
471#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
472QDebug operator<<(QDebug dbg,
const AVChannelLayout &layout)
475 dbg <<
"nb_channels:" << layout.nb_channels;
476 dbg <<
", order:" << layout.order;
478 if (layout.order == AV_CHANNEL_ORDER_NATIVE || layout.order == AV_CHANNEL_ORDER_AMBISONIC)
479 dbg <<
", mask:" << Qt::bin << layout.u.mask << Qt::dec;
480 else if (layout.order == AV_CHANNEL_ORDER_CUSTOM && layout.u.map)
481 dbg <<
", id: " << layout.u.map->id;
489#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
490QDebug operator<<(QDebug dbg,
const AVCodecConfig value)
493 case AV_CODEC_CONFIG_CHANNEL_LAYOUT:
494 dbg <<
"AV_CODEC_CONFIG_CHANNEL_LAYOUT";
496 case AV_CODEC_CONFIG_COLOR_RANGE:
497 dbg <<
"AV_CODEC_CONFIG_COLOR_RANGE";
499 case AV_CODEC_CONFIG_COLOR_SPACE:
500 dbg <<
"AV_CODEC_CONFIG_COLOR_SPACE";
502 case AV_CODEC_CONFIG_FRAME_RATE:
503 dbg <<
"AV_CODEC_CONFIG_FRAME_RATE";
505 case AV_CODEC_CONFIG_PIX_FORMAT:
506 dbg <<
"AV_CODEC_CONFIG_PIX_FORMAT";
508 case AV_CODEC_CONFIG_SAMPLE_FORMAT:
509 dbg <<
"AV_CODEC_CONFIG_SAMPLE_FORMAT";
511 case AV_CODEC_CONFIG_SAMPLE_RATE:
512 dbg <<
"AV_CODEC_CONFIG_SAMPLE_RATE";
515 dbg <<
"<UNKNOWN_CODEC_CONFIG>";
530QString flagsToString(
int flags,
const QSpan<
const FlagName> &flagNames)
533 int leftover = flags;
534 for (
const auto &flagAndName : flagNames)
535 if ((flags & flagAndName.value) != 0) {
536 leftover &= ~flagAndName.value;
537 if (!result.isEmpty())
539 result += QLatin1StringView(flagAndName.name);
543 if (!result.isEmpty())
545 result += QString::number(leftover, 16);
554 static constexpr std::array<FlagName, 21> flagNames = {{
555 { AV_CODEC_CAP_DRAW_HORIZ_BAND,
"DRAW_HORIZ_BAND" },
556 { AV_CODEC_CAP_DR1,
"DR1" },
557 { AV_CODEC_CAP_DELAY,
"DELAY" },
558 { AV_CODEC_CAP_SMALL_LAST_FRAME,
"SMALL_LAST_FRAME" },
559#ifdef AV_CODEC_CAP_SUBFRAMES
560 { AV_CODEC_CAP_SUBFRAMES,
"SUBFRAMES" },
562 { AV_CODEC_CAP_EXPERIMENTAL,
"EXPERIMENTAL" },
563 { AV_CODEC_CAP_CHANNEL_CONF,
"CHANNEL_CONF" },
564 { AV_CODEC_CAP_FRAME_THREADS,
"FRAME_THREADS" },
565 { AV_CODEC_CAP_SLICE_THREADS,
"SLICE_THREADS" },
566 { AV_CODEC_CAP_PARAM_CHANGE,
"PARAM_CHANGE" },
567 { AV_CODEC_CAP_OTHER_THREADS,
"OTHER_THREADS" },
568 { AV_CODEC_CAP_VARIABLE_FRAME_SIZE,
"VARIABLE_FRAME_SIZE" },
569 { AV_CODEC_CAP_AVOID_PROBING,
"AVOID_PROBING" },
570 { AV_CODEC_CAP_HARDWARE,
"HARDWARE" },
571 { AV_CODEC_CAP_HYBRID,
"HYBRID" },
572 { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
"ENCODER_REORDERED_OPAQUE" },
573 { AV_CODEC_CAP_ENCODER_FLUSH,
"ENCODER_FLUSH" },
575 return flagsToString(qToUnderlying(capabilities), QSpan(flagNames));
580 static constexpr std::array<FlagName, 9> flagNames = {{
581 { AV_PIX_FMT_FLAG_BE,
"BE" },
582 { AV_PIX_FMT_FLAG_PAL,
"PAL" },
583 { AV_PIX_FMT_FLAG_BITSTREAM,
"BITSTREAM" },
584 { AV_PIX_FMT_FLAG_HWACCEL,
"HWACCEL" },
585 { AV_PIX_FMT_FLAG_PLANAR,
"PLANAR" },
586 { AV_PIX_FMT_FLAG_RGB,
"RGB" },
587 { AV_PIX_FMT_FLAG_ALPHA,
"ALPHA" },
588 { AV_PIX_FMT_FLAG_BAYER,
"BAYER" },
589 { AV_PIX_FMT_FLAG_FLOAT,
"FLOAT" },
591 return flagsToString(qToUnderlying(flags), QSpan(flagNames));
596 static constexpr std::array<FlagName, 4> flagNames = {{
597 { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
"HW_DEVICE_CTX" },
598 { AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX,
"HW_FRAMES_CTX" },
599 { AV_CODEC_HW_CONFIG_METHOD_INTERNAL,
"INTERNAL" },
600 { AV_CODEC_HW_CONFIG_METHOD_AD_HOC,
"AD_HOC" }
602 return flagsToString(qToUnderlying(methods), QSpan(flagNames));
607 return dbg <<
QFFmpeg::toString(caps);
612 return dbg <<
QFFmpeg::toString(flags);
617 return dbg <<
QFFmpeg::toString(methods);
AVColorSpace toAvColorSpace(QVideoFrameFormat::ColorSpace colorSpace)
SwsContextUPtr createSwsContext(const QSize &srcSize, AVPixelFormat srcPixFmt, const QSize &dstSize, AVPixelFormat dstPixFmt, SwsFlags conversionType)
void applyExperimentalCodecOptions(const Codec &codec, AVDictionary **opts)
bool isHwPixelFormat(AVPixelFormat format)
AVPacketSideData * addStreamSideData(AVStream *stream, AVPacketSideData sideData)
AVHWDeviceContext * avFrameDeviceContext(const AVFrame *frame)
AVColorTransferCharacteristic toAvColorTransfer(QVideoFrameFormat::ColorTransfer colorTrc)
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
QString toString(AVPixelFormatFlags flags)
QVideoFrameFormat::ColorSpace fromAvColorSpace(AVColorSpace colorSpace)
QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc)
QVideoFrameFormat::ColorRange fromAvColorRange(AVColorRange colorRange)
SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat, const AVAudioFormat &outputFormat)
AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
QString toString(AVCodecCapabilities capabilities)
bool isAVFormatSupported(const Codec &codec, const PixelOrSampleFormat &format)
const AVPacketSideData * streamSideData(const AVStream *stream, AVPacketSideDataType type)
AVColorRange toAvColorRange(QVideoFrameFormat::ColorRange colorRange)
QString toString(AVHwConfigMethods methods)
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
QDebug operator<<(QDebug debug, QDir::Filters filters)
QDebug operator<<(QDebug dbg, const QFFmpeg::AVDictionaryHolder &dict)
QDebug operator<<(QDebug dbg, QFFmpeg::AVCodecCapabilities caps)
QDebug operator<<(QDebug dbg, QFFmpeg::AVPixelFormatFlags flags)
QDebug operator<<(QDebug dbg, QFFmpeg::AVHwConfigMethods methods)
QDebug operator<<(QDebug dbg, QFFmpeg::AVError error)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)