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