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