Commit 4e0a97c6 authored by Derek Buitenhuis's avatar Derek Buitenhuis Committed by Thomas Daede
Browse files

API: Expose minimum quantizer option


Signed-off-by: default avatarDerek Buitenhuis <derek.buitenhuis@gmail.com>
parent 5d8952a7
......@@ -81,6 +81,8 @@ pub struct EncoderConfig {
pub reservoir_frame_delay: Option<i32>,
pub low_latency: bool,
pub quantizer: usize,
/// The minimum allowed base quantizer to use in bitrate mode.
pub min_quantizer: u8,
pub bitrate: i32,
pub tune: Tune,
pub tile_cols_log2: usize,
......@@ -127,6 +129,7 @@ impl EncoderConfig {
time_base: Rational { num: 1, den: 30 },
min_key_frame_interval: 12,
max_key_frame_interval: 240,
min_quantizer: 0,
reservoir_frame_delay: None,
low_latency: false,
quantizer: 100,
......@@ -816,6 +819,7 @@ impl<T: Pixel> ContextInner<T> {
enc.time_base.num as i64,
enc.bitrate,
maybe_ac_qi_max,
enc.min_quantizer,
enc.max_key_frame_interval as i32,
enc.reservoir_frame_delay
),
......
......@@ -109,6 +109,12 @@ pub fn parse_cli() -> CliOptions {
.long("quantizer")
.takes_value(true)
)
.arg(
Arg::with_name("MINQP")
.help("Minimum quantizer (0-255) to use in bitrate mode [default: 0]")
.long("min_quantizer")
.takes_value(true)
)
.arg(
Arg::with_name("BITRATE")
.help("Bitrate (kbps)")
......@@ -445,6 +451,7 @@ fn parse_config(matches: &ArgMatches<'_>) -> EncoderConfig {
};
cfg.quantizer = quantizer;
cfg.min_quantizer = matches.value_of("MINQP").unwrap().parse().unwrap_or(0);
cfg.bitrate = bitrate.checked_mul(1000).expect("Bitrate too high");
cfg.reservoir_frame_delay = matches.value_of("RESERVOIR_FRAME_DELAY").map(|reservior_frame_delay| reservior_frame_delay.parse().unwrap());
cfg.show_psnr = matches.is_present("PSNR");
......
......@@ -379,6 +379,8 @@ pub struct RCState {
// The maximum quantizer index to allow (for the luma AC coefficients, other
// quantizers will still be adjusted to match).
maybe_ac_qi_max: Option<u8>,
// The minimum quantizer index to allow (for the luma AC coefficients).
ac_qi_min: u8,
// Will we drop frames to meet bitrate requirements?
drop_frames: bool,
// Do we respect the maximum reservoir fullness?
......@@ -489,7 +491,8 @@ impl RCState {
pub fn new(
frame_width: i32, frame_height: i32, framerate_num: i64,
framerate_den: i64, target_bitrate: i32, maybe_ac_qi_max: Option<u8>,
max_key_frame_interval: i32, maybe_reservoir_frame_delay: Option<i32>
ac_qi_min: u8, max_key_frame_interval: i32,
maybe_reservoir_frame_delay: Option<i32>
) -> RCState {
// The default buffer size is set equal to 1.5x the keyframe interval, or 240
// frames; whichsever is smaller.
......@@ -553,6 +556,7 @@ impl RCState {
target_bitrate,
reservoir_frame_delay,
maybe_ac_qi_max,
ac_qi_min,
drop_frames: false,
cap_overflow: true,
cap_underflow: false,
......@@ -643,7 +647,7 @@ impl RCState {
// There's no easy closed form solution, so we bisection searh for it.
let bit_depth = ctx.config.bit_depth;
// TODO: Proper handling of lossless.
let mut log_qlo = blog64(dc_q(0, 0, bit_depth) as i64)
let mut log_qlo = blog64(ac_q(self.ac_qi_min, 0, bit_depth) as i64)
- q57(QSCALE + bit_depth as i32 - 8);
// The AC quantizer tables map to values larger than the DC quantizer
// tables, so we use that as the upper bound to make sure we can use
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment