Skip to main content

ffmpeg_sys_the_third/avutil/
channel_layout.rs

1use libc::c_int;
2
3use crate::AVChannel::*;
4use crate::*;
5use crate::{AVChannelLayout, AVChannelOrder};
6
7use std::fmt;
8use std::mem::{align_of, size_of};
9use std::ptr::null_mut;
10
11impl AVChannelLayout {
12    #[inline]
13    pub const fn empty() -> Self {
14        Self {
15            order: AVChannelOrder::AV_CHANNEL_ORDER_UNSPEC,
16            nb_channels: 0,
17            u: AVChannelLayout__bindgen_ty_1 { mask: 0 },
18            opaque: null_mut(),
19        }
20    }
21}
22
23impl Clone for AVChannelLayout {
24    fn clone(&self) -> Self {
25        let mut cloned = Self::empty();
26        cloned.clone_from(self);
27
28        cloned
29    }
30
31    fn clone_from(&mut self, source: &Self) {
32        #[cold]
33        fn clone_failed(channels: c_int) -> ! {
34            use std::alloc::{handle_alloc_error, Layout};
35
36            let alloc_size = channels as usize * size_of::<AVChannelCustom>();
37            let layout =
38                Layout::from_size_align(alloc_size, align_of::<AVChannelCustom>()).unwrap();
39            handle_alloc_error(layout)
40        }
41
42        let ret = unsafe { av_channel_layout_copy(self as _, source as _) };
43
44        if ret < 0 {
45            clone_failed(self.nb_channels);
46        }
47    }
48}
49
50impl Drop for AVChannelLayout {
51    fn drop(&mut self) {
52        unsafe { av_channel_layout_uninit(self as _) }
53    }
54}
55
56impl PartialEq for AVChannelLayout {
57    fn eq(&self, other: &Self) -> bool {
58        unsafe { av_channel_layout_compare(self as _, other as _) == 0 }
59    }
60}
61
62impl fmt::Debug for AVChannelLayout {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        let mut dbg = f.debug_struct("AVChannelLayout");
65        dbg.field("order", &self.order)
66            .field("nb_channels", &self.nb_channels);
67
68        unsafe {
69            match self.order {
70                AVChannelOrder::AV_CHANNEL_ORDER_UNSPEC => {} // no other valid fields
71                AVChannelOrder::AV_CHANNEL_ORDER_NATIVE
72                | AVChannelOrder::AV_CHANNEL_ORDER_AMBISONIC => {
73                    dbg.field("mask", &format_args!("0x{:X}", self.u.mask));
74                }
75                AVChannelOrder::AV_CHANNEL_ORDER_CUSTOM => {
76                    dbg.field(
77                        "map",
78                        &std::slice::from_raw_parts(self.u.map, self.nb_channels as usize),
79                    );
80                }
81                // Not part of public API, but we have to exhaustively match
82                #[cfg(feature = "ffmpeg_7_0")]
83                AVChannelOrder::FF_CHANNEL_ORDER_NB => {}
84            }
85        }
86
87        dbg.field("opaque", &self.opaque).finish()
88    }
89}
90
91impl fmt::Debug for AVChannelCustom {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        unsafe {
94            f.debug_struct("AVChannelCustom")
95                .field("id", &self.id)
96                .field("name", &std::ffi::CStr::from_ptr(self.name.as_ptr()))
97                .field("opaque", &self.opaque)
98                .finish()
99        }
100    }
101}
102
103// Here until https://github.com/rust-lang/rust-bindgen/issues/2192 /
104// https://github.com/rust-lang/rust-bindgen/issues/258 is fixed.
105
106// The constants here should be kept up to date with libavutil/channel_layout.h.
107
108// Audio channel masks
109pub const AV_CH_FRONT_LEFT: u64 = 1 << (AV_CHAN_FRONT_LEFT as i32);
110pub const AV_CH_FRONT_RIGHT: u64 = 1 << (AV_CHAN_FRONT_RIGHT as i32);
111pub const AV_CH_FRONT_CENTER: u64 = 1 << (AV_CHAN_FRONT_CENTER as i32);
112pub const AV_CH_LOW_FREQUENCY: u64 = 1 << (AV_CHAN_LOW_FREQUENCY as i32);
113pub const AV_CH_BACK_LEFT: u64 = 1 << (AV_CHAN_BACK_LEFT as i32);
114pub const AV_CH_BACK_RIGHT: u64 = 1 << (AV_CHAN_BACK_RIGHT as i32);
115pub const AV_CH_FRONT_LEFT_OF_CENTER: u64 = 1 << (AV_CHAN_FRONT_LEFT_OF_CENTER as i32);
116pub const AV_CH_FRONT_RIGHT_OF_CENTER: u64 = 1 << (AV_CHAN_FRONT_RIGHT_OF_CENTER as i32);
117pub const AV_CH_BACK_CENTER: u64 = 1 << (AV_CHAN_BACK_CENTER as i32);
118pub const AV_CH_SIDE_LEFT: u64 = 1 << (AV_CHAN_SIDE_LEFT as i32);
119pub const AV_CH_SIDE_RIGHT: u64 = 1 << (AV_CHAN_SIDE_RIGHT as i32);
120pub const AV_CH_TOP_CENTER: u64 = 1 << (AV_CHAN_TOP_CENTER as i32);
121pub const AV_CH_TOP_FRONT_LEFT: u64 = 1 << (AV_CHAN_TOP_FRONT_LEFT as i32);
122pub const AV_CH_TOP_FRONT_CENTER: u64 = 1 << (AV_CHAN_TOP_FRONT_CENTER as i32);
123pub const AV_CH_TOP_FRONT_RIGHT: u64 = 1 << (AV_CHAN_TOP_FRONT_RIGHT as i32);
124pub const AV_CH_TOP_BACK_LEFT: u64 = 1 << (AV_CHAN_TOP_BACK_LEFT as i32);
125pub const AV_CH_TOP_BACK_CENTER: u64 = 1 << (AV_CHAN_TOP_BACK_CENTER as i32);
126pub const AV_CH_TOP_BACK_RIGHT: u64 = 1 << (AV_CHAN_TOP_BACK_RIGHT as i32);
127pub const AV_CH_STEREO_LEFT: u64 = 1 << (AV_CHAN_STEREO_LEFT as i32);
128pub const AV_CH_STEREO_RIGHT: u64 = 1 << (AV_CHAN_STEREO_RIGHT as i32);
129pub const AV_CH_WIDE_LEFT: u64 = 1 << (AV_CHAN_WIDE_LEFT as i32);
130pub const AV_CH_WIDE_RIGHT: u64 = 1 << (AV_CHAN_WIDE_RIGHT as i32);
131pub const AV_CH_SURROUND_DIRECT_LEFT: u64 = 1 << (AV_CHAN_SURROUND_DIRECT_LEFT as i32);
132pub const AV_CH_SURROUND_DIRECT_RIGHT: u64 = 1 << (AV_CHAN_SURROUND_DIRECT_RIGHT as i32);
133pub const AV_CH_LOW_FREQUENCY_2: u64 = 1 << (AV_CHAN_LOW_FREQUENCY_2 as i32);
134pub const AV_CH_TOP_SIDE_LEFT: u64 = 1 << (AV_CHAN_TOP_SIDE_LEFT as i32);
135pub const AV_CH_TOP_SIDE_RIGHT: u64 = 1 << (AV_CHAN_TOP_SIDE_RIGHT as i32);
136pub const AV_CH_BOTTOM_FRONT_CENTER: u64 = 1 << (AV_CHAN_BOTTOM_FRONT_CENTER as i32);
137pub const AV_CH_BOTTOM_FRONT_LEFT: u64 = 1 << (AV_CHAN_BOTTOM_FRONT_LEFT as i32);
138pub const AV_CH_BOTTOM_FRONT_RIGHT: u64 = 1 << (AV_CHAN_BOTTOM_FRONT_RIGHT as i32);
139
140#[cfg(feature = "ffmpeg_7_1")]
141pub const AV_CH_SIDE_SURROUND_LEFT: u64 = 1 << (AV_CHAN_SIDE_SURROUND_LEFT as i32);
142#[cfg(feature = "ffmpeg_7_1")]
143pub const AV_CH_SIDE_SURROUND_RIGHT: u64 = 1 << (AV_CHAN_SIDE_SURROUND_RIGHT as i32);
144#[cfg(feature = "ffmpeg_7_1")]
145pub const AV_CH_TOP_SURROUND_LEFT: u64 = 1 << (AV_CHAN_TOP_SURROUND_LEFT as i32);
146#[cfg(feature = "ffmpeg_7_1")]
147pub const AV_CH_TOP_SURROUND_RIGHT: u64 = 1 << (AV_CHAN_TOP_SURROUND_RIGHT as i32);
148
149#[cfg(feature = "ffmpeg_8_0")]
150pub const AV_CH_BINAURAL_LEFT: u64 = 1 << (AV_CHAN_BINAURAL_LEFT as i32);
151#[cfg(feature = "ffmpeg_8_0")]
152pub const AV_CH_BINAURAL_RIGHT: u64 = 1 << (AV_CHAN_BINAURAL_RIGHT as i32);
153
154// Audio channel layouts
155pub const AV_CH_LAYOUT_MONO: u64 = AV_CH_FRONT_CENTER;
156pub const AV_CH_LAYOUT_STEREO: u64 = AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT;
157pub const AV_CH_LAYOUT_2POINT1: u64 = AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY;
158pub const AV_CH_LAYOUT_2_1: u64 = AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER;
159pub const AV_CH_LAYOUT_SURROUND: u64 = AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER;
160pub const AV_CH_LAYOUT_3POINT1: u64 = AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY;
161pub const AV_CH_LAYOUT_4POINT0: u64 = AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER;
162pub const AV_CH_LAYOUT_4POINT1: u64 = AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY;
163pub const AV_CH_LAYOUT_2_2: u64 = AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT;
164pub const AV_CH_LAYOUT_QUAD: u64 = AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT;
165pub const AV_CH_LAYOUT_5POINT0: u64 = AV_CH_LAYOUT_SURROUND | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT;
166pub const AV_CH_LAYOUT_5POINT1: u64 = AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY;
167pub const AV_CH_LAYOUT_5POINT0_BACK: u64 =
168    AV_CH_LAYOUT_SURROUND | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT;
169pub const AV_CH_LAYOUT_5POINT1_BACK: u64 = AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY;
170pub const AV_CH_LAYOUT_6POINT0: u64 = AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER;
171pub const AV_CH_LAYOUT_6POINT0_FRONT: u64 =
172    AV_CH_LAYOUT_2_2 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
173pub const AV_CH_LAYOUT_HEXAGONAL: u64 = AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER;
174pub const AV_CH_LAYOUT_3POINT1POINT2: u64 =
175    AV_CH_LAYOUT_3POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT;
176pub const AV_CH_LAYOUT_6POINT1: u64 = AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER;
177pub const AV_CH_LAYOUT_6POINT1_BACK: u64 = AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER;
178pub const AV_CH_LAYOUT_6POINT1_FRONT: u64 = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY;
179pub const AV_CH_LAYOUT_7POINT0: u64 = AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT;
180pub const AV_CH_LAYOUT_7POINT0_FRONT: u64 =
181    AV_CH_LAYOUT_5POINT0 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
182pub const AV_CH_LAYOUT_7POINT1: u64 = AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT;
183pub const AV_CH_LAYOUT_7POINT1_WIDE: u64 =
184    AV_CH_LAYOUT_5POINT1 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
185pub const AV_CH_LAYOUT_7POINT1_WIDE_BACK: u64 =
186    AV_CH_LAYOUT_5POINT1_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
187#[cfg(feature = "ffmpeg_8_0")]
188pub const AV_CH_LAYOUT_5POINT1POINT2: u64 = AV_CH_LAYOUT_5POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT;
189pub const AV_CH_LAYOUT_5POINT1POINT2_BACK: u64 =
190    AV_CH_LAYOUT_5POINT1_BACK | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT;
191pub const AV_CH_LAYOUT_OCTAGONAL: u64 =
192    AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT;
193pub const AV_CH_LAYOUT_CUBE: u64 = AV_CH_LAYOUT_QUAD
194    | AV_CH_TOP_FRONT_LEFT
195    | AV_CH_TOP_FRONT_RIGHT
196    | AV_CH_TOP_BACK_LEFT
197    | AV_CH_TOP_BACK_RIGHT;
198pub const AV_CH_LAYOUT_5POINT1POINT4_BACK: u64 =
199    AV_CH_LAYOUT_5POINT1POINT2_BACK | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT;
200pub const AV_CH_LAYOUT_7POINT1POINT2: u64 =
201    AV_CH_LAYOUT_7POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT;
202pub const AV_CH_LAYOUT_7POINT1POINT4_BACK: u64 =
203    AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT;
204#[cfg(feature = "ffmpeg_7_0")]
205pub const AV_CH_LAYOUT_7POINT2POINT3: u64 =
206    AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_CENTER | AV_CH_LOW_FREQUENCY_2;
207#[cfg(feature = "ffmpeg_7_0")]
208pub const AV_CH_LAYOUT_9POINT1POINT4_BACK: u64 =
209    AV_CH_LAYOUT_7POINT1POINT4_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER;
210#[cfg(feature = "ffmpeg_8_0")]
211pub const AV_CH_LAYOUT_9POINT1POINT6: u64 = AV_CH_LAYOUT_9POINT1POINT4_BACK | AV_CH_TOP_SIDE_LEFT | AV_CH_TOP_SIDE_RIGHT;
212pub const AV_CH_LAYOUT_HEXADECAGONAL: u64 = AV_CH_LAYOUT_OCTAGONAL
213    | AV_CH_WIDE_LEFT
214    | AV_CH_WIDE_RIGHT
215    | AV_CH_TOP_BACK_LEFT
216    | AV_CH_TOP_BACK_RIGHT
217    | AV_CH_TOP_BACK_CENTER
218    | AV_CH_TOP_FRONT_CENTER
219    | AV_CH_TOP_FRONT_LEFT
220    | AV_CH_TOP_FRONT_RIGHT;
221#[cfg(feature = "ffmpeg_8_0")]
222pub const AV_CH_LAYOUT_BINAURAL: u64 = AV_CH_BINAURAL_LEFT | AV_CH_BINAURAL_RIGHT;
223pub const AV_CH_LAYOUT_STEREO_DOWNMIX: u64 = AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT;
224pub const AV_CH_LAYOUT_22POINT2: u64 = AV_CH_LAYOUT_5POINT1_BACK
225    | AV_CH_FRONT_LEFT_OF_CENTER
226    | AV_CH_FRONT_RIGHT_OF_CENTER
227    | AV_CH_BACK_CENTER
228    | AV_CH_LOW_FREQUENCY_2
229    | AV_CH_SIDE_LEFT
230    | AV_CH_SIDE_RIGHT
231    | AV_CH_TOP_FRONT_LEFT
232    | AV_CH_TOP_FRONT_RIGHT
233    | AV_CH_TOP_FRONT_CENTER
234    | AV_CH_TOP_CENTER
235    | AV_CH_TOP_BACK_LEFT
236    | AV_CH_TOP_BACK_RIGHT
237    | AV_CH_TOP_SIDE_LEFT
238    | AV_CH_TOP_SIDE_RIGHT
239    | AV_CH_TOP_BACK_CENTER
240    | AV_CH_BOTTOM_FRONT_CENTER
241    | AV_CH_BOTTOM_FRONT_LEFT
242    | AV_CH_BOTTOM_FRONT_RIGHT;
243
244pub const AV_CH_LAYOUT_7POINT1_TOP_BACK: u64 = AV_CH_LAYOUT_5POINT1POINT2_BACK;
245
246// Audio channel layouts as AVChannelLayout
247pub const fn AV_CHANNEL_LAYOUT_MASK(nb_channels: c_int, channel_mask: u64) -> AVChannelLayout {
248    AVChannelLayout {
249        order: AVChannelOrder::AV_CHANNEL_ORDER_NATIVE,
250        nb_channels,
251        u: crate::AVChannelLayout__bindgen_ty_1 { mask: channel_mask },
252        opaque: std::ptr::null_mut(),
253    }
254}
255
256pub const AV_CHANNEL_LAYOUT_MONO: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(1, AV_CH_LAYOUT_MONO);
257pub const AV_CHANNEL_LAYOUT_STEREO: AVChannelLayout =
258    AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_STEREO);
259pub const AV_CHANNEL_LAYOUT_2POINT1: AVChannelLayout =
260    AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_2POINT1);
261pub const AV_CHANNEL_LAYOUT_2_1: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_2_1);
262pub const AV_CHANNEL_LAYOUT_SURROUND: AVChannelLayout =
263    AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_SURROUND);
264pub const AV_CHANNEL_LAYOUT_3POINT1: AVChannelLayout =
265    AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_3POINT1);
266pub const AV_CHANNEL_LAYOUT_4POINT0: AVChannelLayout =
267    AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_4POINT0);
268pub const AV_CHANNEL_LAYOUT_4POINT1: AVChannelLayout =
269    AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_4POINT1);
270pub const AV_CHANNEL_LAYOUT_2_2: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_2_2);
271pub const AV_CHANNEL_LAYOUT_QUAD: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_QUAD);
272pub const AV_CHANNEL_LAYOUT_5POINT0: AVChannelLayout =
273    AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_5POINT0);
274pub const AV_CHANNEL_LAYOUT_5POINT1: AVChannelLayout =
275    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_5POINT1);
276pub const AV_CHANNEL_LAYOUT_5POINT0_BACK: AVChannelLayout =
277    AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_5POINT0_BACK);
278pub const AV_CHANNEL_LAYOUT_5POINT1_BACK: AVChannelLayout =
279    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_5POINT1_BACK);
280pub const AV_CHANNEL_LAYOUT_6POINT0: AVChannelLayout =
281    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_6POINT0);
282pub const AV_CHANNEL_LAYOUT_6POINT0_FRONT: AVChannelLayout =
283    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_6POINT0_FRONT);
284pub const AV_CHANNEL_LAYOUT_3POINT1POINT2: AVChannelLayout =
285    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_3POINT1POINT2);
286pub const AV_CHANNEL_LAYOUT_HEXAGONAL: AVChannelLayout =
287    AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_HEXAGONAL);
288pub const AV_CHANNEL_LAYOUT_6POINT1: AVChannelLayout =
289    AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1);
290pub const AV_CHANNEL_LAYOUT_6POINT1_BACK: AVChannelLayout =
291    AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1_BACK);
292pub const AV_CHANNEL_LAYOUT_6POINT1_FRONT: AVChannelLayout =
293    AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1_FRONT);
294pub const AV_CHANNEL_LAYOUT_7POINT0: AVChannelLayout =
295    AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_7POINT0);
296pub const AV_CHANNEL_LAYOUT_7POINT0_FRONT: AVChannelLayout =
297    AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_7POINT0_FRONT);
298pub const AV_CHANNEL_LAYOUT_7POINT1: AVChannelLayout =
299    AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1);
300pub const AV_CHANNEL_LAYOUT_7POINT1_WIDE: AVChannelLayout =
301    AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1_WIDE);
302pub const AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK: AVChannelLayout =
303    AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1_WIDE_BACK);
304#[cfg(feature = "ffmpeg_8_0")]
305pub const AV_CHANNEL_LAYOUT_5POINT1POINT2: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_5POINT1POINT2);
306pub const AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK: AVChannelLayout =
307    AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_5POINT1POINT2_BACK);
308pub const AV_CHANNEL_LAYOUT_OCTAGONAL: AVChannelLayout =
309    AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_OCTAGONAL);
310pub const AV_CHANNEL_LAYOUT_CUBE: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_CUBE);
311pub const AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK: AVChannelLayout =
312    AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_5POINT1POINT4_BACK);
313pub const AV_CHANNEL_LAYOUT_7POINT1POINT2: AVChannelLayout =
314    AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2);
315pub const AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK: AVChannelLayout =
316    AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT1POINT4_BACK);
317#[cfg(feature = "ffmpeg_7_0")]
318pub const AV_CHANNEL_LAYOUT_7POINT2POINT3: AVChannelLayout =
319    AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT2POINT3);
320#[cfg(feature = "ffmpeg_7_0")]
321pub const AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK: AVChannelLayout =
322    AV_CHANNEL_LAYOUT_MASK(14, AV_CH_LAYOUT_9POINT1POINT4_BACK);
323#[cfg(feature = "ffmpeg_8_0")]
324pub const AV_CHANNEL_LAYOUT_9POINT1POINT6: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_9POINT1POINT6);
325pub const AV_CHANNEL_LAYOUT_HEXADECAGONAL: AVChannelLayout =
326    AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL);
327#[cfg(feature = "ffmpeg_8_0")]
328pub const AV_CHANNEL_LAYOUT_BINAURAL: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_BINAURAL);
329pub const AV_CHANNEL_LAYOUT_STEREO_DOWNMIX: AVChannelLayout =
330    AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_STEREO_DOWNMIX);
331pub const AV_CHANNEL_LAYOUT_22POINT2: AVChannelLayout =
332    AV_CHANNEL_LAYOUT_MASK(24, AV_CH_LAYOUT_22POINT2);
333
334pub const AV_CHANNEL_LAYOUT_7POINT1_TOP_BACK: AVChannelLayout =
335    AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK;
336
337#[cfg(test)]
338mod test {
339    use super::*;
340    use libc::c_char;
341
342    // TODO: Missing: Ambisonic layout
343
344    const EMPTY: AVChannelLayout = AVChannelLayout::empty();
345    const UNSPEC: AVChannelLayout = {
346        let mut layout = AVChannelLayout::empty();
347        layout.nb_channels = 5;
348        layout
349    };
350
351    const NATIVE: AVChannelLayout = {
352        let mut layout = AVChannelLayout::empty();
353        layout.order = AVChannelOrder::AV_CHANNEL_ORDER_NATIVE;
354        layout.nb_channels = 6;
355        layout.u.mask = AV_CH_LAYOUT_5POINT1;
356        layout
357    };
358
359    // TODO: Replace with cstr literals when MSRV is 1.77
360    const fn c_string<const N: usize, const K: usize>(byte_str: &[u8; N]) -> [c_char; K] {
361        // Need at least one NUL byte at the end
362        assert!(N < K, "input string is too long (max 15 char)");
363
364        let mut result = [0; K];
365        let mut i = 0;
366
367        while i < N {
368            result[i] = byte_str[i] as c_char;
369            i += 1;
370        }
371
372        result
373    }
374
375    fn custom_ch<const N: usize>(id: AVChannel, name: &[u8; N]) -> AVChannelCustom {
376        AVChannelCustom {
377            id,
378            name: c_string(name),
379            opaque: null_mut(),
380        }
381    }
382
383    fn custom() -> AVChannelLayout {
384        let mut my_data = vec![0u8; 200];
385
386        let channels = [
387            custom_ch(AVChannel::AV_CHAN_FRONT_LEFT, b"front left"),
388            custom_ch(AVChannel::AV_CHAN_TOP_FRONT_RIGHT, b"top front right"),
389            custom_ch(AVChannel::AV_CHAN_FRONT_RIGHT, b"front right"),
390            custom_ch(AVChannel::AV_CHAN_BOTTOM_FRONT_RIGHT, b"btm frt right"),
391            custom_ch(AVChannel::AV_CHAN_TOP_SIDE_LEFT, b"top side left"),
392            AVChannelCustom {
393                id: AVChannel::AV_CHAN_LOW_FREQUENCY,
394                name: c_string(b"subwoofer"),
395                opaque: my_data.as_mut_ptr() as _,
396            },
397        ];
398
399        let mut layout = AVChannelLayout::empty();
400        layout.order = AVChannelOrder::AV_CHANNEL_ORDER_CUSTOM;
401        layout.nb_channels = channels.len() as c_int;
402        unsafe {
403            layout.u.map = av_calloc(channels.len(), size_of::<AVChannelCustom>()) as _;
404            assert!(!layout.u.map.is_null());
405        }
406
407        for (i, ch) in channels.iter().enumerate() {
408            unsafe {
409                std::ptr::write(layout.u.map.add(i), *ch);
410            }
411        }
412
413        layout
414    }
415
416    #[test]
417    fn check() {
418        let tests = [
419            (EMPTY, false),
420            (UNSPEC, true),
421            (NATIVE, true),
422            (custom(), true),
423        ];
424
425        for (i, (layout, valid)) in tests.iter().enumerate() {
426            unsafe {
427                println!("{i}");
428                assert!((av_channel_layout_check(layout as _) != 0) == *valid);
429            }
430        }
431    }
432
433    #[test]
434    fn debug() {
435        for layout in [EMPTY, UNSPEC, NATIVE, custom()] {
436            println!("{layout:?}");
437        }
438    }
439
440    #[test]
441    fn clone_eq() {
442        for layout in [EMPTY, UNSPEC, NATIVE, custom()] {
443            let cloned = layout.clone();
444            assert_eq!(layout, cloned);
445        }
446    }
447}