Skip to main content

h264_parser/
sps.rs

1use crate::bitreader::BitReader;
2use crate::eg::{read_se, read_ue};
3use crate::{Error, Result};
4
5#[derive(Debug, Clone)]
6pub struct Sps {
7    pub profile_idc: u8,
8    pub constraint_set0_flag: bool,
9    pub constraint_set1_flag: bool,
10    pub constraint_set2_flag: bool,
11    pub constraint_set3_flag: bool,
12    pub constraint_set4_flag: bool,
13    pub constraint_set5_flag: bool,
14    pub level_idc: u8,
15    pub seq_parameter_set_id: u8,
16
17    pub chroma_format_idc: u8,
18    pub separate_colour_plane_flag: bool,
19    pub bit_depth_luma_minus8: u8,
20    pub bit_depth_chroma_minus8: u8,
21    pub qpprime_y_zero_transform_bypass_flag: bool,
22    pub seq_scaling_matrix_present_flag: bool,
23
24    pub log2_max_frame_num_minus4: u8,
25    pub pic_order_cnt_type: u8,
26    pub log2_max_pic_order_cnt_lsb_minus4: u8,
27    pub delta_pic_order_always_zero_flag: bool,
28    pub offset_for_non_ref_pic: i32,
29    pub offset_for_top_to_bottom_field: i32,
30    pub num_ref_frames_in_pic_order_cnt_cycle: u8,
31
32    pub max_num_ref_frames: u32,
33    pub gaps_in_frame_num_value_allowed_flag: bool,
34    pub pic_width_in_mbs_minus1: u32,
35    pub pic_height_in_map_units_minus1: u32,
36    pub frame_mbs_only_flag: bool,
37    pub mb_adaptive_frame_field_flag: bool,
38    pub direct_8x8_inference_flag: bool,
39
40    pub frame_cropping_flag: bool,
41    pub frame_crop_left_offset: u32,
42    pub frame_crop_right_offset: u32,
43    pub frame_crop_top_offset: u32,
44    pub frame_crop_bottom_offset: u32,
45
46    pub vui_parameters_present_flag: bool,
47
48    pub width: u32,
49    pub height: u32,
50}
51
52impl Sps {
53    pub fn parse(rbsp: &[u8]) -> Result<Self> {
54        let mut reader = BitReader::new(rbsp);
55
56        let profile_idc = reader.read_u8()?;
57        let constraint_set0_flag = reader.read_flag()?;
58        let constraint_set1_flag = reader.read_flag()?;
59        let constraint_set2_flag = reader.read_flag()?;
60        let constraint_set3_flag = reader.read_flag()?;
61        let constraint_set4_flag = reader.read_flag()?;
62        let constraint_set5_flag = reader.read_flag()?;
63        let _reserved_zero_2bits = reader.read_bits(2)?;
64        let level_idc = reader.read_u8()?;
65
66        let seq_parameter_set_id = read_ue(&mut reader)?;
67        if seq_parameter_set_id > 31 {
68            return Err(Error::MalformedSps("Invalid SPS ID".into()));
69        }
70
71        let mut chroma_format_idc = 1;
72        let mut separate_colour_plane_flag = false;
73        let mut bit_depth_luma_minus8 = 0;
74        let mut bit_depth_chroma_minus8 = 0;
75        let mut qpprime_y_zero_transform_bypass_flag = false;
76        let mut seq_scaling_matrix_present_flag = false;
77
78        if profile_idc == 100
79            || profile_idc == 110
80            || profile_idc == 122
81            || profile_idc == 244
82            || profile_idc == 44
83            || profile_idc == 83
84            || profile_idc == 86
85            || profile_idc == 118
86            || profile_idc == 128
87            || profile_idc == 138
88            || profile_idc == 139
89            || profile_idc == 134
90            || profile_idc == 135
91        {
92            chroma_format_idc = read_ue(&mut reader)? as u8;
93            if chroma_format_idc > 3 {
94                return Err(Error::MalformedSps("Invalid chroma format".into()));
95            }
96
97            if chroma_format_idc == 3 {
98                separate_colour_plane_flag = reader.read_flag()?;
99            }
100
101            bit_depth_luma_minus8 = read_ue(&mut reader)? as u8;
102            bit_depth_chroma_minus8 = read_ue(&mut reader)? as u8;
103            qpprime_y_zero_transform_bypass_flag = reader.read_flag()?;
104            seq_scaling_matrix_present_flag = reader.read_flag()?;
105
106            if seq_scaling_matrix_present_flag {
107                let num_lists = if chroma_format_idc != 3 { 8 } else { 12 };
108                for i in 0..num_lists {
109                    let seq_scaling_list_present_flag = reader.read_flag()?;
110                    if seq_scaling_list_present_flag {
111                        // 4x4 lists (i < 6) hold 16 entries, 8x8 lists (i >= 6) hold 64.
112                        let size = if i < 6 { 16 } else { 64 };
113                        skip_scaling_list(&mut reader, size)?;
114                    }
115                }
116            }
117        }
118
119        let log2_max_frame_num_minus4 = read_ue(&mut reader)? as u8;
120        if log2_max_frame_num_minus4 > 12 {
121            return Err(Error::MalformedSps("Invalid log2_max_frame_num".into()));
122        }
123
124        let pic_order_cnt_type = read_ue(&mut reader)? as u8;
125
126        let mut log2_max_pic_order_cnt_lsb_minus4 = 0;
127        let mut delta_pic_order_always_zero_flag = false;
128        let mut offset_for_non_ref_pic = 0;
129        let mut offset_for_top_to_bottom_field = 0;
130        let mut num_ref_frames_in_pic_order_cnt_cycle = 0;
131
132        match pic_order_cnt_type {
133            0 => {
134                log2_max_pic_order_cnt_lsb_minus4 = read_ue(&mut reader)? as u8;
135                if log2_max_pic_order_cnt_lsb_minus4 > 12 {
136                    return Err(Error::MalformedSps(
137                        "Invalid log2_max_pic_order_cnt_lsb".into(),
138                    ));
139                }
140            }
141            1 => {
142                delta_pic_order_always_zero_flag = reader.read_flag()?;
143                offset_for_non_ref_pic = read_se(&mut reader)?;
144                offset_for_top_to_bottom_field = read_se(&mut reader)?;
145                num_ref_frames_in_pic_order_cnt_cycle = read_ue(&mut reader)? as u8;
146
147                for _ in 0..num_ref_frames_in_pic_order_cnt_cycle {
148                    let _offset_for_ref_frame = read_se(&mut reader)?;
149                }
150            }
151            2 => {}
152            _ => return Err(Error::MalformedSps("Invalid pic_order_cnt_type".into())),
153        }
154
155        let max_num_ref_frames = read_ue(&mut reader)?;
156        let gaps_in_frame_num_value_allowed_flag = reader.read_flag()?;
157
158        let pic_width_in_mbs_minus1 = read_ue(&mut reader)?;
159        let pic_height_in_map_units_minus1 = read_ue(&mut reader)?;
160
161        let frame_mbs_only_flag = reader.read_flag()?;
162        let mut mb_adaptive_frame_field_flag = false;
163        if !frame_mbs_only_flag {
164            mb_adaptive_frame_field_flag = reader.read_flag()?;
165        }
166
167        let direct_8x8_inference_flag = reader.read_flag()?;
168
169        let frame_cropping_flag = reader.read_flag()?;
170        let mut frame_crop_left_offset = 0;
171        let mut frame_crop_right_offset = 0;
172        let mut frame_crop_top_offset = 0;
173        let mut frame_crop_bottom_offset = 0;
174
175        if frame_cropping_flag {
176            frame_crop_left_offset = read_ue(&mut reader)?;
177            frame_crop_right_offset = read_ue(&mut reader)?;
178            frame_crop_top_offset = read_ue(&mut reader)?;
179            frame_crop_bottom_offset = read_ue(&mut reader)?;
180        }
181
182        let vui_parameters_present_flag = reader.read_flag()?;
183
184        let width = (pic_width_in_mbs_minus1 + 1) * 16;
185        let height =
186            (pic_height_in_map_units_minus1 + 1) * 16 * if frame_mbs_only_flag { 1 } else { 2 };
187
188        let (sub_width_c, sub_height_c) = match chroma_format_idc {
189            0 => (0, 0),
190            1 => (2, 2),
191            2 => (2, 1),
192            3 => (1, 1),
193            _ => (0, 0),
194        };
195
196        let width = if frame_cropping_flag && sub_width_c > 0 {
197            width - sub_width_c * (frame_crop_left_offset + frame_crop_right_offset)
198        } else {
199            width
200        };
201
202        let height = if frame_cropping_flag && sub_height_c > 0 {
203            let mult = if frame_mbs_only_flag { 1 } else { 2 };
204            height - sub_height_c * mult * (frame_crop_top_offset + frame_crop_bottom_offset)
205        } else {
206            height
207        };
208
209        Ok(Sps {
210            profile_idc,
211            constraint_set0_flag,
212            constraint_set1_flag,
213            constraint_set2_flag,
214            constraint_set3_flag,
215            constraint_set4_flag,
216            constraint_set5_flag,
217            level_idc,
218            seq_parameter_set_id: seq_parameter_set_id as u8,
219            chroma_format_idc,
220            separate_colour_plane_flag,
221            bit_depth_luma_minus8,
222            bit_depth_chroma_minus8,
223            qpprime_y_zero_transform_bypass_flag,
224            seq_scaling_matrix_present_flag,
225            log2_max_frame_num_minus4,
226            pic_order_cnt_type,
227            log2_max_pic_order_cnt_lsb_minus4,
228            delta_pic_order_always_zero_flag,
229            offset_for_non_ref_pic,
230            offset_for_top_to_bottom_field,
231            num_ref_frames_in_pic_order_cnt_cycle,
232            max_num_ref_frames,
233            gaps_in_frame_num_value_allowed_flag,
234            pic_width_in_mbs_minus1,
235            pic_height_in_map_units_minus1,
236            frame_mbs_only_flag,
237            mb_adaptive_frame_field_flag,
238            direct_8x8_inference_flag,
239            frame_cropping_flag,
240            frame_crop_left_offset,
241            frame_crop_right_offset,
242            frame_crop_top_offset,
243            frame_crop_bottom_offset,
244            vui_parameters_present_flag,
245            width,
246            height,
247        })
248    }
249}
250
251fn skip_scaling_list(reader: &mut BitReader, size: usize) -> Result<()> {
252    let mut last_scale = 8;
253    let mut next_scale = 8;
254
255    for _ in 0..size {
256        if next_scale != 0 {
257            let delta_scale = read_se(reader)?;
258            next_scale = (last_scale + delta_scale + 256) % 256;
259        }
260        last_scale = if next_scale == 0 {
261            last_scale
262        } else {
263            next_scale
264        };
265    }
266
267    Ok(())
268}
269
270#[cfg(test)]
271mod tests {
272    use super::*;
273    use crate::nal::ebsp_to_rbsp;
274
275    #[test]
276    fn test_basic_sps_parse() {
277        let ebsp = vec![
278            0x42, 0x00, 0x1f, 0xac, 0x34, 0xc8, 0x14, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00,
279            0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc6, 0x58,
280        ];
281
282        let rbsp = ebsp_to_rbsp(&ebsp);
283        let sps = Sps::parse(&rbsp).unwrap();
284
285        assert_eq!(sps.profile_idc, 66);
286        assert_eq!(sps.level_idc, 31);
287        assert!(sps.width > 0);
288        assert!(sps.height > 0);
289    }
290
291    /// Regression test: an SPS with an 8x8 scaling list (list index >= 6) must
292    /// skip 64 entries, not 16. Under-skipping desyncs the bit reader and
293    /// yields a bogus resolution (e.g. 10x16 instead of 1920x1080).
294    #[test]
295    fn test_sps_with_8x8_scaling_list() {
296        // Real-world 1920x1080i High Profile SPS carrying two 8x8 scaling lists.
297        let nal = vec![
298            0x27, 0x64, 0x00, 0x28, 0xad, 0x84, 0x05, 0x45, 0x62, 0xb8, 0xac, 0x54, 0x71, 0x08, 0x0a,
299            0x8a, 0xc5, 0x71, 0x58, 0xa8, 0xe2, 0x10, 0x24, 0x85, 0x21, 0x39, 0x3c, 0x9f, 0x27, 0xe4,
300            0xfe, 0x4f, 0xc9, 0xf2, 0x79, 0xb9, 0xb3, 0x4d, 0x08, 0x12, 0x42, 0x90, 0x9c, 0x9e, 0x4f,
301            0x93, 0xf2, 0x7f, 0x27, 0xe4, 0xf9, 0x3c, 0xdc, 0xd9, 0xa6, 0x1b, 0x2b, 0x01, 0xe0, 0x11,
302            0x1f, 0x78, 0x08, 0x80, 0x00, 0x01, 0xf4, 0x80, 0x00, 0x75, 0x30, 0x42,
303        ];
304
305        let rbsp = ebsp_to_rbsp(&nal[1..]);
306        let sps = Sps::parse(&rbsp).unwrap();
307
308        assert_eq!(sps.profile_idc, 100);
309        assert_eq!(sps.level_idc, 40);
310        assert_eq!(sps.width, 1920);
311        assert_eq!(sps.height, 1080);
312    }
313}