async_ffmpeg_sidecar/
metadata.rs

1//! Information about an Ffmpeg process and its streams.
2
3use crate::event::{FfmpegEvent, FfmpegInput, FfmpegOutput, FfmpegStream};
4use anyhow::bail;
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct FfmpegMetadata {
8  expected_output_streams: usize,
9  pub outputs: Vec<FfmpegOutput>,
10  pub output_streams: Vec<FfmpegStream>,
11  pub inputs: Vec<FfmpegInput>,
12  pub input_streams: Vec<FfmpegStream>,
13
14  /// Whether all metadata from the parent process has been gathered into this struct
15  completed: bool,
16}
17
18impl Default for FfmpegMetadata {
19  fn default() -> Self {
20    Self::new()
21  }
22}
23
24impl FfmpegMetadata {
25  pub fn new() -> Self {
26    Self {
27      expected_output_streams: 0,
28      outputs: Vec::new(),
29      output_streams: Vec::new(),
30      inputs: Vec::new(),
31      input_streams: Vec::new(),
32      completed: false,
33    }
34  }
35
36  pub fn is_completed(&self) -> bool {
37    self.completed
38  }
39
40  /// A shortcut to obtain the expected duration (in seconds).
41  ///
42  /// Usually this is the duration of the first input stream. Theoretically
43  /// different streams could have different (or conflicting) durations, but
44  /// this handles the common case.
45  pub fn duration(&self) -> Option<f64> {
46    self.inputs[0].duration
47  }
48
49  pub fn handle_event(&mut self, item: &FfmpegEvent) -> anyhow::Result<()> {
50    if self.is_completed() {
51      bail!("Metadata is already completed")
52    }
53
54    match item {
55      // Every stream mapping corresponds to one output stream
56      // We count these to know when we're received all the output streams
57      FfmpegEvent::ParsedStreamMapping(_) => self.expected_output_streams += 1,
58      FfmpegEvent::ParsedInput(input) => self.inputs.push(input.clone()),
59      FfmpegEvent::ParsedOutput(output) => self.outputs.push(output.clone()),
60      FfmpegEvent::ParsedDuration(duration) => {
61        self.inputs[duration.input_index as usize].duration = Some(duration.duration)
62      }
63      FfmpegEvent::ParsedOutputStream(stream) => self.output_streams.push(stream.clone()),
64      FfmpegEvent::ParsedInputStream(stream) => self.input_streams.push(stream.clone()),
65      _ => (),
66    }
67
68    if self.expected_output_streams > 0 && self.output_streams.len() == self.expected_output_streams
69    {
70      self.completed = true;
71    }
72
73    Ok(())
74  }
75}