ffmpeg_sidecar/
metadata.rs

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