h264: reword MB reconstruction and add weighted MC
[nihav.git] / nihav-itu / src / codecs / h264 / slice.rs
... / ...
CommitLineData
1use nihav_core::codecs::{DecoderResult, DecoderError};
2use nihav_core::frame::FrameType;
3use nihav_core::io::bitreader::*;
4
5use super::ReadUE;
6use super::sets::*;
7
8pub const MAX_FRAMES: usize = 32;
9
10#[derive(Clone,Copy,Debug,PartialEq)]
11pub enum SliceType {
12 I,
13 P,
14 B,
15 SI,
16 SP,
17}
18
19impl SliceType {
20 pub fn is_intra(self) -> bool {
21 match self {
22 SliceType::I | SliceType::SI => true,
23 _ => false,
24 }
25 }
26 pub fn is_p(self) -> bool {
27 match self {
28 SliceType::P | SliceType::SP => true,
29 _ => false,
30 }
31 }
32 pub fn is_b(self) -> bool { self == SliceType::B }
33 pub fn is_s(self) -> bool {
34 match self {
35 SliceType::SI | SliceType::SP => true,
36 _ => false,
37 }
38 }
39 pub fn to_frame_type(self) -> FrameType {
40 match self {
41 SliceType::I | SliceType::SI => FrameType::I,
42 SliceType::P | SliceType::SP => FrameType::P,
43 SliceType::B => FrameType::B,
44 }
45 }
46}
47
48const SLICE_TYPES: [SliceType; 10] = [
49 SliceType::P, SliceType::B, SliceType::I, SliceType::SP, SliceType::SI,
50 SliceType::P, SliceType::B, SliceType::I, SliceType::SP, SliceType::SI,
51];
52
53#[derive(Clone,Copy,Default)]
54pub struct WeightInfo {
55 pub luma_weighted: bool,
56 pub luma_weight: i8,
57 pub luma_offset: i8,
58 pub luma_shift: u8,
59 pub chroma_weighted: bool,
60 pub chroma_weight: [i8; 2],
61 pub chroma_offset: [i8; 2],
62 pub chroma_shift: u8,
63}
64
65impl WeightInfo {
66 pub fn is_weighted(&self) -> bool {
67 self.luma_weighted || self.chroma_weighted
68 }
69}
70
71#[derive(Clone,Copy)]
72pub struct ReorderingInfo {
73 pub reordering_of_pic_nums_idc: [u8; MAX_FRAMES],
74 pub abs_diff_or_num: [u16; MAX_FRAMES],
75 pub num_ops: usize,
76}
77
78#[derive(Clone,Copy)]
79pub struct AdaptiveMarking {
80 pub memory_management_control_op: [u8; MAX_FRAMES],
81 pub operation_arg: [u16; MAX_FRAMES],
82 pub operation_arg2: [u16; MAX_FRAMES],
83 pub num_ops: usize,
84}
85
86#[derive(Clone)]
87pub struct SliceHeader {
88 pub first_mb_in_slice: usize,
89 pub slice_type: SliceType,
90 pub same_slice_type: bool,
91 pub pic_parameter_set_id: u32,
92 pub frame_num: u16,
93 pub field_pic: bool,
94 pub bottom_field: bool,
95 pub idr_pic_id: u16,
96 pub pic_order_cnt_lsb: u16,
97 pub delta_pic_order_cnt_bottom: i32,
98 pub delta_pic_order_cnt: [i32; 2],
99 pub redundant_pic_cnt: u8,
100 pub direct_spatial_mv_pred: bool,
101 pub num_ref_idx_active_override: bool,
102 pub num_ref_idx_l0_active: usize,
103 pub num_ref_idx_l1_active: usize,
104 pub ref_pic_list_reordering_l0: bool,
105 pub reordering_list_l0: ReorderingInfo,
106 pub ref_pic_list_reordering_l1: bool,
107 pub reordering_list_l1: ReorderingInfo,
108 pub luma_log2_weight_denom: u8,
109 pub chroma_log2_weight_denom: u8,
110 pub weights_l0: [WeightInfo; MAX_FRAMES],
111 pub weights_l1: [WeightInfo; MAX_FRAMES],
112 pub no_output_of_prior_pics: bool,
113 pub long_term_reference: bool,
114 pub adaptive_ref_pic_marking_mode: bool,
115 pub adaptive_ref_pic_marking: AdaptiveMarking,
116 pub cabac_init_idc: u8,
117 pub slice_qp_delta: i32,
118 pub slice_qp: u8,
119 pub sp_for_switch: bool,
120 pub slice_qs_delta: i32,
121 pub slice_qs: u8,
122 pub disable_deblocking_filter_idc: u8,
123 pub slice_alpha_c0_offset: i8,
124 pub slice_beta_offset: i8,
125 pub slice_group_change_cycle: u32,
126}
127
128pub const DEF_WEIGHT_INFO: WeightInfo = WeightInfo {
129 luma_weighted: false,
130 luma_weight: 0,
131 luma_offset: 0,
132 luma_shift: 0,
133 chroma_weighted: false,
134 chroma_weight: [0; 2],
135 chroma_offset: [0; 2],
136 chroma_shift: 0,
137};
138
139impl SliceHeader {
140 pub fn get_weight(&self, list_id: u8, idx: usize) -> WeightInfo {
141 if list_id == 0 {
142 if idx < self.num_ref_idx_l0_active {
143 self.weights_l0[idx]
144 } else {
145 DEF_WEIGHT_INFO
146 }
147 } else {
148 if idx < self.num_ref_idx_l1_active {
149 self.weights_l1[idx]
150 } else {
151 DEF_WEIGHT_INFO
152 }
153 }
154 }
155}
156
157pub fn parse_slice_header_minimal(br: &mut BitReader) -> DecoderResult<(usize, SliceType)> {
158 let first_mb_in_slice = br.read_ue()? as usize;
159 let stype = br.read_ue_lim(SLICE_TYPES.len() as u32 - 1)?;
160 let slice_type = SLICE_TYPES[stype as usize];
161 Ok((first_mb_in_slice, slice_type))
162}
163
164#[allow(clippy::cognitive_complexity)]
165pub fn parse_slice_header(br: &mut BitReader, sps_arr: &[SeqParameterSet], pps_arr: &[PicParameterSet], is_idr: bool, nal_ref_idc: u8) -> DecoderResult<SliceHeader> {
166 let mut hdr: SliceHeader = unsafe { std::mem::zeroed() };
167
168 hdr.first_mb_in_slice = br.read_ue()? as usize;
169 let stype = br.read_ue_lim(SLICE_TYPES.len() as u32 - 1)?;
170 hdr.slice_type = SLICE_TYPES[stype as usize];
171 hdr.same_slice_type = stype >= 5;
172 hdr.pic_parameter_set_id = br.read_ue()?;
173
174 let mut pps_ptr = None;
175 for pps in pps_arr.iter() {
176 if pps.pic_parameter_set_id == hdr.pic_parameter_set_id {
177 pps_ptr = Some(pps);
178 break;
179 }
180 }
181 validate!(pps_ptr.is_some());
182 let pps = pps_ptr.unwrap();
183 let mut sps_ptr = None;
184 for sps in sps_arr.iter() {
185 if sps.seq_parameter_set_id == pps.seq_parameter_set_id {
186 sps_ptr = Some(sps);
187 break;
188 }
189 }
190 validate!(sps_ptr.is_some());
191 let sps = sps_ptr.unwrap();
192
193 hdr.frame_num = br.read(sps.log2_max_frame_num)? as u16;
194 if !sps.frame_mbs_only {
195 hdr.field_pic = br.read_bool()?;
196 if hdr.field_pic {
197 hdr.bottom_field = br.read_bool()?;
198 }
199 }
200
201 if is_idr {
202 hdr.idr_pic_id = br.read_ue_lim(65535)? as u16;
203 }
204 if sps.pic_order_cnt_type == 0 {
205 hdr.pic_order_cnt_lsb = br.read(sps.log2_max_pic_order_cnt_lsb)? as u16;
206 if pps.pic_order_present && !hdr.field_pic {
207 hdr.delta_pic_order_cnt_bottom = br.read_se()?;
208 }
209 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
210 hdr.delta_pic_order_cnt[0] = br.read_se()?;
211 if pps.pic_order_present && !hdr.field_pic {
212 hdr.delta_pic_order_cnt[1] = br.read_se()?;
213 }
214 }
215 if pps.redundant_pic_cnt_present {
216 hdr.redundant_pic_cnt = br.read_ue_lim(127)? as u8;
217 }
218 if hdr.slice_type.is_b() {
219 hdr.direct_spatial_mv_pred = br.read_bool()?;
220 }
221 if !hdr.slice_type.is_intra() {
222 hdr.num_ref_idx_active_override = br.read_bool()?;
223 if hdr.num_ref_idx_active_override {
224 hdr.num_ref_idx_l0_active = (br.read_ue_lim(15)? + 1) as usize;
225 if hdr.slice_type.is_b() {
226 hdr.num_ref_idx_l1_active = (br.read_ue_lim(15)? + 1) as usize;
227 }
228 } else {
229 hdr.num_ref_idx_l0_active = pps.num_ref_idx_l0_active;
230 if hdr.slice_type.is_b() {
231 hdr.num_ref_idx_l1_active = pps.num_ref_idx_l1_active;
232 }
233 }
234 }
235 parse_ref_pic_list_reordering(&mut hdr, br)?;
236 if (pps.weighted_pred && hdr.slice_type.is_p()) ||
237 (pps.weighted_bipred_idc == 1 && hdr.slice_type.is_b()) {
238 parse_pred_weight_table(&mut hdr, br)?;
239 } else {
240 for weight in hdr.weights_l0[..hdr.num_ref_idx_l0_active].iter_mut() {
241 weight.luma_weighted = false;
242 weight.chroma_weighted = false;
243 }
244 for weight in hdr.weights_l1[..hdr.num_ref_idx_l1_active].iter_mut() {
245 weight.luma_weighted = false;
246 weight.chroma_weighted = false;
247 }
248 }
249 if nal_ref_idc != 0 {
250 if is_idr {
251 hdr.no_output_of_prior_pics = br.read_bool()?;
252 hdr.long_term_reference = br.read_bool()?;
253 } else {
254 hdr.adaptive_ref_pic_marking_mode = br.read_bool()?;
255 if hdr.adaptive_ref_pic_marking_mode {
256 let mark_info = &mut hdr.adaptive_ref_pic_marking;
257 loop {
258 let memory_management_control_op = br.read_ue_lim(6)? as u8;
259 if memory_management_control_op == 0 {
260 break;
261 }
262 if mark_info.num_ops >= mark_info.memory_management_control_op.len() {
263 return Err(DecoderError::NotImplemented);
264 }
265 mark_info.memory_management_control_op[mark_info.num_ops] = memory_management_control_op;
266 mark_info.operation_arg[mark_info.num_ops] = match memory_management_control_op {
267 1 | 3 => {
268 let difference_of_pic_nums = br.read_ue()? + 1;
269 difference_of_pic_nums as u16
270 },
271 2 => {
272 let long_term_pic_num = br.read_ue_lim(65535)?;
273 long_term_pic_num as u16
274 },
275 6 => {
276 let long_term_frame_idx = br.read_ue_lim(65536)?;
277 long_term_frame_idx as u16
278 },
279 4 => {
280 let max_long_term_frame_idx_plus1 = br.read_ue()?;
281 max_long_term_frame_idx_plus1 as u16
282 },
283 _ => 0,
284 };
285 mark_info.operation_arg2[mark_info.num_ops] = if memory_management_control_op == 3 {
286 let long_term_frame_idx = br.read_ue_lim(65536)?;
287 long_term_frame_idx as u16
288 } else {
289 0
290 };
291 mark_info.num_ops += 1;
292 }
293 }
294 }
295 }
296 if pps.entropy_coding_mode && !hdr.slice_type.is_intra() {
297 hdr.cabac_init_idc = br.read_ue_lim(2)? as u8;
298 }
299 hdr.slice_qp_delta = br.read_se()?;
300 let qp = i32::from(pps.pic_init_qp) + hdr.slice_qp_delta;
301 validate!(qp >= 0 && qp <= 51);
302 hdr.slice_qp = qp as u8;
303 if hdr.slice_type.is_s() {
304 if hdr.slice_type == SliceType::SP {
305 hdr.sp_for_switch = br.read_bool()?;
306 }
307 hdr.slice_qs_delta = br.read_se()?;
308 let qs = i32::from(pps.pic_init_qs) + hdr.slice_qs_delta;
309 validate!(qs >= 0 && qs <= 51);
310 hdr.slice_qs = qs as u8;
311 }
312 if pps.deblocking_filter_control_present {
313 hdr.disable_deblocking_filter_idc = br.read_ue_lim(2)? as u8;
314 if hdr.disable_deblocking_filter_idc != 1 {
315 let val = br.read_se()?;
316 validate!(val >= -6 && val <= 6);
317 hdr.slice_alpha_c0_offset = val as i8 * 2;
318 let val = br.read_se()?;
319 validate!(val >= -6 && val <= 6);
320 hdr.slice_beta_offset = val as i8 * 2;
321 }
322 }
323 if pps.num_slice_groups > 1 && pps.slice_group_map_type >= 3 && pps.slice_group_map_type <= 5 {
324 hdr.slice_group_change_cycle = br.read_ue()?;
325 }
326
327 Ok(hdr)
328}
329
330fn parse_ref_pic_list_reordering(hdr: &mut SliceHeader, br: &mut BitReader) -> DecoderResult<()> {
331 if !hdr.slice_type.is_intra() {
332 hdr.ref_pic_list_reordering_l0 = br.read_bool()?;
333 let reord_list = &mut hdr.reordering_list_l0;
334 reord_list.num_ops = 0;
335 if hdr.ref_pic_list_reordering_l0 {
336 loop {
337 let reordering_of_pic_nums_idc = br.read_ue_lim(3)?;
338 if reordering_of_pic_nums_idc == 3 {
339 break;
340 }
341 validate!(reord_list.num_ops < MAX_FRAMES);
342 reord_list.reordering_of_pic_nums_idc[reord_list.num_ops] = reordering_of_pic_nums_idc as u8;
343 if reordering_of_pic_nums_idc != 2 {
344 let abs_diff_pic_num = br.read_ue()? + 1;
345 reord_list.abs_diff_or_num[reord_list.num_ops] = abs_diff_pic_num as u16;
346 } else {
347 let long_term_pic_num = br.read_ue()?;
348 reord_list.abs_diff_or_num[reord_list.num_ops] = long_term_pic_num as u16;
349 }
350 reord_list.num_ops += 1;
351 }
352 validate!(reord_list.num_ops > 0);
353 }
354 }
355 if hdr.slice_type.is_b() {
356 hdr.ref_pic_list_reordering_l1 = br.read_bool()?;
357 let reord_list = &mut hdr.reordering_list_l1;
358 reord_list.num_ops = 0;
359 if hdr.ref_pic_list_reordering_l1 {
360 loop {
361 let reordering_of_pic_nums_idc = br.read_ue_lim(3)?;
362 if reordering_of_pic_nums_idc == 3 {
363 break;
364 }
365 validate!(reord_list.num_ops < MAX_FRAMES);
366 reord_list.reordering_of_pic_nums_idc[reord_list.num_ops] = reordering_of_pic_nums_idc as u8;
367 if reordering_of_pic_nums_idc != 2 {
368 let abs_diff_pic_num = br.read_ue()? + 1;
369 reord_list.abs_diff_or_num[reord_list.num_ops] = abs_diff_pic_num as u16;
370 } else {
371 let long_term_pic_num = br.read_ue()?;
372 reord_list.abs_diff_or_num[reord_list.num_ops] = long_term_pic_num as u16;
373 }
374 reord_list.num_ops += 1;
375 }
376 validate!(reord_list.num_ops > 0);
377 }
378 }
379 Ok(())
380}
381
382fn parse_pred_weight_table(hdr: &mut SliceHeader, br: &mut BitReader) -> DecoderResult<()> {
383 hdr.luma_log2_weight_denom = br.read_ue_lim(7)? as u8;
384 hdr.chroma_log2_weight_denom = br.read_ue_lim(7)? as u8;
385 for weight in hdr.weights_l0[..hdr.num_ref_idx_l0_active].iter_mut() {
386 weight.luma_weighted = br.read_bool()?;
387 if weight.luma_weighted {
388 let w = br.read_se()?;
389 validate!(w >= -128 && w <= 127);
390 weight.luma_weight = w as i8;
391 let offset = br.read_se()?;
392 validate!(offset >= -128 && offset <= 127);
393 weight.luma_offset = offset as i8;
394 }
395 weight.luma_shift = hdr.luma_log2_weight_denom;
396
397 weight.chroma_weighted = br.read_bool()?;
398 if weight.chroma_weighted {
399 for i in 0..2 {
400 let w = br.read_se()?;
401 validate!(w >= -128 && w <= 127);
402 weight.chroma_weight[i] = w as i8;
403 let offset = br.read_se()?;
404 validate!(offset >= -128 && offset <= 127);
405 weight.chroma_offset[i] = offset as i8;
406 }
407 }
408 weight.chroma_shift = hdr.chroma_log2_weight_denom;
409 }
410 for weight in hdr.weights_l1[..hdr.num_ref_idx_l1_active].iter_mut() {
411 weight.luma_weighted = br.read_bool()?;
412 if weight.luma_weighted {
413 let w = br.read_se()?;
414 validate!(w >= -128 && w <= 127);
415 weight.luma_weight = w as i8;
416 let offset = br.read_se()?;
417 validate!(offset >= -128 && offset <= 127);
418 weight.luma_offset = offset as i8;
419 }
420 weight.luma_shift = hdr.luma_log2_weight_denom;
421
422 weight.chroma_weighted = br.read_bool()?;
423 if weight.chroma_weighted {
424 for i in 0..2 {
425 let w = br.read_se()?;
426 validate!(w >= -128 && w <= 127);
427 weight.chroma_weight[i] = w as i8;
428 let offset = br.read_se()?;
429 validate!(offset >= -128 && offset <= 127);
430 weight.chroma_offset[i] = offset as i8;
431 }
432 }
433 weight.chroma_shift = hdr.chroma_log2_weight_denom;
434 }
435
436 Ok(())
437}