5#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaformatinfo_p.h>
6#include <QtFFmpegMediaPluginImpl/private/qffmpegrecordingengineutils_p.h>
8#include <QtMultimedia/qaudioformat.h>
9#include <QtCore/private/qflatmap_p.h>
17#include <libavcodec/avcodec.h>
21#include <libavutil/channel_layout.h>
41 const double bitsPerPixel[
int(QMediaFormat::VideoCodec::LastVideoCodec)+1][QMediaRecorder::VeryHighQuality+1] = {
42 { 1.2, 2.25, 5, 9, 15 },
43 { 0.8, 1.5, 3.5, 6, 10 },
44 { 0.4, 0.75, 1.75, 3, 5 },
45 { 0.4, 0.75, 1.75, 3, 5 },
46 { 0.3, 0.5, 0.2, 2, 3 },
47 { 0.4, 0.75, 1.75, 3, 5 },
48 { 0.3, 0.5, 0.2, 2, 3 },
49 { 0.2, 0.4, 0.9, 1.5, 2.5 },
50 { 0.4, 0.75, 1.75, 3, 5 },
51 { 0.8, 1.5, 3.5, 6, 10 },
52 { 16, 24, 32, 40, 48 },
55 QSize s = settings.videoResolution();
56 double bitrate = bitsPerPixel[
int(settings.videoCodec())][settings.quality()]*s.width()*s.height();
59 const double frameRate = settings.videoFrameRate() > 0.
60 ? settings.videoFrameRate()
61 :
static_cast<
double>(QFFmpeg::DefaultVideoFrameRate);
63 if (settings.videoCodec() != QMediaFormat::VideoCodec::MotionJPEG) {
66 float rateMultiplier = log2(frameRate / 30.);
67 bitrate *= pow(1.5, rateMultiplier);
70 bitrate *= frameRate / 30.;
79static void apply_openh264(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
82 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
83 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
84 codec->bit_rate = settings.videoBitRate();
85 av_dict_set(opts,
"rc_mode",
"bitrate", 0);
87 av_dict_set(opts,
"rc_mode",
"quality", 0);
88 static const int q[] = { 51, 48, 38, 25, 5 };
89 codec->qmax = codec->qmin = q[settings.quality()];
93static void apply_x264(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
95 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
96 codec->bit_rate = settings.videoBitRate();
98 const char *scales[] = {
99 "29",
"26",
"23",
"21",
"19"
101 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
105static void apply_x265(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
107 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
108 codec->bit_rate = settings.videoBitRate();
110 const char *scales[QMediaRecorder::VeryHighQuality+1] = {
111 "40",
"34",
"28",
"26",
"24",
113 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
117static void apply_libvpx(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
119 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
120 codec->bit_rate = settings.videoBitRate();
122 const char *scales[QMediaRecorder::VeryHighQuality+1] = {
123 "38",
"34",
"31",
"28",
"25",
125 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
126 av_dict_set(opts,
"b",
nullptr, 0);
128 av_dict_set(opts,
"row-mt",
"1", 0);
131static void apply_mpeg4(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
136 QMediaRecorder::EncodingMode encodingMode = settings.encodingMode();
137 switch (encodingMode) {
138 case QMediaRecorder::ConstantBitRateEncoding:
139 case QMediaRecorder::QMediaRecorder::AverageBitRateEncoding: {
140 codec->bit_rate = settings.videoBitRate();
141 if (encodingMode == QMediaRecorder::ConstantBitRateEncoding)
142 codec->rc_min_rate = codec->rc_max_rate = settings.videoBitRate();
146 case QMediaRecorder::ConstantQualityEncoding: {
147 constexpr auto scales = std::array{
154 av_dict_set_int(opts,
"qscale", scales[settings.quality()], 0);
155 codec->global_quality = scales[settings.quality()] * FF_QP2LAMBDA;
156 codec->flags |= AV_CODEC_FLAG_QSCALE;
159 case QMediaRecorder::TwoPassEncoding: {
160 qWarning(
"Two pass encoding is not supported for MPEG4");
164 Q_UNREACHABLE_RETURN();
170static void apply_videotoolbox(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
172 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
173 codec->bit_rate = settings.videoBitRate();
177#if defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM_64)
181 const int scales[] = {
182 3000, 4800, 5900, 6900, 7700,
184 codec->global_quality = scales[settings.quality()];
185 codec->flags |= AV_CODEC_FLAG_QSCALE;
187 codec->bit_rate = bitrateForSettings(settings);
196 av_dict_set(opts,
"allow_sw",
"1", 0);
201static void apply_vaapi(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **)
204 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding) {
205 codec->bit_rate = settings.videoBitRate();
206 codec->rc_max_rate = settings.videoBitRate();
207 }
else if (settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
208 codec->bit_rate = settings.videoBitRate();
210 const int *quality =
nullptr;
212 switch (settings.videoCodec()) {
213 case QMediaFormat::VideoCodec::MPEG2: {
214 static const int q[] = { 20, 15, 10, 8, 6 };
218 case QMediaFormat::VideoCodec::MPEG4:
219 case QMediaFormat::VideoCodec::H264: {
220 static const int q[] = { 29, 26, 23, 21, 19 };
224 case QMediaFormat::VideoCodec::H265: {
225 static const int q[] = { 40, 34, 28, 26, 24 };
229 case QMediaFormat::VideoCodec::VP8: {
230 static const int q[] = { 56, 48, 40, 34, 28 };
234 case QMediaFormat::VideoCodec::VP9: {
235 static const int q[] = { 124, 112, 100, 88, 76 };
239 case QMediaFormat::VideoCodec::MotionJPEG: {
240 static const int q[] = { 40, 60, 80, 90, 95 };
244 case QMediaFormat::VideoCodec::AV1:
245 case QMediaFormat::VideoCodec::Theora:
246 case QMediaFormat::VideoCodec::WMV:
252 codec->global_quality = quality[settings.quality()];
257static void apply_nvenc(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
260 switch (settings.encodingMode()) {
261 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
262 av_dict_set(opts,
"vbr",
"1", 0);
263 codec->bit_rate = settings.videoBitRate();
265 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
266 av_dict_set(opts,
"cbr",
"1", 0);
267 codec->bit_rate = settings.videoBitRate();
268 codec->rc_max_rate = codec->rc_min_rate = codec->bit_rate;
270 case QMediaRecorder::EncodingMode::ConstantQualityEncoding: {
271 static const char *q[] = {
"51",
"48",
"35",
"15",
"1" };
272 av_dict_set(opts,
"cq", q[settings.quality()], 0);
280static void apply_mf(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
282 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
283 codec->bit_rate = settings.videoBitRate();
284 av_dict_set(opts,
"rate_control",
"cbr", 0);
286 av_dict_set(opts,
"rate_control",
"quality", 0);
287 const char *scales[] = {
288 "25",
"50",
"75",
"90",
"100"
290 av_dict_set(opts,
"quality", scales[settings.quality()], 0);
296static void apply_mediacodec(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
299 if (settings.videoBitRate() != -1)
300 codec->bit_rate = settings.videoBitRate();
302 codec->bit_rate = bitrateForSettings(settings);
304 const int quality[] = { 25, 50, 75, 90, 100 };
305 codec->global_quality = quality[settings.quality()];
307 switch (settings.encodingMode()) {
308 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
309 av_dict_set(opts,
"bitrate_mode",
"vbr", 1);
311 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
312 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
314 case QMediaRecorder::EncodingMode::ConstantQualityEncoding:
316 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
322 switch (settings.videoCodec()) {
323 case QMediaFormat::VideoCodec::H264: {
324 const char *levels[] = {
"2.2",
"3.2",
"4.2",
"5.2",
"6.2" };
325 av_dict_set(opts,
"level", levels[settings.quality()], 1);
326 codec->profile = AV_PROFILE_H264_HIGH;
329 case QMediaFormat::VideoCodec::H265: {
333 if (avcodec_version() < 4000612 || avcodec_version() > 4002660) {
334 const char *levels[] = {
"h2.1",
"h3.1",
"h4.1",
"h5.1",
"h6.1" };
335 av_dict_set(opts,
"level", levels[settings.quality()], 1);
338 codec->profile = AV_PROFILE_HEVC_MAIN;
350 AVCodecContext *codec, AVDictionary **opts);
394 AVCodecContext *codec, AVDictionary **opts)
396 av_dict_set(opts,
"threads",
"auto", 0);
398 auto entry = videoCodecOptionTable.find(codecName);
400 if (entry != videoCodecOptionTable.end())
401 entry->second(settings, codec, opts);
408 codec->thread_count = -1;
409 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
410 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding)
411 codec->bit_rate = settings.audioBitRate();
413 if (settings.audioSampleRate() != -1)
414 codec->sample_rate = settings.audioSampleRate();
416 if (settings.audioChannelCount() != -1) {
417 auto mask = QFFmpegMediaFormatInfo::avChannelLayout(
418 QAudioFormat::defaultChannelConfigForChannelCount(settings.audioChannelCount()));
420#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
421 av_channel_layout_from_mask(&codec->ch_layout, mask);
423 codec->channel_layout = mask;
424 codec->channels = qPopulationCount(codec->channel_layout);
void applyAudioEncoderOptions(const QMediaEncoderSettings &settings, QLatin1StringView, AVCodecContext *codec, AVDictionary **)
void applyVideoEncoderOptions(const QMediaEncoderSettings &settings, QLatin1StringView codecName, AVCodecContext *codec, AVDictionary **opts)
void(*)(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts) ApplyVideoCodecOptions
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
const VideoCodecOptionsTableType videoCodecOptionTable
Combined button and popup list for selecting options.
static void apply_libvpx(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
static QT_BEGIN_NAMESPACE int bitrateForSettings(const QMediaEncoderSettings &settings, bool hdr=false)
static void apply_mpeg4(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
static void apply_x265(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
static void apply_nvenc(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
static void apply_x264(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
static void apply_openh264(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)