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