Skip to main content

dvb_si/descriptors/
aac.rs

1//! AAC Descriptor — ETSI EN 300 468 Annex H, Table H.1 (tag 0x7C).
2//!
3//! Carried in the PMT ES_info loop to identify MPEG-4 AAC / HE-AAC / HE-AAC v2
4//! audio. Per the SI PDF (etsi_en_300_468_v01.19.01, Annex H §H.2.1, Table H.1,
5//! PDF pp. 196-197) the body is:
6//!   profile_and_level(8)
7//!   if (descriptor_length > 1) {
8//!     AAC_type_flag(1) + SAOC_DE_flag(1) + reserved_zero_future_use(6)
9//!     if (AAC_type_flag == 1) AAC_type(8)
10//!     additional_info_byte(8*N)
11//!   }
12//! The optional block (everything after profile_and_level) is modelled as an
13//! `Option<AacExtension>`: `None` means descriptor_length == 1.
14
15use crate::error::{Error, Result};
16use crate::traits::Descriptor;
17use dvb_common::{Parse, Serialize};
18
19/// Descriptor tag for AAC_descriptor.
20pub const TAG: u8 = 0x7C;
21const HEADER_LEN: usize = 2;
22
23const FLAG_AAC_TYPE: u8 = 0x80;
24const FLAG_SAOC_DE: u8 = 0x40;
25/// reserved_zero_future_use(6) — the spec mandates these are zero.
26const RESERVED_ZERO_MASK: u8 = 0x3F;
27
28/// Optional extension carried when descriptor_length > 1.
29#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
32pub struct AacExtension<'a> {
33    /// SAOC_DE_flag — embedded SAOC-DE parametric data present (Table H.2).
34    pub saoc_de_flag: bool,
35    /// AAC_type — component_type when stream_content is 0x06 (Table 26).
36    /// `Some` iff AAC_type_flag was set.
37    pub aac_type: Option<u8>,
38    /// Trailing additional_info bytes.
39    pub additional_info: &'a [u8],
40}
41
42/// AAC Descriptor.
43#[derive(Debug, Clone, PartialEq, Eq)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize))]
45#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
46pub struct AacDescriptor<'a> {
47    /// 8-bit profile_and_level (MPEG-4_audio_profile_and_level).
48    pub profile_and_level: u8,
49    /// Optional extension; `None` means the body was a single byte.
50    pub extension: Option<AacExtension<'a>>,
51}
52
53impl<'a> Parse<'a> for AacDescriptor<'a> {
54    type Error = crate::error::Error;
55    fn parse(bytes: &'a [u8]) -> Result<Self> {
56        if bytes.len() < HEADER_LEN + 1 {
57            return Err(Error::BufferTooShort {
58                need: HEADER_LEN + 1,
59                have: bytes.len(),
60                what: "AacDescriptor header+profile",
61            });
62        }
63        if bytes[0] != TAG {
64            return Err(Error::InvalidDescriptor {
65                tag: bytes[0],
66                reason: "unexpected tag for AAC_descriptor",
67            });
68        }
69        let length = bytes[1] as usize;
70        let end = HEADER_LEN + length;
71        if bytes.len() < end {
72            return Err(Error::BufferTooShort {
73                need: end,
74                have: bytes.len(),
75                what: "AacDescriptor body",
76            });
77        }
78        if length < 1 {
79            return Err(Error::InvalidDescriptor {
80                tag: TAG,
81                reason: "AAC_descriptor body shorter than 1 byte",
82            });
83        }
84        let body = &bytes[HEADER_LEN..end];
85        let profile_and_level = body[0];
86        let extension = if length > 1 {
87            let flags = body[1];
88            let aac_type_flag = (flags & FLAG_AAC_TYPE) != 0;
89            let saoc_de_flag = (flags & FLAG_SAOC_DE) != 0;
90            let mut pos = 2;
91            let aac_type = if aac_type_flag {
92                if pos >= body.len() {
93                    return Err(Error::InvalidDescriptor {
94                        tag: TAG,
95                        reason: "AAC_type_flag set but AAC_type byte missing",
96                    });
97                }
98                let t = body[pos];
99                pos += 1;
100                Some(t)
101            } else {
102                None
103            };
104            let additional_info = &body[pos..];
105            Some(AacExtension {
106                saoc_de_flag,
107                aac_type,
108                additional_info,
109            })
110        } else {
111            None
112        };
113        Ok(Self {
114            profile_and_level,
115            extension,
116        })
117    }
118}
119
120impl Serialize for AacDescriptor<'_> {
121    type Error = crate::error::Error;
122    fn serialized_len(&self) -> usize {
123        let body = 1 + match &self.extension {
124            None => 0,
125            Some(ext) => 1 + usize::from(ext.aac_type.is_some()) + ext.additional_info.len(),
126        };
127        HEADER_LEN + body
128    }
129
130    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
131        let body_len = self.serialized_len() - HEADER_LEN;
132        if body_len > u8::MAX as usize {
133            return Err(Error::InvalidDescriptor {
134                tag: TAG,
135                reason: "AAC_descriptor body exceeds 255 bytes",
136            });
137        }
138        let len = self.serialized_len();
139        if buf.len() < len {
140            return Err(Error::OutputBufferTooSmall {
141                need: len,
142                have: buf.len(),
143            });
144        }
145        buf[0] = TAG;
146        buf[1] = body_len as u8;
147        buf[2] = self.profile_and_level;
148        let mut pos = 3;
149        if let Some(ext) = &self.extension {
150            let mut flags = 0u8;
151            if ext.aac_type.is_some() {
152                flags |= FLAG_AAC_TYPE;
153            }
154            if ext.saoc_de_flag {
155                flags |= FLAG_SAOC_DE;
156            }
157            // reserved_zero_future_use(6) emitted as zeros per spec.
158            buf[pos] = flags & !RESERVED_ZERO_MASK;
159            pos += 1;
160            if let Some(t) = ext.aac_type {
161                buf[pos] = t;
162                pos += 1;
163            }
164            buf[pos..pos + ext.additional_info.len()].copy_from_slice(ext.additional_info);
165        }
166        Ok(len)
167    }
168}
169
170impl<'a> Descriptor<'a> for AacDescriptor<'a> {
171    const TAG: u8 = TAG;
172    fn descriptor_length(&self) -> u8 {
173        (self.serialized_len() - HEADER_LEN) as u8
174    }
175}
176
177impl<'a> crate::traits::DescriptorDef<'a> for AacDescriptor<'a> {
178    const TAG: u8 = TAG;
179    const NAME: &'static str = "AAC";
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn parse_profile_only() {
188        let bytes = [TAG, 1, 0x50];
189        let d = AacDescriptor::parse(&bytes).unwrap();
190        assert_eq!(d.profile_and_level, 0x50);
191        assert!(d.extension.is_none());
192    }
193
194    #[test]
195    fn parse_with_flags_no_aac_type() {
196        // flags: SAOC_DE set, AAC_type clear.
197        let bytes = [TAG, 2, 0x51, FLAG_SAOC_DE];
198        let d = AacDescriptor::parse(&bytes).unwrap();
199        let ext = d.extension.unwrap();
200        assert!(ext.saoc_de_flag);
201        assert!(ext.aac_type.is_none());
202        assert!(ext.additional_info.is_empty());
203    }
204
205    #[test]
206    fn parse_with_aac_type() {
207        let bytes = [TAG, 3, 0x52, FLAG_AAC_TYPE, 0x03];
208        let d = AacDescriptor::parse(&bytes).unwrap();
209        let ext = d.extension.unwrap();
210        assert!(!ext.saoc_de_flag);
211        assert_eq!(ext.aac_type, Some(0x03));
212        assert!(ext.additional_info.is_empty());
213    }
214
215    #[test]
216    fn parse_with_aac_type_and_additional_info() {
217        let bytes = [TAG, 5, 0x52, FLAG_AAC_TYPE | FLAG_SAOC_DE, 0x05, 0xAA, 0xBB];
218        let d = AacDescriptor::parse(&bytes).unwrap();
219        let ext = d.extension.unwrap();
220        assert!(ext.saoc_de_flag);
221        assert_eq!(ext.aac_type, Some(0x05));
222        assert_eq!(ext.additional_info, &[0xAA, 0xBB]);
223    }
224
225    #[test]
226    fn parse_rejects_wrong_tag() {
227        let bytes = [0x7B, 1, 0x50];
228        assert!(matches!(
229            AacDescriptor::parse(&bytes).unwrap_err(),
230            Error::InvalidDescriptor { tag: 0x7B, .. }
231        ));
232    }
233
234    #[test]
235    fn parse_rejects_aac_type_flag_without_byte() {
236        // length=2 covers profile + flags only, but AAC_type_flag claims a byte.
237        let bytes = [TAG, 2, 0x50, FLAG_AAC_TYPE];
238        assert!(matches!(
239            AacDescriptor::parse(&bytes).unwrap_err(),
240            Error::InvalidDescriptor { .. }
241        ));
242    }
243
244    #[test]
245    fn parse_rejects_length_overrunning_buffer() {
246        let bytes = [TAG, 4, 0x50];
247        assert!(matches!(
248            AacDescriptor::parse(&bytes).unwrap_err(),
249            Error::BufferTooShort { .. }
250        ));
251    }
252
253    #[test]
254    fn serialize_round_trip_profile_only() {
255        let d = AacDescriptor {
256            profile_and_level: 0x58,
257            extension: None,
258        };
259        let mut buf = vec![0u8; d.serialized_len()];
260        d.serialize_into(&mut buf).unwrap();
261        assert_eq!(buf, vec![TAG, 1, 0x58]);
262        assert_eq!(AacDescriptor::parse(&buf).unwrap(), d);
263    }
264
265    #[test]
266    fn serialize_round_trip_full() {
267        let d = AacDescriptor {
268            profile_and_level: 0x52,
269            extension: Some(AacExtension {
270                saoc_de_flag: true,
271                aac_type: Some(0x40),
272                additional_info: &[0xFE, 0xED],
273            }),
274        };
275        let mut buf = vec![0u8; d.serialized_len()];
276        d.serialize_into(&mut buf).unwrap();
277        assert_eq!(AacDescriptor::parse(&buf).unwrap(), d);
278    }
279
280    #[test]
281    fn serialize_emits_reserved_bits_zero() {
282        let d = AacDescriptor {
283            profile_and_level: 0x50,
284            extension: Some(AacExtension {
285                saoc_de_flag: false,
286                aac_type: None,
287                additional_info: &[],
288            }),
289        };
290        let mut buf = vec![0u8; d.serialized_len()];
291        d.serialize_into(&mut buf).unwrap();
292        // flags byte: no flags set, reserved zeros => 0x00.
293        assert_eq!(buf[3] & RESERVED_ZERO_MASK, 0);
294        assert_eq!(buf[3], 0x00);
295    }
296
297    #[cfg(feature = "serde")]
298    #[test]
299    fn serde_serializes_to_stable_json() {
300        // Borrowed `&[u8]` cannot deserialize from a JSON number array, so we
301        // assert the Serialize impl is wired and emits stable JSON.
302        let d = AacDescriptor {
303            profile_and_level: 0x52,
304            extension: Some(AacExtension {
305                saoc_de_flag: true,
306                aac_type: Some(0x03),
307                additional_info: &[0x11],
308            }),
309        };
310        let j = serde_json::to_string(&d).unwrap();
311        // Valid, re-parseable JSON (key order is map-defined, so we do not
312        // assert byte-for-byte string stability).
313        let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
314        assert!(j.contains("profile_and_level"));
315    }
316}