Skip to main content

ffmpeg_pipeline/audio/
spec.rs

1use super::*;
2use ffmpeg_next::{codec::context::Context, media::Type as MediaType, Codec, Rational, Stream};
3
4pub(crate) fn decoder_channel_layout(decoder: &ffmpeg_next::decoder::Audio) -> ChannelLayout {
5    let layout = decoder.channel_layout();
6    if layout.is_empty() {
7        ChannelLayout::default(decoder.channels().into())
8    } else {
9        layout
10    }
11}
12
13#[derive(Clone)]
14pub struct AudioSpec {
15    pub(super) sample_rate: u32,
16    pub(super) time_base: Rational,
17    pub(super) format: Sample,
18    pub(super) channel_layout: ChannelLayout,
19    pub(super) codec: Option<Codec>,
20    pub(super) frame_size: u32,
21}
22
23impl AudioSpec {
24    pub fn new(channel_layout: ChannelLayout, format: Sample, sample_rate: u32) -> Self {
25        Self {
26            channel_layout,
27            format,
28            frame_size: 0,
29            sample_rate,
30            time_base: (1, sample_rate as i32).into(),
31            codec: None,
32        }
33    }
34
35    pub fn with_codec(mut self, codec: Option<Codec>) -> Self {
36        self.codec = codec;
37        self
38    }
39
40    pub fn with_frame_size(mut self, frame_size: u32) -> Self {
41        self.frame_size = frame_size;
42        self
43    }
44
45    pub fn with_time_base(mut self, time_base: Rational) -> Self {
46        self.time_base = time_base;
47        self
48    }
49}
50
51impl TryFrom<&AudioSpec> for AudioSpec {
52    type Error = FFmpegError;
53    fn try_from(a: &AudioSpec) -> Result<Self, Self::Error> {
54        Ok(a.clone())
55    }
56}
57
58impl TryFrom<&Decoder<'_>> for AudioSpec {
59    type Error = FFmpegError;
60    fn try_from(decoder: &Decoder<'_>) -> Result<Self, Self::Error> {
61        match decoder.get_decoder() {
62            StreamDecoder::Audio(decoder) => Ok(Self::new(
63                decoder_channel_layout(decoder),
64                decoder.format(),
65                decoder.rate(),
66            )
67            .with_codec(decoder.codec())
68            .with_frame_size(decoder.frame_size())
69            .with_time_base(decoder.time_base())),
70            _ => Err(FFmpegError::InvalidStreamType("Video".into())),
71        }
72    }
73}
74
75impl TryFrom<&Encoder<'_>> for AudioSpec {
76    type Error = FFmpegError;
77    fn try_from(encoder: &Encoder<'_>) -> Result<Self, Self::Error> {
78        match encoder.get_encoder() {
79            StreamEncoder::Audio(encoder) => {
80                Ok(
81                    Self::new(encoder.channel_layout(), encoder.format(), encoder.rate())
82                        .with_codec(encoder.codec())
83                        .with_frame_size(encoder.frame_size())
84                        .with_time_base(encoder.time_base()),
85                )
86            }
87            _ => Err(FFmpegError::InvalidStreamType("Video".into())),
88        }
89    }
90}
91
92impl TryFrom<&Stream<'_>> for AudioSpec {
93    type Error = FFmpegError;
94    fn try_from(stream: &Stream) -> Result<Self, Self::Error> {
95        let codec = Context::from_parameters(stream.parameters())?;
96        if codec.medium() == MediaType::Audio {
97            let decoder = codec.decoder().audio()?;
98            Ok(AudioSpec::new(
99                decoder_channel_layout(&decoder),
100                decoder.format(),
101                decoder.rate(),
102            )
103            .with_codec(decoder.codec())
104            .with_frame_size(decoder.frame_size())
105            .with_time_base(decoder.time_base()))
106        } else {
107            Err(FFmpegError::CodecNotFound(stream.parameters().id()))
108        }
109    }
110}