Skip to main content

ffmpeg_next/codec/
audio.rs

1use std::ops::Deref;
2
3use super::codec::Codec;
4use crate::ffi::*;
5use crate::{ChannelLayout, format};
6
7#[derive(PartialEq, Eq, Copy, Clone)]
8pub struct Audio {
9    codec: Codec,
10}
11
12impl Audio {
13    pub unsafe fn new(codec: Codec) -> Audio {
14        Audio { codec }
15    }
16}
17
18impl Audio {
19    pub fn rates(&self) -> Option<RateIter> {
20        unsafe {
21            #[cfg(feature = "ffmpeg_9_0")]
22            let ptr = super::supported_config::<i32>(
23                self.codec.as_ptr(),
24                AVCodecConfig::AV_CODEC_CONFIG_SAMPLE_RATE,
25            );
26            #[cfg(not(feature = "ffmpeg_9_0"))]
27            let ptr = (*self.codec.as_ptr()).supported_samplerates;
28
29            if ptr.is_null() {
30                None
31            } else {
32                Some(RateIter::new(ptr))
33            }
34        }
35    }
36
37    pub fn formats(&self) -> Option<FormatIter> {
38        unsafe {
39            #[cfg(feature = "ffmpeg_9_0")]
40            let ptr = super::supported_config::<AVSampleFormat>(
41                self.codec.as_ptr(),
42                AVCodecConfig::AV_CODEC_CONFIG_SAMPLE_FORMAT,
43            );
44            #[cfg(not(feature = "ffmpeg_9_0"))]
45            let ptr = (*self.codec.as_ptr()).sample_fmts;
46
47            if ptr.is_null() {
48                None
49            } else {
50                Some(FormatIter::new(ptr))
51            }
52        }
53    }
54
55    pub fn channel_layouts(&self) -> Option<ChannelLayoutIter> {
56        unsafe {
57            #[cfg(not(feature = "ffmpeg_7_0"))]
58            let ptr = (*self.codec.as_ptr()).channel_layouts;
59
60            #[cfg(all(feature = "ffmpeg_7_0", not(feature = "ffmpeg_9_0")))]
61            let ptr = (*self.codec.as_ptr()).ch_layouts;
62
63            #[cfg(feature = "ffmpeg_9_0")]
64            let ptr = super::supported_config::<AVChannelLayout>(
65                self.codec.as_ptr(),
66                AVCodecConfig::AV_CODEC_CONFIG_CHANNEL_LAYOUT,
67            );
68
69            if ptr.is_null() {
70                None
71            } else {
72                Some(ChannelLayoutIter::new(ptr))
73            }
74        }
75    }
76}
77
78impl Deref for Audio {
79    type Target = Codec;
80
81    fn deref(&self) -> &Self::Target {
82        &self.codec
83    }
84}
85
86pub struct RateIter {
87    ptr: *const i32,
88}
89
90impl RateIter {
91    pub fn new(ptr: *const i32) -> Self {
92        RateIter { ptr }
93    }
94}
95
96impl Iterator for RateIter {
97    type Item = i32;
98
99    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
100        unsafe {
101            if *self.ptr == 0 {
102                return None;
103            }
104
105            let rate = *self.ptr;
106            self.ptr = self.ptr.offset(1);
107
108            Some(rate)
109        }
110    }
111}
112
113pub struct FormatIter {
114    ptr: *const AVSampleFormat,
115}
116
117impl FormatIter {
118    pub fn new(ptr: *const AVSampleFormat) -> Self {
119        FormatIter { ptr }
120    }
121}
122
123impl Iterator for FormatIter {
124    type Item = format::Sample;
125
126    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
127        unsafe {
128            if *self.ptr == AVSampleFormat::AV_SAMPLE_FMT_NONE {
129                return None;
130            }
131
132            let format = (*self.ptr).into();
133            self.ptr = self.ptr.offset(1);
134
135            Some(format)
136        }
137    }
138}
139
140#[cfg(not(feature = "ffmpeg_7_0"))]
141type ChannelLayoutType = u64;
142#[cfg(feature = "ffmpeg_7_0")]
143type ChannelLayoutType = AVChannelLayout;
144
145pub struct ChannelLayoutIter {
146    ptr: *const ChannelLayoutType,
147}
148
149impl ChannelLayoutIter {
150    pub fn new(ptr: *const ChannelLayoutType) -> Self {
151        ChannelLayoutIter { ptr }
152    }
153
154    pub fn best(self, max: i32) -> ChannelLayout {
155        self.fold(ChannelLayout::MONO, |acc, cur| {
156            if cur.channels() > acc.channels() && cur.channels() <= max as _ {
157                cur
158            } else {
159                acc
160            }
161        })
162    }
163}
164
165impl Iterator for ChannelLayoutIter {
166    type Item = ChannelLayout;
167
168    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
169        unsafe {
170            #[cfg(not(feature = "ffmpeg_7_0"))]
171            if *self.ptr == 0 {
172                return None;
173            }
174
175            #[cfg(feature = "ffmpeg_7_0")]
176            if self.ptr.is_null() || (*self.ptr).u.mask == 0 {
177                return None;
178            }
179
180            #[cfg(not(feature = "ffmpeg_7_0"))]
181            let layout = ChannelLayout::from_bits_truncate(*self.ptr);
182
183            #[cfg(feature = "ffmpeg_7_0")]
184            let layout = ChannelLayout::from(*self.ptr);
185
186            self.ptr = self.ptr.offset(1);
187
188            Some(layout)
189        }
190    }
191}