Skip to main content

ff_encode/video/codec_options/
h264.rs

1//! H.264 (AVC) per-codec encoding options.
2
3/// H.264 (AVC) per-codec options.
4#[derive(Debug, Clone)]
5pub struct H264Options {
6    /// Encoding profile.
7    pub profile: H264Profile,
8    /// Encoding level as an integer (e.g. `31` = 3.1, `40` = 4.0, `51` = 5.1).
9    ///
10    /// `None` leaves the encoder default.
11    pub level: Option<u32>,
12    /// Maximum consecutive B-frames (0–16).
13    pub bframes: u32,
14    /// GOP size: number of frames between keyframes.
15    pub gop_size: u32,
16    /// Number of reference frames.
17    pub refs: u32,
18    /// libx264 encoding speed/quality preset.
19    ///
20    /// Overrides the global [`Preset`](crate::Preset) when set. `None` falls
21    /// back to whatever the builder's `.preset()` selector chose.
22    /// Hardware encoders do not support libx264 presets — the option is
23    /// silently skipped with a `warn!` log when unsupported.
24    pub preset: Option<H264Preset>,
25    /// libx264 perceptual tuning parameter.
26    ///
27    /// `None` leaves the encoder default. Hardware encoders ignore this
28    /// option (logged as a warning and skipped).
29    pub tune: Option<H264Tune>,
30}
31
32impl Default for H264Options {
33    fn default() -> Self {
34        Self {
35            profile: H264Profile::High,
36            level: None,
37            bframes: 2,
38            gop_size: 250,
39            refs: 3,
40            preset: None,
41            tune: None,
42        }
43    }
44}
45
46/// H.264 encoding profile.
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
48pub enum H264Profile {
49    /// Baseline profile — no B-frames, no CABAC (low latency / mobile).
50    Baseline,
51    /// Main profile.
52    Main,
53    /// High profile (recommended for most uses).
54    #[default]
55    High,
56    /// High 10-bit profile.
57    High10,
58}
59
60impl H264Profile {
61    pub(in crate::video) fn as_str(self) -> &'static str {
62        match self {
63            Self::Baseline => "baseline",
64            Self::Main => "main",
65            Self::High => "high",
66            Self::High10 => "high10",
67        }
68    }
69}
70
71/// libx264 encoding speed/quality preset.
72///
73/// Slower presets produce higher quality at the same bitrate but take longer
74/// to encode. Not supported by hardware encoders (NVENC, QSV, etc.) — the
75/// option is skipped with a warning when the encoder does not recognise it.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum H264Preset {
78    /// Fastest encoding, lowest quality.
79    Ultrafast,
80    /// Very fast encoding.
81    Superfast,
82    /// Fast encoding.
83    Veryfast,
84    /// Faster than default.
85    Faster,
86    /// Slightly faster than default.
87    Fast,
88    /// Default preset — balanced speed and quality.
89    Medium,
90    /// Slower encoding, better quality.
91    Slow,
92    /// Noticeably slower, noticeably better quality.
93    Slower,
94    /// Very slow, near-optimal quality.
95    Veryslow,
96    /// Slowest, maximum compression (not recommended for production).
97    Placebo,
98}
99
100impl H264Preset {
101    pub(in crate::video) fn as_str(self) -> &'static str {
102        match self {
103            Self::Ultrafast => "ultrafast",
104            Self::Superfast => "superfast",
105            Self::Veryfast => "veryfast",
106            Self::Faster => "faster",
107            Self::Fast => "fast",
108            Self::Medium => "medium",
109            Self::Slow => "slow",
110            Self::Slower => "slower",
111            Self::Veryslow => "veryslow",
112            Self::Placebo => "placebo",
113        }
114    }
115}
116
117/// libx264 perceptual tuning parameter.
118///
119/// Adjusts encoder settings for a specific type of source content or
120/// quality metric. Not supported by hardware encoders — skipped with a
121/// warning when the encoder does not recognise the option.
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub enum H264Tune {
124    /// Optimised for live-action film content.
125    Film,
126    /// Optimised for animation.
127    Animation,
128    /// Optimised for grainy content.
129    Grain,
130    /// Optimised for still images (single-frame encoding).
131    Stillimage,
132    /// Optimise for PSNR quality metric.
133    Psnr,
134    /// Optimise for SSIM quality metric.
135    Ssim,
136    /// Reduce decoding complexity (disables certain features).
137    Fastdecode,
138    /// Minimise encoding latency (no B-frames, no lookahead).
139    Zerolatency,
140}
141
142impl H264Tune {
143    pub(in crate::video) fn as_str(self) -> &'static str {
144        match self {
145            Self::Film => "film",
146            Self::Animation => "animation",
147            Self::Grain => "grain",
148            Self::Stillimage => "stillimage",
149            Self::Psnr => "psnr",
150            Self::Ssim => "ssim",
151            Self::Fastdecode => "fastdecode",
152            Self::Zerolatency => "zerolatency",
153        }
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn h264_profile_should_return_correct_str() {
163        assert_eq!(H264Profile::Baseline.as_str(), "baseline");
164        assert_eq!(H264Profile::Main.as_str(), "main");
165        assert_eq!(H264Profile::High.as_str(), "high");
166        assert_eq!(H264Profile::High10.as_str(), "high10");
167    }
168
169    #[test]
170    fn h264_preset_should_return_correct_str() {
171        assert_eq!(H264Preset::Ultrafast.as_str(), "ultrafast");
172        assert_eq!(H264Preset::Superfast.as_str(), "superfast");
173        assert_eq!(H264Preset::Veryfast.as_str(), "veryfast");
174        assert_eq!(H264Preset::Faster.as_str(), "faster");
175        assert_eq!(H264Preset::Fast.as_str(), "fast");
176        assert_eq!(H264Preset::Medium.as_str(), "medium");
177        assert_eq!(H264Preset::Slow.as_str(), "slow");
178        assert_eq!(H264Preset::Slower.as_str(), "slower");
179        assert_eq!(H264Preset::Veryslow.as_str(), "veryslow");
180        assert_eq!(H264Preset::Placebo.as_str(), "placebo");
181    }
182
183    #[test]
184    fn h264_tune_should_return_correct_str() {
185        assert_eq!(H264Tune::Film.as_str(), "film");
186        assert_eq!(H264Tune::Animation.as_str(), "animation");
187        assert_eq!(H264Tune::Grain.as_str(), "grain");
188        assert_eq!(H264Tune::Stillimage.as_str(), "stillimage");
189        assert_eq!(H264Tune::Psnr.as_str(), "psnr");
190        assert_eq!(H264Tune::Ssim.as_str(), "ssim");
191        assert_eq!(H264Tune::Fastdecode.as_str(), "fastdecode");
192        assert_eq!(H264Tune::Zerolatency.as_str(), "zerolatency");
193    }
194
195    #[test]
196    fn h264_options_default_should_have_high_profile() {
197        let opts = H264Options::default();
198        assert_eq!(opts.profile, H264Profile::High);
199        assert_eq!(opts.level, None);
200        assert_eq!(opts.bframes, 2);
201        assert_eq!(opts.gop_size, 250);
202        assert_eq!(opts.refs, 3);
203        assert!(opts.preset.is_none());
204        assert!(opts.tune.is_none());
205    }
206}