Skip to main content

pito_codecs/mp4/
entry.rs

1use crate::media::{Error, Result};
2use crate::mp4::boxes::{BoxBuf, Cur, FourCc, boxes};
3
4#[derive(Clone, Debug, PartialEq)]
5pub struct SampleEntry {
6    pub format: FourCc,
7    pub codec: CodecConfig,
8    pub video: Option<VideoParams>,
9    pub audio: Option<AudioParams>,
10    pub bitrate: Option<BitRate>,
11    pub raw: Vec<u8>,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
15pub struct VideoParams {
16    pub width: u16,
17    pub height: u16,
18    pub pixel_aspect: Option<(u32, u32)>,
19}
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct BitRate {
23    pub buffer_size: u32,
24    pub max_bitrate: u32,
25    pub avg_bitrate: u32,
26}
27
28#[derive(Clone, Debug, PartialEq, Default)]
29pub struct AudioParams {
30    pub qt_version: u16,
31    pub channels: u32,
32    pub sample_size: u16,
33    pub sample_rate: f64,
34    pub samples_per_packet: u32,
35    pub bytes_per_frame: u32,
36    pub const_bits_per_channel: u32,
37    pub lpcm_flags: u32,
38    pub little_endian: Option<bool>,
39}
40
41#[derive(Clone, Debug, PartialEq)]
42pub enum CodecConfig {
43    Avc(AvcConfig),
44    Hevc(HevcConfig),
45    Vp9(VpcConfig),
46    Aac(AacConfig),
47    Mp3,
48    Pcm(PcmConfig),
49    Other(FourCc),
50}
51
52impl CodecConfig {
53    pub fn name(&self) -> String {
54        match self {
55            CodecConfig::Avc(_) => "h264".into(),
56            CodecConfig::Hevc(_) => "hevc".into(),
57            CodecConfig::Vp9(_) => "vp9".into(),
58            CodecConfig::Aac(_) => "aac".into(),
59            CodecConfig::Mp3 => "mp3".into(),
60            CodecConfig::Pcm(_) => "pcm".into(),
61            CodecConfig::Other(f) if &f.0 == b"ac-3" => "ac3".into(),
62            CodecConfig::Other(f) if &f.0 == b"ec-3" => "eac3".into(),
63            CodecConfig::Other(f) => f.to_string_lossy().trim().to_string(),
64        }
65    }
66
67    pub fn extradata(&self) -> Option<Vec<u8>> {
68        match self {
69            CodecConfig::Avc(c) => Some(c.to_bytes()),
70            CodecConfig::Hevc(c) => Some(c.to_bytes()),
71            CodecConfig::Vp9(c) => Some(c.to_bytes()),
72            CodecConfig::Aac(c) => Some(c.asc.clone()),
73            _ => None,
74        }
75    }
76}
77
78#[derive(Clone, Debug, PartialEq, Eq, Default)]
79pub struct AvcConfig {
80    pub profile: u8,
81    pub compatibility: u8,
82    pub level: u8,
83    pub length_size: u8,
84    pub sps: Vec<Vec<u8>>,
85    pub pps: Vec<Vec<u8>>,
86    pub ext: Vec<u8>,
87}
88
89impl AvcConfig {
90    pub fn new(sps: Vec<Vec<u8>>, pps: Vec<Vec<u8>>) -> Self {
91        let (profile, compatibility, level) = sps
92            .first()
93            .filter(|s| s.len() >= 4)
94            .map(|s| (s[1], s[2], s[3]))
95            .unwrap_or((0, 0, 0));
96        let ext = if matches!(profile, 100 | 110 | 122 | 144) {
97            vec![0xFD, 0xF8, 0xF8, 0]
98        } else {
99            Vec::new()
100        };
101        AvcConfig {
102            profile,
103            compatibility,
104            level,
105            length_size: 4,
106            sps,
107            pps,
108            ext,
109        }
110    }
111
112    pub fn parameter_sets_annexb(&self) -> Vec<u8> {
113        let mut out = Vec::new();
114        for nal in self.sps.iter().chain(&self.pps) {
115            out.extend_from_slice(&[0, 0, 0, 1]);
116            out.extend_from_slice(nal);
117        }
118        out
119    }
120
121    pub fn parse(data: &[u8]) -> Result<Self> {
122        let mut c = Cur::new(data, "avcC");
123        let _version = c.u8()?;
124        let profile = c.u8()?;
125        let compatibility = c.u8()?;
126        let level = c.u8()?;
127        let length_size = (c.u8()? & 3) + 1;
128        let nsps = (c.u8()? & 0x1F) as usize;
129        let mut sps = Vec::with_capacity(nsps);
130        for _ in 0..nsps {
131            let n = c.u16()? as usize;
132            sps.push(c.bytes(n)?.to_vec());
133        }
134        let npps = c.u8()? as usize;
135        let mut pps = Vec::with_capacity(npps);
136        for _ in 0..npps {
137            let n = c.u16()? as usize;
138            pps.push(c.bytes(n)?.to_vec());
139        }
140        Ok(AvcConfig {
141            profile,
142            compatibility,
143            level,
144            length_size,
145            sps,
146            pps,
147            ext: c.rest().to_vec(),
148        })
149    }
150
151    pub fn to_bytes(&self) -> Vec<u8> {
152        let mut b = BoxBuf::new();
153        b.u8(1);
154        b.u8(self.profile);
155        b.u8(self.compatibility);
156        b.u8(self.level);
157        b.u8(0xFC | (self.length_size.clamp(1, 4) - 1));
158        b.u8(0xE0 | (self.sps.len().min(31) as u8));
159        for s in self.sps.iter().take(31) {
160            b.u16(s.len() as u16);
161            b.bytes(s);
162        }
163        b.u8(self.pps.len().min(255) as u8);
164        for p in self.pps.iter().take(255) {
165            b.u16(p.len() as u16);
166            b.bytes(p);
167        }
168        b.bytes(&self.ext);
169        b.buf
170    }
171}
172
173#[derive(Clone, Debug, PartialEq, Eq, Default)]
174pub struct NalArray {
175    pub completeness: bool,
176    pub nal_type: u8,
177    pub nalus: Vec<Vec<u8>>,
178}
179
180#[derive(Clone, Debug, PartialEq, Eq, Default)]
181pub struct HevcConfig {
182    pub profile_space: u8,
183    pub tier: bool,
184    pub profile: u8,
185    pub compatibility: u32,
186    pub constraints: u64,
187    pub level: u8,
188    pub min_spatial_segmentation: u16,
189    pub parallelism: u8,
190    pub chroma_format: u8,
191    pub bit_depth_luma: u8,
192    pub bit_depth_chroma: u8,
193    pub avg_frame_rate: u16,
194    pub constant_frame_rate: u8,
195    pub temporal_layers: u8,
196    pub temporal_id_nested: bool,
197    pub length_size: u8,
198    pub arrays: Vec<NalArray>,
199}
200
201impl HevcConfig {
202    pub fn parse(data: &[u8]) -> Result<Self> {
203        let mut c = Cur::new(data, "hvcC");
204        let _version = c.u8()?;
205        let b = c.u8()?;
206        let compatibility = c.u32()?;
207        let hi = c.u16()? as u64;
208        let lo = c.u32()? as u64;
209        let level = c.u8()?;
210        let min_seg = c.u16()? & 0x0FFF;
211        let par = c.u8()? & 3;
212        let chroma = c.u8()? & 3;
213        let bdl = (c.u8()? & 7) + 8;
214        let bdc = (c.u8()? & 7) + 8;
215        let afr = c.u16()?;
216        let x = c.u8()?;
217        let narrays = c.u8()? as usize;
218        let mut arrays = Vec::new();
219        for _ in 0..narrays {
220            let t = c.u8()?;
221            let n = c.u16()? as usize;
222            c.check_count(n, 2)?;
223            let mut nalus = Vec::with_capacity(n);
224            for _ in 0..n {
225                let len = c.u16()? as usize;
226                nalus.push(c.bytes(len)?.to_vec());
227            }
228            arrays.push(NalArray {
229                completeness: t & 0x80 != 0,
230                nal_type: t & 0x3F,
231                nalus,
232            });
233        }
234        Ok(HevcConfig {
235            profile_space: b >> 6,
236            tier: b & 0x20 != 0,
237            profile: b & 0x1F,
238            compatibility,
239            constraints: (hi << 32) | lo,
240            level,
241            min_spatial_segmentation: min_seg,
242            parallelism: par,
243            chroma_format: chroma,
244            bit_depth_luma: bdl,
245            bit_depth_chroma: bdc,
246            avg_frame_rate: afr,
247            constant_frame_rate: x >> 6,
248            temporal_layers: (x >> 3) & 7,
249            temporal_id_nested: x & 4 != 0,
250            length_size: (x & 3) + 1,
251            arrays,
252        })
253    }
254
255    pub fn to_bytes(&self) -> Vec<u8> {
256        let mut b = BoxBuf::new();
257        b.u8(1);
258        b.u8((self.profile_space << 6) | ((self.tier as u8) << 5) | (self.profile & 0x1F));
259        b.u32(self.compatibility);
260        b.u16((self.constraints >> 32) as u16);
261        b.u32(self.constraints as u32);
262        b.u8(self.level);
263        b.u16(0xF000 | (self.min_spatial_segmentation & 0x0FFF));
264        b.u8(0xFC | (self.parallelism & 3));
265        b.u8(0xFC | (self.chroma_format & 3));
266        b.u8(0xF8 | (self.bit_depth_luma.saturating_sub(8) & 7));
267        b.u8(0xF8 | (self.bit_depth_chroma.saturating_sub(8) & 7));
268        b.u16(self.avg_frame_rate);
269        b.u8((self.constant_frame_rate << 6)
270            | ((self.temporal_layers & 7) << 3)
271            | ((self.temporal_id_nested as u8) << 2)
272            | (self.length_size.clamp(1, 4) - 1));
273        b.u8(self.arrays.len() as u8);
274        for a in &self.arrays {
275            b.u8(((a.completeness as u8) << 7) | (a.nal_type & 0x3F));
276            b.u16(a.nalus.len() as u16);
277            for n in &a.nalus {
278                b.u16(n.len() as u16);
279                b.bytes(n);
280            }
281        }
282        b.buf
283    }
284
285    fn nalus(&self, t: u8) -> Vec<&[u8]> {
286        self.arrays
287            .iter()
288            .filter(|a| a.nal_type == t)
289            .flat_map(|a| a.nalus.iter().map(Vec::as_slice))
290            .collect()
291    }
292
293    pub fn vps(&self) -> Vec<&[u8]> {
294        self.nalus(32)
295    }
296
297    pub fn sps(&self) -> Vec<&[u8]> {
298        self.nalus(33)
299    }
300
301    pub fn pps(&self) -> Vec<&[u8]> {
302        self.nalus(34)
303    }
304}
305
306#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
307pub struct VpcConfig {
308    pub profile: u8,
309    pub level: u8,
310    pub bit_depth: u8,
311    pub chroma_subsampling: u8,
312    pub full_range: bool,
313    pub colour_primaries: u8,
314    pub transfer_characteristics: u8,
315    pub matrix_coefficients: u8,
316}
317
318const VP9_LEVELS: [(u8, u64, u64, u32); 14] = [
319    (10, 829_440, 36_864, 512),
320    (11, 2_764_800, 73_728, 768),
321    (20, 4_608_000, 122_880, 1_536),
322    (21, 9_216_000, 245_760, 2_816),
323    (30, 20_736_000, 552_960, 6_656),
324    (31, 36_864_000, 983_040, 10_496),
325    (40, 83_558_400, 2_228_224, 16_384),
326    (41, 160_432_128, 2_228_224, 16_384),
327    (50, 311_951_360, 8_912_896, 32_768),
328    (51, 588_251_136, 8_912_896, 32_768),
329    (52, 1_176_502_272, 8_912_896, 32_768),
330    (60, 1_176_502_272, 35_651_584, 65_536),
331    (61, 2_353_004_544, 35_651_584, 65_536),
332    (62, 4_706_009_088, 35_651_584, 65_536),
333];
334
335impl VpcConfig {
336    pub fn new(
337        (profile, bit_depth, chroma_subsampling): (u8, u8, u8),
338        (color_space, full_range): (u8, bool),
339        (width, height): (u32, u32),
340        fps: (u32, u32),
341    ) -> Self {
342        let (colour_primaries, transfer_characteristics, matrix_coefficients) = match color_space {
343            1 => (5, 6, 5),
344            2 => (1, 1, 1),
345            3 => (6, 6, 6),
346            4 => (7, 7, 7),
347            5 => (9, 2, 9),
348            7 => (1, 13, 0),
349            _ => (2, 2, 2),
350        };
351        VpcConfig {
352            profile,
353            level: vp9_level((width, height), fps),
354            bit_depth,
355            chroma_subsampling,
356            full_range,
357            colour_primaries,
358            transfer_characteristics,
359            matrix_coefficients,
360        }
361    }
362
363    pub fn parse(data: &[u8]) -> Result<Self> {
364        let mut c = Cur::new(data, "vpcC");
365        let (version, _) = c.full_header()?;
366        if version != 1 {
367            return Err(Error::Unsupported(format!("vpcC version {version}")));
368        }
369        let profile = c.u8()?;
370        let level = c.u8()?;
371        let packed = c.u8()?;
372        Ok(VpcConfig {
373            profile,
374            level,
375            bit_depth: packed >> 4,
376            chroma_subsampling: (packed >> 1) & 7,
377            full_range: packed & 1 == 1,
378            colour_primaries: c.u8()?,
379            transfer_characteristics: c.u8()?,
380            matrix_coefficients: c.u8()?,
381        })
382    }
383
384    pub fn to_bytes(&self) -> Vec<u8> {
385        vec![
386            1,
387            0,
388            0,
389            0,
390            self.profile,
391            self.level,
392            (self.bit_depth << 4) | ((self.chroma_subsampling & 7) << 1) | self.full_range as u8,
393            self.colour_primaries,
394            self.transfer_characteristics,
395            self.matrix_coefficients,
396            0,
397            0,
398        ]
399    }
400}
401
402fn vp9_level((width, height): (u32, u32), (num, den): (u32, u32)) -> u8 {
403    let picture = width as u64 * height as u64;
404    let rate = picture * num as u64 / den.max(1) as u64;
405    let breadth = width.max(height);
406    VP9_LEVELS
407        .iter()
408        .find(|l| rate <= l.1 && picture <= l.2 && breadth <= l.3)
409        .map_or(62, |l| l.0)
410}
411
412#[derive(Clone, Debug, PartialEq, Eq, Default)]
413pub struct AacConfig {
414    pub asc: Vec<u8>,
415    pub object_type: u8,
416    pub sample_rate: u32,
417    pub channel_config: u8,
418    pub max_bitrate: u32,
419    pub avg_bitrate: u32,
420    pub buffer_size: u32,
421}
422
423const AAC_RATES: [u32; 13] = [
424    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350,
425];
426
427impl AacConfig {
428    pub fn from_asc(asc: Vec<u8>) -> Self {
429        let (object_type, sample_rate, channel_config) = parse_asc(&asc).unwrap_or((0, 0, 0));
430        AacConfig {
431            asc,
432            object_type,
433            sample_rate,
434            channel_config,
435            ..Default::default()
436        }
437    }
438
439    pub fn channels(&self) -> u32 {
440        match self.channel_config {
441            1..=6 => self.channel_config as u32,
442            7 => 8,
443            _ => 0,
444        }
445    }
446}
447
448fn parse_asc(asc: &[u8]) -> Option<(u8, u32, u8)> {
449    let bit = |i: usize| asc.get(i / 8).map(|b| (b >> (7 - i % 8)) & 1);
450    let bits = |at: &mut usize, n: usize| -> Option<u32> {
451        let mut v = 0u32;
452        for _ in 0..n {
453            v = (v << 1) | bit(*at)? as u32;
454            *at += 1;
455        }
456        Some(v)
457    };
458    let mut at = 0;
459    let mut t = bits(&mut at, 5)? as u8;
460    if t == 31 {
461        t = 32 + bits(&mut at, 6)? as u8;
462    }
463    let i = bits(&mut at, 4)? as usize;
464    let sr = if i == 15 {
465        bits(&mut at, 24)?
466    } else {
467        *AAC_RATES.get(i)?
468    };
469    let ch = bits(&mut at, 4)? as u8;
470    Some((t, sr, ch))
471}
472
473#[derive(Clone, Copy, Debug, PartialEq, Default)]
474pub struct PcmConfig {
475    pub bits: u16,
476    pub float: bool,
477    pub big_endian: bool,
478    pub signed: bool,
479    pub channels: u32,
480    pub sample_rate: f64,
481}
482
483impl PcmConfig {
484    pub fn bytes_per_frame(&self) -> u32 {
485        (self.bits as u32)
486            .div_ceil(8)
487            .saturating_mul(self.channels.max(1))
488    }
489}
490
491fn is_video_fourcc(f: &[u8; 4]) -> bool {
492    matches!(
493        f,
494        b"avc1"
495            | b"avc3"
496            | b"hvc1"
497            | b"hev1"
498            | b"av01"
499            | b"vp09"
500            | b"vp08"
501            | b"apch"
502            | b"apcn"
503            | b"apcs"
504            | b"apco"
505            | b"ap4h"
506            | b"ap4x"
507            | b"jpeg"
508            | b"mjpa"
509            | b"mjpb"
510            | b"AVdn"
511            | b"AVdh"
512            | b"mp4v"
513            | b"encv"
514            | b"2vuy"
515            | b"v210"
516    )
517}
518
519fn is_audio_fourcc(f: &[u8; 4]) -> bool {
520    matches!(
521        f,
522        b"mp4a"
523            | b"lpcm"
524            | b"sowt"
525            | b"twos"
526            | b"in24"
527            | b"in32"
528            | b"fl32"
529            | b"fl64"
530            | b"ipcm"
531            | b"fpcm"
532            | b"alac"
533            | b"Opus"
534            | b"fLaC"
535            | b"ac-3"
536            | b"ec-3"
537            | b".mp3"
538            | b".mp2"
539            | b"enca"
540            | b"ulaw"
541            | b"alaw"
542            | b"NONE"
543    )
544}
545
546pub(crate) fn parse_sample_entry(
547    format: FourCc,
548    payload: &[u8],
549    handler: FourCc,
550    is_qt: bool,
551) -> Result<SampleEntry> {
552    let mut c = Cur::new(payload, "sample entry");
553    c.skip(8)?;
554    let f = &format.0;
555    let mut entry = SampleEntry {
556        format,
557        codec: CodecConfig::Other(format),
558        video: None,
559        audio: None,
560        bitrate: None,
561        raw: payload.to_vec(),
562    };
563    let video_like = is_video_fourcc(f) || (handler == b"vide" && !is_audio_fourcc(f));
564    let audio_like = is_audio_fourcc(f) || (handler == b"soun" && !video_like);
565    if handler == b"tmcd" || f == b"tmcd" {
566        return Ok(entry);
567    }
568    if video_like {
569        let mut v = VideoParams::default();
570        c.skip(16)?;
571        v.width = c.u16()?;
572        v.height = c.u16()?;
573        c.skip(50)?;
574        for b in boxes(c.rest()).map_while(|b| b.ok()) {
575            let p = b.payload;
576            match &b.kind.0 {
577                b"avcC" if matches!(f, b"avc1" | b"avc3") => {
578                    entry.codec = CodecConfig::Avc(AvcConfig::parse(p)?)
579                }
580                b"hvcC" if matches!(f, b"hvc1" | b"hev1") => {
581                    entry.codec = CodecConfig::Hevc(HevcConfig::parse(p)?)
582                }
583                b"vpcC" if f == b"vp09" => entry.codec = CodecConfig::Vp9(VpcConfig::parse(p)?),
584                b"pasp" => {
585                    let mut c = Cur::new(p, "pasp");
586                    v.pixel_aspect = Some((c.u32()?, c.u32()?));
587                }
588                b"btrt" => entry.bitrate = Some(parse_btrt(p)?),
589                _ => {}
590            }
591        }
592        entry.video = Some(v);
593        return Ok(entry);
594    }
595    if !audio_like {
596        return Ok(entry);
597    }
598    let mut a = AudioParams {
599        qt_version: c.u16()?,
600        ..Default::default()
601    };
602    c.skip(6)?;
603    a.channels = c.u16()? as u32;
604    a.sample_size = c.u16()?;
605    c.skip(4)?;
606    a.sample_rate = c.u32()? as f64 / 65536.0;
607    if is_qt && a.qt_version == 1 {
608        a.samples_per_packet = c.u32()?;
609        c.skip(4)?;
610        a.bytes_per_frame = c.u32()?;
611        c.skip(4)?;
612    } else if is_qt && a.qt_version == 2 {
613        c.skip(4)?;
614        a.sample_rate = c.f64()?;
615        a.channels = c.u32()?;
616        c.skip(4)?;
617        a.const_bits_per_channel = c.u32()?;
618        a.lpcm_flags = c.u32()?;
619        c.skip(8)?;
620    }
621    let mut ext: Vec<(FourCc, &[u8])> = Vec::new();
622    for b in boxes(c.rest()).map_while(|b| b.ok()) {
623        if b.kind == b"wave" {
624            for w in boxes(b.payload).map_while(|b| b.ok()) {
625                ext.push((w.kind, w.payload));
626            }
627        } else {
628            ext.push((b.kind, b.payload));
629        }
630    }
631    let get = |k: &[u8; 4]| ext.iter().find(|(kk, _)| kk == k).map(|(_, p)| *p);
632    if let Some(p) = get(b"enda") {
633        let v = if p.len() >= 2 {
634            u16::from_be_bytes([p[0], p[1]])
635        } else {
636            p.first().copied().unwrap_or(0) as u16
637        };
638        a.little_endian = Some(v != 0);
639    }
640    entry.bitrate = get(b"btrt").and_then(|p| parse_btrt(p).ok());
641    entry.codec = match f {
642        b"mp4a" => match get(b"esds") {
643            Some(p) => parse_esds(p)?,
644            None => CodecConfig::Other(format),
645        },
646        b".mp3" | b".mp2" => CodecConfig::Mp3,
647        b"lpcm" | b"sowt" | b"twos" | b"in24" | b"in32" | b"fl32" | b"fl64" | b"raw " | b"NONE" => {
648            CodecConfig::Pcm(qt_pcm(f, &a))
649        }
650        b"ipcm" | b"fpcm" => {
651            let mut pcm = PcmConfig {
652                bits: a.sample_size,
653                float: f == b"fpcm",
654                big_endian: true,
655                signed: true,
656                channels: a.channels,
657                sample_rate: a.sample_rate,
658            };
659            if let Some(p) = get(b"pcmC") {
660                let mut c = Cur::new(p, "pcmC");
661                c.full_header()?;
662                pcm.big_endian = c.u8()? & 1 == 0;
663                pcm.bits = c.u8()? as u16;
664            }
665            CodecConfig::Pcm(pcm)
666        }
667        _ => CodecConfig::Other(format),
668    };
669    entry.audio = Some(a);
670    Ok(entry)
671}
672
673fn qt_pcm(f: &[u8; 4], a: &AudioParams) -> PcmConfig {
674    let mut p = PcmConfig {
675        channels: a.channels,
676        sample_rate: a.sample_rate,
677        signed: true,
678        ..Default::default()
679    };
680    match f {
681        b"lpcm" => {
682            p.bits = a.const_bits_per_channel as u16;
683            p.float = a.lpcm_flags & 1 != 0;
684            p.big_endian = a.lpcm_flags & 2 != 0;
685            p.signed = a.lpcm_flags & 4 != 0 || p.float;
686            if p.bits == 0 {
687                p.bits = a.sample_size;
688            }
689        }
690        b"sowt" => {
691            p.bits = if a.sample_size == 0 {
692                16
693            } else {
694                a.sample_size
695            }
696        }
697        b"twos" => {
698            p.bits = if a.sample_size == 0 {
699                16
700            } else {
701                a.sample_size
702            };
703            p.big_endian = true;
704        }
705        b"raw " | b"NONE" => {
706            p.bits = if a.sample_size == 0 { 8 } else { a.sample_size };
707            p.signed = p.bits != 8;
708            p.big_endian = true;
709        }
710        _ => {
711            p.bits = match f {
712                b"in24" => 24,
713                b"in32" | b"fl32" => 32,
714                _ => 64,
715            };
716            p.float = f[0] == b'f';
717            p.big_endian = !a.little_endian.unwrap_or(false);
718        }
719    }
720    p
721}
722
723fn parse_btrt(p: &[u8]) -> Result<BitRate> {
724    let mut c = Cur::new(p, "btrt");
725    Ok(BitRate {
726        buffer_size: c.u32()?,
727        max_bitrate: c.u32()?,
728        avg_bitrate: c.u32()?,
729    })
730}
731
732fn descriptor(c: &mut Cur) -> Result<(u8, usize)> {
733    let tag = c.u8()?;
734    let mut len = 0usize;
735    for _ in 0..4 {
736        let b = c.u8()?;
737        len = (len << 7) | (b & 0x7F) as usize;
738        if b & 0x80 == 0 {
739            break;
740        }
741    }
742    Ok((tag, len))
743}
744
745fn parse_esds(p: &[u8]) -> Result<CodecConfig> {
746    let mut c = Cur::new(p, "esds");
747    c.full_header()?;
748    let (tag, len) = descriptor(&mut c)?;
749    if tag != 3 {
750        return Err(Error::Invalid(format!(
751            "esds: expected ES_Descriptor, got tag {tag}"
752        )));
753    }
754    let es = c.bytes(len.min(c.remaining()))?;
755    let mut c = Cur::new(es, "ES_Descriptor");
756    c.u16()?;
757    let fl = c.u8()?;
758    if fl & 0x80 != 0 {
759        c.u16()?;
760    }
761    if fl & 0x40 != 0 {
762        let n = c.u8()? as usize;
763        c.skip(n)?;
764    }
765    if fl & 0x20 != 0 {
766        c.u16()?;
767    }
768    while c.remaining() > 0 {
769        let (tag, len) = descriptor(&mut c)?;
770        let body = c.bytes(len.min(c.remaining()))?;
771        if tag != 4 {
772            continue;
773        }
774        let mut d = Cur::new(body, "DecoderConfigDescriptor");
775        let oti = d.u8()?;
776        let _stream_type = d.u8()?;
777        let buffer_size = d.u24()?;
778        let max_bitrate = d.u32()?;
779        let avg_bitrate = d.u32()?;
780        let mut asc = Vec::new();
781        while d.remaining() > 0 {
782            let (t, l) = descriptor(&mut d)?;
783            let b = d.bytes(l.min(d.remaining()))?;
784            if t == 5 {
785                asc = b.to_vec();
786                break;
787            }
788        }
789        return Ok(match oti {
790            0x69 | 0x6B => CodecConfig::Mp3,
791            _ => {
792                let mut a = AacConfig::from_asc(asc);
793                a.max_bitrate = max_bitrate;
794                a.avg_bitrate = avg_bitrate;
795                a.buffer_size = buffer_size;
796                CodecConfig::Aac(a)
797            }
798        });
799    }
800    Err(Error::Invalid(
801        "esds without DecoderConfigDescriptor".into(),
802    ))
803}
804
805fn put_descriptor(b: &mut BoxBuf, tag: u8, body: &[u8]) {
806    b.u8(tag);
807    let n = body.len() as u32;
808    b.u8(0x80 | ((n >> 21) & 0x7F) as u8);
809    b.u8(0x80 | ((n >> 14) & 0x7F) as u8);
810    b.u8(0x80 | ((n >> 7) & 0x7F) as u8);
811    b.u8((n & 0x7F) as u8);
812    b.bytes(body);
813}
814
815fn esds_payload(asc: &[u8], max_bitrate: u32, avg_bitrate: u32, buffer_size: u32) -> Vec<u8> {
816    let mut dcd = BoxBuf::new();
817    dcd.u8(0x40);
818    dcd.u8(0x15);
819    dcd.u8((buffer_size >> 16) as u8);
820    dcd.u16(buffer_size as u16);
821    dcd.u32(max_bitrate);
822    dcd.u32(avg_bitrate);
823    if !asc.is_empty() {
824        put_descriptor(&mut dcd, 5, asc);
825    }
826    let mut es = BoxBuf::new();
827    es.u16(1);
828    es.u8(0);
829    put_descriptor(&mut es, 4, &dcd.buf);
830    put_descriptor(&mut es, 6, &[2]);
831    let mut b = BoxBuf::new();
832    b.u32(0);
833    put_descriptor(&mut b, 3, &es.buf);
834    b.buf
835}
836
837impl SampleEntry {
838    pub fn ac3_channels(&self) -> Option<u32> {
839        let extra = match self.audio.as_ref()?.qt_version {
840            1 => 16,
841            2 => 36,
842            _ => 0,
843        };
844        let mut rest = self.raw.get(28 + extra..)?;
845        while rest.len() >= 8 {
846            let size = u32::from_be_bytes(rest.get(..4)?.try_into().ok()?) as usize;
847            if size < 8 || size > rest.len() {
848                return None;
849            }
850            let body = rest.get(8..size)?;
851            let nfchans = |acmod: u64| [2, 1, 2, 3, 3, 4, 4, 5][acmod as usize & 7];
852            match rest.get(4..8)? {
853                b"dac3" => {
854                    let b = body.get(..3)?;
855                    let v = u64::from_be_bytes([0, 0, 0, 0, 0, b[0], b[1], b[2]]);
856                    return Some(nfchans(v >> 11) + ((v >> 10) & 1) as u32);
857                }
858                b"dec3" => {
859                    let b = body.get(..5)?;
860                    let v = u64::from_be_bytes([0, 0, 0, b[0], b[1], b[2], b[3], b[4]]);
861                    let deps = if (v >> 1) & 15 > 0 { 2 } else { 0 };
862                    return Some(nfchans(v >> 9) + ((v >> 8) & 1) as u32 + deps);
863                }
864                _ => rest = rest.get(size..)?,
865            }
866        }
867        None
868    }
869
870    fn video(format: &[u8; 4], codec: CodecConfig, width: u16, height: u16) -> Self {
871        SampleEntry {
872            format: FourCc(*format),
873            codec,
874            video: Some(VideoParams {
875                width,
876                height,
877                pixel_aspect: None,
878            }),
879            audio: None,
880            bitrate: None,
881            raw: Vec::new(),
882        }
883    }
884
885    pub fn h264(config: AvcConfig, width: u16, height: u16) -> Self {
886        Self::video(b"avc1", CodecConfig::Avc(config), width, height)
887    }
888
889    pub fn hevc(config: HevcConfig, width: u16, height: u16) -> Self {
890        Self::video(b"hvc1", CodecConfig::Hevc(config), width, height)
891    }
892
893    pub fn vp9(config: VpcConfig, width: u16, height: u16) -> Self {
894        Self::video(b"vp09", CodecConfig::Vp9(config), width, height)
895    }
896
897    pub fn aac(asc: Vec<u8>, channels: u32, sample_rate: u32, bitrate: u32) -> Self {
898        let mut config = AacConfig::from_asc(asc);
899        config.avg_bitrate = bitrate;
900        config.max_bitrate = bitrate;
901        SampleEntry {
902            format: FourCc(*b"mp4a"),
903            codec: CodecConfig::Aac(config),
904            video: None,
905            audio: Some(AudioParams {
906                channels,
907                sample_rate: sample_rate as f64,
908                sample_size: 16,
909                ..Default::default()
910            }),
911            bitrate: None,
912            raw: Vec::new(),
913        }
914    }
915
916    pub fn is_video(&self) -> bool {
917        self.video.is_some()
918    }
919
920    pub fn is_audio(&self) -> bool {
921        self.audio.is_some()
922    }
923
924    pub(crate) fn write(&self, b: &mut BoxBuf) -> Result<()> {
925        if !self.raw.is_empty() {
926            let m = b.start(&self.format.0);
927            b.bytes(&self.raw);
928            b.end(m);
929            return Ok(());
930        }
931        if let Some(v) = &self.video {
932            let m = b.start(&self.format.0);
933            b.zeros(6);
934            b.u16(1);
935            b.zeros(16);
936            b.u16(v.width);
937            b.u16(v.height);
938            b.u32(0x0048_0000);
939            b.u32(0x0048_0000);
940            b.u32(0);
941            b.u16(1);
942            b.zeros(32);
943            b.u16(24);
944            b.i16(-1);
945            match &self.codec {
946                CodecConfig::Avc(c) => b.leaf(b"avcC", &c.to_bytes()),
947                CodecConfig::Hevc(c) => b.leaf(b"hvcC", &c.to_bytes()),
948                CodecConfig::Vp9(c) => b.leaf(b"vpcC", &c.to_bytes()),
949                _ => {
950                    return Err(Error::Unsupported(format!(
951                        "writing {} video",
952                        self.codec.name()
953                    )));
954                }
955            }
956            if let Some((h, vv)) = v.pixel_aspect {
957                let m = b.start(b"pasp");
958                b.u32(h);
959                b.u32(vv);
960                b.end(m);
961            }
962            b.end(m);
963            return Ok(());
964        }
965        let (Some(a), CodecConfig::Aac(c)) = (&self.audio, &self.codec) else {
966            return Err(Error::Unsupported(format!(
967                "writing {} audio",
968                self.codec.name()
969            )));
970        };
971        let m = b.start(&self.format.0);
972        b.zeros(6);
973        b.u16(1);
974        b.zeros(8);
975        b.u16(a.channels.min(u16::MAX as u32) as u16);
976        b.u16(16);
977        b.zeros(4);
978        b.u32(if a.sample_rate < 65536.0 {
979            (a.sample_rate * 65536.0).round() as u32
980        } else {
981            0
982        });
983        b.leaf(
984            b"esds",
985            &esds_payload(&c.asc, c.max_bitrate, c.avg_bitrate, c.buffer_size),
986        );
987        if c.avg_bitrate > 0 {
988            let m = b.start(b"btrt");
989            b.u32(c.buffer_size);
990            b.u32(c.max_bitrate);
991            b.u32(c.avg_bitrate);
992            b.end(m);
993        }
994        b.end(m);
995        Ok(())
996    }
997}