ffmpeg_pipeline/audio/
spec.rs1use 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}