1use crate::bitreader::BitReader;
2use crate::eg::{read_se, read_ue};
3use crate::{Error, Result};
4
5#[derive(Debug, Clone)]
6pub struct Pps {
7 pub pic_parameter_set_id: u8,
8 pub seq_parameter_set_id: u8,
9 pub entropy_coding_mode_flag: bool,
10 pub bottom_field_pic_order_in_frame_present_flag: bool,
11
12 pub num_slice_groups_minus1: u32,
13 pub slice_group_map_type: u32,
14
15 pub num_ref_idx_l0_default_active_minus1: u8,
16 pub num_ref_idx_l1_default_active_minus1: u8,
17 pub weighted_pred_flag: bool,
18 pub weighted_bipred_idc: u8,
19 pub pic_init_qp_minus26: i8,
20 pub pic_init_qs_minus26: i8,
21 pub chroma_qp_index_offset: i8,
22 pub deblocking_filter_control_present_flag: bool,
23 pub constrained_intra_pred_flag: bool,
24 pub redundant_pic_cnt_present_flag: bool,
25
26 pub transform_8x8_mode_flag: bool,
27 pub pic_scaling_matrix_present_flag: bool,
28 pub second_chroma_qp_index_offset: i8,
29}
30
31impl Pps {
32 pub fn parse(rbsp: &[u8]) -> Result<Self> {
33 let mut reader = BitReader::new(rbsp);
34
35 let pic_parameter_set_id = read_ue(&mut reader)?;
36 if pic_parameter_set_id > 255 {
37 return Err(Error::MalformedPps("Invalid PPS ID".into()));
38 }
39
40 let seq_parameter_set_id = read_ue(&mut reader)?;
41 if seq_parameter_set_id > 31 {
42 return Err(Error::MalformedPps("Invalid SPS ID reference".into()));
43 }
44
45 let entropy_coding_mode_flag = reader.read_flag()?;
46 let bottom_field_pic_order_in_frame_present_flag = reader.read_flag()?;
47
48 let num_slice_groups_minus1 = read_ue(&mut reader)?;
49 let mut slice_group_map_type = 0;
50
51 if num_slice_groups_minus1 > 0 {
52 slice_group_map_type = read_ue(&mut reader)?;
53
54 match slice_group_map_type {
55 0 => {
56 for _ in 0..=num_slice_groups_minus1 {
57 let _run_length_minus1 = read_ue(&mut reader)?;
58 }
59 }
60 2 => {
61 for _ in 0..num_slice_groups_minus1 {
62 let _top_left = read_ue(&mut reader)?;
63 let _bottom_right = read_ue(&mut reader)?;
64 }
65 }
66 3 | 4 | 5 => {
67 let _slice_group_change_direction_flag = reader.read_flag()?;
68 let _slice_group_change_rate_minus1 = read_ue(&mut reader)?;
69 }
70 6 => {
71 let pic_size_in_map_units_minus1 = read_ue(&mut reader)?;
72 let num_bits = (num_slice_groups_minus1 + 1).ilog2() as u32;
73 for _ in 0..=pic_size_in_map_units_minus1 {
74 reader.read_bits(num_bits)?;
75 }
76 }
77 _ => {}
78 }
79 }
80
81 let num_ref_idx_l0_default_active_minus1 = read_ue(&mut reader)?;
82 if num_ref_idx_l0_default_active_minus1 > 31 {
83 return Err(Error::MalformedPps("Invalid num_ref_idx_l0".into()));
84 }
85
86 let num_ref_idx_l1_default_active_minus1 = read_ue(&mut reader)?;
87 if num_ref_idx_l1_default_active_minus1 > 31 {
88 return Err(Error::MalformedPps("Invalid num_ref_idx_l1".into()));
89 }
90
91 let weighted_pred_flag = reader.read_flag()?;
92 let weighted_bipred_idc = reader.read_bits(2)? as u8;
93
94 let pic_init_qp_minus26 = read_se(&mut reader)?;
95 if pic_init_qp_minus26 < -26 || pic_init_qp_minus26 > 25 {
96 return Err(Error::MalformedPps("Invalid pic_init_qp".into()));
97 }
98
99 let pic_init_qs_minus26 = read_se(&mut reader)?;
100 if pic_init_qs_minus26 < -26 || pic_init_qs_minus26 > 25 {
101 return Err(Error::MalformedPps("Invalid pic_init_qs".into()));
102 }
103
104 let chroma_qp_index_offset = read_se(&mut reader)?;
105 if chroma_qp_index_offset < -12 || chroma_qp_index_offset > 12 {
106 return Err(Error::MalformedPps("Invalid chroma_qp_index_offset".into()));
107 }
108
109 let deblocking_filter_control_present_flag = reader.read_flag()?;
110 let constrained_intra_pred_flag = reader.read_flag()?;
111 let redundant_pic_cnt_present_flag = reader.read_flag()?;
112
113 let mut transform_8x8_mode_flag = false;
114 let mut pic_scaling_matrix_present_flag = false;
115 let mut second_chroma_qp_index_offset = chroma_qp_index_offset;
116
117 if reader.more_rbsp_data() {
118 transform_8x8_mode_flag = reader.read_flag()?;
119 pic_scaling_matrix_present_flag = reader.read_flag()?;
120
121 if pic_scaling_matrix_present_flag {
122 let num_lists = 6 + if transform_8x8_mode_flag { 2 } else { 0 };
123 for i in 0..num_lists {
124 let pic_scaling_list_present_flag = reader.read_flag()?;
125 if pic_scaling_list_present_flag {
126 let size = if i < 6 { 16 } else { 64 };
127 skip_scaling_list(&mut reader, size)?;
128 }
129 }
130 }
131
132 second_chroma_qp_index_offset = read_se(&mut reader)?;
133 if second_chroma_qp_index_offset < -12 || second_chroma_qp_index_offset > 12 {
134 return Err(Error::MalformedPps("Invalid second_chroma_qp_index_offset".into()));
135 }
136 }
137
138 Ok(Pps {
139 pic_parameter_set_id: pic_parameter_set_id as u8,
140 seq_parameter_set_id: seq_parameter_set_id as u8,
141 entropy_coding_mode_flag,
142 bottom_field_pic_order_in_frame_present_flag,
143 num_slice_groups_minus1,
144 slice_group_map_type,
145 num_ref_idx_l0_default_active_minus1: num_ref_idx_l0_default_active_minus1 as u8,
146 num_ref_idx_l1_default_active_minus1: num_ref_idx_l1_default_active_minus1 as u8,
147 weighted_pred_flag,
148 weighted_bipred_idc,
149 pic_init_qp_minus26: pic_init_qp_minus26 as i8,
150 pic_init_qs_minus26: pic_init_qs_minus26 as i8,
151 chroma_qp_index_offset: chroma_qp_index_offset as i8,
152 deblocking_filter_control_present_flag,
153 constrained_intra_pred_flag,
154 redundant_pic_cnt_present_flag,
155 transform_8x8_mode_flag,
156 pic_scaling_matrix_present_flag,
157 second_chroma_qp_index_offset: second_chroma_qp_index_offset as i8,
158 })
159 }
160}
161
162fn skip_scaling_list(reader: &mut BitReader, size: usize) -> Result<()> {
163 let mut last_scale = 8;
164 let mut next_scale = 8;
165
166 for _ in 0..size {
167 if next_scale != 0 {
168 let delta_scale = read_se(reader)?;
169 next_scale = (last_scale + delta_scale + 256) % 256;
170 }
171 last_scale = if next_scale == 0 { last_scale } else { next_scale };
172 }
173
174 Ok(())
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use crate::nal::ebsp_to_rbsp;
181
182 #[test]
183 fn test_basic_pps_parse() {
184 let ebsp = vec![0xee, 0x3c, 0x80];
185 let rbsp = ebsp_to_rbsp(&ebsp);
186 let pps = Pps::parse(&rbsp).unwrap();
187
188 assert_eq!(pps.pic_parameter_set_id, 0);
189 assert_eq!(pps.seq_parameter_set_id, 0);
190 }
191}