From: Kostya Shishkov Date: Wed, 14 Jun 2023 16:41:31 +0000 (+0200) Subject: h264: split current slice references into a separate structure X-Git-Url: https://git.nihav.org/?p=nihav.git;a=commitdiff_plain;h=56a17e69f584e41c2bfd2cb808b812be6b8796e5 h264: split current slice references into a separate structure This will become useful when decoding a whole frame at once. --- diff --git a/nihav-itu/src/codecs/h264/decoder_st.rs b/nihav-itu/src/codecs/h264/decoder_st.rs index d906e59..3cffc6a 100644 --- a/nihav-itu/src/codecs/h264/decoder_st.rs +++ b/nihav-itu/src/codecs/h264/decoder_st.rs @@ -272,7 +272,7 @@ println!("PAFF?"); Ok(()) } - fn pred_mv(sstate: &mut SliceState, frame_refs: &FrameRefs, mb_info: &mut CurrentMBInfo, cur_id: u16, temporal_mv: bool, direct_8x8: bool) { + fn pred_mv(sstate: &mut SliceState, frame_refs: &SliceRefs, mb_info: &mut CurrentMBInfo, cur_id: u16, temporal_mv: bool, direct_8x8: bool) { let mb_type = mb_info.mb_type; if !mb_type.is_4x4() { let (pw, ph) = mb_type.size(); @@ -399,7 +399,7 @@ println!("PAFF?"); self.sstate.reset_mb_mv(); } if !mb_info.mb_type.is_intra() { - Self::pred_mv(&mut self.sstate, &self.frame_refs, mb_info, self.cur_id, self.temporal_mv, self.sps[self.cur_sps].direct_8x8_inference); + Self::pred_mv(&mut self.sstate, &self.frame_refs.cur_refs, mb_info, self.cur_id, self.temporal_mv, self.sps[self.cur_sps].direct_8x8_inference); } if !pps.constrained_intra_pred && mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 { self.sstate.fill_ipred(IntraPredMode::DC); @@ -417,7 +417,7 @@ println!("PAFF?"); } else { 0 }; - recon_mb(&mut frm, slice_hdr, mb_info, &mut self.sstate, &self.frame_refs, &mut self.mc_dsp, weight_mode); + recon_mb(&mut frm, slice_hdr, mb_info, &mut self.sstate, &self.frame_refs.cur_refs, &mut self.mc_dsp, weight_mode); } else { for (dline, src) in frm.data[frm.offset[0] + xpos + ypos * frm.stride[0]..].chunks_mut(frm.stride[0]).take(16).zip(self.ipcm_buf.chunks(16)) { dline[..16].copy_from_slice(src); @@ -451,13 +451,13 @@ _ => {}, mb.mv[blk4] = self.sstate.get_cur_blk4(blk4).mv; } for blk8 in 0..4 { - mb.ref_poc[blk8] = self.frame_refs.map_refs(self.sstate.get_cur_blk8(blk8).ref_idx); + mb.ref_poc[blk8] = self.frame_refs.cur_refs.map_refs(self.sstate.get_cur_blk8(blk8).ref_idx); mb.ref_idx[blk8] = self.sstate.get_cur_blk8(blk8).ref_idx; } mv_info.mbs[mb_pos] = mb; } if !self.deblock_skip && self.deblock_mode != 1 { - self.sstate.fill_deblock(&self.frame_refs, self.deblock_mode, self.is_s); + self.sstate.fill_deblock(&self.frame_refs.cur_refs, self.deblock_mode, self.is_s); if let Some(ref mut pic) = self.cur_pic { let mut frm = NASimpleVideoFrame::from_video_buf(&mut pic.buf).unwrap(); loop_filter_mb(&mut frm, &self.sstate, self.lf_alpha, self.lf_beta); diff --git a/nihav-itu/src/codecs/h264/mb_recon.rs b/nihav-itu/src/codecs/h264/mb_recon.rs index e17095b..eb32792 100644 --- a/nihav-itu/src/codecs/h264/mb_recon.rs +++ b/nihav-itu/src/codecs/h264/mb_recon.rs @@ -2,7 +2,7 @@ use nihav_core::frame::*; use nihav_codec_support::codecs::MV; use super::{CurrentMBInfo, I4X4_SCAN}; use super::dsp::*; -use super::pic_ref::FrameRefs; +use super::pic_ref::SliceRefs; use super::slice::{SliceHeader, WeightInfo, DEF_WEIGHT_INFO}; use super::types::*; @@ -368,7 +368,7 @@ fn do_b_mc(frm: &mut NASimpleVideoFrame, mode: BMode, xpos: usize, ypos: usi } } -fn get_weights(slice_hdr: &SliceHeader, frame_refs: &FrameRefs, mode: BMode, weight_mode: u8, ref_l0: PicRef, ref_l1: PicRef) -> (WeightInfo, WeightInfo) { +fn get_weights(slice_hdr: &SliceHeader, frame_refs: &SliceRefs, mode: BMode, weight_mode: u8, ref_l0: PicRef, ref_l1: PicRef) -> (WeightInfo, WeightInfo) { let idx_l0 = ref_l0.index(); let idx_l1 = ref_l1.index(); if mode != BMode::Bi || weight_mode != 2 { @@ -418,7 +418,7 @@ fn get_weights(slice_hdr: &SliceHeader, frame_refs: &FrameRefs, mode: BMode, wei } } -pub fn recon_mb(frm: &mut NASimpleVideoFrame, slice_hdr: &SliceHeader, mb_info: &CurrentMBInfo, sstate: &mut SliceState, frame_refs: &FrameRefs, mc_dsp: &mut H264MC, weight_mode: u8) { +pub fn recon_mb(frm: &mut NASimpleVideoFrame, slice_hdr: &SliceHeader, mb_info: &CurrentMBInfo, sstate: &mut SliceState, frame_refs: &SliceRefs, mc_dsp: &mut H264MC, weight_mode: u8) { let xpos = sstate.mb_x * 16; let ypos = sstate.mb_y * 16; diff --git a/nihav-itu/src/codecs/h264/pic_ref.rs b/nihav-itu/src/codecs/h264/pic_ref.rs index cafcc56..bf838be 100644 --- a/nihav-itu/src/codecs/h264/pic_ref.rs +++ b/nihav-itu/src/codecs/h264/pic_ref.rs @@ -45,12 +45,103 @@ impl FrameMV { } } -pub struct FrameRefs { - pub ref_pics: Vec, +#[derive(Clone)] +pub struct SliceRefs { pub ref_list0: Vec>, pub ref_list1: Vec>, + pub cur_id: u32, +} + +impl SliceRefs { + pub fn select_ref_pic(&self, list_id: u8, ref_id: usize) -> Option> { + let ref_list = if list_id == 0 { &self.ref_list0 } else { &self.ref_list1 }; + if ref_list.len() > ref_id { + ref_list[ref_id].as_ref().map(|pic| pic.buf.clone()) + } else { + None + } + } + pub fn get_colocated_info(&self, mb_x: usize, mb_y: usize) -> (FrameMBInfo, u16, bool) { + if let Some(ref ref_pic) = &self.ref_list1[0] { + let mv_info = &ref_pic.mv_info; + let mb = mv_info.mbs[mb_x + mb_y * mv_info.mb_stride]; + (mb, ref_pic.full_id as u16, ref_pic.long_term.is_some()) + } else { + (FrameMBInfo::default(), 0, false) + } + } + pub fn map_ref0(&self, ref0_id: u16) -> (PicRef, bool) { + let mut r0_idx = 0; + let mut long = false; + for (i, rpic0) in self.ref_list0.iter().enumerate() { + if let Some(ref pic) = rpic0 { + if (pic.full_id as u16) == ref0_id { + r0_idx = i as u8; + long = pic.long_term.is_some(); + break; + } + } + } + (PicRef::new(r0_idx), long) + } + pub fn map_refs(&self, ref_idx: [PicRef; 2]) -> [u16; 2] { + let r0 = ref_idx[0].index(); + let r1 = ref_idx[1].index(); + let ref0 = if r0 < self.ref_list0.len() { + if let Some(ref pic) = self.ref_list0[r0] { + pic.full_id as u16 + } else { + MISSING_POC + } + } else { + MISSING_POC + }; + let ref1 = if r1 < self.ref_list1.len() { + if let Some(ref pic) = self.ref_list1[r1] { + pic.full_id as u16 + } else { + MISSING_POC + } + } else { + MISSING_POC + }; + [ref0, ref1] + } + pub fn cmp_refs(&self, ref1: [PicRef; 2], ref2: [PicRef; 2]) -> bool { + if ref1 != ref2 { + self.cmp_ref(ref1[0], ref2[0], 0) && self.cmp_ref(ref1[1], ref2[1], 1) + } else { + true + } + } + fn cmp_ref(&self, ref1: PicRef, ref2: PicRef, list: u8) -> bool { + if ref1 == ref2 { + true + } else { + let idx0 = ref1.index(); + let idx1 = ref2.index(); + if idx0 == idx1 { + return true; + } + let src = if list == 0 { &self.ref_list0 } else { &self.ref_list1 }; + if idx0 >= src.len() || idx1 >= src.len() { +//panic!("wrong refs"); + return false; + } + if let (Some(ref pic0), Some(ref pic1)) = (&src[idx0], &src[idx1]) { + pic0.full_id == pic1.full_id + } else { +//panic!("missing pics"); + false + } + } + } +} + +pub struct FrameRefs { + pub ref_pics: Vec, + pub cur_refs: SliceRefs, pub long_term: Vec>, - pub cur_id: u32, prev_poc_msb: u32, prev_poc_lsb: u16, @@ -64,10 +155,12 @@ impl FrameRefs { pub fn new() -> Self { Self { ref_pics: Vec::with_capacity(16), - ref_list0: Vec::with_capacity(3), - ref_list1: Vec::with_capacity(3), + cur_refs: SliceRefs { + ref_list0: Vec::with_capacity(3), + ref_list1: Vec::with_capacity(3), + cur_id: 0, + }, long_term: Vec::new(), - cur_id: 0, prev_poc_msb: 0, prev_poc_lsb: 0, @@ -222,14 +315,15 @@ impl FrameRefs { } #[allow(clippy::cognitive_complexity)] pub fn select_refs(&mut self, sps: &SeqParameterSet, slice_hdr: &SliceHeader, cur_id: u32) { - self.cur_id = cur_id; - self.ref_list0.clear(); - self.ref_list1.clear(); + self.cur_refs.cur_id = cur_id; + self.cur_refs.ref_list0.clear(); + self.cur_refs.ref_list1.clear(); let pic_num_mask = if sps.log2_max_frame_num == 16 { 0xFFFF } else { (1 << sps.log2_max_frame_num) - 1 }; + if !slice_hdr.slice_type.is_intra() { let has_reordering = slice_hdr.ref_pic_list_reordering_l0; if !has_reordering { @@ -237,7 +331,7 @@ impl FrameRefs { if slice_hdr.slice_type.is_p() { if !self.ref_pics.is_empty() { for pic in self.ref_pics.iter().rev().take(num_ref) { - self.ref_list0.push(Some(pic.clone())); + self.cur_refs.ref_list0.push(Some(pic.clone())); } } } else { @@ -249,26 +343,26 @@ impl FrameRefs { } } for pic in self.ref_pics[..pivot].iter().rev() { - if self.ref_list0.len() >= num_ref { + if self.cur_refs.ref_list0.len() >= num_ref { break; } - self.ref_list0.push(Some(pic.clone())); + self.cur_refs.ref_list0.push(Some(pic.clone())); } for pic in self.ref_pics.iter().skip(pivot) { - if self.ref_list0.len() >= num_ref { + if self.cur_refs.ref_list0.len() >= num_ref { break; } - self.ref_list0.push(Some(pic.clone())); + self.cur_refs.ref_list0.push(Some(pic.clone())); } } - if !self.long_term.is_empty() && self.ref_list0.len() < num_ref { - let copy_size = num_ref - self.ref_list0.len(); + if !self.long_term.is_empty() && self.cur_refs.ref_list0.len() < num_ref { + let copy_size = num_ref - self.cur_refs.ref_list0.len(); for ltpic in self.long_term.iter().take(copy_size) { - self.ref_list0.push(ltpic.clone()); + self.cur_refs.ref_list0.push(ltpic.clone()); } } } else { - form_ref_list(&mut self.ref_list0, + form_ref_list(&mut self.cur_refs.ref_list0, &self.ref_pics, &self.long_term, &slice_hdr.reordering_list_l0, slice_hdr.frame_num, pic_num_mask); @@ -285,26 +379,26 @@ impl FrameRefs { } } for pic in self.ref_pics.iter().skip(pivot) { - if self.ref_list1.len() >= num_ref { + if self.cur_refs.ref_list1.len() >= num_ref { break; } - self.ref_list1.push(Some(pic.clone())); + self.cur_refs.ref_list1.push(Some(pic.clone())); } for pic in self.ref_pics[..pivot].iter().rev() { - if self.ref_list1.len() >= num_ref { + if self.cur_refs.ref_list1.len() >= num_ref { break; } - self.ref_list1.push(Some(pic.clone())); + self.cur_refs.ref_list1.push(Some(pic.clone())); } - if !self.long_term.is_empty() && self.ref_list1.len() < num_ref { - let copy_size = num_ref - self.ref_list1.len(); + if !self.long_term.is_empty() && self.cur_refs.ref_list1.len() < num_ref { + let copy_size = num_ref - self.cur_refs.ref_list1.len(); for ltpic in self.long_term.iter().take(copy_size) { - self.ref_list1.push(ltpic.clone()); + self.cur_refs.ref_list1.push(ltpic.clone()); } } - if self.ref_list1.len() > 1 && self.ref_list0.len() == self.ref_list1.len() { + if self.cur_refs.ref_list1.len() > 1 && self.cur_refs.ref_list0.len() == self.cur_refs.ref_list1.len() { let mut equal = true; - for (pic1, pic2) in self.ref_list0.iter().zip(self.ref_list1.iter()) { + for (pic1, pic2) in self.cur_refs.ref_list0.iter().zip(self.cur_refs.ref_list1.iter()) { match (pic1, pic2) { (Some(p1), Some(p2)) => { if p1.full_id != p2.full_id { @@ -320,11 +414,11 @@ impl FrameRefs { }; } if equal { - self.ref_list1.swap(0, 1); + self.cur_refs.ref_list1.swap(0, 1); } } } else { - form_ref_list(&mut self.ref_list1, + form_ref_list(&mut self.cur_refs.ref_list1, &self.ref_pics, &self.long_term, &slice_hdr.reordering_list_l1, slice_hdr.frame_num, pic_num_mask); @@ -368,89 +462,6 @@ impl FrameRefs { self.long_term[lt_idx] = Some(cpic); } } - pub fn select_ref_pic(&self, list_id: u8, ref_id: usize) -> Option> { - let ref_list = if list_id == 0 { &self.ref_list0 } else { &self.ref_list1 }; - if ref_list.len() > ref_id { - ref_list[ref_id].as_ref().map(|pic| pic.buf.clone()) - } else { - None - } - } - pub fn get_colocated_info(&self, mb_x: usize, mb_y: usize) -> (FrameMBInfo, u16, bool) { - if let Some(ref ref_pic) = &self.ref_list1[0] { - let mv_info = &ref_pic.mv_info; - let mb = mv_info.mbs[mb_x + mb_y * mv_info.mb_stride]; - (mb, ref_pic.full_id as u16, ref_pic.long_term.is_some()) - } else { - (FrameMBInfo::default(), 0, false) - } - } - pub fn map_ref0(&self, ref0_id: u16) -> (PicRef, bool) { - let mut r0_idx = 0; - let mut long = false; - for (i, rpic0) in self.ref_list0.iter().enumerate() { - if let Some(ref pic) = rpic0 { - if (pic.full_id as u16) == ref0_id { - r0_idx = i as u8; - long = pic.long_term.is_some(); - break; - } - } - } - (PicRef::new(r0_idx), long) - } - pub fn map_refs(&self, ref_idx: [PicRef; 2]) -> [u16; 2] { - let r0 = ref_idx[0].index(); - let r1 = ref_idx[1].index(); - let ref0 = if r0 < self.ref_list0.len() { - if let Some(ref pic) = self.ref_list0[r0] { - pic.full_id as u16 - } else { - MISSING_POC - } - } else { - MISSING_POC - }; - let ref1 = if r1 < self.ref_list1.len() { - if let Some(ref pic) = self.ref_list1[r1] { - pic.full_id as u16 - } else { - MISSING_POC - } - } else { - MISSING_POC - }; - [ref0, ref1] - } - pub fn cmp_refs(&self, ref1: [PicRef; 2], ref2: [PicRef; 2]) -> bool { - if ref1 != ref2 { - self.cmp_ref(ref1[0], ref2[0], 0) && self.cmp_ref(ref1[1], ref2[1], 1) - } else { - true - } - } - fn cmp_ref(&self, ref1: PicRef, ref2: PicRef, list: u8) -> bool { - if ref1 == ref2 { - true - } else { - let idx0 = ref1.index(); - let idx1 = ref2.index(); - if idx0 == idx1 { - return true; - } - let src = if list == 0 { &self.ref_list0 } else { &self.ref_list1 }; - if idx0 >= src.len() || idx1 >= src.len() { -//panic!("wrong refs"); - return false; - } - if let (Some(ref pic0), Some(ref pic1)) = (&src[idx0], &src[idx1]) { - pic0.full_id == pic1.full_id - } else { -//panic!("missing pics"); - false - } - } - } } fn form_ref_list(ref_list: &mut Vec>, ref_pics: &[PictureInfo], long_term: &[Option], reord_info: &ReorderingInfo, cur_id: u16, pic_num_mask: u16) { diff --git a/nihav-itu/src/codecs/h264/types.rs b/nihav-itu/src/codecs/h264/types.rs index 319ebf5..9df866e 100644 --- a/nihav-itu/src/codecs/h264/types.rs +++ b/nihav-itu/src/codecs/h264/types.rs @@ -1,7 +1,7 @@ use nihav_core::frame::NASimpleVideoFrame; use nihav_codec_support::codecs::{MV, ZERO_MV}; use nihav_codec_support::data::GenericCache; -use super::FrameRefs; +use super::SliceRefs; use super::pic_ref::FrameMBInfo; #[repr(u8)] @@ -490,7 +490,7 @@ impl SliceState { } } } - pub fn fill_deblock(&mut self, frefs: &FrameRefs, deblock_mode: u8, is_s: bool) { + pub fn fill_deblock(&mut self, frefs: &SliceRefs, deblock_mode: u8, is_s: bool) { if deblock_mode == 1 { return; } @@ -744,7 +744,7 @@ impl SliceState { self.fill_mv (0, 0, 16, 16, 0, mv); self.fill_ref(0, 0, 16, 16, 0, ref_idx); } - pub fn predict_direct_mb(&mut self, frame_refs: &FrameRefs, temporal_mv: bool, direct_8x8: bool, cur_id: u16) { + pub fn predict_direct_mb(&mut self, frame_refs: &SliceRefs, temporal_mv: bool, direct_8x8: bool, cur_id: u16) { let (col_mb, r1_poc, r1_long) = frame_refs.get_colocated_info(self.mb_x, self.mb_y); if direct_8x8 { for blk4 in 0..16 { @@ -764,7 +764,7 @@ impl SliceState { } } } - pub fn predict_direct_sub(&mut self, frame_refs: &FrameRefs, temporal_mv: bool, direct8x8: bool, cur_id: u16, blk4: usize) { + pub fn predict_direct_sub(&mut self, frame_refs: &SliceRefs, temporal_mv: bool, direct8x8: bool, cur_id: u16, blk4: usize) { let src_blk = if !direct8x8 { blk4 } else { BLK4_TO_D8[blk4] }; let (mbi, r1_poc, r1_long) = frame_refs.get_colocated_info(self.mb_x, self.mb_y); let (mv0, ref0, mv1, ref1) = self.get_direct_mv(frame_refs, &mbi, r1_poc, r1_long, temporal_mv, cur_id, src_blk); @@ -772,7 +772,7 @@ impl SliceState { self.get_cur_blk8(blk4_to_blk8(blk4)).ref_idx = [ref0, ref1]; } #[allow(clippy::nonminimal_bool)] - pub fn get_direct_mv(&self, frame_refs: &FrameRefs, mbi: &FrameMBInfo, r1_poc: u16, r1_long: bool, temporal_mv: bool, cur_id: u16, blk4: usize) -> (MV, PicRef, MV, PicRef) { + pub fn get_direct_mv(&self, frame_refs: &SliceRefs, mbi: &FrameMBInfo, r1_poc: u16, r1_long: bool, temporal_mv: bool, cur_id: u16, blk4: usize) -> (MV, PicRef, MV, PicRef) { let blk8 = blk4_to_blk8(blk4); let (col_mv, r0_poc, col_idx) = if mbi.ref_poc[blk8] == [MISSING_POC; 2] { (ZERO_MV, MISSING_POC, MISSING_REF)