Skip to main content

rusty_h264_encoder/
config.rs

1//! Encoder configuration.
2
3use rusty_h264_common::{ChromaFormat, Profile};
4
5/// Speed/quality trade-off, in the spirit of x264's `-preset`. The bitstream is
6/// valid (and decodes bit-exactly) either way; only the encoder's effort differs.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum Preset {
9    /// **Fast** (default) — built to mirror x264's fastest presets: mode decision
10    /// by cheap **SAD** estimation (no rate-distortion trial-encoding; SAD
11    /// auto-vectorizes to `psadbw`), `P_16x16`-only inter, `I_16x16`-only intra,
12    /// and **integer-pel** motion (no sub-pel `mc_luma` interpolation — profiling
13    /// showed it was ~55% of the encode). Much faster; larger files, and a little
14    /// quality lost on sub-pixel motion (none on integer/screen content).
15    #[default]
16    Fast,
17    /// **Quality** — full rate-distortion mode decision (every candidate
18    /// trial-encoded for real `J = SSD + λ·bits`), `16x8`/`8x16` sub-partitions,
19    /// and the full `I_4x4` intra search. Smaller files; much slower.
20    Quality,
21}
22
23/// Configuration for an [`crate::Encoder`].
24#[derive(Debug, Clone)]
25pub struct EncoderConfig {
26    /// Picture width in luma samples. Arbitrary (not restricted to /16).
27    pub width: usize,
28    /// Picture height in luma samples.
29    pub height: usize,
30    /// Target profile. Only [`Profile::ConstrainedBaseline`] is implemented.
31    pub profile: Profile,
32    /// Chroma format. Only [`ChromaFormat::Yuv420`] is implemented.
33    pub chroma: ChromaFormat,
34    /// `level_idc` (e.g. 30 = level 3.0). Caller is responsible for choosing a
35    /// level that admits the resolution/bitrate; not yet validated.
36    pub level_idc: u8,
37    /// Quantization parameter (0..=51). With rate control off this is the fixed
38    /// QP for every frame; with it on, the base/fallback QP and `pic_init_qp`.
39    pub qp: u8,
40    /// Frames between IDR pictures. `1` = all-intra (every frame an IDR).
41    pub gop_size: u32,
42    /// Target bitrate in bits per second. `0` disables rate control (constant
43    /// QP); any positive value enables average-bitrate control, which varies the
44    /// per-frame QP around [`qp`](Self::qp) to converge on this rate.
45    pub bitrate: u32,
46    /// Frame rate (frames per second), used by rate control to turn the bitrate
47    /// target into a per-frame bit budget.
48    pub framerate: f32,
49    /// Number of reference frames the encoder may use for P-pictures (1..=16).
50    /// `1` keeps the single-reference bitstream; higher values let P-macroblocks
51    /// pick an older reference (`ref_idx`), helping occlusion/periodic motion.
52    pub num_ref_frames: u32,
53    /// Speed/quality trade-off. Defaults to [`Preset::Fast`].
54    pub preset: Preset,
55}
56
57impl EncoderConfig {
58    /// A minimal all-intra Constrained Baseline configuration at the given size.
59    pub fn new(width: usize, height: usize) -> Self {
60        Self {
61            width,
62            height,
63            profile: Profile::ConstrainedBaseline,
64            chroma: ChromaFormat::Yuv420,
65            level_idc: 30,
66            qp: 26,
67            gop_size: 1,
68            bitrate: 0,
69            framerate: 30.0,
70            num_ref_frames: 1,
71            preset: Preset::Fast,
72        }
73    }
74
75    /// Picture width rounded up to whole macroblocks.
76    pub fn mb_width(&self) -> usize {
77        self.width.div_ceil(16)
78    }
79
80    /// Picture height rounded up to whole macroblocks.
81    pub fn mb_height(&self) -> usize {
82        self.height.div_ceil(16)
83    }
84}