Skip to main content

dvb_si/descriptors/
enhanced_ac3.rs

1//! Enhanced AC-3 Descriptor — ETSI EN 300 468 Annex D (tag 0x7A).
2//!
3//! Carried inside PMT's ES_info loop for Enhanced AC-3 (E-AC-3, Dolby Digital
4//! Plus) audio components.  The layout is a single flags byte whose eight bits
5//! are all assigned (no reserved nibble, unlike the AC-3 descriptor), followed
6//! by up to seven optional 1-byte fields and an optional free-form
7//! `additional_info_byte` trailer.
8
9use super::descriptor_body;
10use crate::error::{Error, Result};
11use dvb_common::{Parse, Serialize};
12
13/// Descriptor tag for Enhanced AC-3 (E-AC-3, Dolby Digital Plus).
14pub const TAG: u8 = 0x7A;
15const HEADER_LEN: usize = 2;
16
17const FLAG_COMPONENT_TYPE: u8 = 0x80;
18const FLAG_BSID: u8 = 0x40;
19const FLAG_MAINID: u8 = 0x20;
20const FLAG_ASVC: u8 = 0x10;
21const FLAG_MIXINFO_EXISTS: u8 = 0x08;
22const FLAG_SUBSTREAM1: u8 = 0x04;
23const FLAG_SUBSTREAM2: u8 = 0x02;
24const FLAG_SUBSTREAM3: u8 = 0x01;
25
26/// Enhanced AC-3 Descriptor — EN 300 468 Annex D (tag 0x7A).
27#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
30pub struct EnhancedAc3Descriptor<'a> {
31    /// AC-3 component_type (layout per Annex D).
32    pub component_type: Option<u8>,
33    /// Bit stream identification.
34    pub bsid: Option<u8>,
35    /// Main audio service id.
36    pub mainid: Option<u8>,
37    /// Associated service id.
38    pub asvc: Option<u8>,
39    /// mixinfoexists flag — indicates whether mixing metadata is present in
40    /// the enhanced AC-3 bit stream.
41    pub mixinfoexists: bool,
42    /// Sub-stream 1 identification.
43    pub substream1: Option<u8>,
44    /// Sub-stream 2 identification.
45    pub substream2: Option<u8>,
46    /// Sub-stream 3 identification.
47    pub substream3: Option<u8>,
48    /// Raw trailing `additional_info_byte` run.
49    pub additional_info: &'a [u8],
50}
51
52impl<'a> Parse<'a> for EnhancedAc3Descriptor<'a> {
53    type Error = crate::error::Error;
54    fn parse(bytes: &'a [u8]) -> Result<Self> {
55        let body = descriptor_body(
56            bytes,
57            TAG,
58            "EnhancedAc3Descriptor",
59            "unexpected tag for EAC-3 descriptor",
60        )?;
61        if body.is_empty() {
62            return Err(Error::InvalidDescriptor {
63                tag: TAG,
64                reason: "descriptor body is empty (length=0)",
65            });
66        }
67        let flags = body[0];
68        let mixinfoexists = (flags & FLAG_MIXINFO_EXISTS) != 0;
69        let mut pos = 1;
70        let mut read_one = |set: bool| -> Result<Option<u8>> {
71            if !set {
72                return Ok(None);
73            }
74            if pos >= body.len() {
75                return Err(Error::InvalidDescriptor {
76                    tag: TAG,
77                    reason: "enhanced AC-3 descriptor flags claim more bytes than length permits",
78                });
79            }
80            let b = body[pos];
81            pos += 1;
82            Ok(Some(b))
83        };
84
85        let component_type = read_one(flags & FLAG_COMPONENT_TYPE != 0)?;
86        let bsid = read_one(flags & FLAG_BSID != 0)?;
87        let mainid = read_one(flags & FLAG_MAINID != 0)?;
88        let asvc = read_one(flags & FLAG_ASVC != 0)?;
89        let substream1 = read_one(flags & FLAG_SUBSTREAM1 != 0)?;
90        let substream2 = read_one(flags & FLAG_SUBSTREAM2 != 0)?;
91        let substream3 = read_one(flags & FLAG_SUBSTREAM3 != 0)?;
92        let additional_info = &body[pos..];
93        Ok(Self {
94            component_type,
95            bsid,
96            mainid,
97            asvc,
98            mixinfoexists,
99            substream1,
100            substream2,
101            substream3,
102            additional_info,
103        })
104    }
105}
106
107impl Serialize for EnhancedAc3Descriptor<'_> {
108    type Error = crate::error::Error;
109    fn serialized_len(&self) -> usize {
110        HEADER_LEN
111            + 1
112            + usize::from(self.component_type.is_some())
113            + usize::from(self.bsid.is_some())
114            + usize::from(self.mainid.is_some())
115            + usize::from(self.asvc.is_some())
116            + usize::from(self.substream1.is_some())
117            + usize::from(self.substream2.is_some())
118            + usize::from(self.substream3.is_some())
119            + self.additional_info.len()
120    }
121
122    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
123        let len = self.serialized_len();
124        if buf.len() < len {
125            return Err(Error::OutputBufferTooSmall {
126                need: len,
127                have: buf.len(),
128            });
129        }
130        buf[0] = TAG;
131        buf[1] = (len - HEADER_LEN) as u8;
132        let mut flags: u8 = 0;
133        if self.component_type.is_some() {
134            flags |= FLAG_COMPONENT_TYPE;
135        }
136        if self.bsid.is_some() {
137            flags |= FLAG_BSID;
138        }
139        if self.mainid.is_some() {
140            flags |= FLAG_MAINID;
141        }
142        if self.asvc.is_some() {
143            flags |= FLAG_ASVC;
144        }
145        if self.mixinfoexists {
146            flags |= FLAG_MIXINFO_EXISTS;
147        }
148        if self.substream1.is_some() {
149            flags |= FLAG_SUBSTREAM1;
150        }
151        if self.substream2.is_some() {
152            flags |= FLAG_SUBSTREAM2;
153        }
154        if self.substream3.is_some() {
155            flags |= FLAG_SUBSTREAM3;
156        }
157        buf[2] = flags;
158        let mut pos = 3;
159        for b in [
160            self.component_type,
161            self.bsid,
162            self.mainid,
163            self.asvc,
164            self.substream1,
165            self.substream2,
166            self.substream3,
167        ]
168        .into_iter()
169        .flatten()
170        {
171            buf[pos] = b;
172            pos += 1;
173        }
174        buf[pos..pos + self.additional_info.len()].copy_from_slice(self.additional_info);
175        Ok(len)
176    }
177}
178impl<'a> crate::traits::DescriptorDef<'a> for EnhancedAc3Descriptor<'a> {
179    const TAG: u8 = TAG;
180    const NAME: &'static str = "ENHANCED_AC3";
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186
187    #[test]
188    fn parse_with_all_fields() {
189        let bytes = [
190            TAG,
191            8,
192            FLAG_COMPONENT_TYPE
193                | FLAG_BSID
194                | FLAG_MAINID
195                | FLAG_ASVC
196                | FLAG_MIXINFO_EXISTS
197                | FLAG_SUBSTREAM1
198                | FLAG_SUBSTREAM2
199                | FLAG_SUBSTREAM3,
200            0x11,
201            0x22,
202            0x33,
203            0x44,
204            0x55,
205            0x66,
206            0x77,
207        ];
208        let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
209        assert_eq!(d.component_type, Some(0x11));
210        assert_eq!(d.bsid, Some(0x22));
211        assert_eq!(d.mainid, Some(0x33));
212        assert_eq!(d.asvc, Some(0x44));
213        assert!(d.mixinfoexists);
214        assert_eq!(d.substream1, Some(0x55));
215        assert_eq!(d.substream2, Some(0x66));
216        assert_eq!(d.substream3, Some(0x77));
217        assert_eq!(d.additional_info, &[] as &[u8]);
218    }
219
220    #[test]
221    fn parse_with_only_component_type_and_mixinfoexists() {
222        let bytes = [TAG, 2, FLAG_COMPONENT_TYPE | FLAG_MIXINFO_EXISTS, 0x07];
223        let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
224        assert_eq!(d.component_type, Some(0x07));
225        assert!(d.mixinfoexists);
226        assert_eq!(d.bsid, None);
227        assert_eq!(d.substream1, None);
228    }
229
230    #[test]
231    fn parse_with_additional_info_only() {
232        let bytes = [TAG, 3, 0x00, 0xAA, 0xBB];
233        let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
234        assert_eq!(d.component_type, None);
235        assert!(!d.mixinfoexists);
236        assert_eq!(d.additional_info, &[0xAA, 0xBB]);
237    }
238
239    #[test]
240    fn parse_rejects_wrong_tag() {
241        assert!(matches!(
242            EnhancedAc3Descriptor::parse(&[0x6A, 1, 0]).unwrap_err(),
243            Error::InvalidDescriptor { tag: 0x6A, .. }
244        ));
245    }
246
247    #[test]
248    fn parse_rejects_flags_past_length() {
249        let bytes = [TAG, 1, FLAG_COMPONENT_TYPE];
250        assert!(matches!(
251            EnhancedAc3Descriptor::parse(&bytes).unwrap_err(),
252            Error::InvalidDescriptor { .. }
253        ));
254    }
255
256    #[test]
257    fn parse_rejects_short_buffer() {
258        assert!(matches!(
259            EnhancedAc3Descriptor::parse(&[TAG]).unwrap_err(),
260            Error::BufferTooShort { .. }
261        ));
262    }
263
264    #[test]
265    fn serialize_round_trip() {
266        let d = EnhancedAc3Descriptor {
267            component_type: Some(0x40),
268            bsid: Some(8),
269            mainid: None,
270            asvc: None,
271            mixinfoexists: true,
272            substream1: Some(0xAA),
273            substream2: None,
274            substream3: None,
275            additional_info: &[0xFE, 0xED],
276        };
277        let mut buf = vec![0u8; d.serialized_len()];
278        d.serialize_into(&mut buf).unwrap();
279        assert_eq!(EnhancedAc3Descriptor::parse(&buf).unwrap(), d);
280    }
281
282    #[test]
283    fn serialize_round_trip_no_flags() {
284        let d = EnhancedAc3Descriptor {
285            component_type: None,
286            bsid: None,
287            mainid: None,
288            asvc: None,
289            mixinfoexists: false,
290            substream1: None,
291            substream2: None,
292            substream3: None,
293            additional_info: &[],
294        };
295        let mut buf = vec![0u8; d.serialized_len()];
296        d.serialize_into(&mut buf).unwrap();
297        assert_eq!(EnhancedAc3Descriptor::parse(&buf).unwrap(), d);
298        assert_eq!(buf, [TAG, 1, 0x00]);
299    }
300
301    #[test]
302    fn parse_rejects_empty_body() {
303        let bytes = [TAG, 0];
304        assert!(matches!(
305            EnhancedAc3Descriptor::parse(&bytes).unwrap_err(),
306            Error::InvalidDescriptor { .. }
307        ));
308    }
309}