scuffle_mp4/boxes/types/
av01.rs1use 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)]
17pub 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}