This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
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",
|
||||
]
|
||||
}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user