Skip to main content

pito_codecs/ac3/
header.rs

1use super::bits::Bits;
2use super::tables::FRAME_WORDS;
3use crate::media::{Error, Result};
4
5pub const NFCHANS: [usize; 8] = [2, 1, 2, 3, 3, 4, 4, 5];
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum Kind {
9    Independent,
10    Dependent,
11    Convert,
12}
13
14#[derive(Clone, Copy, Debug)]
15pub struct Header {
16    pub eac3: bool,
17    pub kind: Kind,
18    pub substream: u8,
19    pub bytes: usize,
20    pub fscod: u8,
21    pub rate: u32,
22    pub blocks: usize,
23    pub acmod: u8,
24    pub nfchans: usize,
25    pub lfeon: bool,
26    pub chanmap: Option<u16>,
27    pub bits: usize,
28}
29
30impl Header {
31    pub fn nchans(&self) -> usize {
32        self.nfchans + self.lfeon as usize
33    }
34}
35
36fn invalid(what: &str) -> Error {
37    Error::Invalid(format!("AC-3 {what}"))
38}
39
40pub fn frame_len(data: &[u8]) -> Option<usize> {
41    if data.len() < 6 || data[0] != 0x0B || data[1] != 0x77 {
42        return None;
43    }
44    let bsid = data[5] >> 3;
45    if bsid <= 10 {
46        let fscod = (data[4] >> 6) as usize;
47        let code = (data[4] & 0x3F) as usize;
48        let words = FRAME_WORDS.get(code)?.get(fscod)?;
49        Some(*words as usize * 2)
50    } else {
51        let frmsiz = (((data[2] & 7) as usize) << 8) | data[3] as usize;
52        Some((frmsiz + 1) * 2)
53    }
54}
55
56pub fn parse(data: &[u8]) -> Result<Header> {
57    if data.len() < 6 {
58        return Err(invalid("frame shorter than its header"));
59    }
60    if data[0] != 0x0B || data[1] != 0x77 {
61        return Err(invalid("frame without a sync word"));
62    }
63    if data[5] >> 3 <= 10 {
64        ac3(data)
65    } else {
66        eac3(data)
67    }
68}
69
70fn ac3(data: &[u8]) -> Result<Header> {
71    let fscod = data[4] >> 6;
72    let code = (data[4] & 0x3F) as usize;
73    let rate = match fscod {
74        0 => 48_000,
75        1 => 44_100,
76        2 => 32_000,
77        _ => return Err(invalid("frame with a reserved sample rate")),
78    };
79    let words = FRAME_WORDS
80        .get(code)
81        .ok_or_else(|| invalid("frame with a reserved frame size"))?[fscod as usize];
82    let mut b = Bits::new(&data[5..]);
83    b.skip(8)?;
84    let acmod = b.read(3)? as u8;
85    if acmod & 1 != 0 && acmod != 1 {
86        b.skip(2)?;
87    }
88    if acmod & 4 != 0 {
89        b.skip(2)?;
90    }
91    if acmod == 2 {
92        b.skip(2)?;
93    }
94    let lfeon = b.flag()?;
95    for _ in 0..if acmod == 0 { 2 } else { 1 } {
96        b.skip(5)?;
97        if b.flag()? {
98            b.skip(8)?;
99        }
100        if b.flag()? {
101            b.skip(8)?;
102        }
103        if b.flag()? {
104            b.skip(7)?;
105        }
106    }
107    b.skip(2)?;
108    if b.flag()? {
109        b.skip(14)?;
110    }
111    if b.flag()? {
112        b.skip(14)?;
113    }
114    if b.flag()? {
115        let n = b.read(6)? as usize + 1;
116        b.skip(n * 8)?;
117    }
118    Ok(Header {
119        eac3: false,
120        kind: Kind::Independent,
121        substream: 0,
122        bytes: words as usize * 2,
123        fscod,
124        rate,
125        blocks: 6,
126        acmod,
127        nfchans: NFCHANS[acmod as usize],
128        lfeon,
129        chanmap: None,
130        bits: 40 + b.pos(),
131    })
132}
133
134fn eac3(data: &[u8]) -> Result<Header> {
135    let mut b = Bits::new(&data[2..]);
136    let kind = match b.read(2)? {
137        0 => Kind::Independent,
138        1 => Kind::Dependent,
139        2 => Kind::Convert,
140        _ => return Err(invalid("E-AC-3 frame with a reserved stream type")),
141    };
142    let substream = b.read(3)? as u8;
143    let bytes = (b.read(11)? as usize + 1) * 2;
144    if bytes < 8 {
145        return Err(invalid("E-AC-3 frame too small"));
146    }
147    let fscod = b.read(2)? as u8;
148    let numblkscod = if fscod == 3 {
149        return Err(Error::Unsupported(
150            "E-AC-3 at a reduced sample rate (16 to 24 kHz)".into(),
151        ));
152    } else {
153        b.read(2)? as u8
154    };
155    let rate = [48_000, 44_100, 32_000][fscod as usize];
156    let blocks = [1, 2, 3, 6][numblkscod as usize];
157    let acmod = b.read(3)? as u8;
158    let lfeon = b.flag()?;
159    let bsid = b.read(5)? as u8;
160    if !(11..=16).contains(&bsid) {
161        return Err(Error::Unsupported(format!("E-AC-3 bitstream id {bsid}")));
162    }
163    for _ in 0..if acmod == 0 { 2 } else { 1 } {
164        b.skip(5)?;
165        if b.flag()? {
166            b.skip(8)?;
167        }
168    }
169    let mut chanmap = None;
170    if kind == Kind::Dependent && b.flag()? {
171        chanmap = Some(b.read(16)? as u16);
172    }
173    if b.flag()? {
174        mixing(&mut b, acmod, lfeon, kind, numblkscod)?;
175    }
176    if b.flag()? {
177        b.skip(5)?;
178        if acmod == 2 {
179            b.skip(4)?;
180        }
181        if acmod >= 6 {
182            b.skip(2)?;
183        }
184        for _ in 0..if acmod == 0 { 2 } else { 1 } {
185            if b.flag()? {
186                b.skip(8)?;
187            }
188        }
189        if fscod < 3 {
190            b.skip(1)?;
191        }
192    }
193    if kind == Kind::Independent && numblkscod != 3 {
194        b.skip(1)?;
195    }
196    if kind == Kind::Convert && (numblkscod == 3 || b.flag()?) {
197        b.skip(6)?;
198    }
199    if b.flag()? {
200        let n = b.read(6)? as usize + 1;
201        b.skip(n * 8)?;
202    }
203    Ok(Header {
204        eac3: true,
205        kind,
206        substream,
207        bytes,
208        fscod,
209        rate,
210        blocks,
211        acmod,
212        nfchans: NFCHANS[acmod as usize],
213        lfeon,
214        chanmap,
215        bits: 16 + b.pos(),
216    })
217}
218
219fn mixing(b: &mut Bits, acmod: u8, lfeon: bool, kind: Kind, numblkscod: u8) -> Result<()> {
220    if acmod > 2 {
221        b.skip(2)?;
222    }
223    if acmod & 1 != 0 && acmod > 2 {
224        b.skip(6)?;
225    }
226    if acmod & 4 != 0 {
227        b.skip(6)?;
228    }
229    if lfeon && b.flag()? {
230        b.skip(5)?;
231    }
232    if kind != Kind::Independent {
233        return Ok(());
234    }
235    if b.flag()? {
236        b.skip(6)?;
237    }
238    if acmod == 0 && b.flag()? {
239        b.skip(6)?;
240    }
241    if b.flag()? {
242        b.skip(6)?;
243    }
244    match b.read(2)? {
245        1 => b.skip(5)?,
246        2 => b.skip(12)?,
247        3 => {
248            let len = b.read(5)? as usize;
249            b.skip(8 * (len + 2) - 5)?;
250        }
251        _ => {}
252    }
253    if acmod < 2 {
254        if b.flag()? {
255            b.skip(14)?;
256        }
257        if acmod == 0 && b.flag()? {
258            b.skip(14)?;
259        }
260    }
261    if b.flag()? {
262        if numblkscod == 0 {
263            b.skip(5)?;
264        } else {
265            for _ in 0..[1, 2, 3, 6][numblkscod as usize] {
266                if b.flag()? {
267                    b.skip(5)?;
268                }
269            }
270        }
271    }
272    Ok(())
273}