Skip to main content

ffmpeg_sys_the_third/avutil/
channel_layout.rs

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