Skip to main content

selene_core/media_container/
stream.rs

1use serde::{Deserialize, Serialize};
2use symphonia::core::{codecs::audio::AudioCodecParameters, units::Duration};
3
4use crate::media_container::{
5    CodecError, ContainerError, codec::Codec, sample_format::SampleFormat,
6};
7
8#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Copy)]
9pub struct Stream {
10    pub id: u32,
11    pub codec_params: CodecParameters,
12    pub time_base: Option<(u32, u32)>,
13    pub num_frames: Option<u64>,
14    pub duration: u64,
15    pub start_ts: i64,
16    pub delay: Option<u32>,
17    pub padding: Option<u32>,
18}
19
20impl Stream {
21    #[must_use] 
22    pub fn duration(&self) -> f64 {
23        if let Some(frames) = self.num_frames {
24            return frames as f64 / f64::from(self.codec_params.sample_rate);
25        }
26
27        if let Some((n, d)) = self.time_base
28            && d > 0
29        {
30            return self.duration as f64 * (f64::from(n) / f64::from(d));
31        }
32
33        0.0
34    }
35}
36
37#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Copy)]
38pub struct CodecParameters {
39    pub codec: Codec,
40    pub sample_rate: u32,
41    pub sample_format: Option<SampleFormat>,
42    pub bits_per_sample: Option<u32>,
43    pub bits_per_coded_sample: Option<u32>,
44    pub channels: usize,
45    pub max_frames_per_packet: Option<u64>,
46    pub frames_per_block: Option<u64>,
47}
48
49impl TryFrom<&AudioCodecParameters> for CodecParameters {
50    type Error = ContainerError;
51
52    fn try_from(value: &AudioCodecParameters) -> Result<Self, Self::Error> {
53        Ok(Self {
54            codec: Codec::try_from(value.codec)?,
55            sample_rate: value.sample_rate.ok_or(ContainerError::NoSampleRate)?,
56            sample_format: value.sample_format.map(SampleFormat::from),
57            bits_per_sample: value.bits_per_sample,
58            bits_per_coded_sample: value.bits_per_coded_sample,
59            channels: value
60                .channels
61                .as_ref()
62                .ok_or(ContainerError::NoChannelCount)?
63                .count(),
64            max_frames_per_packet: value.max_frames_per_packet,
65            frames_per_block: value.frames_per_block,
66        })
67    }
68}
69
70impl TryFrom<&symphonia::core::formats::Track> for Stream {
71    type Error = ContainerError;
72
73    fn try_from(value: &symphonia::core::formats::Track) -> Result<Self, Self::Error> {
74        let duration = value.duration.map_or(0, Duration::get);
75
76        let codec_params =
77            value
78                .codec_params
79                .as_ref()
80                .ok_or(ContainerError::Codec(CodecError::Unknown(
81                    "Codec parameters could not be determined".to_owned(),
82                )))?;
83
84        Ok(Self {
85            id: value.id,
86            codec_params: CodecParameters::try_from(
87                codec_params
88                    .audio()
89                    .expect("Only audio tracks are supported"),
90            )?,
91            time_base: value.time_base.map(|tb| (tb.numer.get(), tb.denom.get())),
92            num_frames: value.num_frames,
93            duration,
94            start_ts: value.start_ts.get(),
95            delay: value.delay,
96            padding: value.padding,
97        })
98    }
99}