Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qffmpegvideoencoderutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6extern "C" {
7#include <libavutil/pixdesc.h>
8}
9
11
12namespace QFFmpeg {
13
14static AVScore calculateTargetSwFormatScore(const AVPixFmtDescriptor *sourceSwFormatDesc,
15 AVPixelFormat fmt)
16{
17 const auto *desc = av_pix_fmt_desc_get(fmt);
18 if (!desc)
19 return NotSuitableAVScore;
20
21 const int sourceDepth = sourceSwFormatDesc ? sourceSwFormatDesc->comp[0].depth : 0;
22
23 if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
24 // we really don't want HW accelerated formats here
25 return NotSuitableAVScore;
26
27 auto score = DefaultAVScore;
28
29 if (desc == sourceSwFormatDesc)
30 // prefer exact matches
31 score += 10;
32 if (desc->comp[0].depth == sourceDepth)
33 score += 100;
34 else if (desc->comp[0].depth < sourceDepth)
35 score -= 100 + (sourceDepth - desc->comp[0].depth);
36 if (desc->log2_chroma_h == 1)
37 score += 1;
38 if (desc->log2_chroma_w == 1)
39 score += 1;
40 if (desc->flags & AV_PIX_FMT_FLAG_BE)
41 score -= 10;
42 if (desc->flags & AV_PIX_FMT_FLAG_PAL)
43 // we don't want paletted formats
44 score -= 10000;
45 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
46 // we don't want RGB formats
47 score -= 1000;
48
49 // qCDebug(qLcVideoFrameEncoder)
50 // << "checking format" << fmt << Qt::hex << desc->flags << desc->comp[0].depth
51 // << desc->log2_chroma_h << desc->log2_chroma_w << "score:" << score;
52
53 return score;
54}
55
56static AVScore calculateTargetFormatScore(const HWAccel *accel, AVPixelFormat sourceFormat,
57 const AVPixFmtDescriptor *sourceSwFormatDesc,
58 AVPixelFormat fmt)
59{
60 if (accel) {
61 // accept source format as the best one to ensure zero-copy
62 // TODO: maybe, checking of accel->hwFormat() should go first,
63 // to be investigated
64 if (fmt == sourceFormat)
65 return BestAVScore;
66
67 if (accel->hwFormat() == fmt)
68 return BestAVScore - 1;
69
70 // The case is suspicious, but probably we should accept it
72 return BestAVScore - 2;
73 } else {
75 return NotSuitableAVScore;
76
77 if (fmt == sourceFormat)
78 return BestAVScore;
79 }
80
81 return calculateTargetSwFormatScore(sourceSwFormatDesc, fmt);
82}
83
84static auto targetFormatScoreCalculator(const HWAccel *accel, AVPixelFormat sourceFormat,
85 AVPixelFormat sourceSWFormat)
86{
87 const auto sourceSwFormatDesc = av_pix_fmt_desc_get(sourceSWFormat);
88 return [=](AVPixelFormat fmt) {
89 return calculateTargetFormatScore(accel, sourceFormat, sourceSwFormatDesc, fmt);
90 };
91}
92
93AVPixelFormat findTargetSWFormat(AVPixelFormat sourceSWFormat, const HWAccel &accel)
94{
95 // determine the format used by the encoder.
96 // We prefer YUV422 based formats such as NV12 or P010. Selection trues to find the best
97 // matching format for the encoder depending on the bit depth of the source format
98
99 const auto sourceFormatDesc = av_pix_fmt_desc_get(sourceSWFormat);
100 const auto constraints = accel.constraints();
101
102 if (!constraints || !constraints->valid_sw_formats)
103 return sourceSWFormat;
104
105 auto [format, scores] = findBestAVFormat(constraints->valid_sw_formats, [&](AVPixelFormat fmt) {
106 return calculateTargetSwFormatScore(sourceFormatDesc, fmt);
107 });
108
109 return format;
110}
111
112AVPixelFormat findTargetFormat(AVPixelFormat sourceFormat, AVPixelFormat sourceSWFormat,
113 const AVCodec *codec, const HWAccel *accel)
114{
115 if (!codec->pix_fmts) {
116 qWarning() << "Codec pix formats are undefined, it's likely to behave incorrectly";
117
118 // if no accel created, accept only sw format
119 return accel || !isHwPixelFormat(sourceFormat) ? sourceFormat : sourceSWFormat;
120 }
121
122 auto scoreCalculator = targetFormatScoreCalculator(accel, sourceFormat, sourceSWFormat);
123 return findBestAVFormat(codec->pix_fmts, scoreCalculator).first;
124}
125
126std::pair<const AVCodec *, std::unique_ptr<HWAccel>> findHwEncoder(AVCodecID codecID,
127 const QSize &sourceSize)
128{
129 auto matchesSizeConstraints = [&sourceSize](const HWAccel &accel) {
130 const auto constraints = accel.constraints();
131 if (!constraints)
132 return true;
133
134 return sourceSize.width() >= constraints->min_width
135 && sourceSize.height() >= constraints->min_height
136 && sourceSize.width() <= constraints->max_width
137 && sourceSize.height() <= constraints->max_height;
138 };
139
140 // 1st - attempt to find hw accelerated encoder
141 auto result = HWAccel::findEncoderWithHwAccel(codecID, matchesSizeConstraints);
142 Q_ASSERT(!!result.first == !!result.second);
143
144 return result;
145}
146
147const AVCodec *findSwEncoder(AVCodecID codecID, AVPixelFormat sourceFormat,
148 AVPixelFormat sourceSWFormat)
149{
150 auto formatScoreCalculator = targetFormatScoreCalculator(nullptr, sourceFormat, sourceSWFormat);
151
152 return findAVEncoder(codecID, [&formatScoreCalculator](const AVCodec *codec) {
153 if (!codec->pix_fmts)
154 // codecs without pix_fmts are suspicious
155 return MinAVScore;
156
157 return findBestAVFormat(codec->pix_fmts, formatScoreCalculator).second;
158 });
159}
160
161} // namespace QFFmpeg
162
AVHWFramesConstraintsUPtr constraints() const
static std::pair< const AVCodec *, std::unique_ptr< HWAccel > > findEncoderWithHwAccel(AVCodecID id, const std::function< bool(const HWAccel &)> &hwAccelPredicate=nullptr)
AVPixelFormat hwFormat() const
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr AVScore BestAVScore
Definition qffmpeg_p.h:140
std::pair< const AVCodec *, std::unique_ptr< HWAccel > > findHwEncoder(AVCodecID codecID, const QSize &sourceSize)
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
Definition qffmpeg.cpp:276
std::pair< Format, AVScore > findBestAVFormat(const Format *fmts, const CalculateScore &calculateScore)
Definition qffmpeg_p.h:174
AVPixelFormat findTargetFormat(AVPixelFormat sourceFormat, AVPixelFormat sourceSWFormat, const AVCodec *codec, const HWAccel *accel)
bool isHwPixelFormat(AVPixelFormat format)
Definition qffmpeg.cpp:299
AVPixelFormat findTargetSWFormat(AVPixelFormat sourceSWFormat, const HWAccel &accel)
constexpr AVScore DefaultAVScore
Definition qffmpeg_p.h:141
int AVScore
Definition qffmpeg_p.h:139
constexpr AVScore NotSuitableAVScore
Definition qffmpeg_p.h:142
static AVScore calculateTargetFormatScore(const HWAccel *accel, AVPixelFormat sourceFormat, const AVPixFmtDescriptor *sourceSwFormatDesc, AVPixelFormat fmt)
static AVScore calculateTargetSwFormatScore(const AVPixFmtDescriptor *sourceSwFormatDesc, AVPixelFormat fmt)
const AVCodec * findSwEncoder(AVCodecID codecID, AVPixelFormat sourceFormat, AVPixelFormat sourceSWFormat)
constexpr AVScore MinAVScore
Definition qffmpeg_p.h:143
static auto targetFormatScoreCalculator(const HWAccel *accel, AVPixelFormat sourceFormat, AVPixelFormat sourceSWFormat)
Combined button and popup list for selecting options.
QMediaFormat::AudioCodec codec
#define qWarning
Definition qlogging.h:162
GLint GLsizei GLsizei GLenum format
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
@ desc
QVideoFrameFormat::PixelFormat fmt