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