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//! Same flags-and-fields layout as AC-3 plus two extra bits
4//! (mixinfoexists, substream ids). A simpler subset is modelled here; the
5//! descriptor body beyond the documented flags is retained as raw bytes.
6
7use crate::error::{Error, Result};
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for Enhanced AC-3 (E-AC-3, Dolby Digital Plus).
12pub const TAG: u8 = 0x7A;
13const HEADER_LEN: usize = 2;
14
15/// Enhanced AC-3 Descriptor. Body is opaque for this subset — full Annex D
16/// parsing is deferred; we preserve the bytes verbatim.
17#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19pub struct EnhancedAc3Descriptor<'a> {
20    /// Raw payload (everything after the 2-byte header).
21    pub body: &'a [u8],
22}
23
24impl<'a> Parse<'a> for EnhancedAc3Descriptor<'a> {
25    type Error = crate::error::Error;
26    fn parse(bytes: &'a [u8]) -> Result<Self> {
27        if bytes.len() < HEADER_LEN {
28            return Err(Error::BufferTooShort {
29                need: HEADER_LEN,
30                have: bytes.len(),
31                what: "EnhancedAc3Descriptor header",
32            });
33        }
34        if bytes[0] != TAG {
35            return Err(Error::InvalidDescriptor {
36                tag: bytes[0],
37                reason: "unexpected tag for EAC-3 descriptor",
38            });
39        }
40        let length = bytes[1] as usize;
41        let end = HEADER_LEN + length;
42        if bytes.len() < end {
43            return Err(Error::BufferTooShort {
44                need: end,
45                have: bytes.len(),
46                what: "EnhancedAc3Descriptor body",
47            });
48        }
49        Ok(Self {
50            body: &bytes[HEADER_LEN..end],
51        })
52    }
53}
54
55impl Serialize for EnhancedAc3Descriptor<'_> {
56    type Error = crate::error::Error;
57    fn serialized_len(&self) -> usize {
58        HEADER_LEN + self.body.len()
59    }
60
61    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
62        let len = self.serialized_len();
63        if buf.len() < len {
64            return Err(Error::OutputBufferTooSmall {
65                need: len,
66                have: buf.len(),
67            });
68        }
69        buf[0] = TAG;
70        buf[1] = self.body.len() as u8;
71        buf[HEADER_LEN..len].copy_from_slice(self.body);
72        Ok(len)
73    }
74}
75
76impl<'a> Descriptor<'a> for EnhancedAc3Descriptor<'a> {
77    const TAG: u8 = TAG;
78    fn descriptor_length(&self) -> u8 {
79        self.body.len() as u8
80    }
81}
82
83impl<'a> crate::traits::DescriptorDef<'a> for EnhancedAc3Descriptor<'a> {
84    const TAG: u8 = TAG;
85    const NAME: &'static str = "ENHANCED_AC3";
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn parse_extracts_body() {
94        let bytes = [TAG, 3, 0xAA, 0xBB, 0xCC];
95        let d = EnhancedAc3Descriptor::parse(&bytes).unwrap();
96        assert_eq!(d.body, &[0xAA, 0xBB, 0xCC]);
97    }
98
99    #[test]
100    fn parse_rejects_wrong_tag() {
101        assert!(matches!(
102            EnhancedAc3Descriptor::parse(&[0x6A, 0]).unwrap_err(),
103            Error::InvalidDescriptor { tag: 0x6A, .. }
104        ));
105    }
106
107    #[test]
108    fn parse_rejects_short_buffer() {
109        assert!(matches!(
110            EnhancedAc3Descriptor::parse(&[TAG]).unwrap_err(),
111            Error::BufferTooShort { .. }
112        ));
113    }
114
115    #[test]
116    fn serialize_round_trip() {
117        let d = EnhancedAc3Descriptor {
118            body: &[0x01, 0x02, 0x03],
119        };
120        let mut buf = vec![0u8; d.serialized_len()];
121        d.serialize_into(&mut buf).unwrap();
122        assert_eq!(EnhancedAc3Descriptor::parse(&buf).unwrap(), d);
123    }
124
125    #[test]
126    fn empty_body_valid() {
127        let d = EnhancedAc3Descriptor::parse(&[TAG, 0]).unwrap();
128        assert_eq!(d.body, &[] as &[u8]);
129    }
130}