From 0587ada6dc444270605f005dcb07c9799fc1f032 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 25 Jan 2019 00:15:07 -0600 Subject: [PATCH] Integrate Constant Rate Factor (CRF) for FFmpegWriter (#186) * First implementation of CRF (Constant Rate Factor) * Include AV1 in the codecs that can use crf * First version that uses SetOption to set crf quality * Clarify comments * Delete setting the bitrate for crf in SetVideoOption because it is not needed, it is set later with SetOptions. --- src/FFmpegWriter.cpp | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 56f98354..d8f07c83 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -146,7 +146,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i info.pixel_ratio.num = pixel_ratio.num; info.pixel_ratio.den = pixel_ratio.den; } - if (bit_rate >= 1000) + if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; @@ -237,7 +237,8 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || - name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate")) + name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || + name == "crf")) { // Check for specific named options if (name == "g") @@ -284,6 +285,39 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Buffer size convert >> c->rc_buffer_size; + else if (name == "crf") { + // encode quality and special settings like lossless + // This might be better in an extra methods as more options + // and way to set quality are possible + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + switch (c->codec_id) { + case AV_CODEC_ID_VP8 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + break; + case AV_CODEC_ID_VP9 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + if (stoi(value) == 0) { + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); + if (stoi(value) == 0) { + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + #ifdef AV_CODEC_ID_AV1 + case AV_CODEC_ID_AV1 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + break; + #endif + } + #endif + } + else // Set AVOption AV_OPTION_SET(st, c->priv_data, name.c_str(), value.c_str(), c); @@ -934,7 +968,9 @@ AVStream* FFmpegWriter::add_video_stream() #endif /* Init video encoder options */ - c->bit_rate = info.video_bit_rate; + if (info.video_bit_rate > 1000) { + c->bit_rate = info.video_bit_rate; + } //TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc...