ffmpeg_the_third/util/channel_layout/
channel_custom.rs

1use libc::c_char;
2
3use crate::ffi::{AVChannel, AVChannelCustom};
4
5use super::Channel;
6
7/// Wrapper around [`AVChannelCustom`][crate::ffi::AVChannelCustom].
8///
9/// This struct does not support reading or writing user data via the opaque pointer.
10#[derive(Debug, Clone, PartialEq, Eq)]
11#[repr(transparent)]
12pub struct ChannelCustom(AVChannelCustom);
13
14impl ChannelCustom {
15    pub fn new(id: Channel) -> Self {
16        Self(AVChannelCustom {
17            id: AVChannel::from(id),
18            name: [0; 16],
19            opaque: std::ptr::null_mut(),
20        })
21    }
22
23    pub fn named<S: AsRef<str>>(id: Channel, name: S) -> Self {
24        let name = name.as_ref();
25        let name = to_char_array(name.as_bytes());
26
27        Self(AVChannelCustom {
28            id: AVChannel::from(id),
29            name,
30            opaque: std::ptr::null_mut(),
31        })
32    }
33}
34
35fn to_char_array(bytes: &[u8]) -> [c_char; 16] {
36    let mut result = [0; 16];
37
38    // Only take the first 15 bytes, leaving at least one NUL byte
39    for (b, r) in bytes.iter().take(15).zip(&mut result) {
40        *r = *b as c_char;
41    }
42
43    result
44}
45
46impl From<AVChannelCustom> for ChannelCustom {
47    fn from(value: AVChannelCustom) -> Self {
48        Self(value)
49    }
50}
51
52impl From<ChannelCustom> for AVChannelCustom {
53    fn from(value: ChannelCustom) -> Self {
54        value.0
55    }
56}
57
58#[cfg(test)]
59mod test {
60    use super::*;
61    use std::alloc::Layout;
62
63    #[test]
64    fn is_repr_transparent() {
65        // ChannelLayout::map relies on this being true.
66        assert_eq!(
67            Layout::new::<AVChannelCustom>(),
68            Layout::new::<ChannelCustom>()
69        );
70    }
71
72    #[test]
73    fn new() {
74        let custom = ChannelCustom::new(Channel::FrontRight);
75        assert_eq!(custom.0.id, AVChannel::AV_CHAN_FRONT_RIGHT);
76        assert_eq!(custom.0.name, [0; 16]);
77        assert!(custom.0.opaque.is_null());
78    }
79
80    #[test]
81    fn named() {
82        // "Bottom front ri\0"
83        let c_str_name = [
84            66, 111, 116, 116, 111, 109, 32, 102, 114, 111, 110, 116, 32, 114, 105, 0,
85        ];
86
87        let custom = ChannelCustom::named(Channel::BottomFrontRight, "Bottom front right");
88        assert_eq!(custom.0.id, AVChannel::AV_CHAN_BOTTOM_FRONT_RIGHT);
89        assert_eq!(custom.0.name, c_str_name);
90        assert!(custom.0.opaque.is_null());
91    }
92}