Skip to main content

ff_pipeline/
encoder_config.rs

1//! Codec and quality configuration for the pipeline output.
2
3use ff_encode::BitrateMode;
4use ff_filter::HwAccel;
5use ff_format::{AudioCodec, VideoCodec};
6
7/// Codec and quality configuration for the pipeline output.
8///
9/// Passed to [`PipelineBuilder::output`](crate::PipelineBuilder::output) alongside the output path.
10///
11/// Construct via [`EncoderConfig::builder`].
12#[non_exhaustive]
13pub struct EncoderConfig {
14    /// Video codec to use for the output stream.
15    pub video_codec: VideoCodec,
16
17    /// Audio codec to use for the output stream.
18    pub audio_codec: AudioCodec,
19
20    /// Bitrate control mode (CBR, VBR, or CRF).
21    pub bitrate_mode: BitrateMode,
22
23    /// Output resolution as `(width, height)` in pixels.
24    ///
25    /// Resolution precedence in [`Pipeline::run`](crate::Pipeline::run):
26    /// 1. This field when `Some` — explicit value always wins.
27    /// 2. The output dimensions of a `scale` filter, inferred automatically.
28    /// 3. The source video's native resolution.
29    ///
30    /// When a `scale` filter is used via [`PipelineBuilder::filter`](crate::PipelineBuilder::filter) you
31    /// typically do **not** need to set this field; the pipeline infers the
32    /// encoder dimensions from the filter. Set it explicitly only to override
33    /// the filter's output size or to resize without a filter.
34    pub resolution: Option<(u32, u32)>,
35
36    /// Output frame rate in frames per second.
37    ///
38    /// `None` preserves the source frame rate.
39    pub framerate: Option<f64>,
40
41    /// Hardware acceleration device to use during encoding.
42    ///
43    /// `None` uses software (CPU) encoding.
44    pub hardware: Option<HwAccel>,
45}
46
47impl EncoderConfig {
48    /// Returns an [`EncoderConfigBuilder`] with sensible defaults:
49    /// H.264 video, AAC audio, CRF 23, no resolution/framerate override, software encoding.
50    #[must_use]
51    pub fn builder() -> EncoderConfigBuilder {
52        EncoderConfigBuilder::new()
53    }
54}
55
56/// Consuming builder for [`EncoderConfig`].
57///
58/// Obtain via [`EncoderConfig::builder`].
59pub struct EncoderConfigBuilder {
60    video_codec: VideoCodec,
61    audio_codec: AudioCodec,
62    bitrate_mode: BitrateMode,
63    resolution: Option<(u32, u32)>,
64    framerate: Option<f64>,
65    hardware: Option<HwAccel>,
66}
67
68impl EncoderConfigBuilder {
69    fn new() -> Self {
70        Self {
71            video_codec: VideoCodec::H264,
72            audio_codec: AudioCodec::Aac,
73            bitrate_mode: BitrateMode::Crf(23),
74            resolution: None,
75            framerate: None,
76            hardware: None,
77        }
78    }
79
80    /// Sets the video codec.
81    #[must_use]
82    pub fn video_codec(mut self, codec: VideoCodec) -> Self {
83        self.video_codec = codec;
84        self
85    }
86
87    /// Sets the audio codec.
88    #[must_use]
89    pub fn audio_codec(mut self, codec: AudioCodec) -> Self {
90        self.audio_codec = codec;
91        self
92    }
93
94    /// Sets the bitrate control mode.
95    #[must_use]
96    pub fn bitrate_mode(mut self, mode: BitrateMode) -> Self {
97        self.bitrate_mode = mode;
98        self
99    }
100
101    /// Convenience: sets `BitrateMode::Crf(crf)`.
102    #[must_use]
103    pub fn crf(mut self, crf: u32) -> Self {
104        self.bitrate_mode = BitrateMode::Crf(crf);
105        self
106    }
107
108    /// Sets the output resolution in pixels.
109    #[must_use]
110    pub fn resolution(mut self, width: u32, height: u32) -> Self {
111        self.resolution = Some((width, height));
112        self
113    }
114
115    /// Sets the output frame rate in frames per second.
116    #[must_use]
117    pub fn framerate(mut self, fps: f64) -> Self {
118        self.framerate = Some(fps);
119        self
120    }
121
122    /// Sets the hardware acceleration backend.
123    #[must_use]
124    pub fn hardware(mut self, hw: HwAccel) -> Self {
125        self.hardware = Some(hw);
126        self
127    }
128
129    /// Builds the [`EncoderConfig`]. Never fails; returns the config directly.
130    #[must_use]
131    pub fn build(self) -> EncoderConfig {
132        EncoderConfig {
133            video_codec: self.video_codec,
134            audio_codec: self.audio_codec,
135            bitrate_mode: self.bitrate_mode,
136            resolution: self.resolution,
137            framerate: self.framerate,
138            hardware: self.hardware,
139        }
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn builder_should_use_h264_aac_crf23_as_defaults() {
149        let config = EncoderConfig::builder().build();
150        assert!(matches!(config.video_codec, VideoCodec::H264));
151        assert!(matches!(config.audio_codec, AudioCodec::Aac));
152        assert!(matches!(config.bitrate_mode, BitrateMode::Crf(23)));
153        assert!(config.resolution.is_none());
154        assert!(config.framerate.is_none());
155        assert!(config.hardware.is_none());
156    }
157
158    #[test]
159    fn builder_should_store_all_fields() {
160        let config = EncoderConfig::builder()
161            .video_codec(VideoCodec::H265)
162            .audio_codec(AudioCodec::Opus)
163            .bitrate_mode(BitrateMode::Cbr(4_000_000))
164            .resolution(1280, 720)
165            .framerate(30.0)
166            .build();
167
168        assert!(matches!(config.video_codec, VideoCodec::H265));
169        assert!(matches!(config.audio_codec, AudioCodec::Opus));
170        assert!(matches!(config.bitrate_mode, BitrateMode::Cbr(4_000_000)));
171        assert_eq!(config.resolution, Some((1280, 720)));
172        assert_eq!(config.framerate, Some(30.0));
173    }
174
175    #[test]
176    fn crf_convenience_should_set_crf_mode() {
177        let config = EncoderConfig::builder().crf(28).build();
178        assert!(matches!(config.bitrate_mode, BitrateMode::Crf(28)));
179    }
180}