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