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