selene_core/media_container/
stream.rs1use 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}