7#include <QtMultimedia/qaudioformat.h>
8#include <QtCore/private/qflatmap_p.h>
16#include <libavcodec/avcodec.h>
20#include <libavutil/channel_layout.h>
40 const double bitsPerPixel[
int(QMediaFormat::VideoCodec::LastVideoCodec)+1][QMediaRecorder::VeryHighQuality+1] = {
41 { 1.2, 2.25, 5, 9, 15 },
42 { 0.8, 1.5, 3.5, 6, 10 },
43 { 0.4, 0.75, 1.75, 3, 5 },
44 { 0.4, 0.75, 1.75, 3, 5 },
45 { 0.3, 0.5, 0.2, 2, 3 },
46 { 0.4, 0.75, 1.75, 3, 5 },
47 { 0.3, 0.5, 0.2, 2, 3 },
48 { 0.2, 0.4, 0.9, 1.5, 2.5 },
49 { 0.4, 0.75, 1.75, 3, 5 },
50 { 0.8, 1.5, 3.5, 6, 10 },
51 { 16, 24, 32, 40, 48 },
54 QSize s = settings.videoResolution();
55 double bitrate = bitsPerPixel[
int(settings.videoCodec())][settings.quality()]*s.width()*s.height();
57 if (settings.videoCodec() != QMediaFormat::VideoCodec::MotionJPEG) {
60 float rateMultiplier = log2(settings.videoFrameRate()/30.);
61 bitrate *= pow(1.5, rateMultiplier);
64 bitrate *= settings.videoFrameRate()/30.;
73static void apply_openh264(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
76 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
77 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
78 codec->bit_rate = settings.videoBitRate();
79 av_dict_set(opts,
"rc_mode",
"bitrate", 0);
81 av_dict_set(opts,
"rc_mode",
"quality", 0);
82 static const int q[] = { 51, 48, 38, 25, 5 };
83 codec->qmax = codec->qmin = q[settings.quality()];
87static void apply_x264(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
89 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
90 codec->bit_rate = settings.videoBitRate();
92 const char *scales[] = {
93 "29",
"26",
"23",
"21",
"19"
95 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
99static void apply_x265(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
101 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
102 codec->bit_rate = settings.videoBitRate();
104 const char *scales[QMediaRecorder::VeryHighQuality+1] = {
105 "40",
"34",
"28",
"26",
"24",
107 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
111static void apply_libvpx(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
113 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
114 codec->bit_rate = settings.videoBitRate();
116 const char *scales[QMediaRecorder::VeryHighQuality+1] = {
117 "38",
"34",
"31",
"28",
"25",
119 av_dict_set(opts,
"crf", scales[settings.quality()], 0);
120 av_dict_set(opts,
"b",
nullptr, 0);
122 av_dict_set(opts,
"row-mt",
"1", 0);
125static void apply_mpeg4(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
130 QMediaRecorder::EncodingMode encodingMode = settings.encodingMode();
131 switch (encodingMode) {
132 case QMediaRecorder::ConstantBitRateEncoding:
133 case QMediaRecorder::QMediaRecorder::AverageBitRateEncoding: {
134 codec->bit_rate = settings.videoBitRate();
135 if (encodingMode == QMediaRecorder::ConstantBitRateEncoding)
136 codec->rc_min_rate = codec->rc_max_rate = settings.videoBitRate();
140 case QMediaRecorder::ConstantQualityEncoding: {
141 constexpr auto scales = std::array{
148 av_dict_set_int(opts,
"qscale", scales[settings.quality()], 0);
149 codec->global_quality = scales[settings.quality()] * FF_QP2LAMBDA;
150 codec->flags |= AV_CODEC_FLAG_QSCALE;
153 case QMediaRecorder::TwoPassEncoding: {
154 qWarning(
"Two pass encoding is not supported for MPEG4");
158 Q_UNREACHABLE_RETURN();
164static void apply_videotoolbox(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
166 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
167 codec->bit_rate = settings.videoBitRate();
171#if defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM_64)
175 const int scales[] = {
176 3000, 4800, 5900, 6900, 7700,
178 codec->global_quality = scales[settings.quality()];
179 codec->flags |= AV_CODEC_FLAG_QSCALE;
181 codec->bit_rate = bitrateForSettings(settings);
190 av_dict_set(opts,
"allow_sw",
"1", 0);
195static void apply_vaapi(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **)
198 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding) {
199 codec->bit_rate = settings.videoBitRate();
200 codec->rc_max_rate = settings.videoBitRate();
201 }
else if (settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
202 codec->bit_rate = settings.videoBitRate();
204 const int *quality =
nullptr;
206 switch (settings.videoCodec()) {
207 case QMediaFormat::VideoCodec::MPEG2: {
208 static const int q[] = { 20, 15, 10, 8, 6 };
212 case QMediaFormat::VideoCodec::MPEG4:
213 case QMediaFormat::VideoCodec::H264: {
214 static const int q[] = { 29, 26, 23, 21, 19 };
218 case QMediaFormat::VideoCodec::H265: {
219 static const int q[] = { 40, 34, 28, 26, 24 };
223 case QMediaFormat::VideoCodec::VP8: {
224 static const int q[] = { 56, 48, 40, 34, 28 };
228 case QMediaFormat::VideoCodec::VP9: {
229 static const int q[] = { 124, 112, 100, 88, 76 };
233 case QMediaFormat::VideoCodec::MotionJPEG: {
234 static const int q[] = { 40, 60, 80, 90, 95 };
238 case QMediaFormat::VideoCodec::AV1:
239 case QMediaFormat::VideoCodec::Theora:
240 case QMediaFormat::VideoCodec::WMV:
246 codec->global_quality = quality[settings.quality()];
251static void apply_nvenc(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
254 switch (settings.encodingMode()) {
255 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
256 av_dict_set(opts,
"vbr",
"1", 0);
257 codec->bit_rate = settings.videoBitRate();
259 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
260 av_dict_set(opts,
"cbr",
"1", 0);
261 codec->bit_rate = settings.videoBitRate();
262 codec->rc_max_rate = codec->rc_min_rate = codec->bit_rate;
264 case QMediaRecorder::EncodingMode::ConstantQualityEncoding: {
265 static const char *q[] = {
"51",
"48",
"35",
"15",
"1" };
266 av_dict_set(opts,
"cq", q[settings.quality()], 0);
274static void apply_mf(
const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts)
276 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding) {
277 codec->bit_rate = settings.videoBitRate();
278 av_dict_set(opts,
"rate_control",
"cbr", 0);
280 av_dict_set(opts,
"rate_control",
"quality", 0);
281 const char *scales[] = {
282 "25",
"50",
"75",
"90",
"100"
284 av_dict_set(opts,
"quality", scales[settings.quality()], 0);
290static void apply_mediacodec(
const QMediaEncoderSettings &settings, AVCodecContext *codec,
293 if (settings.videoBitRate() != -1)
294 codec->bit_rate = settings.videoBitRate();
296 codec->bit_rate = bitrateForSettings(settings);
298 const int quality[] = { 25, 50, 75, 90, 100 };
299 codec->global_quality = quality[settings.quality()];
301 switch (settings.encodingMode()) {
302 case QMediaRecorder::EncodingMode::AverageBitRateEncoding:
303 av_dict_set(opts,
"bitrate_mode",
"vbr", 1);
305 case QMediaRecorder::EncodingMode::ConstantBitRateEncoding:
306 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
308 case QMediaRecorder::EncodingMode::ConstantQualityEncoding:
310 av_dict_set(opts,
"bitrate_mode",
"cbr", 1);
316 switch (settings.videoCodec()) {
317 case QMediaFormat::VideoCodec::H264: {
318 const char *levels[] = {
"2.2",
"3.2",
"4.2",
"5.2",
"6.2" };
319 av_dict_set(opts,
"level", levels[settings.quality()], 1);
320 codec->profile = AV_PROFILE_H264_HIGH;
323 case QMediaFormat::VideoCodec::H265: {
327 if (avcodec_version() < 4000612 || avcodec_version() > 4002660) {
328 const char *levels[] = {
"h2.1",
"h3.1",
"h4.1",
"h5.1",
"h6.1" };
329 av_dict_set(opts,
"level", levels[settings.quality()], 1);
332 codec->profile = AV_PROFILE_HEVC_MAIN;
344 AVCodecContext *codec, AVDictionary **opts);
387void applyVideoEncoderOptions(
const QMediaEncoderSettings &settings, QLatin1StringView codecName,
388 AVCodecContext *codec, AVDictionary **opts)
390 av_dict_set(opts,
"threads",
"auto", 0);
392 auto entry = videoCodecOptionTable.find(codecName);
394 if (entry != videoCodecOptionTable.end())
395 entry->second(settings, codec, opts);
398void applyAudioEncoderOptions(
const QMediaEncoderSettings &settings,
399 QLatin1StringView , AVCodecContext *codec,
402 codec->thread_count = -1;
403 if (settings.encodingMode() == QMediaRecorder::ConstantBitRateEncoding
404 || settings.encodingMode() == QMediaRecorder::AverageBitRateEncoding)
405 codec->bit_rate = settings.audioBitRate();
407 if (settings.audioSampleRate() != -1)
408 codec->sample_rate = settings.audioSampleRate();
410 if (settings.audioChannelCount() != -1) {
411 auto mask = QFFmpegMediaFormatInfo::avChannelLayout(
412 QAudioFormat::defaultChannelConfigForChannelCount(settings.audioChannelCount()));
414#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
415 av_channel_layout_from_mask(&codec->ch_layout, mask);
417 codec->channel_layout = mask;
418 codec->channels = qPopulationCount(codec->channel_layout);
void(*)(const QMediaEncoderSettings &settings, AVCodecContext *codec, AVDictionary **opts) ApplyVideoCodecOptions
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
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)