1use itertools::*;
11
12use crate::api::color::*;
13use crate::api::config::GrainTableSegment;
14use crate::api::{Rational, SpeedSettings};
15use crate::encoder::Tune;
16use crate::serialize::{Deserialize, Serialize};
17
18use std::fmt;
19
20pub(crate) const MAX_RDO_LOOKAHEAD_FRAMES: usize = usize::MAX - 1;
22pub(crate) const MAX_MAX_KEY_FRAME_INTERVAL: u64 = i32::MAX as u64 / 3;
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct EncoderConfig {
28 pub width: usize,
31 pub height: usize,
33 pub sample_aspect_ratio: Rational,
35 pub time_base: Rational,
37
38 pub bit_depth: usize,
41 pub chroma_sampling: ChromaSampling,
43 pub chroma_sample_position: ChromaSamplePosition,
45 pub pixel_range: PixelRange,
47 pub color_description: Option<ColorDescription>,
49 pub mastering_display: Option<MasteringDisplay>,
51 pub content_light: Option<ContentLight>,
53
54 pub level_idx: Option<u8>,
59
60 pub enable_timing_info: bool,
62
63 pub still_picture: bool,
65
66 pub error_resilient: bool,
68
69 pub switch_frame_interval: u64,
71
72 pub min_key_frame_interval: u64,
75 pub max_key_frame_interval: u64,
77 pub reservoir_frame_delay: Option<i32>,
80 pub low_latency: bool,
84 pub quantizer: usize,
86 pub min_quantizer: u8,
88 pub bitrate: i32,
90 pub tune: Tune,
92 pub film_grain_params: Option<Vec<GrainTableSegment>>,
94 pub tile_cols: usize,
100 pub tile_rows: usize,
106 pub tiles: usize,
114
115 pub speed_settings: SpeedSettings,
117}
118
119impl Default for EncoderConfig {
124 fn default() -> Self {
125 const DEFAULT_SPEED: u8 = 6;
126 Self::with_speed_preset(DEFAULT_SPEED)
127 }
128}
129
130impl EncoderConfig {
131 pub fn with_speed_preset(speed: u8) -> Self {
138 EncoderConfig {
139 width: 640,
140 height: 480,
141 sample_aspect_ratio: Rational { num: 1, den: 1 },
142 time_base: Rational { num: 1, den: 30 },
143
144 bit_depth: 8,
145 chroma_sampling: ChromaSampling::Cs420,
146 chroma_sample_position: ChromaSamplePosition::Unknown,
147 pixel_range: Default::default(),
148 color_description: None,
149 mastering_display: None,
150 content_light: None,
151
152 level_idx: None,
153
154 enable_timing_info: false,
155
156 still_picture: false,
157
158 error_resilient: false,
159 switch_frame_interval: 0,
160
161 min_key_frame_interval: 12,
162 max_key_frame_interval: 240,
163 min_quantizer: 0,
164 reservoir_frame_delay: None,
165 low_latency: false,
166 quantizer: 100,
167 bitrate: 0,
168 tune: Tune::default(),
169 film_grain_params: None,
170 tile_cols: 0,
171 tile_rows: 0,
172 tiles: 0,
173 speed_settings: SpeedSettings::from_preset(speed),
174 }
175 }
176
177 pub fn set_key_frame_interval(
179 &mut self, min_interval: u64, max_interval: u64,
180 ) {
181 self.min_key_frame_interval = min_interval;
182
183 self.max_key_frame_interval = if max_interval == 0 {
185 MAX_MAX_KEY_FRAME_INTERVAL
186 } else {
187 max_interval
188 };
189 }
190
191 pub fn frame_rate(&self) -> f64 {
195 Rational::from_reciprocal(self.time_base).as_f64()
196 }
197
198 pub fn render_size(&self) -> (usize, usize) {
205 let sar = self.sample_aspect_ratio.as_f64();
206
207 if sar > 1.0 {
208 ((self.width as f64 * sar).round() as usize, self.height)
209 } else {
210 (self.width, (self.height as f64 / sar).round() as usize)
211 }
212 }
213
214 #[inline]
216 pub const fn temporal_rdo(&self) -> bool {
217 !self.speed_settings.transform.tx_domain_distortion
229 }
230
231 pub fn is_hdr(&self) -> bool {
233 self
234 .color_description
235 .map(|colors| {
236 colors.transfer_characteristics == TransferCharacteristics::SMPTE2084
237 })
238 .unwrap_or(false)
239 }
240
241 pub(crate) fn get_film_grain_at(
242 &self, timestamp: u64,
243 ) -> Option<&GrainTableSegment> {
244 self.film_grain_params.as_ref().and_then(|entries| {
245 entries.iter().find(|entry| {
246 timestamp >= entry.start_time && timestamp < entry.end_time
247 })
248 })
249 }
250
251 pub(crate) fn get_film_grain_mut_at(
252 &mut self, timestamp: u64,
253 ) -> Option<&mut GrainTableSegment> {
254 self.film_grain_params.as_mut().and_then(|entries| {
255 entries.iter_mut().find(|entry| {
256 timestamp >= entry.start_time && timestamp < entry.end_time
257 })
258 })
259 }
260}
261
262impl fmt::Display for EncoderConfig {
263 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
264 let pairs = [
265 ("keyint_min", self.min_key_frame_interval.to_string()),
266 ("keyint_max", self.max_key_frame_interval.to_string()),
267 ("quantizer", self.quantizer.to_string()),
268 ("bitrate", self.bitrate.to_string()),
269 ("min_quantizer", self.min_quantizer.to_string()),
270 ("low_latency", self.low_latency.to_string()),
271 ("tune", self.tune.to_string()),
272 (
273 "rdo_lookahead_frames",
274 self.speed_settings.rdo_lookahead_frames.to_string(),
275 ),
276 (
277 "multiref",
278 (!self.low_latency || self.speed_settings.multiref).to_string(),
279 ),
280 ("fast_deblock", self.speed_settings.fast_deblock.to_string()),
281 (
282 "scene_detection_mode",
283 self.speed_settings.scene_detection_mode.to_string(),
284 ),
285 ("cdef", self.speed_settings.cdef.to_string()),
286 ("lrf", self.speed_settings.lrf.to_string()),
287 ("enable_timing_info", self.enable_timing_info.to_string()),
288 (
289 "min_block_size",
290 self.speed_settings.partition.partition_range.min.to_string(),
291 ),
292 (
293 "max_block_size",
294 self.speed_settings.partition.partition_range.max.to_string(),
295 ),
296 (
297 "encode_bottomup",
298 self.speed_settings.partition.encode_bottomup.to_string(),
299 ),
300 (
301 "non_square_partition_max_threshold",
302 self
303 .speed_settings
304 .partition
305 .non_square_partition_max_threshold
306 .to_string(),
307 ),
308 (
309 "reduced_tx_set",
310 self.speed_settings.transform.reduced_tx_set.to_string(),
311 ),
312 (
313 "tx_domain_distortion",
314 self.speed_settings.transform.tx_domain_distortion.to_string(),
315 ),
316 (
317 "tx_domain_rate",
318 self.speed_settings.transform.tx_domain_rate.to_string(),
319 ),
320 (
321 "rdo_tx_decision",
322 self.speed_settings.transform.rdo_tx_decision.to_string(),
323 ),
324 (
325 "prediction_modes",
326 self.speed_settings.prediction.prediction_modes.to_string(),
327 ),
328 (
329 "fine_directional_intra",
330 self.speed_settings.prediction.fine_directional_intra.to_string(),
331 ),
332 (
333 "include_near_mvs",
334 self.speed_settings.motion.include_near_mvs.to_string(),
335 ),
336 (
337 "use_satd_subpel",
338 self.speed_settings.motion.use_satd_subpel.to_string(),
339 ),
340 ];
341 write!(
342 f,
343 "{}",
344 pairs.iter().map(|pair| format!("{}={}", pair.0, pair.1)).join(" ")
345 )
346 }
347}