6#include <QtMultimedia/private/qmultimediautils_p.h>
7#include <QtCore/qoperatingsystemversion.h>
8#include <QtCore/private/qminimalflatset_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qffmpegrecordingengineutils_p.h>
12#include <libavutil/pixdesc.h>
23bool is16BitFormat(
const AVPixFmtDescriptor *desc)
25 return desc->comp[0].depth == 16;
28bool is10BitFormat(
const AVPixFmtDescriptor *desc)
30 return desc->comp[0].depth == 10;
33bool is8BitFormat(
const AVPixFmtDescriptor *desc)
35 return desc->comp[0].depth == 8;
38bool is444Format(
const AVPixFmtDescriptor *desc)
40 return desc->log2_chroma_h == 0 && desc->log2_chroma_w == 0;
43bool is422Format(
const AVPixFmtDescriptor *desc)
45 return desc->log2_chroma_h == 1 && desc->log2_chroma_w == 0;
48bool is420Format(
const AVPixFmtDescriptor *desc)
50 return desc->log2_chroma_h == 1 && desc->log2_chroma_w == 1;
53bool isGreyFormat(
const AVPixFmtDescriptor *desc)
55 return desc->nb_components == 1;
58AVScore scoreTargetSwFormat(
const AVPixFmtDescriptor *sourceSwFormatDesc, AVPixelFormat fmt)
64 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
66 return NotSuitableAVScore;
68 if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
70 return NotSuitableAVScore;
72 AVScore score = DefaultAVScore;
74 if (desc == sourceSwFormatDesc)
78 const int sourceBpp = av_get_bits_per_pixel(sourceSwFormatDesc);
79 const int bpp = av_get_bits_per_pixel(desc);
84 else if (bpp < sourceBpp)
85 score -= 100 + (sourceBpp - bpp);
88 if (is8BitFormat(sourceSwFormatDesc)) {
89 if (is10BitFormat(desc))
91 else if (is16BitFormat(desc))
96 if (is420Format(desc))
98 else if (is422Format(desc))
100 else if (is444Format(desc))
103 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Android) {
106 if (fmt == AV_PIX_FMT_NV12)
110 if (isGreyFormat(desc) && !isGreyFormat(sourceSwFormatDesc))
111 return AVScore::NotSuitableAVScore;
113 if (desc->flags & AV_PIX_FMT_FLAG_BE)
115 if (desc->flags & AV_PIX_FMT_FLAG_PAL)
117 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
123auto targetSwFormatScoreCalculator(AVPixelFormat sourceFormat)
125 const auto sourceSwFormatDesc = av_pix_fmt_desc_get(sourceFormat);
126 return [=](AVPixelFormat fmt) {
127 return scoreTargetSwFormat(sourceSwFormatDesc, fmt);
131bool isHwFormatAcceptedByCodec(AVPixelFormat pixFormat)
134 case AV_PIX_FMT_MEDIACODEC:
145 const HWAccel &accel,
146 const AVPixelFormatSet &prohibitedFormats)
148 using namespace QtMultimediaPrivate;
150 auto scoreTargetSwFormat = targetSwFormatScoreCalculator(sourceSWFormat);
152 const auto constraints = accel.constraints();
153 if (constraints && constraints->valid_sw_formats) {
155 const auto validSWFormatsForHWAccel =
156 makeSpan(constraints->valid_sw_formats) | ranges::to<QMinimalFlatSet>();
158 const auto codecPixelFormats = codec.pixelFormats();
159 auto validCodecPixelFormats = views::filter(codecPixelFormats, [&](AVPixelFormat fmt) {
160 if (!validSWFormatsForHWAccel.contains(fmt))
163 return !prohibitedFormats.count(fmt);
166 if constexpr (
false) {
167 qDebug() <<
"validSWFormats" << (validSWFormatsForHWAccel | ranges::to<std::vector>())
168 <<
"scoredPixelFormats"
169 << (validCodecPixelFormats | views::transform([&](
auto arg) {
170 return std::pair(arg, scoreTargetSwFormat(arg));
171 }) | ranges::to<std::vector>());
174 std::optional bestPixelFormat =
175 findBestAVValue(validCodecPixelFormats, scoreTargetSwFormat);
177 return bestPixelFormat;
182 const auto codecPixelFormats = codec.pixelFormats();
183 auto pixelFormats = views::filter(codecPixelFormats, [&](AVPixelFormat fmt) {
184 return !prohibitedFormats.count(fmt);
187 return findBestAVValue(pixelFormats, scoreTargetSwFormat);
191 const HWAccel *accel,
192 const AVPixelFormatSet &prohibitedFormats)
194 using namespace QtMultimediaPrivate;
197 const auto hwFormat = accel->hwFormat();
200 if (!isHwFormatAcceptedByCodec(hwFormat) || prohibitedFormats.count(hwFormat))
201 return findTargetSWFormat(sourceSWFormat, codec, *accel, prohibitedFormats);
203 const auto constraints = accel->constraints();
204 if (constraints && ranges::contains(makeSpan(constraints->valid_hw_formats), hwFormat))
210 if (isAVFormatSupported(codec, hwFormat))
214 const auto pixelFormats = codec.pixelFormats();
215 if (pixelFormats.empty()) {
216 qWarning() <<
"Codec pix formats are undefined, it's likely to behave incorrectly";
218 return sourceSWFormat;
221 auto candidatePixelFormats = views::filter(pixelFormats, [&](AVPixelFormat fmt) {
222 return !prohibitedFormats.count(fmt);
225 auto swScoreCalculator = targetSwFormatScoreCalculator(sourceSWFormat);
226 return findBestAVValue(candidatePixelFormats, swScoreCalculator);
231 const auto pixelFormats = codec.pixelFormats();
232 if (pixelFormats.empty())
236 auto formatScoreCalculator = targetSwFormatScoreCalculator(sourceSWFormat);
237 std::optional bestFormatWithScore =
238 findBestAVValueWithScore(pixelFormats, formatScoreCalculator);
239 if (bestFormatWithScore)
240 return bestFormatWithScore->score;
248 qreal preferredRate = 0.;
249 if (settingsRate > 0)
250 preferredRate = settingsRate;
251 else if (sourceRate > 0)
252 preferredRate = sourceRate;
253 else if (supportedRates.empty())
256 preferredRate = qreal(DefaultVideoFrameRate);
258 auto calcScore = [preferredRate](
const AVRational &rate) {
260 return qMin(preferredRate * rate.den, qreal(rate.num))
261 / qMax(preferredRate * rate.den, qreal(rate.num));
264 const auto result = findBestAVValue(supportedRates, calcScore);
265 if (result && result->num && result->den)
268 const auto [num, den] = qRealToFraction(preferredRate);
276 if (!supportedRates.empty()) {
277 auto hasFrameRate = [&]() {
278 for (AVRational rate : supportedRates)
279 if (rate.den == frameRate.den && rate.num == frameRate.num)
285 Q_ASSERT(hasFrameRate());
287 return { frameRate.den, frameRate.num };
291 return { frameRate.den, frameRate.num };
293 constexpr int TimeScaleFactor = 1000;
294 return { frameRate.den, frameRate.num * TimeScaleFactor };
299 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows) {
301 if (codec.name() ==
"h264_mf"_L1) {
302 auto makeEven = [](
int size) {
return size & ~1; };
303 return QSize(makeEven(requestedResolution.width()), makeEven(requestedResolution.height()));
306 return requestedResolution;
311 SwsFlags conversionType = SWS_FAST_BILINEAR;
313 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Android) {
316 if (targetSize.width() > sourceSize.width() || targetSize.height() > sourceSize.height())
317 conversionType = SWS_BICUBIC;
320 return conversionType;
std::optional< AVPixelFormat > findTargetFormat(AVPixelFormat sourceSWFormat, const Codec &codec, const HWAccel *accel, const AVPixelFormatSet &prohibitedFormats)
AVScore findSWFormatScores(const Codec &codec, AVPixelFormat sourceSWFormat)
SwsFlags getScaleConversionType(const QSize &sourceSize, const QSize &targetSize)
QSize adjustVideoResolution(const Codec &codec, QSize requestedResolution)
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
AVRational adjustFrameRate(QSpan< const AVRational > supportedRates, qreal settingsRate, qreal sourceRate)
adjustFrameRate resolves the effective frame rate to negotiate with a codec.
AVRational adjustFrameTimeBase(QSpan< const AVRational > supportedRates, AVRational frameRate, bool isFixedRate)
adjustFrameTimeBase gets adjusted timebase by a list of supported frame rates and an already adjusted...
std::optional< AVPixelFormat > findTargetSWFormat(AVPixelFormat sourceSWFormat, const Codec &codec, const HWAccel &accel, const AVPixelFormatSet &prohibitedFormats)