scuffle_mp4/boxes/types/
av01.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::io;

use bytes::{Buf, Bytes};
use scuffle_av1::seq::SequenceHeaderObu;
use scuffle_av1::{ObuHeader, ObuType};
use scuffle_bytes_util::BytesCursorExt;

use super::av1c::Av1C;
use super::btrt::Btrt;
use super::stsd::{SampleEntry, VisualSampleEntry};
use crate::boxes::header::BoxHeader;
use crate::boxes::traits::BoxType;
use crate::boxes::DynBox;
use crate::codec::VideoCodec;

#[derive(Debug, Clone, PartialEq)]
/// AV1 Codec Box
/// <https://aomediacodec.github.io/av1-isobmff/#av1sampleentry-section>
pub struct Av01 {
    pub header: BoxHeader,
    pub visual_sample_entry: SampleEntry<VisualSampleEntry>,
    pub av1c: Av1C,
    pub btrt: Option<Btrt>,
    pub unknown: Vec<DynBox>,
}

impl Av01 {
    pub fn new(visual_sample_entry: SampleEntry<VisualSampleEntry>, av1c: Av1C, btrt: Option<Btrt>) -> Self {
        Self {
            header: BoxHeader::new(Self::NAME),
            visual_sample_entry,
            av1c,
            btrt,
            unknown: Vec::new(),
        }
    }

    pub fn codec(&self) -> io::Result<VideoCodec> {
        let mut cursor = io::Cursor::new(self.av1c.av1_config.config_obu.clone());
        let header = ObuHeader::parse(&mut cursor)?;

        let data = cursor.extract_bytes(header.size.unwrap_or(cursor.remaining() as u64) as usize)?;

        if header.obu_type != ObuType::SequenceHeader {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "av1c box is missing sequence header",
            ));
        }

        let seq_obu = SequenceHeaderObu::parse(header, &mut io::Cursor::new(data))?;
        let op_point = &seq_obu.operating_points[0];

        Ok(VideoCodec::Av1 {
            profile: seq_obu.seq_profile,
            level: op_point.seq_level_idx,
            tier: op_point.seq_tier,
            depth: seq_obu.color_config.bit_depth as u8,
            monochrome: seq_obu.color_config.mono_chrome,
            sub_sampling_x: seq_obu.color_config.subsampling_x,
            sub_sampling_y: seq_obu.color_config.subsampling_y,
            color_primaries: seq_obu.color_config.color_primaries,
            transfer_characteristics: seq_obu.color_config.transfer_characteristics,
            matrix_coefficients: seq_obu.color_config.matrix_coefficients,
            full_range_flag: seq_obu.color_config.full_color_range,
        })
    }
}

impl BoxType for Av01 {
    const NAME: [u8; 4] = *b"av01";

    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
        let mut reader = io::Cursor::new(data);

        let mut visual_sample_entry = SampleEntry::<VisualSampleEntry>::demux(&mut reader)?;

        let mut av1c = None;
        let mut btrt = None;
        let mut unknown = Vec::new();

        while reader.has_remaining() {
            let dyn_box = DynBox::demux(&mut reader)?;
            match dyn_box {
                DynBox::Av1C(b) => {
                    av1c = Some(b);
                }
                DynBox::Btrt(b) => {
                    btrt = Some(b);
                }
                DynBox::Clap(b) => {
                    visual_sample_entry.extension.clap = Some(*b);
                }
                DynBox::Pasp(b) => {
                    visual_sample_entry.extension.pasp = Some(*b);
                }
                DynBox::Colr(b) => {
                    visual_sample_entry.extension.colr = Some(*b);
                }
                _ => {
                    unknown.push(dyn_box);
                }
            }
        }

        let av1c = av1c.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "trak box is missing tkhd box"))?;

        Ok(Self {
            header,
            visual_sample_entry,
            av1c: *av1c,
            btrt: btrt.map(|b| *b),
            unknown,
        })
    }

    fn primitive_size(&self) -> u64 {
        self.visual_sample_entry.size()
            + self.av1c.size()
            + self.btrt.as_ref().map(|b| b.size()).unwrap_or(0)
            + self.unknown.iter().map(|b| b.size()).sum::<u64>()
    }

    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
        self.visual_sample_entry.mux(writer)?;
        self.av1c.mux(writer)?;
        if let Some(btrt) = &self.btrt {
            btrt.mux(writer)?;
        }
        for unknown in &self.unknown {
            unknown.mux(writer)?;
        }
        Ok(())
    }
}