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