Files
lan-play/src/media/playback/profile.rs
T
Ultradesu eb0d4fb1c5
Build and Publish / Build and Publish Docker Image (push) Successful in 10m8s
Init
2026-08-05 12:32:52 +01:00

96 lines
2.9 KiB
Rust

use super::VideoPipeline;
#[derive(Debug, Clone)]
pub struct PlaybackPlan {
pub video_pipeline: VideoPipeline,
pub audio_streams: Vec<u32>,
pub duration_seconds: Option<f64>,
pub segment_seconds: u8,
}
impl PlaybackPlan {
pub fn live_dash(
video_pipeline: VideoPipeline,
audio_streams: Vec<u32>,
duration_seconds: Option<f64>,
) -> Self {
Self {
video_pipeline,
audio_streams,
duration_seconds,
segment_seconds: 2,
}
}
pub fn audio_count(&self) -> usize {
self.audio_streams.len()
}
pub fn ffmpeg_output_args(&self) -> Vec<String> {
let mut args = vec!["-map".into(), "0:v:0".into()];
args.extend(self.video_pipeline.ffmpeg_args(self.segment_seconds));
for stream in &self.audio_streams {
args.extend(["-map".into(), format!("0:{stream}")]);
}
if !self.audio_streams.is_empty() {
args.extend([
"-c:a".into(),
"aac".into(),
"-profile:a".into(),
"aac_low".into(),
"-b:a".into(),
"192k".into(),
"-ac".into(),
"2".into(),
]);
}
let mut adaptation_sets = vec!["id=0,streams=0".to_owned()];
adaptation_sets.extend(
(1..=self.audio_streams.len()).map(|output| format!("id={output},streams={output}")),
);
args.extend([
"-sn".into(),
"-f".into(),
"dash".into(),
"-seg_duration".into(),
self.segment_seconds.to_string(),
"-update_period".into(),
"1".into(),
"-use_template".into(),
"1".into(),
"-use_timeline".into(),
"1".into(),
"-window_size".into(),
"0".into(),
"-extra_window_size".into(),
"0".into(),
"-adaptation_sets".into(),
adaptation_sets.join(" "),
"manifest.mpd".into(),
]);
args
}
}
#[cfg(test)]
mod tests {
use super::{PlaybackPlan, VideoPipeline};
#[test]
fn live_profile_copies_video_and_encodes_audio_to_aac() {
let args = PlaybackPlan::live_dash(VideoPipeline::Copy, vec![1, 3], Some(120.0))
.ffmpeg_output_args();
assert!(args.windows(2).any(|pair| pair == ["-c:v", "copy"]));
assert!(args.windows(2).any(|pair| pair == ["-c:a", "aac"]));
assert!(args.windows(2).any(|pair| pair == ["-ac", "2"]));
assert!(args.windows(2).any(|pair| pair == ["-map", "0:1"]));
assert!(args.windows(2).any(|pair| pair == ["-map", "0:3"]));
assert!(args.windows(2).any(|pair| {
pair == [
"-adaptation_sets",
"id=0,streams=0 id=1,streams=1 id=2,streams=2",
]
}));
}
}