scuffle_h264/
config.rs

1use std::io::{
2    Write, {self},
3};
4
5use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
6use bytes::{Buf, Bytes};
7use scuffle_bytes_util::{BitWriter, BytesCursorExt};
8
9#[derive(Debug, Clone, PartialEq)]
10/// AVC (H.264) Decoder Configuration Record
11/// ISO/IEC 14496-15:2022(E) - 5.3.2.1.2
12pub struct AVCDecoderConfigurationRecord {
13    pub configuration_version: u8,
14    pub profile_indication: u8,
15    pub profile_compatibility: u8,
16    pub level_indication: u8,
17    pub length_size_minus_one: u8,
18    pub sps: Vec<Bytes>,
19    pub pps: Vec<Bytes>,
20    pub extended_config: Option<AvccExtendedConfig>,
21}
22
23#[derive(Debug, Clone, PartialEq)]
24/// AVC (H.264) Extended Configuration
25/// ISO/IEC 14496-15:2022(E) - 5.3.2.1.2
26pub struct AvccExtendedConfig {
27    pub chroma_format: u8,
28    pub bit_depth_luma_minus8: u8,
29    pub bit_depth_chroma_minus8: u8,
30    pub sequence_parameter_set_ext: Vec<Bytes>,
31}
32
33impl AVCDecoderConfigurationRecord {
34    pub fn demux(reader: &mut io::Cursor<Bytes>) -> io::Result<Self> {
35        let configuration_version = reader.read_u8()?;
36        let profile_indication = reader.read_u8()?;
37        let profile_compatibility = reader.read_u8()?;
38        let level_indication = reader.read_u8()?;
39        let length_size_minus_one = reader.read_u8()? & 0b00000011;
40        let num_of_sequence_parameter_sets = reader.read_u8()? & 0b00011111;
41
42        let mut sps = Vec::with_capacity(num_of_sequence_parameter_sets as usize);
43        for _ in 0..num_of_sequence_parameter_sets {
44            let sps_length = reader.read_u16::<BigEndian>()?;
45            let sps_data = reader.extract_bytes(sps_length as usize)?;
46            sps.push(sps_data);
47        }
48
49        let num_of_picture_parameter_sets = reader.read_u8()?;
50        let mut pps = Vec::with_capacity(num_of_picture_parameter_sets as usize);
51        for _ in 0..num_of_picture_parameter_sets {
52            let pps_length = reader.read_u16::<BigEndian>()?;
53            let pps_data = reader.extract_bytes(pps_length as usize)?;
54            pps.push(pps_data);
55        }
56
57        // It turns out that sometimes the extended config is not present, even though
58        // the avc_profile_indication is not 66, 77 or 88. We need to be lenient here on
59        // decoding.
60        let extended_config = match profile_indication {
61            66 | 77 | 88 => None,
62            _ => {
63                if reader.has_remaining() {
64                    let chroma_format = reader.read_u8()? & 0b00000011; // 2 bits (6 bits reserved)
65                    let bit_depth_luma_minus8 = reader.read_u8()? & 0b00000111; // 3 bits (5 bits reserved)
66                    let bit_depth_chroma_minus8 = reader.read_u8()? & 0b00000111; // 3 bits (5 bits reserved)
67                    let number_of_sequence_parameter_set_ext = reader.read_u8()?; // 8 bits
68
69                    let mut sequence_parameter_set_ext = Vec::with_capacity(number_of_sequence_parameter_set_ext as usize);
70                    for _ in 0..number_of_sequence_parameter_set_ext {
71                        let sps_ext_length = reader.read_u16::<BigEndian>()?;
72                        let sps_ext_data = reader.extract_bytes(sps_ext_length as usize)?;
73                        sequence_parameter_set_ext.push(sps_ext_data);
74                    }
75
76                    Some(AvccExtendedConfig {
77                        chroma_format,
78                        bit_depth_luma_minus8,
79                        bit_depth_chroma_minus8,
80                        sequence_parameter_set_ext,
81                    })
82                } else {
83                    // No extended config present even though avc_profile_indication is not 66, 77
84                    // or 88
85                    None
86                }
87            }
88        };
89
90        Ok(Self {
91            configuration_version,
92            profile_indication,
93            profile_compatibility,
94            level_indication,
95            length_size_minus_one,
96            sps,
97            pps,
98            extended_config,
99        })
100    }
101
102    pub fn size(&self) -> u64 {
103        1 // configuration_version
104        + 1 // avc_profile_indication
105        + 1 // profile_compatibility
106        + 1 // avc_level_indication
107        + 1 // length_size_minus_one
108        + 1 // num_of_sequence_parameter_sets (5 bits reserved, 3 bits)
109        + self.sps.iter().map(|sps| {
110            2 // sps_length
111            + sps.len() as u64
112        }).sum::<u64>() // sps
113        + 1 // num_of_picture_parameter_sets
114        + self.pps.iter().map(|pps| {
115            2 // pps_length
116            + pps.len() as u64
117        }).sum::<u64>() // pps
118        + match &self.extended_config {
119            Some(config) => {
120                1 // chroma_format (6 bits reserved, 2 bits)
121                + 1 // bit_depth_luma_minus8 (5 bits reserved, 3 bits)
122                + 1 // bit_depth_chroma_minus8 (5 bits reserved, 3 bits)
123                + 1 // number_of_sequence_parameter_set_ext
124                + config.sequence_parameter_set_ext.iter().map(|sps_ext| {
125                    2 // sps_ext_length
126                    + sps_ext.len() as u64
127                }).sum::<u64>() // sps_ext
128            }
129            None => 0,
130        }
131    }
132
133    pub fn mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
134        let mut bit_writer = BitWriter::new(writer);
135
136        bit_writer.write_u8(self.configuration_version)?;
137        bit_writer.write_u8(self.profile_indication)?;
138        bit_writer.write_u8(self.profile_compatibility)?;
139        bit_writer.write_u8(self.level_indication)?;
140        bit_writer.write_bits(0b111111, 6)?;
141        bit_writer.write_bits(self.length_size_minus_one as u64, 2)?;
142        bit_writer.write_bits(0b111, 3)?;
143
144        bit_writer.write_bits(self.sps.len() as u64, 5)?;
145        for sps in &self.sps {
146            bit_writer.write_u16::<BigEndian>(sps.len() as u16)?;
147            bit_writer.write_all(sps)?;
148        }
149
150        bit_writer.write_bits(self.pps.len() as u64, 8)?;
151        for pps in &self.pps {
152            bit_writer.write_u16::<BigEndian>(pps.len() as u16)?;
153            bit_writer.write_all(pps)?;
154        }
155
156        if let Some(config) = &self.extended_config {
157            bit_writer.write_bits(0b111111, 6)?;
158            bit_writer.write_bits(config.chroma_format as u64, 2)?;
159            bit_writer.write_bits(0b11111, 5)?;
160            bit_writer.write_bits(config.bit_depth_luma_minus8 as u64, 3)?;
161            bit_writer.write_bits(0b11111, 5)?;
162            bit_writer.write_bits(config.bit_depth_chroma_minus8 as u64, 3)?;
163
164            bit_writer.write_bits(config.sequence_parameter_set_ext.len() as u64, 8)?;
165            for sps_ext in &config.sequence_parameter_set_ext {
166                bit_writer.write_u16::<BigEndian>(sps_ext.len() as u16)?;
167                bit_writer.write_all(sps_ext)?;
168            }
169        }
170
171        bit_writer.finish()?;
172
173        Ok(())
174    }
175}