diff --git a/crates/av1/src/header.rs b/crates/av1/src/header.rs index 85133df8..524e6d01 100644 --- a/crates/av1/src/header.rs +++ b/crates/av1/src/header.rs @@ -429,6 +429,38 @@ pub struct FrameHeader { pub spatial_id: u32, } +/// mark_ref_frames( idLen ): invalidates reference slots whose frame id is too far from the current one. +fn mark_ref_frames(st: &mut HeaderState, cur: u32, id_len: u32) { + let diff_len = st.seq.delta_frame_id_length_minus_2 + 2; + for rs in st.refs.iter_mut() { + if cur > (1 << diff_len) { + if rs.frame_id > cur || rs.frame_id < cur - (1 << diff_len) { + rs.valid = false; + } + } else if rs.frame_id > cur && rs.frame_id < (1 << id_len) + cur - (1 << diff_len) { + rs.valid = false; + } + } +} + +/// Skips buffer_removal_time for every operating point that includes this layer. +fn skip_buffer_removal_times(r: &mut BitReader, seq: &SequenceHeader, temporal_id: u32, spatial_id: u32) -> Result<()> { + if !(seq.decoder_model_info_present && r.flag()?) { + return Ok(()); + } + for op in 0..=seq.operating_points_cnt_minus_1 { + if seq.decoder_model_present_for_this_op[op] { + let idc = seq.operating_point_idc[op]; + let in_t = (idc >> temporal_id) & 1; + let in_s = (idc >> (spatial_id + 8)) & 1; + if idc == 0 || (in_t == 1 && in_s == 1) { + r.f(seq.buffer_removal_time_length_minus_1 + 1)?; + } + } + } + Ok(()) +} + impl FrameHeader { pub fn get_relative_dist(&self, seq: &SequenceHeader, a: u32, b: u32) -> i32 { relative_dist(seq, a, b) @@ -494,35 +526,10 @@ impl FrameHeader { } else { h.show_existing_frame = r.flag()?; if h.show_existing_frame { - h.frame_to_show_map_idx = r.f(3)? as usize; - if seq.decoder_model_info_present && !seq.equal_picture_interval { - r.f(seq.frame_presentation_time_length_minus_1 + 1)?; - } - if seq.frame_id_numbers_present { - r.f(id_len)?; - } - let rs = &st.refs[h.frame_to_show_map_idx]; - if !rs.valid { - return Err(Error::Invalid("show_existing_frame of an empty slot")); - } - h.frame_type = rs.frame_type; - if h.frame_type == KEY_FRAME as u8 { - h.refresh_frame_flags = all_frames; - } - if seq.film_grain_params_present { - h.film_grain = rs.grain.clone(); - } + h.parse_show_existing_frame(r, st, id_len)?; return Ok(h); } - h.frame_type = r.f(2)? as u8; - h.frame_is_intra = h.frame_type == INTRA_ONLY_FRAME as u8 || h.frame_type == KEY_FRAME as u8; - h.show_frame = r.flag()?; - if h.show_frame && seq.decoder_model_info_present && !seq.equal_picture_interval { - r.f(seq.frame_presentation_time_length_minus_1 + 1)?; - } - h.showable_frame = if h.show_frame { h.frame_type != KEY_FRAME as u8 } else { r.flag()? }; - h.error_resilient_mode = - if h.frame_type == SWITCH_FRAME as u8 || (h.frame_type == KEY_FRAME as u8 && h.show_frame) { true } else { r.flag()? }; + h.parse_frame_type_and_flags(r, seq)?; } if h.frame_type == KEY_FRAME as u8 && h.show_frame { for rs in st.refs.iter_mut() { @@ -533,33 +540,11 @@ impl FrameHeader { h.order_hints[LAST_FRAME + i] = 0; } } - h.disable_cdf_update = r.flag()?; - h.allow_screen_content_tools = if seq.seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS as u32 { - r.flag()? - } else { - seq.seq_force_screen_content_tools != 0 - }; - if h.allow_screen_content_tools { - h.force_integer_mv = if seq.seq_force_integer_mv == SELECT_INTEGER_MV as u32 { r.flag()? } else { seq.seq_force_integer_mv != 0 }; - } - if h.frame_is_intra { - h.force_integer_mv = true; - } + h.parse_screen_content_flags(r, seq)?; if seq.frame_id_numbers_present { h.current_frame_id = r.f(id_len)?; - // mark_ref_frames( idLen ) - let diff_len = seq.delta_frame_id_length_minus_2 + 2; - let cur = h.current_frame_id; - for rs in st.refs.iter_mut() { - if cur > (1 << diff_len) { - if rs.frame_id > cur || rs.frame_id < cur - (1 << diff_len) { - rs.valid = false; - } - } else if rs.frame_id > cur && rs.frame_id < (1 << id_len) + cur - (1 << diff_len) { - rs.valid = false; - } - } - st.current_frame_id = cur; + mark_ref_frames(st, h.current_frame_id, id_len); + st.current_frame_id = h.current_frame_id; } h.frame_size_override_flag = if h.frame_type == SWITCH_FRAME as u8 { true @@ -570,18 +555,7 @@ impl FrameHeader { }; h.order_hint = r.f(seq.order_hint_bits)?; h.primary_ref_frame = if h.frame_is_intra || h.error_resilient_mode { PRIMARY_REF_NONE } else { r.f(3)? as usize }; - if seq.decoder_model_info_present && r.flag()? { - for op in 0..=seq.operating_points_cnt_minus_1 { - if seq.decoder_model_present_for_this_op[op] { - let idc = seq.operating_point_idc[op]; - let in_t = (idc >> temporal_id) & 1; - let in_s = (idc >> (spatial_id + 8)) & 1; - if idc == 0 || (in_t == 1 && in_s == 1) { - r.f(seq.buffer_removal_time_length_minus_1 + 1)?; - } - } - } - } + skip_buffer_removal_times(r, seq, temporal_id, spatial_id)?; h.refresh_frame_flags = if h.frame_type == SWITCH_FRAME as u8 || (h.frame_type == KEY_FRAME as u8 && h.show_frame) { all_frames } else { r.f(8)? }; if (!h.frame_is_intra || h.refresh_frame_flags != all_frames) && h.error_resilient_mode && seq.enable_order_hint { @@ -599,126 +573,16 @@ impl FrameHeader { h.allow_intrabc = r.flag()?; } } else { - let mut short = false; - if seq.enable_order_hint { - short = r.flag()?; - if short { - let last = r.f(3)? as usize; - let gold = r.f(3)? as usize; - h.set_frame_refs(seq, st.refs, last, gold); - } - } - for i in 0..REFS_PER_FRAME { - if !short { - h.ref_frame_idx[i] = r.f(3)? as usize; - } - if seq.frame_id_numbers_present { - r.f(seq.delta_frame_id_length_minus_2 + 2)?; - } - } - for i in 0..REFS_PER_FRAME { - if !st.refs[h.ref_frame_idx[i]].valid { - return Err(Error::Invalid("reference to an empty slot")); - } - } - if h.frame_size_override_flag && !h.error_resilient_mode { - // frame_size_with_refs( ) - let mut found = false; - for i in 0..REFS_PER_FRAME { - if r.flag()? { - let rs = &st.refs[h.ref_frame_idx[i]]; - h.upscaled_width = rs.upscaled_width; - h.frame_width = h.upscaled_width; - h.frame_height = rs.frame_height; - h.render_width = rs.render_width; - h.render_height = rs.render_height; - found = true; - break; - } - } - if !found { - h.frame_size(r, seq)?; - h.render_size(r)?; - } else { - h.superres_params(r, seq)?; - h.compute_image_size(); - } - } else { - h.frame_size(r, seq)?; - h.render_size(r)?; - } - h.allow_high_precision_mv = if h.force_integer_mv { false } else { r.flag()? }; - h.interpolation_filter = if r.flag()? { SWITCHABLE } else { r.f(2)? as u8 }; - h.is_motion_mode_switchable = r.flag()?; - h.use_ref_frame_mvs = if h.error_resilient_mode || !seq.enable_ref_frame_mvs { false } else { r.flag()? }; - for i in 0..REFS_PER_FRAME { - let rf = LAST_FRAME + i; - let hint = st.refs[h.ref_frame_idx[i]].order_hint; - h.order_hints[rf] = hint; - h.ref_frame_sign_bias[rf] = seq.enable_order_hint && relative_dist(seq, hint, h.order_hint) > 0; - } + h.parse_inter_frame_refs(r, st)?; } h.disable_frame_end_update_cdf = if seq.reduced_still_picture_header || h.disable_cdf_update { true } else { r.flag()? }; - if h.primary_ref_frame == PRIMARY_REF_NONE { - // setup_past_independence( ) - st.seg_features = SegmentationFeatures::default(); - st.prev_gm_params = default_gm_params(); - st.lf_deltas = LoopFilterDeltas::defaults(); - h.lf.delta_enabled = true; - } else { - // load_previous( ) - let prev = &st.refs[h.ref_frame_idx[h.primary_ref_frame]]; - st.prev_gm_params = prev.gm_params; - st.lf_deltas = prev.lf_deltas; - st.seg_features = prev.seg_features; - } + h.setup_or_load_previous(st); h.prev_gm_params = st.prev_gm_params; h.tile_info(r, seq)?; h.quantization_params(r, seq)?; h.segmentation_params(r, st)?; - // delta_q_params( ) - if h.quant.base_q_idx > 0 { - h.delta_q_present = r.flag()?; - } - if h.delta_q_present { - h.delta_q_res = r.f(2)?; - } - // delta_lf_params( ) - if h.delta_q_present { - if !h.allow_intrabc { - h.delta_lf_present = r.flag()?; - } - if h.delta_lf_present { - h.delta_lf_res = r.f(2)?; - h.delta_lf_multi = r.flag()?; - } - } - h.coded_lossless = true; - for seg_id in 0..MAX_SEGMENTS { - let q = h.get_qindex(true, seg_id, 0); - let ll = q == 0 - && h.quant.delta_q_y_dc == 0 - && h.quant.delta_q_u_ac == 0 - && h.quant.delta_q_u_dc == 0 - && h.quant.delta_q_v_ac == 0 - && h.quant.delta_q_v_dc == 0; - h.lossless_array[seg_id] = ll; - if !ll { - h.coded_lossless = false; - } - if h.quant.using_qmatrix { - if ll { - h.seg_qm_level[0][seg_id] = 15; - h.seg_qm_level[1][seg_id] = 15; - h.seg_qm_level[2][seg_id] = 15; - } else { - h.seg_qm_level[0][seg_id] = h.quant.qm_y; - h.seg_qm_level[1][seg_id] = h.quant.qm_u; - h.seg_qm_level[2][seg_id] = h.quant.qm_v; - } - } - } - h.all_lossless = h.coded_lossless && h.frame_width == h.upscaled_width; + h.delta_q_lf_params(r)?; + h.compute_lossless(); h.loop_filter_params(r, seq, st)?; h.cdef_params(r, seq)?; h.lr_params(r, seq)?; @@ -739,6 +603,182 @@ impl FrameHeader { Ok(h) } + /// The show_existing_frame branch: picks the slot to show and inherits its frame type and grain. + fn parse_show_existing_frame(&mut self, r: &mut BitReader, st: &HeaderState, id_len: u32) -> Result<()> { + let seq = st.seq; + self.frame_to_show_map_idx = r.f(3)? as usize; + if seq.decoder_model_info_present && !seq.equal_picture_interval { + r.f(seq.frame_presentation_time_length_minus_1 + 1)?; + } + if seq.frame_id_numbers_present { + r.f(id_len)?; + } + let rs = &st.refs[self.frame_to_show_map_idx]; + if !rs.valid { + return Err(Error::Invalid("show_existing_frame of an empty slot")); + } + self.frame_type = rs.frame_type; + if self.frame_type == KEY_FRAME as u8 { + self.refresh_frame_flags = (1u32 << NUM_REF_FRAMES) - 1; + } + if seq.film_grain_params_present { + self.film_grain = rs.grain.clone(); + } + Ok(()) + } + + /// frame_type, show_frame, showable_frame and error_resilient_mode. + fn parse_frame_type_and_flags(&mut self, r: &mut BitReader, seq: &SequenceHeader) -> Result<()> { + self.frame_type = r.f(2)? as u8; + self.frame_is_intra = self.frame_type == INTRA_ONLY_FRAME as u8 || self.frame_type == KEY_FRAME as u8; + self.show_frame = r.flag()?; + if self.show_frame && seq.decoder_model_info_present && !seq.equal_picture_interval { + r.f(seq.frame_presentation_time_length_minus_1 + 1)?; + } + self.showable_frame = if self.show_frame { self.frame_type != KEY_FRAME as u8 } else { r.flag()? }; + self.error_resilient_mode = + if self.frame_type == SWITCH_FRAME as u8 || (self.frame_type == KEY_FRAME as u8 && self.show_frame) { true } else { r.flag()? }; + Ok(()) + } + + /// disable_cdf_update, allow_screen_content_tools and force_integer_mv. + fn parse_screen_content_flags(&mut self, r: &mut BitReader, seq: &SequenceHeader) -> Result<()> { + self.disable_cdf_update = r.flag()?; + self.allow_screen_content_tools = if seq.seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS as u32 { + r.flag()? + } else { + seq.seq_force_screen_content_tools != 0 + }; + if self.allow_screen_content_tools { + self.force_integer_mv = if seq.seq_force_integer_mv == SELECT_INTEGER_MV as u32 { r.flag()? } else { seq.seq_force_integer_mv != 0 }; + } + if self.frame_is_intra { + self.force_integer_mv = true; + } + Ok(()) + } + + /// Reference selection, frame size, motion vector precision and filter flags of an inter frame. + fn parse_inter_frame_refs(&mut self, r: &mut BitReader, st: &HeaderState) -> Result<()> { + let seq = st.seq; + let mut short = false; + if seq.enable_order_hint { + short = r.flag()?; + if short { + let last = r.f(3)? as usize; + let gold = r.f(3)? as usize; + self.set_frame_refs(seq, st.refs, last, gold); + } + } + for i in 0..REFS_PER_FRAME { + if !short { + self.ref_frame_idx[i] = r.f(3)? as usize; + } + if seq.frame_id_numbers_present { + r.f(seq.delta_frame_id_length_minus_2 + 2)?; + } + } + for i in 0..REFS_PER_FRAME { + if !st.refs[self.ref_frame_idx[i]].valid { + return Err(Error::Invalid("reference to an empty slot")); + } + } + if self.frame_size_override_flag && !self.error_resilient_mode { + self.frame_size_with_refs(r, seq, st.refs)?; + } else { + self.frame_size(r, seq)?; + self.render_size(r)?; + } + self.allow_high_precision_mv = if self.force_integer_mv { false } else { r.flag()? }; + self.interpolation_filter = if r.flag()? { SWITCHABLE } else { r.f(2)? as u8 }; + self.is_motion_mode_switchable = r.flag()?; + self.use_ref_frame_mvs = if self.error_resilient_mode || !seq.enable_ref_frame_mvs { false } else { r.flag()? }; + for i in 0..REFS_PER_FRAME { + let rf = LAST_FRAME + i; + let hint = st.refs[self.ref_frame_idx[i]].order_hint; + self.order_hints[rf] = hint; + self.ref_frame_sign_bias[rf] = seq.enable_order_hint && relative_dist(seq, hint, self.order_hint) > 0; + } + Ok(()) + } + + /// frame_size_with_refs( ). + fn frame_size_with_refs(&mut self, r: &mut BitReader, seq: &SequenceHeader, refs: &[RefInfo; NUM_REF_FRAMES]) -> Result<()> { + for i in 0..REFS_PER_FRAME { + if r.flag()? { + let rs = &refs[self.ref_frame_idx[i]]; + self.upscaled_width = rs.upscaled_width; + self.frame_width = self.upscaled_width; + self.frame_height = rs.frame_height; + self.render_width = rs.render_width; + self.render_height = rs.render_height; + self.superres_params(r, seq)?; + self.compute_image_size(); + return Ok(()); + } + } + self.frame_size(r, seq)?; + self.render_size(r) + } + + /// setup_past_independence( ) or load_previous( ), depending on primary_ref_frame. + fn setup_or_load_previous(&mut self, st: &mut HeaderState) { + if self.primary_ref_frame == PRIMARY_REF_NONE { + st.seg_features = SegmentationFeatures::default(); + st.prev_gm_params = default_gm_params(); + st.lf_deltas = LoopFilterDeltas::defaults(); + self.lf.delta_enabled = true; + } else { + let prev = &st.refs[self.ref_frame_idx[self.primary_ref_frame]]; + st.prev_gm_params = prev.gm_params; + st.lf_deltas = prev.lf_deltas; + st.seg_features = prev.seg_features; + } + } + + /// delta_q_params( ) and delta_lf_params( ). + fn delta_q_lf_params(&mut self, r: &mut BitReader) -> Result<()> { + if self.quant.base_q_idx > 0 { + self.delta_q_present = r.flag()?; + } + if self.delta_q_present { + self.delta_q_res = r.f(2)?; + if !self.allow_intrabc { + self.delta_lf_present = r.flag()?; + } + if self.delta_lf_present { + self.delta_lf_res = r.f(2)?; + self.delta_lf_multi = r.flag()?; + } + } + Ok(()) + } + + /// Per-segment lossless flags, quantizer matrix levels and the frame-wide lossless flags. + fn compute_lossless(&mut self) { + self.coded_lossless = true; + for seg_id in 0..MAX_SEGMENTS { + let q = self.get_qindex(true, seg_id, 0); + let ll = q == 0 + && self.quant.delta_q_y_dc == 0 + && self.quant.delta_q_u_ac == 0 + && self.quant.delta_q_u_dc == 0 + && self.quant.delta_q_v_ac == 0 + && self.quant.delta_q_v_dc == 0; + self.lossless_array[seg_id] = ll; + if !ll { + self.coded_lossless = false; + } + if self.quant.using_qmatrix { + let levels = if ll { [15; 3] } else { [self.quant.qm_y, self.quant.qm_u, self.quant.qm_v] }; + for (plane, level) in levels.into_iter().enumerate() { + self.seg_qm_level[plane][seg_id] = level; + } + } + } + self.all_lossless = self.coded_lossless && self.frame_width == self.upscaled_width; + } + fn superres_params(&mut self, r: &mut BitReader, seq: &SequenceHeader) -> Result<()> { self.use_superres = if seq.enable_superres { r.flag()? } else { false }; self.superres_denom = if self.use_superres { r.f(SUPERRES_DENOM_BITS as u32)? + SUPERRES_DENOM_MIN as u32 } else { SUPERRES_NUM as u32 }; diff --git a/crates/av1/src/inter.rs b/crates/av1/src/inter.rs index f14e59b9..ea3cdcd3 100644 --- a/crates/av1/src/inter.rs +++ b/crates/av1/src/inter.rs @@ -420,20 +420,8 @@ impl TileDecoder<'_, '_> { let fh = &self.fs.fh; for ref_list in 0..1 + is_compound as usize { let ref_frame = cand_refs[ref_list]; - let ym = self.b.y_mode; - let global = - (ym == GLOBALMV || ym == GLOBAL_GLOBALMV) && ref_frame > INTRA_FRAME as i8 && fh.gm_type[ref_frame as usize] as usize > TRANSLATION; - let global_valid = global && setup_shear(&fh.gm_params[ref_frame as usize]).0; let ref_idx: i32 = if self.b.use_intrabc { -1 } else { fh.ref_frame_idx[ref_frame as usize - LAST_FRAME] as i32 }; - let use_warp = if w < 8 || h < 8 || fh.force_integer_mv { - 0 - } else if self.b.motion_mode as usize == LOCALWARP && self.b.local_valid { - 1 - } else if global && !self.is_scaled_ref(ref_idx) && global_valid { - 2 - } else { - 0 - }; + let use_warp = self.warp_mode(ref_frame, ref_idx, w, h); let mv = [cand_mvs[ref_list].row as i32, cand_mvs[ref_list].col as i32]; if use_warp != 0 { let params = if use_warp == 1 { self.b.local_warp_params } else { fh.gm_params[ref_frame as usize] }; @@ -448,40 +436,7 @@ impl TileDecoder<'_, '_> { } } let ct = self.b.compound_type; - if ct == COMPOUND_WEDGE && plane == 0 { - let m = &wedge_masks()[self.b.mi_size][self.b.wedge_index][self.b.wedge_sign]; - for i in 0..h { - for j in 0..w { - self.mask[i * PRED_STRIDE + j] = m[i * w + j] as i32; - } - } - } else if ct == COMPOUND_INTRA { - let size_scale = MAX_SB_SIZE / h.max(w); - let im = self.b.interintra_mode; - for i in 0..h { - for j in 0..w { - self.mask[i * PRED_STRIDE + j] = if im == II_V_PRED { - II_WEIGHTS_1D[i * size_scale] as i32 - } else if im == II_H_PRED { - II_WEIGHTS_1D[j * size_scale] as i32 - } else if im == II_SMOOTH_PRED { - II_WEIGHTS_1D[i.min(j) * size_scale] as i32 - } else { - 32 - }; - } - } - } else if ct == COMPOUND_DIFFWTD && plane == 0 { - for i in 0..h { - for j in 0..w { - let k = i * PRED_STRIDE + j; - let diff = (preds[0][k] - preds[1][k]).abs(); - let diff = round2(diff, (bd - 8) + rnd.2); - let m = (38 + diff / 16).clamp(0, 64); - self.mask[k] = if self.b.mask_type == 1 { 64 - m } else { m }; - } - } - } + self.fill_blend_mask(plane, w, h, &preds, rnd.2); let (fwd, bck) = if ct == COMPOUND_DISTANCE { self.distance_weights(cand_refs) } else { (0, 0) }; let max = (1i32 << bd) - 1; let is_inter_intra = self.b.is_inter && self.b.ref_frame[1] == INTRA_FRAME as i8; @@ -521,6 +476,64 @@ impl TileDecoder<'_, '_> { } } + /// Warp selection for one reference: 0 none, 1 local warp, 2 global warp. + fn warp_mode(&self, ref_frame: i8, ref_idx: i32, w: usize, h: usize) -> u8 { + let fh = &self.fs.fh; + let ym = self.b.y_mode; + let global = + (ym == GLOBALMV || ym == GLOBAL_GLOBALMV) && ref_frame > INTRA_FRAME as i8 && fh.gm_type[ref_frame as usize] as usize > TRANSLATION; + let global_valid = global && setup_shear(&fh.gm_params[ref_frame as usize]).0; + if w < 8 || h < 8 || fh.force_integer_mv { + 0 + } else if self.b.motion_mode as usize == LOCALWARP && self.b.local_valid { + 1 + } else if global && !self.is_scaled_ref(ref_idx) && global_valid { + 2 + } else { + 0 + } + } + + /// Builds the blend mask (wedge, inter-intra or difference-weighted) for the current compound type. + fn fill_blend_mask(&mut self, plane: usize, w: usize, h: usize, preds: &[Vec; 2], round_post: u32) { + let bd = self.fs.bit_depth; + let ct = self.b.compound_type; + if ct == COMPOUND_WEDGE && plane == 0 { + let m = &wedge_masks()[self.b.mi_size][self.b.wedge_index][self.b.wedge_sign]; + for i in 0..h { + for j in 0..w { + self.mask[i * PRED_STRIDE + j] = m[i * w + j] as i32; + } + } + } else if ct == COMPOUND_INTRA { + let size_scale = MAX_SB_SIZE / h.max(w); + let im = self.b.interintra_mode; + for i in 0..h { + for j in 0..w { + self.mask[i * PRED_STRIDE + j] = if im == II_V_PRED { + II_WEIGHTS_1D[i * size_scale] as i32 + } else if im == II_H_PRED { + II_WEIGHTS_1D[j * size_scale] as i32 + } else if im == II_SMOOTH_PRED { + II_WEIGHTS_1D[i.min(j) * size_scale] as i32 + } else { + 32 + }; + } + } + } else if ct == COMPOUND_DIFFWTD && plane == 0 { + for i in 0..h { + for j in 0..w { + let k = i * PRED_STRIDE + j; + let diff = (preds[0][k] - preds[1][k]).abs(); + let diff = round2(diff, (bd - 8) + round_post); + let m = (38 + diff / 16).clamp(0, 64); + self.mask[k] = if self.b.mask_type == 1 { 64 - m } else { m }; + } + } + } + } + fn is_scaled_ref(&self, ref_idx: i32) -> bool { if ref_idx < 0 { return false; diff --git a/crates/av1/src/tile.rs b/crates/av1/src/tile.rs index 3c11e71f..51eb2253 100644 --- a/crates/av1/src/tile.rs +++ b/crates/av1/src/tile.rs @@ -1682,6 +1682,87 @@ impl<'a, 'f> TileDecoder<'a, 'f> { } } + /// eob_pt, eob_extra and the remaining eob bits. + fn read_eob(&mut self, tx_sz: usize, tx_sz_ctx: usize, ptype: usize, tx_class: usize) -> usize { + let eob_multisize = (TX_WIDTH_LOG2[tx_sz] as usize).min(5) + (TX_HEIGHT_LOG2[tx_sz] as usize).min(5) - 4; + let ectx = (tx_class != TX_CLASS_2D) as usize; + let eob_pt = 1 + match eob_multisize { + 0 => self.sd.read_symbol(&mut self.cdf.eob_pt_16[ptype][ectx]), + 1 => self.sd.read_symbol(&mut self.cdf.eob_pt_32[ptype][ectx]), + 2 => self.sd.read_symbol(&mut self.cdf.eob_pt_64[ptype][ectx]), + 3 => self.sd.read_symbol(&mut self.cdf.eob_pt_128[ptype][ectx]), + 4 => self.sd.read_symbol(&mut self.cdf.eob_pt_256[ptype][ectx]), + 5 => self.sd.read_symbol(&mut self.cdf.eob_pt_512[ptype]), + _ => self.sd.read_symbol(&mut self.cdf.eob_pt_1024[ptype]), + }; + let mut eob = if eob_pt < 2 { eob_pt } else { (1 << (eob_pt - 2)) + 1 }; + let eob_shift = eob_pt as i32 - 3; + if eob_shift >= 0 { + let extra = self.sd.read_symbol(&mut self.cdf.eob_extra[tx_sz_ctx][ptype][eob_pt - 3]); + if extra == 1 { + eob += 1 << eob_shift; + } + for i in 1..(eob_pt as i32 - 2).max(0) { + let sh = (eob_pt as i32 - 2).max(0) - 1 - i; + if self.sd.read_literal(1) == 1 { + eob += 1 << sh; + } + } + } + eob + } + + /// Exp-Golomb coded remainder of a coefficient above the base range (read_golomb). + fn read_golomb(&mut self) -> u32 { + let mut length = 0; + loop { + length += 1; + if self.sd.read_literal(1) == 1 || length > 32 { + break; + } + } + let mut x: u32 = 1; + for _ in (0..length - 1).rev() { + x = (x << 1) | self.sd.read_literal(1); + } + x + } + + /// Reads the signs and Golomb remainders of the first `scan.len()` (= eob) coefficients, applies + /// them to `self.quant`, and returns the culLevel and dcCategory contexts. `blk4` is (x4, y4, w4, h4). + fn read_signs_and_golomb(&mut self, plane: usize, blk4: (usize, usize, usize, usize), scan: &[u16]) -> (u32, u8) { + let (x4, y4, w4, h4) = blk4; + let ptype = (plane > 0) as usize; + let mut cul_level = 0u32; + let mut dc_category = 0u8; + for (c, &p) in scan.iter().enumerate() { + let pos = p as usize; + let sign = if self.quant[pos] != 0 { + if c == 0 { + let ctx = self.dc_sign_ctx(plane, x4, y4, w4, h4); + self.sd.read_symbol(&mut self.cdf.dc_sign[ptype][ctx]) == 1 + } else { + self.sd.read_literal(1) == 1 + } + } else { + false + }; + if self.quant[pos] > (NUM_BASE_LEVELS + COEFF_BASE_RANGE) as i32 { + let x = self.read_golomb(); + self.quant[pos] = (x as i64 + COEFF_BASE_RANGE as i64 + NUM_BASE_LEVELS as i64).min(i32::MAX as i64) as i32; + } + if pos == 0 && self.quant[pos] > 0 { + dc_category = if sign { 1 } else { 2 }; + } + self.quant[pos] &= 0xFFFFF; + cul_level += self.quant[pos] as u32; + if sign { + self.quant[pos] = -self.quant[pos]; + } + } + (cul_level.min(63), dc_category) + } + /// coeffs( ): returns eob. fn coeffs(&mut self, plane: usize, start_x: usize, start_y: usize, tx_sz: usize) -> usize { let x4 = start_x >> 2; @@ -1707,32 +1788,8 @@ impl<'a, 'f> TileDecoder<'a, 'f> { } self.plane_tx_type = self.compute_tx_type(plane, tx_sz, x4, y4); let scan = self.get_scan(tx_sz); - let eob_multisize = (TX_WIDTH_LOG2[tx_sz] as usize).min(5) + (TX_HEIGHT_LOG2[tx_sz] as usize).min(5) - 4; let tx_class = get_tx_class(self.plane_tx_type); - let ectx = (tx_class != TX_CLASS_2D) as usize; - let eob_pt = 1 + match eob_multisize { - 0 => self.sd.read_symbol(&mut self.cdf.eob_pt_16[ptype][ectx]), - 1 => self.sd.read_symbol(&mut self.cdf.eob_pt_32[ptype][ectx]), - 2 => self.sd.read_symbol(&mut self.cdf.eob_pt_64[ptype][ectx]), - 3 => self.sd.read_symbol(&mut self.cdf.eob_pt_128[ptype][ectx]), - 4 => self.sd.read_symbol(&mut self.cdf.eob_pt_256[ptype][ectx]), - 5 => self.sd.read_symbol(&mut self.cdf.eob_pt_512[ptype]), - _ => self.sd.read_symbol(&mut self.cdf.eob_pt_1024[ptype]), - }; - eob = if eob_pt < 2 { eob_pt } else { (1 << (eob_pt - 2)) + 1 }; - let eob_shift = eob_pt as i32 - 3; - if eob_shift >= 0 { - let extra = self.sd.read_symbol(&mut self.cdf.eob_extra[tx_sz_ctx][ptype][eob_pt - 3]); - if extra == 1 { - eob += 1 << eob_shift; - } - for i in 1..(eob_pt as i32 - 2).max(0) { - let sh = (eob_pt as i32 - 2).max(0) - 1 - i; - if self.sd.read_literal(1) == 1 { - eob += 1 << sh; - } - } - } + eob = self.read_eob(tx_sz, tx_sz_ctx, ptype, tx_class); let adj = ADJUSTED_TX_SIZE[tx_sz] as usize; let bwl = TX_WIDTH_LOG2[adj] as usize; let height = TX_HEIGHT[adj] as usize; @@ -1780,45 +1837,7 @@ impl<'a, 'f> TileDecoder<'a, 'f> { lev[li] = level as u8; } self.levels = lev; - for c in 0..eob { - let pos = scan[c] as usize; - let sign = if self.quant[pos] != 0 { - if c == 0 { - let ctx = self.dc_sign_ctx(plane, x4, y4, w4, h4); - self.sd.read_symbol(&mut self.cdf.dc_sign[ptype][ctx]) == 1 - } else { - self.sd.read_literal(1) == 1 - } - } else { - false - }; - if self.quant[pos] > (NUM_BASE_LEVELS + COEFF_BASE_RANGE) as i32 { - let mut length = 0; - loop { - length += 1; - if self.sd.read_literal(1) == 1 { - break; - } - if length > 32 { - break; - } - } - let mut x: u32 = 1; - for _ in (0..length - 1).rev() { - x = (x << 1) | self.sd.read_literal(1); - } - self.quant[pos] = (x as i64 + COEFF_BASE_RANGE as i64 + NUM_BASE_LEVELS as i64).min(i32::MAX as i64) as i32; - } - if pos == 0 && self.quant[pos] > 0 { - dc_category = if sign { 1 } else { 2 }; - } - self.quant[pos] &= 0xFFFFF; - cul_level += self.quant[pos] as u32; - if sign { - self.quant[pos] = -self.quant[pos]; - } - } - cul_level = cul_level.min(63); + (cul_level, dc_category) = self.read_signs_and_golomb(plane, (x4, y4, w4, h4), &scan[..eob]); } for i in 0..w4 { if x4 + i < self.t.above_level[plane].len() {