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();
169#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
170static void apply_v4l2m2m(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
173 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
174 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
175 codec->bit_rate = settings.videoBitRate();
183 codec->bit_rate = bitrateForSettings(settings);
185 const int quality = settings.quality();
186 switch (settings.videoCodec()) {
187 case QMediaFormat::VideoCodec::H264: {
188 static constexpr int q[] = { 45, 38, 28, 20, 10 };
189 codec->qmin = codec->qmax = q[quality];
192 case QMediaFormat::VideoCodec::MPEG4: {
193 static constexpr int q[] = { 28, 22, 16, 10, 4 };
194 codec->qmin = codec->qmax = q[quality];
197 case QMediaFormat::VideoCodec::VP8: {
198 static constexpr int q[] = { 108, 88, 64, 40, 16 };
199 codec->qmin = codec->qmax = q[quality];
202 case QMediaFormat::VideoCodec::VP9: {
203 static constexpr int q[] = { 216, 176, 128, 80, 32 };
204 codec->qmin = codec->qmax = q[quality];
215static void apply_videotoolbox(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
217 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
218 codec->bit_rate = settings.videoBitRate();
222#if defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM_64)
226 const int scales[] = {
227 3000, 4800, 5900, 6900, 7700,
229 codec->global_quality = scales[settings.quality()];
230 codec->flags |= AV_CODEC_FLAG_QSCALE;
232 codec->bit_rate = bitrateForSettings(settings);
241 av_dict_set(opts,
"allow_sw",
"1", 0);
246static void apply_vaapi(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **)
249 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding) {
250 codec->bit_rate = settings.videoBitRate();
251 codec->rc_max_rate = settings.videoBitRate();
252 }
else if (settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
253 codec->bit_rate = settings.videoBitRate();
255 const int *quality =
nullptr;
257 switch (settings.videoCodec()) {
258 case QMediaFormat::VideoCodec::MPEG2: {
259 static const int q[] = { 20, 15, 10, 8, 6 };
263 case QMediaFormat::VideoCodec::MPEG4:
264 case QMediaFormat::VideoCodec::H264: {
265 static const int q[] = { 29, 26, 23, 21, 19 };
269 case QMediaFormat::VideoCodec::H265: {
270 static const int q[] = { 40, 34, 28, 26, 24 };
274 case QMediaFormat::VideoCodec::VP8: {
275 static const int q[] = { 56, 48, 40, 34, 28 };
279 case QMediaFormat::VideoCodec::VP9: {
280 static const int q[] = { 124, 112, 100, 88, 76 };
284 case QMediaFormat::VideoCodec::MotionJPEG: {
285 static const int q[] = { 40, 60, 80, 90, 95 };
289 case QMediaFormat::VideoCodec::AV1:
290 case QMediaFormat::VideoCodec::Theora:
291 case QMediaFormat::VideoCodec::WMV:
297 codec->global_quality = quality[settings.quality()];
302static void apply_nvenc(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
305 switch (settings.encodingMode()) {
306 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
307 av_dict_set(opts,
"vbr",
"1", 0);
308 codec->bit_rate = settings.videoBitRate();
310 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
311 av_dict_set(opts,
"cbr",
"1", 0);
312 codec->bit_rate = settings.videoBitRate();
313 codec->rc_max_rate = codec->rc_min_rate = codec->bit_rate;
315 case QMediaRecorder::EncodingMode::ConstantQualityEncoding: {
316 static const char *q[] = {
"51",
"48",
"35",
"15",
"1" };
317 av_dict_set(opts,
"cq", q[settings.quality()], 0);
325static void apply_mf(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
327 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
328 codec->bit_rate = settings.videoBitRate();
329 av_dict_set(opts,
"rate_control",
"cbr", 0);
331 av_dict_set(opts,
"rate_control",
"quality", 0);
332 const char *scales[] = {
333 "25",
"50",
"75",
"90",
"100"
335 av_dict_set(opts,
"quality", scales[settings.quality()], 0);
341static void apply_mediacodec(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
344 if (settings.videoBitRate() != -1)
345 codec->bit_rate = settings.videoBitRate();
347 codec->bit_rate = bitrateForSettings(settings);
349 const int quality[] = { 25, 50, 75, 90, 100 };
350 codec->global_quality = quality[settings.quality()];
352 switch (settings.encodingMode()) {
353 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
354 av_dict_set(opts,
"bitrate_mode",
"vbr", 1);
356 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
357 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
359 case QMediaRecorder::EncodingMode::ConstantQualityEncoding:
361 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
367 switch (settings.videoCodec()) {
368 case QMediaFormat::VideoCodec::H264: {
369 const char *levels[] = {
"2.2",
"3.2",
"4.2",
"5.2",
"6.2" };
370 av_dict_set(opts,
"level", levels[settings.quality()], 1);
371 codec->profile = AV_PROFILE_H264_HIGH;
374 case QMediaFormat::VideoCodec::H265: {
378 if (avcodec_version() < 4000612 || avcodec_version() > 4002660) {
379 const char *levels[] = {
"h2.1",
"h3.1",
"h4.1",
"h5.1",
"h6.1" };
380 av_dict_set(opts,
"level", levels[settings.quality()], 1);
383 codec->profile = AV_PROFILE_HEVC_MAIN;
395 AVCodecContext *codec, AVDictionary **opts);
413#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
445 AVCodecContext *codec, AVDictionary **opts)
447 av_dict_set(opts,
"threads",
"auto", 0);
449 auto entry = videoCodecOptionTable.find(codecName);
451 if (entry != videoCodecOptionTable.end())
452 entry->second(settings, codec, opts);
459 codec->thread_count = -1;
460 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
461 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding)
462 codec->bit_rate = settings.audioBitRate();
464 if (settings.audioSampleRate() != -1)
465 codec->sample_rate = settings.audioSampleRate();
467 if (settings.audioChannelCount() != -1) {
468 auto mask = QFFmpegMediaFormatInfo::avChannelLayout(
469 QAudioFormat::defaultChannelConfigForChannelCount(settings.audioChannelCount()));
471#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
472 av_channel_layout_from_mask(&codec->ch_layout, mask);
474 codec->channel_layout = mask;
475 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
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)