| 1 | use nihav_core::codecs::DecoderResult; |
| 2 | use nihav_core::frame::{FrameType, NAVideoBufferRef}; |
| 3 | use nihav_codec_support::codecs::MV; |
| 4 | use super::sets::SeqParameterSet; |
| 5 | use super::slice::*; |
| 6 | use super::types::*; |
| 7 | |
| 8 | #[derive(Clone)] |
| 9 | pub struct PictureInfo { |
| 10 | pub id: u16, |
| 11 | pub full_id: u32, |
| 12 | pub pic_type: FrameType, |
| 13 | pub buf: NAVideoBufferRef<u8>, |
| 14 | pub cur_mb: usize, |
| 15 | pub is_ref: bool, |
| 16 | pub long_term: Option<usize>, |
| 17 | |
| 18 | pub mv_info: FrameMV, //todo replace with refcounted index to a pool |
| 19 | } |
| 20 | |
| 21 | #[derive(Clone,Copy,Default, Debug)] |
| 22 | pub struct FrameMBInfo { |
| 23 | pub mb_type: CompactMBType, |
| 24 | pub ref_poc: [[u16; 2]; 4], |
| 25 | pub ref_idx: [[PicRef; 2]; 4], |
| 26 | pub mv: [[MV; 2]; 16], |
| 27 | } |
| 28 | |
| 29 | impl FrameMBInfo { |
| 30 | pub fn new() -> Self { Self::default() } |
| 31 | } |
| 32 | |
| 33 | #[derive(Clone)] |
| 34 | pub struct FrameMV { |
| 35 | pub mbs: Vec<FrameMBInfo>, |
| 36 | pub mb_stride: usize, |
| 37 | } |
| 38 | |
| 39 | impl FrameMV { |
| 40 | pub fn new(mb_w: usize, mb_h: usize) -> Self { |
| 41 | Self { |
| 42 | mbs: vec![FrameMBInfo::default(); mb_w * mb_h], |
| 43 | mb_stride: mb_w, |
| 44 | } |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | pub struct FrameRefs { |
| 49 | pub ref_pics: Vec<PictureInfo>, |
| 50 | pub ref_list0: Vec<Option<PictureInfo>>, |
| 51 | pub ref_list1: Vec<Option<PictureInfo>>, |
| 52 | pub long_term: Vec<Option<PictureInfo>>, |
| 53 | |
| 54 | prev_poc_msb: u32, |
| 55 | prev_poc_lsb: u16, |
| 56 | prev_ref_poc_lsb: u16, |
| 57 | prev_frame_num: u16, |
| 58 | frame_num_offset: u32, |
| 59 | } |
| 60 | |
| 61 | impl FrameRefs { |
| 62 | pub fn new() -> Self { |
| 63 | Self { |
| 64 | ref_pics: Vec::with_capacity(16), |
| 65 | ref_list0: Vec::with_capacity(3), |
| 66 | ref_list1: Vec::with_capacity(3), |
| 67 | long_term: Vec::new(), |
| 68 | |
| 69 | prev_poc_msb: 0, |
| 70 | prev_poc_lsb: 0, |
| 71 | prev_ref_poc_lsb: 0, |
| 72 | prev_frame_num: 0, |
| 73 | frame_num_offset: 0, |
| 74 | } |
| 75 | } |
| 76 | pub fn calc_picture_num(&mut self, slice_hdr: &SliceHeader, is_idr: bool, ref_id: u8, sps: &SeqParameterSet) -> u32 { |
| 77 | match sps.pic_order_cnt_type { |
| 78 | 0 => { |
| 79 | if is_idr { |
| 80 | //self.prev_poc_msb = 0; |
| 81 | self.prev_poc_lsb = 0; |
| 82 | } else { |
| 83 | self.prev_poc_lsb = self.prev_ref_poc_lsb; |
| 84 | } |
| 85 | let max_poc_lsb = 1 << sps.log2_max_pic_order_cnt_lsb; |
| 86 | let half_max_poc_lsb = 1 << (sps.log2_max_pic_order_cnt_lsb - 1); |
| 87 | let cur_lsb = slice_hdr.pic_order_cnt_lsb; |
| 88 | let poc_msb = if cur_lsb < self.prev_poc_lsb && (self.prev_poc_lsb - cur_lsb >= half_max_poc_lsb) { |
| 89 | self.prev_poc_msb + max_poc_lsb |
| 90 | } else if cur_lsb > self.prev_poc_lsb && (cur_lsb - self.prev_poc_lsb > half_max_poc_lsb) { |
| 91 | self.prev_poc_msb.wrapping_sub(max_poc_lsb) |
| 92 | } else { |
| 93 | self.prev_poc_msb |
| 94 | }; |
| 95 | let poc = poc_msb + u32::from(cur_lsb); |
| 96 | if ref_id != 0 { |
| 97 | self.prev_ref_poc_lsb = slice_hdr.pic_order_cnt_lsb; |
| 98 | self.prev_poc_msb = poc_msb; |
| 99 | } |
| 100 | poc |
| 101 | }, |
| 102 | 1 => { |
| 103 | let off = if self.prev_frame_num > slice_hdr.frame_num { |
| 104 | self.frame_num_offset + (1 << sps.log2_max_frame_num) |
| 105 | } else { |
| 106 | self.frame_num_offset |
| 107 | }; |
| 108 | let mut anum = if sps.num_ref_frames_in_pic_order_cnt_cycle != 0 { |
| 109 | (off as i32) + i32::from(slice_hdr.frame_num) |
| 110 | } else { |
| 111 | 0 |
| 112 | }; |
| 113 | if ref_id == 0 && anum > 0 { |
| 114 | anum -= 1; |
| 115 | } |
| 116 | let (poc_cycle_cnt, fno_in_poc_cycle) = if anum > 0 { |
| 117 | let nrf = sps.num_ref_frames_in_pic_order_cnt_cycle as i32; |
| 118 | ((anum - 1) / nrf, (anum - 1) % nrf) |
| 119 | } else { |
| 120 | (0, 0) |
| 121 | }; |
| 122 | let mut expected_delta = 0; |
| 123 | for &offset in sps.offset_for_ref_frame[..sps.num_ref_frames_in_pic_order_cnt_cycle].iter() { |
| 124 | expected_delta += offset; |
| 125 | } |
| 126 | let mut expected_poc = if anum > 0 { |
| 127 | let mut sum = poc_cycle_cnt * expected_delta; |
| 128 | for &offset in sps.offset_for_ref_frame[..=fno_in_poc_cycle as usize].iter() { |
| 129 | sum += offset; |
| 130 | } |
| 131 | sum |
| 132 | } else { |
| 133 | 0 |
| 134 | }; |
| 135 | if ref_id == 0 { |
| 136 | expected_poc += sps.offset_for_non_ref_pic; |
| 137 | } |
| 138 | let (top_id, _bottom_id) = if !slice_hdr.field_pic { |
| 139 | let top_id = expected_poc + slice_hdr.delta_pic_order_cnt[0]; |
| 140 | let bot_id = top_id + sps.offset_for_top_to_bottom_field + slice_hdr.delta_pic_order_cnt[1]; |
| 141 | (top_id, bot_id) |
| 142 | } else if !slice_hdr.bottom_field { |
| 143 | (expected_poc + slice_hdr.delta_pic_order_cnt[0], 0) |
| 144 | } else { |
| 145 | (0, sps.offset_for_top_to_bottom_field + slice_hdr.delta_pic_order_cnt[1]) |
| 146 | }; |
| 147 | self.prev_frame_num = slice_hdr.frame_num; |
| 148 | self.frame_num_offset = off; |
| 149 | top_id as u32 |
| 150 | }, |
| 151 | _ => { |
| 152 | if slice_hdr.frame_num < self.prev_frame_num { |
| 153 | self.frame_num_offset += 1 << sps.log2_max_frame_num; |
| 154 | } |
| 155 | self.prev_frame_num = slice_hdr.frame_num; |
| 156 | self.frame_num_offset + u32::from(slice_hdr.frame_num) |
| 157 | }, |
| 158 | } |
| 159 | } |
| 160 | pub fn apply_adaptive_marking(&mut self, marking: &AdaptiveMarking, cur_id: u16, max_id: u16) -> DecoderResult<()> { |
| 161 | let all_ref_pics = self.ref_pics.clone(); |
| 162 | |
| 163 | for (&op, (&arg1, &arg2)) in marking.memory_management_control_op.iter().zip(marking.operation_arg.iter().zip(marking.operation_arg2.iter())).take(marking.num_ops) { |
| 164 | match op { |
| 165 | 1 => { |
| 166 | let src_id = cur_id.wrapping_sub(arg1) & (max_id - 1); |
| 167 | let mut found = false; |
| 168 | let mut idx = 0; |
| 169 | for (i, pic) in self.ref_pics.iter().enumerate() { |
| 170 | if pic.id == src_id { |
| 171 | found = true; |
| 172 | idx = i; |
| 173 | break; |
| 174 | } |
| 175 | } |
| 176 | if found { |
| 177 | self.ref_pics.remove(idx); |
| 178 | } |
| 179 | }, |
| 180 | 2 => { // mark long term picture as unused |
| 181 | let idx = arg1 as usize; |
| 182 | if idx < self.long_term.len() { |
| 183 | self.long_term[idx] = None; |
| 184 | } |
| 185 | }, |
| 186 | 3 => { |
| 187 | let src_id = cur_id.wrapping_sub(arg1) & (max_id - 1); |
| 188 | |
| 189 | let didx = arg2 as usize; |
| 190 | for pic in all_ref_pics.iter() { |
| 191 | if pic.id == src_id { |
| 192 | if didx < self.long_term.len() { |
| 193 | self.long_term[didx] = Some(pic.clone()); |
| 194 | } |
| 195 | break; |
| 196 | } |
| 197 | } |
| 198 | }, |
| 199 | 4 => { |
| 200 | self.long_term.resize(arg1 as usize, None); |
| 201 | }, |
| 202 | 5 => { |
| 203 | self.ref_pics.clear(); |
| 204 | self.long_term.clear(); |
| 205 | }, |
| 206 | 6 => { |
| 207 | // assign an long term index to current pic - done elsewhere |
| 208 | }, |
| 209 | _ => {}, |
| 210 | }; |
| 211 | } |
| 212 | Ok(()) |
| 213 | } |
| 214 | pub fn clear_refs(&mut self) { |
| 215 | self.ref_pics.clear(); |
| 216 | self.long_term.clear(); |
| 217 | } |
| 218 | #[allow(clippy::cognitive_complexity)] |
| 219 | pub fn select_refs(&mut self, sps: &SeqParameterSet, slice_hdr: &SliceHeader, cur_id: u32) { |
| 220 | self.ref_list0.clear(); |
| 221 | self.ref_list1.clear(); |
| 222 | let pic_num_mask = if sps.log2_max_frame_num == 16 { |
| 223 | 0xFFFF |
| 224 | } else { |
| 225 | (1 << sps.log2_max_frame_num) - 1 |
| 226 | }; |
| 227 | if !slice_hdr.slice_type.is_intra() { |
| 228 | let has_reordering = slice_hdr.ref_pic_list_reordering_l0; |
| 229 | if !has_reordering { |
| 230 | let num_ref = slice_hdr.num_ref_idx_l0_active; |
| 231 | if slice_hdr.slice_type.is_p() { |
| 232 | if !self.ref_pics.is_empty() { |
| 233 | for pic in self.ref_pics.iter().rev().take(num_ref) { |
| 234 | self.ref_list0.push(Some(pic.clone())); |
| 235 | } |
| 236 | } |
| 237 | } else { |
| 238 | let mut pivot = 0; |
| 239 | for (i, pic) in self.ref_pics.iter().enumerate() { |
| 240 | pivot = i; |
| 241 | if pic.full_id > cur_id { |
| 242 | break; |
| 243 | } |
| 244 | } |
| 245 | for pic in self.ref_pics[..pivot].iter().rev() { |
| 246 | if self.ref_list0.len() >= num_ref { |
| 247 | break; |
| 248 | } |
| 249 | self.ref_list0.push(Some(pic.clone())); |
| 250 | } |
| 251 | for pic in self.ref_pics.iter().skip(pivot) { |
| 252 | if self.ref_list0.len() >= num_ref { |
| 253 | break; |
| 254 | } |
| 255 | self.ref_list0.push(Some(pic.clone())); |
| 256 | } |
| 257 | } |
| 258 | if !self.long_term.is_empty() && self.ref_list0.len() < num_ref { |
| 259 | let copy_size = num_ref - self.ref_list0.len(); |
| 260 | for ltpic in self.long_term.iter().take(copy_size) { |
| 261 | self.ref_list0.push(ltpic.clone()); |
| 262 | } |
| 263 | } |
| 264 | } else { |
| 265 | form_ref_list(&mut self.ref_list0, |
| 266 | &self.ref_pics, &self.long_term, |
| 267 | &slice_hdr.reordering_list_l0, |
| 268 | slice_hdr.frame_num, pic_num_mask); |
| 269 | } |
| 270 | if slice_hdr.slice_type.is_b() { |
| 271 | let has_reordering = slice_hdr.ref_pic_list_reordering_l1; |
| 272 | if !has_reordering { |
| 273 | let num_ref = slice_hdr.num_ref_idx_l1_active; |
| 274 | let mut pivot = 0; |
| 275 | for (i, pic) in self.ref_pics.iter().enumerate() { |
| 276 | pivot = i; |
| 277 | if pic.full_id > cur_id { |
| 278 | break; |
| 279 | } |
| 280 | } |
| 281 | for pic in self.ref_pics.iter().skip(pivot) { |
| 282 | if self.ref_list1.len() >= num_ref { |
| 283 | break; |
| 284 | } |
| 285 | self.ref_list1.push(Some(pic.clone())); |
| 286 | } |
| 287 | for pic in self.ref_pics[..pivot].iter().rev() { |
| 288 | if self.ref_list1.len() >= num_ref { |
| 289 | break; |
| 290 | } |
| 291 | self.ref_list1.push(Some(pic.clone())); |
| 292 | } |
| 293 | if !self.long_term.is_empty() && self.ref_list1.len() < num_ref { |
| 294 | let copy_size = num_ref - self.ref_list1.len(); |
| 295 | for ltpic in self.long_term.iter().take(copy_size) { |
| 296 | self.ref_list1.push(ltpic.clone()); |
| 297 | } |
| 298 | } |
| 299 | if self.ref_list1.len() > 1 && self.ref_list0.len() == self.ref_list1.len() { |
| 300 | let mut equal = true; |
| 301 | for (pic1, pic2) in self.ref_list0.iter().zip(self.ref_list1.iter()) { |
| 302 | match (pic1, pic2) { |
| 303 | (Some(p1), Some(p2)) => { |
| 304 | if p1.full_id != p2.full_id { |
| 305 | equal = false; |
| 306 | break; |
| 307 | } |
| 308 | }, |
| 309 | (None, None) => {}, |
| 310 | _ => { |
| 311 | equal = false; |
| 312 | break; |
| 313 | }, |
| 314 | }; |
| 315 | } |
| 316 | if equal { |
| 317 | self.ref_list1.swap(0, 1); |
| 318 | } |
| 319 | } |
| 320 | } else { |
| 321 | form_ref_list(&mut self.ref_list1, |
| 322 | &self.ref_pics, &self.long_term, |
| 323 | &slice_hdr.reordering_list_l1, |
| 324 | slice_hdr.frame_num, pic_num_mask); |
| 325 | } |
| 326 | } |
| 327 | } |
| 328 | } |
| 329 | pub fn add_short_term(&mut self, cpic: PictureInfo, num_ref_frames: usize) { |
| 330 | if !self.ref_pics.is_empty() && self.ref_pics.len() >= num_ref_frames { |
| 331 | self.ref_pics.remove(0); |
| 332 | } |
| 333 | if self.ref_pics.is_empty() || self.ref_pics.last().unwrap().full_id < cpic.full_id { |
| 334 | self.ref_pics.push(cpic); |
| 335 | } else { |
| 336 | let mut idx = 0; |
| 337 | for (i, pic) in self.ref_pics.iter().enumerate() { |
| 338 | if pic.full_id < cpic.full_id { |
| 339 | idx = i; |
| 340 | } else { |
| 341 | break; |
| 342 | } |
| 343 | } |
| 344 | self.ref_pics.insert(idx + 1, cpic); |
| 345 | } |
| 346 | } |
| 347 | pub fn add_long_term(&mut self, lt_idx: usize, cpic: PictureInfo) { |
| 348 | if lt_idx < self.long_term.len() { |
| 349 | self.long_term[lt_idx] = Some(cpic); |
| 350 | } |
| 351 | } |
| 352 | pub fn select_ref_pic(&self, list_id: u8, ref_id: usize) -> Option<NAVideoBufferRef<u8>> { |
| 353 | let ref_list = if list_id == 0 { &self.ref_list0 } else { &self.ref_list1 }; |
| 354 | if ref_list.len() > ref_id { |
| 355 | if let Some(ref pic) = ref_list[ref_id] { |
| 356 | Some(pic.buf.clone()) |
| 357 | } else { |
| 358 | None |
| 359 | } |
| 360 | } else { |
| 361 | None |
| 362 | } |
| 363 | } |
| 364 | pub fn get_colocated_info(&self, mb_x: usize, mb_y: usize) -> (FrameMBInfo, u16, bool) { |
| 365 | if let Some(ref ref_pic) = &self.ref_list1[0] { |
| 366 | let mv_info = &ref_pic.mv_info; |
| 367 | let mb = mv_info.mbs[mb_x + mb_y * mv_info.mb_stride]; |
| 368 | (mb, ref_pic.full_id as u16, ref_pic.long_term.is_some()) |
| 369 | } else { |
| 370 | (FrameMBInfo::default(), 0, false) |
| 371 | } |
| 372 | } |
| 373 | pub fn map_ref0(&self, ref0_id: u16) -> (PicRef, bool) { |
| 374 | let mut r0_idx = 0; |
| 375 | let mut long = false; |
| 376 | for (i, rpic0) in self.ref_list0.iter().enumerate() { |
| 377 | if let Some(ref pic) = rpic0 { |
| 378 | if (pic.full_id as u16) == ref0_id { |
| 379 | r0_idx = i as u8; |
| 380 | long = pic.long_term.is_some(); |
| 381 | break; |
| 382 | } |
| 383 | } |
| 384 | } |
| 385 | (PicRef::new(r0_idx), long) |
| 386 | } |
| 387 | pub fn map_refs(&self, ref_idx: [PicRef; 2]) -> [u16; 2] { |
| 388 | let r0 = ref_idx[0].index(); |
| 389 | let r1 = ref_idx[1].index(); |
| 390 | let ref0 = if r0 < self.ref_list0.len() { |
| 391 | if let Some(ref pic) = self.ref_list0[r0] { |
| 392 | pic.full_id as u16 |
| 393 | } else { |
| 394 | MISSING_POC |
| 395 | } |
| 396 | } else { |
| 397 | MISSING_POC |
| 398 | }; |
| 399 | let ref1 = if r1 < self.ref_list1.len() { |
| 400 | if let Some(ref pic) = self.ref_list1[r1] { |
| 401 | pic.full_id as u16 |
| 402 | } else { |
| 403 | MISSING_POC |
| 404 | } |
| 405 | } else { |
| 406 | MISSING_POC |
| 407 | }; |
| 408 | [ref0, ref1] |
| 409 | } |
| 410 | pub fn cmp_refs(&self, ref1: [PicRef; 2], ref2: [PicRef; 2]) -> bool { |
| 411 | if ref1 != ref2 { |
| 412 | self.cmp_ref(ref1[0], ref2[0], 0) && self.cmp_ref(ref1[1], ref2[1], 1) |
| 413 | } else { |
| 414 | true |
| 415 | } |
| 416 | } |
| 417 | fn cmp_ref(&self, ref1: PicRef, ref2: PicRef, list: u8) -> bool { |
| 418 | if ref1 == ref2 { |
| 419 | true |
| 420 | } else { |
| 421 | let idx0 = ref1.index(); |
| 422 | let idx1 = ref2.index(); |
| 423 | if idx0 == idx1 { |
| 424 | return true; |
| 425 | } |
| 426 | let src = if list == 0 { &self.ref_list0 } else { &self.ref_list1 }; |
| 427 | if idx0 >= src.len() || idx1 >= src.len() { |
| 428 | //panic!("wrong refs"); |
| 429 | return false; |
| 430 | } |
| 431 | if let (Some(ref pic0), Some(ref pic1)) = (&src[idx0], &src[idx1]) { |
| 432 | pic0.full_id == pic1.full_id |
| 433 | } else { |
| 434 | //panic!("missing pics"); |
| 435 | false |
| 436 | } |
| 437 | } |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | fn form_ref_list(ref_list: &mut Vec<Option<PictureInfo>>, ref_pics: &[PictureInfo], long_term: &[Option<PictureInfo>], reord_info: &ReorderingInfo, cur_id: u16, pic_num_mask: u16) { |
| 442 | let mut ref_pic_id = cur_id; |
| 443 | for (&op, &num) in reord_info.reordering_of_pic_nums_idc.iter().zip(reord_info.abs_diff_or_num.iter()).take(reord_info.num_ops) { |
| 444 | if op < 2 { |
| 445 | if op == 0 { |
| 446 | ref_pic_id = ref_pic_id.wrapping_sub(num) & pic_num_mask; |
| 447 | } else { |
| 448 | ref_pic_id = ref_pic_id.wrapping_add(num) & pic_num_mask; |
| 449 | } |
| 450 | let mut found = false; |
| 451 | for pic in ref_pics.iter() { |
| 452 | if pic.id == ref_pic_id { |
| 453 | ref_list.push(Some(pic.clone())); |
| 454 | found = true; |
| 455 | break; |
| 456 | } |
| 457 | } |
| 458 | if !found { |
| 459 | ref_list.push(None); |
| 460 | } |
| 461 | } else { |
| 462 | let idx = num as usize; |
| 463 | if idx < long_term.len() { |
| 464 | ref_list.push(long_term[idx].clone()); |
| 465 | } else { |
| 466 | ref_list.push(None); |
| 467 | } |
| 468 | } |
| 469 | } |
| 470 | } |