Skip to main content

dvb_si/descriptors/
ac3.rs

1//! AC-3 Descriptor — ETSI EN 300 468 Annex D (tag 0x6A).
2//!
3//! Carried inside PMT's ES_info loop for AC-3 audio components. The layout
4//! is a flag byte followed by four optional 1-byte fields and an optional
5//! free-form additional_info trailer.
6
7use crate::error::{Error, Result};
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for AC-3 audio.
12pub const TAG: u8 = 0x6A;
13const HEADER_LEN: usize = 2;
14
15const FLAG_COMPONENT_TYPE: u8 = 0x80;
16const FLAG_BSID: u8 = 0x40;
17const FLAG_MAINID: u8 = 0x20;
18const FLAG_ASVC: u8 = 0x10;
19
20/// AC-3 Descriptor.
21#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Ac3Descriptor<'a> {
24    /// AC-3 component_type (layout per Annex D).
25    pub component_type: Option<u8>,
26    /// Bit stream identification.
27    pub bsid: Option<u8>,
28    /// Main audio service id.
29    pub mainid: Option<u8>,
30    /// Associated service id.
31    pub asvc: Option<u8>,
32    /// Raw trailing additional_info bytes.
33    #[cfg_attr(feature = "serde", serde(borrow))]
34    pub additional_info: &'a [u8],
35}
36
37impl<'a> Parse<'a> for Ac3Descriptor<'a> {
38    type Error = crate::error::Error;
39    fn parse(bytes: &'a [u8]) -> Result<Self> {
40        if bytes.len() < HEADER_LEN + 1 {
41            return Err(Error::BufferTooShort {
42                need: HEADER_LEN + 1,
43                have: bytes.len(),
44                what: "Ac3Descriptor header+flags",
45            });
46        }
47        if bytes[0] != TAG {
48            return Err(Error::InvalidDescriptor {
49                tag: bytes[0],
50                reason: "unexpected tag for AC-3 descriptor",
51            });
52        }
53        let length = bytes[1] as usize;
54        let end = HEADER_LEN + length;
55        if bytes.len() < end {
56            return Err(Error::BufferTooShort {
57                need: end,
58                have: bytes.len(),
59                what: "Ac3Descriptor body",
60            });
61        }
62        let flags = bytes[HEADER_LEN];
63        let mut pos = HEADER_LEN + 1;
64        let mut read_one = |set: bool| -> Result<Option<u8>> {
65            if !set {
66                return Ok(None);
67            }
68            if pos >= end {
69                return Err(Error::InvalidDescriptor {
70                    tag: TAG,
71                    reason: "AC-3 descriptor flags claim more bytes than length permits",
72                });
73            }
74            let b = bytes[pos];
75            pos += 1;
76            Ok(Some(b))
77        };
78
79        let component_type = read_one(flags & FLAG_COMPONENT_TYPE != 0)?;
80        let bsid = read_one(flags & FLAG_BSID != 0)?;
81        let mainid = read_one(flags & FLAG_MAINID != 0)?;
82        let asvc = read_one(flags & FLAG_ASVC != 0)?;
83        let additional_info = &bytes[pos..end];
84        Ok(Self {
85            component_type,
86            bsid,
87            mainid,
88            asvc,
89            additional_info,
90        })
91    }
92}
93
94impl Serialize for Ac3Descriptor<'_> {
95    type Error = crate::error::Error;
96    fn serialized_len(&self) -> usize {
97        HEADER_LEN
98            + 1
99            + usize::from(self.component_type.is_some())
100            + usize::from(self.bsid.is_some())
101            + usize::from(self.mainid.is_some())
102            + usize::from(self.asvc.is_some())
103            + self.additional_info.len()
104    }
105
106    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
107        let len = self.serialized_len();
108        if buf.len() < len {
109            return Err(Error::OutputBufferTooSmall {
110                need: len,
111                have: buf.len(),
112            });
113        }
114        buf[0] = TAG;
115        buf[1] = (len - HEADER_LEN) as u8;
116        let mut flags: u8 = 0;
117        if self.component_type.is_some() {
118            flags |= FLAG_COMPONENT_TYPE;
119        }
120        if self.bsid.is_some() {
121            flags |= FLAG_BSID;
122        }
123        if self.mainid.is_some() {
124            flags |= FLAG_MAINID;
125        }
126        if self.asvc.is_some() {
127            flags |= FLAG_ASVC;
128        }
129        // The low 4 bits are reserved_future_use and must be set to 1.
130        buf[2] = flags | 0x0F;
131        let mut pos = 3;
132        for b in [self.component_type, self.bsid, self.mainid, self.asvc]
133            .into_iter()
134            .flatten()
135        {
136            buf[pos] = b;
137            pos += 1;
138        }
139        buf[pos..pos + self.additional_info.len()].copy_from_slice(self.additional_info);
140        Ok(len)
141    }
142}
143
144impl<'a> Descriptor<'a> for Ac3Descriptor<'a> {
145    const TAG: u8 = TAG;
146    fn descriptor_length(&self) -> u8 {
147        (self.serialized_len() - HEADER_LEN) as u8
148    }
149}
150
151impl<'a> crate::traits::DescriptorDef<'a> for Ac3Descriptor<'a> {
152    const TAG: u8 = TAG;
153    const NAME: &'static str = "AC3";
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn parse_with_all_fields() {
162        let bytes = [
163            TAG,
164            5,
165            FLAG_COMPONENT_TYPE | FLAG_BSID | FLAG_MAINID | FLAG_ASVC,
166            0x11,
167            0x22,
168            0x33,
169            0x44,
170        ];
171        let d = Ac3Descriptor::parse(&bytes).unwrap();
172        assert_eq!(d.component_type, Some(0x11));
173        assert_eq!(d.bsid, Some(0x22));
174        assert_eq!(d.mainid, Some(0x33));
175        assert_eq!(d.asvc, Some(0x44));
176        assert_eq!(d.additional_info, &[] as &[u8]);
177    }
178
179    #[test]
180    fn parse_with_only_component_type() {
181        let bytes = [TAG, 2, FLAG_COMPONENT_TYPE, 0x07];
182        let d = Ac3Descriptor::parse(&bytes).unwrap();
183        assert_eq!(d.component_type, Some(0x07));
184        assert_eq!(d.bsid, None);
185    }
186
187    #[test]
188    fn parse_with_additional_info_only() {
189        let bytes = [TAG, 3, 0x00, 0xAA, 0xBB];
190        let d = Ac3Descriptor::parse(&bytes).unwrap();
191        assert_eq!(d.component_type, None);
192        assert_eq!(d.additional_info, &[0xAA, 0xBB]);
193    }
194
195    #[test]
196    fn parse_rejects_wrong_tag() {
197        assert!(matches!(
198            Ac3Descriptor::parse(&[0x7A, 1, 0]).unwrap_err(),
199            Error::InvalidDescriptor { tag: 0x7A, .. }
200        ));
201    }
202
203    #[test]
204    fn parse_rejects_flags_past_length() {
205        // flags claim component_type but length=1 covers only the flags byte.
206        let bytes = [TAG, 1, FLAG_COMPONENT_TYPE];
207        assert!(matches!(
208            Ac3Descriptor::parse(&bytes).unwrap_err(),
209            Error::InvalidDescriptor { .. }
210        ));
211    }
212
213    #[test]
214    fn serialize_round_trip() {
215        let d = Ac3Descriptor {
216            component_type: Some(0x40),
217            bsid: Some(8),
218            mainid: None,
219            asvc: None,
220            additional_info: &[0xFE, 0xED],
221        };
222        let mut buf = vec![0u8; d.serialized_len()];
223        d.serialize_into(&mut buf).unwrap();
224        assert_eq!(Ac3Descriptor::parse(&buf).unwrap(), d);
225    }
226}