use ff_encode::BitrateMode;
use ff_filter::HwAccel;
use ff_format::{AudioCodec, VideoCodec};
#[non_exhaustive]
pub struct EncoderConfig {
pub video_codec: VideoCodec,
pub audio_codec: AudioCodec,
pub bitrate_mode: BitrateMode,
pub resolution: Option<(u32, u32)>,
pub framerate: Option<f64>,
pub hardware: Option<HwAccel>,
}
impl EncoderConfig {
#[must_use]
pub fn builder() -> EncoderConfigBuilder {
EncoderConfigBuilder::new()
}
}
pub struct EncoderConfigBuilder {
video_codec: VideoCodec,
audio_codec: AudioCodec,
bitrate_mode: BitrateMode,
resolution: Option<(u32, u32)>,
framerate: Option<f64>,
hardware: Option<HwAccel>,
}
impl EncoderConfigBuilder {
fn new() -> Self {
Self {
video_codec: VideoCodec::H264,
audio_codec: AudioCodec::Aac,
bitrate_mode: BitrateMode::Crf(23),
resolution: None,
framerate: None,
hardware: None,
}
}
#[must_use]
pub fn video_codec(mut self, codec: VideoCodec) -> Self {
self.video_codec = codec;
self
}
#[must_use]
pub fn audio_codec(mut self, codec: AudioCodec) -> Self {
self.audio_codec = codec;
self
}
#[must_use]
pub fn bitrate_mode(mut self, mode: BitrateMode) -> Self {
self.bitrate_mode = mode;
self
}
#[must_use]
pub fn crf(mut self, crf: u32) -> Self {
self.bitrate_mode = BitrateMode::Crf(crf);
self
}
#[must_use]
pub fn resolution(mut self, width: u32, height: u32) -> Self {
self.resolution = Some((width, height));
self
}
#[must_use]
pub fn framerate(mut self, fps: f64) -> Self {
self.framerate = Some(fps);
self
}
#[must_use]
pub fn hardware(mut self, hw: HwAccel) -> Self {
self.hardware = Some(hw);
self
}
#[must_use]
pub fn build(self) -> EncoderConfig {
EncoderConfig {
video_codec: self.video_codec,
audio_codec: self.audio_codec,
bitrate_mode: self.bitrate_mode,
resolution: self.resolution,
framerate: self.framerate,
hardware: self.hardware,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_should_use_h264_aac_crf23_as_defaults() {
let config = EncoderConfig::builder().build();
assert!(matches!(config.video_codec, VideoCodec::H264));
assert!(matches!(config.audio_codec, AudioCodec::Aac));
assert!(matches!(config.bitrate_mode, BitrateMode::Crf(23)));
assert!(config.resolution.is_none());
assert!(config.framerate.is_none());
assert!(config.hardware.is_none());
}
#[test]
fn builder_should_store_all_fields() {
let config = EncoderConfig::builder()
.video_codec(VideoCodec::H265)
.audio_codec(AudioCodec::Opus)
.bitrate_mode(BitrateMode::Cbr(4_000_000))
.resolution(1280, 720)
.framerate(30.0)
.build();
assert!(matches!(config.video_codec, VideoCodec::H265));
assert!(matches!(config.audio_codec, AudioCodec::Opus));
assert!(matches!(config.bitrate_mode, BitrateMode::Cbr(4_000_000)));
assert_eq!(config.resolution, Some((1280, 720)));
assert_eq!(config.framerate, Some(30.0));
}
#[test]
fn crf_convenience_should_set_crf_mode() {
let config = EncoderConfig::builder().crf(28).build();
assert!(matches!(config.bitrate_mode, BitrateMode::Crf(28)));
}
}