use itertools::*;
use crate::api::color::*;
use crate::api::{Rational, SpeedSettings};
use crate::encoder::Tune;
use crate::serialize::{Deserialize, Serialize};
use std::fmt;
pub(crate) const MAX_RDO_LOOKAHEAD_FRAMES: usize = usize::max_value() - 1;
pub(crate) const MAX_MAX_KEY_FRAME_INTERVAL: u64 = i32::max_value() as u64 / 3;
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct EncoderConfig {
pub width: usize,
pub height: usize,
pub sample_aspect_ratio: Rational,
pub time_base: Rational,
pub bit_depth: usize,
pub chroma_sampling: ChromaSampling,
pub chroma_sample_position: ChromaSamplePosition,
pub pixel_range: PixelRange,
pub color_description: Option<ColorDescription>,
pub mastering_display: Option<MasteringDisplay>,
pub content_light: Option<ContentLight>,
pub enable_timing_info: bool,
pub still_picture: bool,
pub error_resilient: bool,
pub switch_frame_interval: u64,
pub min_key_frame_interval: u64,
pub max_key_frame_interval: u64,
pub reservoir_frame_delay: Option<i32>,
pub low_latency: bool,
pub quantizer: usize,
pub min_quantizer: u8,
pub bitrate: i32,
pub tune: Tune,
pub tile_cols: usize,
pub tile_rows: usize,
pub tiles: usize,
pub rdo_lookahead_frames: usize,
pub speed_settings: SpeedSettings,
}
impl Default for EncoderConfig {
fn default() -> Self {
const DEFAULT_SPEED: usize = 6;
Self::with_speed_preset(DEFAULT_SPEED)
}
}
impl EncoderConfig {
pub fn with_speed_preset(speed: usize) -> Self {
EncoderConfig {
width: 640,
height: 480,
sample_aspect_ratio: Rational { num: 1, den: 1 },
time_base: Rational { num: 1, den: 30 },
bit_depth: 8,
chroma_sampling: ChromaSampling::Cs420,
chroma_sample_position: ChromaSamplePosition::Unknown,
pixel_range: Default::default(),
color_description: None,
mastering_display: None,
content_light: None,
enable_timing_info: false,
still_picture: false,
error_resilient: false,
switch_frame_interval: 0,
min_key_frame_interval: 12,
max_key_frame_interval: 240,
min_quantizer: 0,
reservoir_frame_delay: None,
low_latency: false,
quantizer: 100,
bitrate: 0,
tune: Tune::default(),
tile_cols: 0,
tile_rows: 0,
tiles: 0,
rdo_lookahead_frames: 40,
speed_settings: SpeedSettings::from_preset(speed),
}
}
pub fn set_key_frame_interval(
&mut self, min_interval: u64, max_interval: u64,
) {
self.min_key_frame_interval = min_interval;
self.max_key_frame_interval = if max_interval == 0 {
MAX_MAX_KEY_FRAME_INTERVAL
} else {
max_interval
};
}
pub fn frame_rate(&self) -> f64 {
Rational::from_reciprocal(self.time_base).as_f64()
}
#[inline]
pub const fn temporal_rdo(&self) -> bool {
!self.speed_settings.tx_domain_distortion
}
}
impl fmt::Display for EncoderConfig {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let pairs = [
("keyint_min", self.min_key_frame_interval.to_string()),
("keyint_max", self.max_key_frame_interval.to_string()),
("quantizer", self.quantizer.to_string()),
("bitrate", self.bitrate.to_string()),
("min_quantizer", self.min_quantizer.to_string()),
("low_latency", self.low_latency.to_string()),
("tune", self.tune.to_string()),
("rdo_lookahead_frames", self.rdo_lookahead_frames.to_string()),
("min_block_size", self.speed_settings.partition_range.min.to_string()),
("max_block_size", self.speed_settings.partition_range.max.to_string()),
(
"multiref",
(!self.low_latency || self.speed_settings.multiref).to_string(),
),
("fast_deblock", self.speed_settings.fast_deblock.to_string()),
("reduced_tx_set", self.speed_settings.reduced_tx_set.to_string()),
(
"tx_domain_distortion",
self.speed_settings.tx_domain_distortion.to_string(),
),
("tx_domain_rate", self.speed_settings.tx_domain_rate.to_string()),
("encode_bottomup", self.speed_settings.encode_bottomup.to_string()),
("rdo_tx_decision", self.speed_settings.rdo_tx_decision.to_string()),
("prediction_modes", self.speed_settings.prediction_modes.to_string()),
("include_near_mvs", self.speed_settings.include_near_mvs.to_string()),
(
"no_scene_detection",
self.speed_settings.no_scene_detection.to_string(),
),
("cdef", self.speed_settings.cdef.to_string()),
("use_satd_subpel", self.speed_settings.use_satd_subpel.to_string()),
(
"non_square_partition",
self.speed_settings.non_square_partition.to_string(),
),
("enable_timing_info", self.enable_timing_info.to_string()),
(
"fine_directional_intra",
self.speed_settings.fine_directional_intra.to_string(),
),
];
write!(
f,
"{}",
pairs.iter().map(|pair| format!("{}={}", pair.0, pair.1)).join(" ")
)
}
}