Files
lan-play/src/media/playback/encoder.rs
T

62 lines
1.7 KiB
Rust
Raw Normal View History

2026-08-05 12:32:52 +01:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoPipeline {
Copy,
Encode(VideoEncoder),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoEncoder {
Libx264,
}
impl VideoPipeline {
pub fn ffmpeg_args(self, segment_seconds: u8) -> Vec<String> {
match self {
Self::Copy => vec!["-c:v".into(), "copy".into()],
Self::Encode(encoder) => encoder.ffmpeg_args(segment_seconds),
}
}
}
impl VideoEncoder {
pub fn portable_software() -> Self {
Self::Libx264
}
fn ffmpeg_args(self, segment_seconds: u8) -> Vec<String> {
match self {
Self::Libx264 => vec![
"-c:v".into(),
"libx264".into(),
"-preset".into(),
"veryfast".into(),
"-crf".into(),
"20".into(),
"-vf".into(),
"scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p".into(),
"-force_key_frames".into(),
format!("expr:gte(t,n_forced*{segment_seconds})"),
"-sc_threshold".into(),
"0".into(),
],
}
}
}
#[cfg(test)]
mod tests {
use super::{VideoEncoder, VideoPipeline};
#[test]
fn libx264_profile_is_browser_compatible_and_segment_aligned() {
let args = VideoPipeline::Encode(VideoEncoder::Libx264).ffmpeg_args(2);
assert!(args.windows(2).any(|pair| pair == ["-c:v", "libx264"]));
assert!(args.windows(2).any(|pair| pair == ["-crf", "20"]));
assert!(
args.windows(2)
.any(|pair| { pair == ["-force_key_frames", "expr:gte(t,n_forced*2)"] })
);
assert!(args.iter().any(|arg| arg.contains("format=yuv420p")));
}
}