6#include <QtMultimedia/private/qmultimediautils_p.h>
7#include <QtCore/qoperatingsystemversion.h>
8#include <QtCore/private/qminimalflatset_p.h>
11#include <libavutil/pixdesc.h>
22bool is16BitFormat(
const AVPixFmtDescriptor *desc)
24 return desc->comp[0].depth == 16;
27bool is10BitFormat(
const AVPixFmtDescriptor *desc)
29 return desc->comp[0].depth == 10;
32bool is8BitFormat(
const AVPixFmtDescriptor *desc)
34 return desc->comp[0].depth == 8;
37bool is444Format(
const AVPixFmtDescriptor *desc)
39 return desc->log2_chroma_h == 0 && desc->log2_chroma_w == 0;
42bool is422Format(
const AVPixFmtDescriptor *desc)
44 return desc->log2_chroma_h == 1 && desc->log2_chroma_w == 0;
47bool is420Format(
const AVPixFmtDescriptor *desc)
49 return desc->log2_chroma_h == 1 && desc->log2_chroma_w == 1;
52bool isGreyFormat(
const AVPixFmtDescriptor *desc)
54 return desc->nb_components == 1;
57AVScore scoreTargetSwFormat(
const AVPixFmtDescriptor *sourceSwFormatDesc, AVPixelFormat fmt)
63 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
65 return NotSuitableAVScore;
67 if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
69 return NotSuitableAVScore;
71 AVScore score = DefaultAVScore;
73 if (desc == sourceSwFormatDesc)
77 const int sourceBpp = av_get_bits_per_pixel(sourceSwFormatDesc);
78 const int bpp = av_get_bits_per_pixel(desc);
83 else if (bpp < sourceBpp)
84 score -= 100 + (sourceBpp - bpp);
87 if (is8BitFormat(sourceSwFormatDesc)) {
88 if (is10BitFormat(desc))
90 else if (is16BitFormat(desc))
95 if (is420Format(desc))
97 else if (is422Format(desc))
99 else if (is444Format(desc))
102 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Android) {
105 if (fmt == AV_PIX_FMT_NV12)
109 if (isGreyFormat(desc) && !isGreyFormat(sourceSwFormatDesc))
110 return AVScore::NotSuitableAVScore;
112 if (desc->flags & AV_PIX_FMT_FLAG_BE)
114 if (desc->flags & AV_PIX_FMT_FLAG_PAL)
116 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
122auto targetSwFormatScoreCalculator(AVPixelFormat sourceFormat)
124 const auto sourceSwFormatDesc = av_pix_fmt_desc_get(sourceFormat);
125 return [=](AVPixelFormat fmt) {
126 return scoreTargetSwFormat(sourceSwFormatDesc, fmt);
130bool isHwFormatAcceptedByCodec(AVPixelFormat pixFormat)
133 case AV_PIX_FMT_MEDIACODEC:
144 const HWAccel &accel,
145 const AVPixelFormatSet &prohibitedFormats)
147 using namespace QtMultimediaPrivate;
149 auto scoreTargetSwFormat = targetSwFormatScoreCalculator(sourceSWFormat);
151 const auto constraints = accel.constraints();
152 if (constraints && constraints->valid_sw_formats) {
154 const auto validSWFormatsForHWAccel =
155 makeSpan(constraints->valid_sw_formats) | ranges::to<QMinimalFlatSet>();
157 const auto codecPixelFormats = codec.pixelFormats();
158 auto validCodecPixelFormats = views::filter(codecPixelFormats, [&](AVPixelFormat fmt) {
159 if (!validSWFormatsForHWAccel.contains(fmt))
162 return !prohibitedFormats.count(fmt);
165 if constexpr (
false) {
166 qDebug() <<
"validSWFormats" << (validSWFormatsForHWAccel | ranges::to<std::vector>())
167 <<
"scoredPixelFormats"
168 << (validCodecPixelFormats | views::transform([&](
auto arg) {
169 return std::pair(arg, scoreTargetSwFormat(arg));
170 }) | ranges::to<std::vector>());
173 std::optional bestPixelFormat =
174 findBestAVValue(validCodecPixelFormats, scoreTargetSwFormat);
176 return bestPixelFormat;
181 const auto codecPixelFormats = codec.pixelFormats();
182 auto pixelFormats = views::filter(codecPixelFormats, [&](AVPixelFormat fmt) {
183 return !prohibitedFormats.count(fmt);
186 return findBestAVValue(pixelFormats, scoreTargetSwFormat);
190 const HWAccel *accel,
191 const AVPixelFormatSet &prohibitedFormats)
193 using namespace QtMultimediaPrivate;
196 const auto hwFormat = accel->hwFormat();
199 if (!isHwFormatAcceptedByCodec(hwFormat) || prohibitedFormats.count(hwFormat))
200 return findTargetSWFormat(sourceSWFormat, codec, *accel, prohibitedFormats);
202 const auto constraints = accel->constraints();
203 if (constraints && ranges::contains(makeSpan(constraints->valid_hw_formats), hwFormat))
209 if (isAVFormatSupported(codec, hwFormat))
213 const auto pixelFormats = codec.pixelFormats();
214 if (pixelFormats.empty()) {
215 qWarning() <<
"Codec pix formats are undefined, it's likely to behave incorrectly";
217 return sourceSWFormat;
220 auto candidatePixelFormats = views::filter(pixelFormats, [&](AVPixelFormat fmt) {
221 return !prohibitedFormats.count(fmt);
224 auto swScoreCalculator = targetSwFormatScoreCalculator(sourceSWFormat);
225 return findBestAVValue(candidatePixelFormats, swScoreCalculator);
230 const auto pixelFormats = codec.pixelFormats();
231 if (pixelFormats.empty())
235 auto formatScoreCalculator = targetSwFormatScoreCalculator(sourceSWFormat);
236 std::optional bestFormatWithScore =
237 findBestAVValueWithScore(pixelFormats, formatScoreCalculator);
238 if (bestFormatWithScore)
239 return bestFormatWithScore->score;
246 auto calcScore = [requestedRate](
const AVRational &rate) {
248 return qMin(requestedRate * rate.den, qreal(rate.num))
249 / qMax(requestedRate * rate.den, qreal(rate.num));
252 const auto result = findBestAVValue(supportedRates, calcScore);
253 if (result && result->num && result->den)
256 const auto [num, den] = qRealToFraction(requestedRate);
263 if (!supportedRates.empty()) {
264 auto hasFrameRate = [&]() {
265 for (AVRational rate : supportedRates)
266 if (rate.den == frameRate.den && rate.num == frameRate.num)
272 Q_ASSERT(hasFrameRate());
274 return { frameRate.den, frameRate.num };
277 constexpr int TimeScaleFactor = 1000;
278 return { frameRate.den, frameRate.num * TimeScaleFactor };
283 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows) {
285 if (codec.name() ==
"h264_mf"_L1) {
286 auto makeEven = [](
int size) {
return size & ~1; };
287 return QSize(makeEven(requestedResolution.width()), makeEven(requestedResolution.height()));
290 return requestedResolution;
295 SwsFlags conversionType = SWS_FAST_BILINEAR;
297 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Android) {
300 if (targetSize.width() > sourceSize.width() || targetSize.height() > sourceSize.height())
301 conversionType = SWS_BICUBIC;
304 return conversionType;
std::optional< AVPixelFormat > findTargetFormat(AVPixelFormat sourceSWFormat, const Codec &codec, const HWAccel *accel, const AVPixelFormatSet &prohibitedFormats)
AVRational adjustFrameTimeBase(QSpan< const AVRational > supportedRates, AVRational frameRate)
adjustFrameTimeBase gets adjusted timebase by a list of supported frame rates and an already adjusted...
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 requestedRate)
adjustFrameRate get a rational frame rate be requested qreal rate. If the codec supports fixed frame ...
std::optional< AVPixelFormat > findTargetSWFormat(AVPixelFormat sourceSWFormat, const Codec &codec, const HWAccel &accel, const AVPixelFormatSet &prohibitedFormats)