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