use serde::{Deserialize, Serialize};
use symphonia::core::{codecs::audio::AudioCodecParameters, units::Duration};
use crate::media_container::{
CodecError, ContainerError, codec::Codec, sample_format::SampleFormat,
};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Copy)]
pub struct Stream {
pub id: u32,
pub codec_params: CodecParameters,
pub time_base: Option<(u32, u32)>,
pub num_frames: Option<u64>,
pub duration: u64,
pub start_ts: i64,
pub delay: Option<u32>,
pub padding: Option<u32>,
}
impl Stream {
#[must_use]
pub fn duration(&self) -> f64 {
if let Some(frames) = self.num_frames {
return frames as f64 / f64::from(self.codec_params.sample_rate);
}
if let Some((n, d)) = self.time_base
&& d > 0
{
return self.duration as f64 * (f64::from(n) / f64::from(d));
}
0.0
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Copy)]
pub struct CodecParameters {
pub codec: Codec,
pub sample_rate: u32,
pub sample_format: Option<SampleFormat>,
pub bits_per_sample: Option<u32>,
pub bits_per_coded_sample: Option<u32>,
pub channels: usize,
pub max_frames_per_packet: Option<u64>,
pub frames_per_block: Option<u64>,
}
impl TryFrom<&AudioCodecParameters> for CodecParameters {
type Error = ContainerError;
fn try_from(value: &AudioCodecParameters) -> Result<Self, Self::Error> {
Ok(Self {
codec: Codec::try_from(value.codec)?,
sample_rate: value.sample_rate.ok_or(ContainerError::NoSampleRate)?,
sample_format: value.sample_format.map(SampleFormat::from),
bits_per_sample: value.bits_per_sample,
bits_per_coded_sample: value.bits_per_coded_sample,
channels: value
.channels
.as_ref()
.ok_or(ContainerError::NoChannelCount)?
.count(),
max_frames_per_packet: value.max_frames_per_packet,
frames_per_block: value.frames_per_block,
})
}
}
impl TryFrom<&symphonia::core::formats::Track> for Stream {
type Error = ContainerError;
fn try_from(value: &symphonia::core::formats::Track) -> Result<Self, Self::Error> {
let duration = value.duration.map_or(0, Duration::get);
let codec_params =
value
.codec_params
.as_ref()
.ok_or(ContainerError::Codec(CodecError::Unknown(
"Codec parameters could not be determined".to_owned(),
)))?;
Ok(Self {
id: value.id,
codec_params: CodecParameters::try_from(
codec_params
.audio()
.expect("Only audio tracks are supported"),
)?,
time_base: value.time_base.map(|tb| (tb.numer.get(), tb.denom.get())),
num_frames: value.num_frames,
duration,
start_ts: value.start_ts.get(),
delay: value.delay,
padding: value.padding,
})
}
}