scuffle_mp4/boxes/types/
av01.rs

1use std::io;
2
3use bytes::{Buf, Bytes};
4use scuffle_av1::seq::SequenceHeaderObu;
5use scuffle_av1::{ObuHeader, ObuType};
6use scuffle_bytes_util::BytesCursorExt;
7
8use super::av1c::Av1C;
9use super::btrt::Btrt;
10use super::stsd::{SampleEntry, VisualSampleEntry};
11use crate::boxes::DynBox;
12use crate::boxes::header::BoxHeader;
13use crate::boxes::traits::BoxType;
14use crate::codec::VideoCodec;
15
16#[derive(Debug, Clone, PartialEq)]
17/// AV1 Codec Box
18/// <https://aomediacodec.github.io/av1-isobmff/#av1sampleentry-section>
19pub struct Av01 {
20    pub header: BoxHeader,
21    pub visual_sample_entry: SampleEntry<VisualSampleEntry>,
22    pub av1c: Av1C,
23    pub btrt: Option<Btrt>,
24    pub unknown: Vec<DynBox>,
25}
26
27impl Av01 {
28    pub fn new(visual_sample_entry: SampleEntry<VisualSampleEntry>, av1c: Av1C, btrt: Option<Btrt>) -> Self {
29        Self {
30            header: BoxHeader::new(Self::NAME),
31            visual_sample_entry,
32            av1c,
33            btrt,
34            unknown: Vec::new(),
35        }
36    }
37
38    pub fn codec(&self) -> io::Result<VideoCodec> {
39        let mut cursor = io::Cursor::new(self.av1c.av1_config.config_obu.clone());
40        let header = ObuHeader::parse(&mut cursor)?;
41
42        let data = cursor.extract_bytes(header.size.unwrap_or(cursor.remaining() as u64) as usize)?;
43
44        if header.obu_type != ObuType::SequenceHeader {
45            return Err(io::Error::new(
46                io::ErrorKind::InvalidData,
47                "av1c box is missing sequence header",
48            ));
49        }
50
51        let seq_obu = SequenceHeaderObu::parse(header, &mut io::Cursor::new(data))?;
52        let op_point = &seq_obu.operating_points[0];
53
54        Ok(VideoCodec::Av1 {
55            profile: seq_obu.seq_profile,
56            level: op_point.seq_level_idx,
57            tier: op_point.seq_tier,
58            depth: seq_obu.color_config.bit_depth as u8,
59            monochrome: seq_obu.color_config.mono_chrome,
60            sub_sampling_x: seq_obu.color_config.subsampling_x,
61            sub_sampling_y: seq_obu.color_config.subsampling_y,
62            color_primaries: seq_obu.color_config.color_primaries,
63            transfer_characteristics: seq_obu.color_config.transfer_characteristics,
64            matrix_coefficients: seq_obu.color_config.matrix_coefficients,
65            full_range_flag: seq_obu.color_config.full_color_range,
66        })
67    }
68}
69
70impl BoxType for Av01 {
71    const NAME: [u8; 4] = *b"av01";
72
73    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
74        let mut reader = io::Cursor::new(data);
75
76        let mut visual_sample_entry = SampleEntry::<VisualSampleEntry>::demux(&mut reader)?;
77
78        let mut av1c = None;
79        let mut btrt = None;
80        let mut unknown = Vec::new();
81
82        while reader.has_remaining() {
83            let dyn_box = DynBox::demux(&mut reader)?;
84            match dyn_box {
85                DynBox::Av1C(b) => {
86                    av1c = Some(b);
87                }
88                DynBox::Btrt(b) => {
89                    btrt = Some(b);
90                }
91                DynBox::Clap(b) => {
92                    visual_sample_entry.extension.clap = Some(*b);
93                }
94                DynBox::Pasp(b) => {
95                    visual_sample_entry.extension.pasp = Some(*b);
96                }
97                DynBox::Colr(b) => {
98                    visual_sample_entry.extension.colr = Some(*b);
99                }
100                _ => {
101                    unknown.push(dyn_box);
102                }
103            }
104        }
105
106        let av1c = av1c.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "trak box is missing tkhd box"))?;
107
108        Ok(Self {
109            header,
110            visual_sample_entry,
111            av1c: *av1c,
112            btrt: btrt.map(|b| *b),
113            unknown,
114        })
115    }
116
117    fn primitive_size(&self) -> u64 {
118        self.visual_sample_entry.size()
119            + self.av1c.size()
120            + self.btrt.as_ref().map(|b| b.size()).unwrap_or(0)
121            + self.unknown.iter().map(|b| b.size()).sum::<u64>()
122    }
123
124    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
125        self.visual_sample_entry.mux(writer)?;
126        self.av1c.mux(writer)?;
127        if let Some(btrt) = &self.btrt {
128            btrt.mux(writer)?;
129        }
130        for unknown in &self.unknown {
131            unknown.mux(writer)?;
132        }
133        Ok(())
134    }
135}