playa_ffmpeg/codec/
audio.rs

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