#![forbid(unsafe_code)]
use crate::include::common::attributes::ctz;
use crate::include::common::bitdepth::BPC;
use crate::include::common::intops::apply_sign64;
use crate::include::common::intops::clip;
use crate::include::common::intops::clip_u8;
use crate::include::common::intops::iclip;
use crate::include::dav1d::common::Rav1dDataProps;
use crate::include::dav1d::headers::RAV1D_PRIMARY_REF_NONE;
use crate::include::dav1d::headers::Rav1dFilterMode;
use crate::include::dav1d::headers::Rav1dFrameHeader;
use crate::include::dav1d::headers::Rav1dFrameHeaderTiling;
use crate::include::dav1d::headers::Rav1dPixelLayout;
use crate::include::dav1d::headers::Rav1dRestorationType;
use crate::include::dav1d::headers::Rav1dSequenceHeader;
use crate::include::dav1d::headers::Rav1dTxfmMode;
use crate::include::dav1d::headers::Rav1dWarpedMotionParams;
use crate::include::dav1d::headers::Rav1dWarpedMotionType;
use crate::include::dav1d::headers::SgrIdx;
use crate::include::dav1d::picture::Rav1dPicture;
use crate::src::align::AlignedVec64;
use crate::src::c_arc::CArc;
use crate::src::cdf::CdfMvComponent;
use crate::src::cdf::CdfThreadContext;
use crate::src::cdf::rav1d_cdf_thread_alloc;
use crate::src::cdf::rav1d_cdf_thread_copy;
use crate::src::cdf::rav1d_cdf_thread_init_static;
use crate::src::cdf::rav1d_cdf_thread_update;
use crate::src::ctx::CaseSet;
use crate::src::dequant_tables::dav1d_dq_tbl;
use crate::src::disjoint_mut::DisjointMut;
use crate::src::disjoint_mut::DisjointMutSlice;
use crate::src::disjoint_mut::TryResizable;
use crate::src::disjoint_mut::TryResizableWith;
use crate::src::enum_map::DefaultValue;
use crate::src::enum_map::enum_map;
use crate::src::enum_map::enum_map_ty;
use crate::src::env::BlockContext;
use crate::src::env::av1_get_bwd_ref_1_ctx;
use crate::src::env::av1_get_bwd_ref_ctx;
use crate::src::env::av1_get_fwd_ref_1_ctx;
use crate::src::env::av1_get_fwd_ref_2_ctx;
use crate::src::env::av1_get_fwd_ref_ctx;
use crate::src::env::av1_get_ref_ctx;
use crate::src::env::av1_get_uni_p1_ctx;
use crate::src::env::fix_mv_precision;
use crate::src::env::gather_left_partition_prob;
use crate::src::env::gather_top_partition_prob;
use crate::src::env::get_comp_ctx;
use crate::src::env::get_comp_dir_ctx;
use crate::src::env::get_cur_frame_segid;
use crate::src::env::get_drl_context;
use crate::src::env::get_filter_ctx;
use crate::src::env::get_gmv_2d;
use crate::src::env::get_intra_ctx;
use crate::src::env::get_jnt_comp_ctx;
use crate::src::env::get_mask_comp_ctx;
use crate::src::env::get_partition_ctx;
use crate::src::env::get_poc_diff;
use crate::src::env::get_tx_ctx;
use crate::src::error::Rav1dError::EINVAL;
use crate::src::error::Rav1dError::ENOMEM;
use crate::src::error::Rav1dError::ENOPROTOOPT;
use crate::src::error::Rav1dResult;
use crate::src::extensions::OptionError as _;
use crate::src::internal::Bxy;
use crate::src::internal::Rav1dBitDepthDSPContext;
use crate::src::internal::Rav1dContext;
use crate::src::internal::Rav1dContextTaskType;
use crate::src::internal::Rav1dFrameContext;
use crate::src::internal::Rav1dFrameContextFrameThread;
use crate::src::internal::Rav1dFrameContextLf;
use crate::src::internal::Rav1dFrameData;
use crate::src::internal::Rav1dState;
use crate::src::internal::Rav1dTaskContext;
use crate::src::internal::Rav1dTileState;
use crate::src::internal::Rav1dTileStateContext;
use crate::src::internal::ScalableMotionParams;
use crate::src::internal::ScratchPal;
use crate::src::internal::TileStateRef;
use crate::src::intra_edge::EdgeFlags;
use crate::src::intra_edge::EdgeIndex;
use crate::src::intra_edge::IntraEdges;
use crate::src::levels::Av1Block;
use crate::src::levels::Av1BlockInter;
use crate::src::levels::Av1BlockInter1d;
use crate::src::levels::Av1BlockInter2d;
use crate::src::levels::Av1BlockInterNd;
use crate::src::levels::Av1BlockIntra;
use crate::src::levels::Av1BlockIntraInter;
use crate::src::levels::BlockLevel;
use crate::src::levels::BlockPartition;
use crate::src::levels::BlockSize;
use crate::src::levels::CFL_PRED;
use crate::src::levels::CompInterType;
use crate::src::levels::DC_PRED;
use crate::src::levels::DrlProximity;
use crate::src::levels::FILTER_PRED;
use crate::src::levels::Filter2d;
use crate::src::levels::GLOBALMV;
use crate::src::levels::GLOBALMV_GLOBALMV;
use crate::src::levels::InterIntraPredMode;
use crate::src::levels::InterIntraType;
use crate::src::levels::MVJoint;
use crate::src::levels::MotionMode;
use crate::src::levels::Mv;
use crate::src::levels::N_COMP_INTER_PRED_MODES;
use crate::src::levels::N_INTRA_PRED_MODES;
use crate::src::levels::N_UV_INTRA_PRED_MODES;
use crate::src::levels::NEARESTMV;
use crate::src::levels::NEARESTMV_NEARESTMV;
use crate::src::levels::NEARMV;
use crate::src::levels::NEWMV;
use crate::src::levels::NEWMV_NEWMV;
use crate::src::levels::SegmentId;
use crate::src::levels::TxfmSize;
use crate::src::levels::VERT_LEFT_PRED;
use crate::src::levels::VERT_PRED;
use crate::src::lf_mask::Av1RestorationUnit;
use crate::src::lf_mask::rav1d_calc_eih;
use crate::src::lf_mask::rav1d_calc_lf_values;
use crate::src::lf_mask::rav1d_create_lf_mask_inter;
use crate::src::lf_mask::rav1d_create_lf_mask_intra;
use crate::src::log::Rav1dLog as _;
use crate::src::lr_apply::LrRestorePlanes;
use crate::src::msac::MsacContext;
use crate::src::msac::rav1d_msac_decode_bool;
use crate::src::msac::rav1d_msac_decode_bool_adapt;
use crate::src::msac::rav1d_msac_decode_bool_equi;
use crate::src::msac::rav1d_msac_decode_bools;
use crate::src::msac::rav1d_msac_decode_subexp;
use crate::src::msac::rav1d_msac_decode_symbol_adapt4;
use crate::src::msac::rav1d_msac_decode_symbol_adapt8;
use crate::src::msac::rav1d_msac_decode_symbol_adapt16;
use crate::src::msac::rav1d_msac_decode_uniform;
use crate::src::pal::Rav1dPalDSPContext;
use crate::src::picture::Rav1dThreadPicture;
use crate::src::picture::rav1d_picture_alloc_copy;
use crate::src::picture::rav1d_thread_picture_alloc;
use crate::src::qm::dav1d_qm_tbl;
use crate::src::recon::debug_block_info;
use crate::src::refmvs::RefMvsBlock;
use crate::src::refmvs::RefMvsFrame;
use crate::src::refmvs::RefMvsMvPair;
use crate::src::refmvs::RefMvsRefPair;
use crate::src::refmvs::rav1d_refmvs_find;
use crate::src::refmvs::rav1d_refmvs_init_frame;
use crate::src::refmvs::rav1d_refmvs_tile_sbrow_init;
use crate::src::relaxed_atomic::RelaxedAtomic;
use crate::src::tables::cfl_allowed_mask;
use crate::src::tables::dav1d_al_part_ctx;
use crate::src::tables::dav1d_block_sizes;
use crate::src::tables::dav1d_comp_inter_pred_modes;
use crate::src::tables::dav1d_filter_2d;
use crate::src::tables::dav1d_filter_dir;
use crate::src::tables::dav1d_intra_mode_context;
use crate::src::tables::dav1d_max_txfm_size_for_bs;
use crate::src::tables::dav1d_partition_type_count;
use crate::src::tables::dav1d_sgr_params;
use crate::src::tables::dav1d_txfm_dimensions;
use crate::src::tables::dav1d_wedge_ctx_lut;
use crate::src::tables::dav1d_ymode_size_context;
use crate::src::tables::interintra_allowed_mask;
use crate::src::tables::wedge_allowed_mask;
use crate::src::thread_task::FRAME_ERROR;
use crate::src::thread_task::TILE_ERROR;
use crate::src::thread_task::rav1d_task_create_tile_sbrow;
use crate::src::thread_task::rav1d_task_frame_init;
use crate::src::warpmv::rav1d_find_affine_int;
use crate::src::warpmv::rav1d_get_shear_params;
use crate::src::warpmv::rav1d_set_affine_mv2d;
use aligned::Aligned;
#[allow(non_camel_case_types)]
type ptrdiff_t = isize;
use std::array;
use std::cmp;
use std::ffi::c_int;
use std::ffi::c_uint;
use std::iter;
use std::mem;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::AtomicU8;
use std::sync::atomic::Ordering;
use strum::EnumCount;
fn init_quant_tables(
seq_hdr: &Rav1dSequenceHeader,
frame_hdr: &Rav1dFrameHeader,
qidx: u8,
dq: &[[[RelaxedAtomic<u16>; 2]; 3]; SegmentId::COUNT],
) {
let tbl = &dav1d_dq_tbl[seq_hdr.hbd as usize];
let segmentation_is_enabled = frame_hdr.segmentation.enabled != 0;
let len = if segmentation_is_enabled {
SegmentId::COUNT
} else {
1
};
for i in 0..len {
let yac = if segmentation_is_enabled {
clip_u8(qidx as c_int + frame_hdr.segmentation.seg_data.d[i].delta_q as c_int)
} else {
qidx
} as i16;
let ydc = clip_u8(yac + frame_hdr.quant.ydc_delta as i16);
let uac = clip_u8(yac + frame_hdr.quant.uac_delta as i16);
let udc = clip_u8(yac + frame_hdr.quant.udc_delta as i16);
let vac = clip_u8(yac + frame_hdr.quant.vac_delta as i16);
let vdc = clip_u8(yac + frame_hdr.quant.vdc_delta as i16);
let dq = &dq[i];
dq[0][0].set(tbl[ydc as usize][0]);
dq[0][1].set(tbl[yac as usize][1]);
dq[1][0].set(tbl[udc as usize][0]);
dq[1][1].set(tbl[uac as usize][1]);
dq[2][0].set(tbl[vdc as usize][0]);
dq[2][1].set(tbl[vac as usize][1]);
}
}
fn read_mv_component_diff(
msac: &mut MsacContext,
mv_comp: &mut CdfMvComponent,
mv_prec: i32,
) -> c_int {
let sign = rav1d_msac_decode_bool_adapt(msac, &mut *mv_comp.sign);
let cl = rav1d_msac_decode_symbol_adapt16(msac, &mut *mv_comp.classes, 10);
let mut up;
let mut fp = 3;
let mut hp = true;
if cl == 0 {
up = rav1d_msac_decode_bool_adapt(msac, &mut *mv_comp.class_0) as u16;
if mv_prec >= 0 {
fp = rav1d_msac_decode_symbol_adapt4(msac, &mut mv_comp.class_0_fp[up as usize], 3);
if mv_prec > 0 {
hp = rav1d_msac_decode_bool_adapt(msac, &mut *mv_comp.class_0_hp);
}
}
} else {
up = 1 << cl;
for n in 0..cl as usize {
up |= (rav1d_msac_decode_bool_adapt(msac, &mut mv_comp.class_n[n]) as u16) << n;
}
if mv_prec >= 0 {
fp = rav1d_msac_decode_symbol_adapt4(msac, &mut *mv_comp.class_n_fp, 3);
if mv_prec > 0 {
hp = rav1d_msac_decode_bool_adapt(msac, &mut *mv_comp.class_n_hp);
}
}
}
let hp = hp as u16;
let diff = ((up << 3 | (fp as u16) << 1 | hp) + 1) as c_int;
if sign { -diff } else { diff }
}
fn read_mv_residual(ts_c: &mut Rav1dTileStateContext, ref_mv: &mut Mv, mv_prec: i32) {
let mv_joint = MVJoint::from_bits_truncate(rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut *ts_c.cdf.mv.joint,
MVJoint::all().bits(),
) as u8);
let mv_cdf = &mut ts_c.cdf.mv;
if mv_joint.contains(MVJoint::V) {
ref_mv.y = ref_mv.y.wrapping_add(read_mv_component_diff(
&mut ts_c.msac,
&mut mv_cdf.comp[0],
mv_prec,
) as i16);
}
if mv_joint.contains(MVJoint::H) {
ref_mv.x = ref_mv.x.wrapping_add(read_mv_component_diff(
&mut ts_c.msac,
&mut mv_cdf.comp[1],
mv_prec,
) as i16);
}
}
fn read_tx_tree(
t: &mut Rav1dTaskContext,
f: &Rav1dFrameData,
ts_c: &mut Rav1dTileStateContext,
from: TxfmSize,
depth: c_int,
masks: &mut [u16; 2],
x_off: usize,
y_off: usize,
) {
let bx4 = t.b.x & 31;
let by4 = t.b.y & 31;
let t_dim = &dav1d_txfm_dimensions[from as usize];
let txw = t_dim.lw;
let txh = t_dim.lh;
let is_split;
if depth < 2 && from > TxfmSize::S4x4 {
let cat = 2 * (TxfmSize::S64x64 as c_int - t_dim.max as c_int) - depth;
let a = ((*f.a[t.a].tx.index(bx4 as usize) as u8) < txw) as c_int;
let l = ((*t.l.tx.index(by4 as usize) as u8) < txh) as c_int;
is_split = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.m.txpart[cat as usize][(a + l) as usize],
);
if is_split {
masks[depth as usize] |= 1 << (y_off * 4 + x_off);
}
} else {
is_split = false;
}
if is_split && t_dim.max > TxfmSize::S8x8 as _ {
let sub = t_dim.sub;
let sub_t_dim = &dav1d_txfm_dimensions[sub as usize];
let txsw = sub_t_dim.w as c_int;
let txsh = sub_t_dim.h as c_int;
read_tx_tree(
t,
f,
ts_c,
sub,
depth + 1,
masks,
x_off * 2 + 0,
y_off * 2 + 0,
);
t.b.x += txsw;
if txw >= txh && t.b.x < f.bw {
read_tx_tree(
t,
f,
ts_c,
sub,
depth + 1,
masks,
x_off * 2 + 1,
y_off * 2 + 0,
);
}
t.b.x -= txsw;
t.b.y += txsh;
if txh >= txw && t.b.y < f.bh {
read_tx_tree(
t,
f,
ts_c,
sub,
depth + 1,
masks,
x_off * 2 + 0,
y_off * 2 + 1,
);
t.b.x += txsw;
if txw >= txh && t.b.x < f.bw {
read_tx_tree(
t,
f,
ts_c,
sub,
depth + 1,
masks,
x_off * 2 + 1,
y_off * 2 + 1,
);
}
t.b.x -= txsw;
}
t.b.y -= txsh;
} else {
CaseSet::<16, false>::many(
[(&t.l, txh), (&f.a[t.a], txw)],
[t_dim.h as usize, t_dim.w as usize],
[by4 as usize, bx4 as usize],
|case, (dir, val)| {
let tx = if is_split {
TxfmSize::S4x4
} else {
TxfmSize::from_repr(val as _).unwrap()
};
case.set_disjoint(&dir.tx, tx);
},
);
};
}
fn neg_deinterleave(diff: u8, r#ref: SegmentId, max: u8) -> u8 {
let r#ref = r#ref.get() as u8;
if r#ref == 0 {
diff
} else if r#ref + 1 >= max {
max.wrapping_sub(diff + 1)
} else if 2 * r#ref < max {
if diff <= 2 * r#ref {
if diff & 1 != 0 {
r#ref + (diff + 1 >> 1)
} else {
r#ref - (diff >> 1)
}
} else {
diff
}
} else {
if diff <= 2 * (max - r#ref - 1) {
if diff & 1 != 0 {
r#ref + (diff + 1 >> 1)
} else {
r#ref - (diff >> 1)
}
} else {
max.wrapping_sub(diff + 1)
}
}
}
fn find_matching_ref(
f: &Rav1dFrameData,
t: &Rav1dTaskContext,
intra_edge_flags: EdgeFlags,
bw4: c_int,
bh4: c_int,
w4: c_int,
h4: c_int,
have_left: bool,
have_top: bool,
r#ref: i8,
masks: &mut [u64; 2],
) {
let r = &t.rt.r[(t.b.y as usize & 31) + 5 - 1..];
let mut count = 0;
let ts = &f.ts[t.ts];
let mut have_topleft = have_top && have_left;
let mut have_topright = cmp::max(bw4, bh4) < 32
&& have_top
&& t.b.x + bw4 < ts.tiling.col_end
&& intra_edge_flags.contains(EdgeFlags::I444_TOP_HAS_RIGHT);
let bs = |rp: RefMvsBlock| rp.bs.dimensions();
let matches = |rp: RefMvsBlock| rp.r#ref.r#ref[0] == r#ref + 1 && rp.r#ref.r#ref[1] == -1;
if have_top {
let mut i = r[0] + t.b.x as usize;
let r2 = *f.rf.r.index(i);
if matches(r2) {
masks[0] |= 1;
count = 1;
}
let mut aw4 = bs(r2)[0] as c_int;
if aw4 >= bw4 {
let off = t.b.x & aw4 - 1;
if off != 0 {
have_topleft = false;
}
if aw4 - off > bw4 {
have_topright = false;
}
} else {
let mut mask = 1 << aw4;
let mut x = aw4;
while x < w4 {
i += aw4 as usize;
let r2 = *f.rf.r.index(i);
if matches(r2) {
masks[0] |= mask;
count += 1;
if count >= 8 {
return;
}
}
aw4 = bs(r2)[0] as c_int;
mask <<= aw4;
x += aw4;
}
}
}
if have_left {
let get_r2 = |i: usize| *f.rf.r.index(r[i] + t.b.x as usize - 1);
let mut i = 1;
let r2 = get_r2(i);
if matches(r2) {
masks[1] |= 1;
count += 1;
if count >= 8 {
return;
}
}
let mut lh4 = bs(r2)[1] as c_int;
if lh4 >= bh4 {
if t.b.y & lh4 - 1 != 0 {
have_topleft = false;
}
} else {
let mut mask = 1 << lh4;
let mut y = lh4;
while y < h4 {
i += lh4 as usize;
let r2 = get_r2(i);
if matches(r2) {
masks[1] |= mask;
count += 1;
if count >= 8 {
return;
}
}
lh4 = bs(r2)[1] as c_int;
mask <<= lh4;
y += lh4;
}
}
}
if have_topleft && matches(*f.rf.r.index(r[0] + t.b.x as usize - 1)) {
masks[1] |= 1 << 32;
count += 1;
if count >= 8 {
return;
}
}
if have_topright && matches(*f.rf.r.index(r[0] + t.b.x as usize + bw4 as usize)) {
masks[0] |= 1 << 32;
}
}
fn derive_warpmv(
r: &DisjointMut<AlignedVec64<RefMvsBlock>>,
t: &Rav1dTaskContext,
bw4: c_int,
bh4: c_int,
masks: &[u64; 2],
mv: Mv,
mut wmp: Rav1dWarpedMotionParams,
) -> Rav1dWarpedMotionParams {
let mut pts = [[[0; 2 ]; 2 ]; 8];
let mut np = 0;
let rp = |i: i32, j: i32| {
let offset = (t.b.y & 31) + 5;
*r.index(t.rt.r[(offset as isize + i as isize) as usize] + j as usize)
};
let bs = |rp: RefMvsBlock| rp.bs.dimensions();
let mut add_sample = |np: usize, dx: i32, dy: i32, sx: i32, sy: i32, rp: RefMvsBlock| {
pts[np][0][0] = 16 * (2 * dx + sx * bs(rp)[0] as i32) - 8;
pts[np][0][1] = 16 * (2 * dy + sy * bs(rp)[1] as i32) - 8;
pts[np][1][0] = pts[np][0][0] + rp.mv.mv[0].x as i32;
pts[np][1][1] = pts[np][0][1] + rp.mv.mv[0].y as i32;
np + 1
};
if masks[0] as u32 == 1 && masks[1] >> 32 == 0 {
let off = t.b.x & bs(rp(-1, t.b.x))[0] as i32 - 1;
np = add_sample(np, -off, 0, 1, -1, rp(-1, t.b.x));
} else {
let mut off = 0;
let mut xmask = masks[0] as u32;
while np < 8 && xmask != 0 {
let tz = ctz(xmask);
off += tz;
xmask >>= tz;
np = add_sample(np, off, 0, 1, -1, rp(-1, t.b.x + off));
xmask &= !1;
}
}
if np < 8 && masks[1] as u32 == 1 {
let off = t.b.y & bs(rp(0, t.b.x - 1))[1] as i32 - 1;
np = add_sample(np, 0, -off, -1, 1, rp(-off, t.b.x - 1));
} else {
let mut off = 0;
let mut ymask = masks[1] as u32;
while np < 8 && ymask != 0 {
let tz = ctz(ymask);
off += tz;
ymask >>= tz;
np = add_sample(np, 0, off, -1, 1, rp(off, t.b.x - 1));
ymask &= !1;
}
}
if np < 8 && masks[1] >> 32 != 0 {
np = add_sample(np, 0, 0, -1, -1, rp(-1, t.b.x - 1));
}
if np < 8 && masks[0] >> 32 != 0 {
np = add_sample(np, bw4, 0, 1, -1, rp(-1, t.b.x + bw4));
}
assert!(np > 0 && np <= 8);
let mut mvd = [0; 8];
let mut ret = 0;
let thresh = 4 * iclip(cmp::max(bw4, bh4), 4, 28);
for (mvd, pts) in std::iter::zip(&mut mvd[..np], &pts[..np]) {
*mvd = (pts[1][0] - pts[0][0] - mv.x as i32).abs()
+ (pts[1][1] - pts[0][1] - mv.y as i32).abs();
if *mvd > thresh {
*mvd = -1;
} else {
ret += 1;
}
}
if ret == 0 {
ret = 1;
} else {
let mut i = 0;
let mut j = np - 1;
for _ in 0..np - ret {
while mvd[i] != -1 {
i += 1;
}
while mvd[j] == -1 {
j -= 1;
}
assert!(i != j);
if i > j {
break;
}
mvd[i] = mvd[j];
pts[i] = pts[j];
i += 1;
j -= 1;
}
}
wmp.r#type = if !rav1d_find_affine_int(&pts, ret, bw4, bh4, mv, &mut wmp, t.b.x, t.b.y)
&& !rav1d_get_shear_params(&wmp)
{
Rav1dWarpedMotionType::Affine
} else {
Rav1dWarpedMotionType::Identity
};
wmp
}
#[inline]
fn findoddzero(buf: &[u8]) -> bool {
buf.iter()
.enumerate()
.find(|&(i, &e)| i & 1 == 1 && e == 0)
.is_some()
}
fn order_palette(
pal_idx: &[u8],
stride: usize,
i: usize,
first: usize,
last: usize,
order: &mut [[u8; u8::BITS as usize]; 64],
ctx: &mut [u8; 64],
) {
let mut have_top = i > first;
let mut offset = first + (i - first) * stride;
for ((ctx, order), j) in ctx
.iter_mut()
.zip(order.iter_mut())
.zip((last..=first).rev())
{
let have_left = j > 0;
assert!(have_left || have_top);
let mut mask = 0u8;
let mut o_idx = 0;
let mut add = |v: u8| {
assert!(v < u8::BITS as u8);
order[o_idx] = v;
o_idx += 1;
mask |= 1 << v;
};
if !have_left {
*ctx = 0;
add(pal_idx[offset - stride]);
} else if !have_top {
*ctx = 0;
add(pal_idx[offset - 1]);
} else {
let l = pal_idx[offset - 1];
let t = pal_idx[offset - stride];
let tl = pal_idx[offset - (stride + 1)];
let same_t_l = t == l;
let same_t_tl = t == tl;
let same_l_tl = l == tl;
let same_all = same_t_l & same_t_tl & same_l_tl;
if same_all {
*ctx = 4;
add(t);
} else if same_t_l {
*ctx = 3;
add(t);
add(tl);
} else if same_t_tl | same_l_tl {
*ctx = 2;
add(tl);
add(if same_t_tl { l } else { t });
} else {
*ctx = 1;
add(cmp::min(t, l));
add(cmp::max(t, l));
add(tl);
}
}
for bit in 0..u8::BITS as u8 {
if mask & (1 << bit) == 0 {
order[o_idx] = bit;
o_idx += 1;
}
}
assert!(o_idx == u8::BITS as usize);
have_top = true;
offset += stride - 1;
}
}
fn read_pal_indices(
ts_c: &mut Rav1dTileStateContext,
pal_dsp: &Rav1dPalDSPContext,
scratch_pal: &mut ScratchPal,
pal_tmp: &mut [u8],
pal_idx: Option<&mut [u8]>, pal_sz: u8,
pl: bool,
w4: c_int,
h4: c_int,
bw4: c_int,
bh4: c_int,
) {
let [w4, h4, bw4, bh4] = [w4, h4, bw4, bh4].map(|n| usize::try_from(n).unwrap());
let pli = pl as usize;
let stride = bw4 * 4;
pal_tmp[0] = rav1d_msac_decode_uniform(&mut ts_c.msac, pal_sz as c_uint) as u8;
let color_map_cdf = &mut ts_c.cdf.m.color_map[pli][pal_sz as usize - 2];
let ScratchPal {
pal_order: order,
pal_ctx: ctx,
} = scratch_pal;
for i in 1..4 * (w4 + h4) - 1 {
let first = cmp::min(i, w4 * 4 - 1);
let last = (i + 1).saturating_sub(h4 * 4);
order_palette(pal_tmp, stride, i, first, last, order, ctx);
for (m, j) in (last..=first).rev().enumerate() {
let color_idx = rav1d_msac_decode_symbol_adapt8(
&mut ts_c.msac,
&mut color_map_cdf[ctx[m] as usize],
pal_sz as u8 - 1,
) as usize;
pal_tmp[(i - j) * stride + j] = order[m][color_idx];
}
}
if bw4 > w4 {
for y in 0..4 * h4 {
let offset = y * stride + (4 * w4);
let len = 4 * (bw4 - w4);
let filler = pal_tmp[offset - 1];
pal_tmp[offset..][..len].fill(filler);
}
}
pal_dsp
.pal_idx_finish
.call(pal_idx, pal_tmp, bw4 * 4, bh4 * 4, w4 * 4, h4 * 4);
}
struct VarTx {
uvtx: TxfmSize,
max_ytx: TxfmSize,
tx_split0: u8,
tx_split1: u16,
}
#[inline(never)]
fn read_vartx_tree(
t: &mut Rav1dTaskContext,
f: &Rav1dFrameData,
ts_c: &mut Rav1dTileStateContext,
b: &Av1Block,
bs: BlockSize,
bx4: c_int,
by4: c_int,
) -> VarTx {
let b_dim = bs.dimensions();
let bw4 = b_dim[0] as usize;
let bh4 = b_dim[1] as usize;
let mut tx_split = [0u16; 2];
let mut max_ytx = dav1d_max_txfm_size_for_bs[bs as usize][0];
let frame_hdr = &***f.frame_hdr.as_ref().unwrap();
let txfm_mode = frame_hdr.txfm_mode;
let uvtx;
if b.skip == 0 && (frame_hdr.segmentation.lossless[b.seg_id.get()] || max_ytx == TxfmSize::S4x4)
{
uvtx = TxfmSize::S4x4;
max_ytx = uvtx;
if txfm_mode == Rav1dTxfmMode::Switchable {
CaseSet::<32, false>::many(
[&t.l, &f.a[t.a]],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, dir| {
case.set_disjoint(&dir.tx, TxfmSize::S4x4);
},
);
}
} else if txfm_mode != Rav1dTxfmMode::Switchable || b.skip != 0 {
if txfm_mode == Rav1dTxfmMode::Switchable {
CaseSet::<32, false>::many(
[(&t.l, 1), (&f.a[t.a], 0)],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, (dir, dir_index)| {
let tx = TxfmSize::from_repr(b_dim[2 + dir_index] as _).unwrap();
case.set_disjoint(&dir.tx, tx);
},
);
}
uvtx = dav1d_max_txfm_size_for_bs[bs as usize][f.cur.p.layout as usize];
} else {
assert!(bw4 <= 16 || bh4 <= 16 || max_ytx == TxfmSize::S64x64);
let ytx = &dav1d_txfm_dimensions[max_ytx as usize];
let h = ytx.h as usize;
let w = ytx.w as usize;
debug_assert_eq!(bh4 % h, 0);
debug_assert_eq!(bw4 % w, 0);
for y_off in 0..bh4 / h {
for x_off in 0..bw4 / w {
read_tx_tree(t, f, ts_c, max_ytx, 0, &mut tx_split, x_off, y_off);
t.b.x += w as c_int;
}
t.b.x -= bw4 as c_int;
t.b.y += h as c_int;
}
t.b.y -= bh4 as c_int;
if debug_block_info!(f, t.b) {
println!(
"Post-vartxtree[{}/{}]: r={}",
tx_split[0], tx_split[1], ts_c.msac.rng
);
}
uvtx = dav1d_max_txfm_size_for_bs[bs as usize][f.cur.p.layout as usize];
}
assert!(tx_split[0] & !0x33 == 0);
let tx_split0 = tx_split[0] as u8;
let tx_split1 = tx_split[1];
VarTx {
uvtx,
max_ytx,
tx_split0,
tx_split1,
}
}
fn get_prev_frame_segid(
frame_hdr: &Rav1dFrameHeader,
b: Bxy,
w4: c_int,
h4: c_int,
ref_seg_map: &DisjointMutSlice<SegmentId>,
stride: ptrdiff_t,
) -> SegmentId {
assert!(frame_hdr.primary_ref_frame != RAV1D_PRIMARY_REF_NONE);
let mut prev_seg_id = SegmentId::max();
for y in 0..h4 as usize {
let offset = (b.y as usize + y) * stride as usize + b.x as usize;
prev_seg_id = ref_seg_map
.index((offset.., ..w4 as usize))
.iter()
.copied()
.fold(prev_seg_id, cmp::min);
if prev_seg_id == SegmentId::min() {
break;
}
}
prev_seg_id
}
#[inline]
fn splat_oneref_mv(
c: &Rav1dContext,
t: &Rav1dTaskContext,
rf: &RefMvsFrame,
bs: BlockSize,
inter: &Av1BlockInter,
bw4: usize,
bh4: usize,
) {
let mode = inter.inter_mode;
let tmpl = Aligned(RefMvsBlock {
mv: RefMvsMvPair {
mv: [inter.nd.one_d.mv[0], Mv::ZERO],
},
r#ref: RefMvsRefPair {
r#ref: [
inter.r#ref[0] + 1,
inter.interintra_type.map(|_| 0).unwrap_or(-1),
],
},
bs,
mf: (mode == GLOBALMV && cmp::min(bw4, bh4) >= 2) as u8 | (mode == NEWMV) as u8 * 2,
});
c.dsp.refmvs.splat_mv.call(rf, &t.rt, &tmpl, t.b, bw4, bh4);
}
#[inline]
fn splat_intrabc_mv(
c: &Rav1dContext,
t: &Rav1dTaskContext,
rf: &RefMvsFrame,
bs: BlockSize,
r#ref: Mv,
bw4: usize,
bh4: usize,
) {
let tmpl = Aligned(RefMvsBlock {
mv: RefMvsMvPair {
mv: [r#ref, Mv::ZERO],
},
r#ref: RefMvsRefPair { r#ref: [0, -1] },
bs,
mf: 0,
});
c.dsp.refmvs.splat_mv.call(rf, &t.rt, &tmpl, t.b, bw4, bh4);
}
#[inline]
fn splat_tworef_mv(
c: &Rav1dContext,
t: &Rav1dTaskContext,
rf: &RefMvsFrame,
bs: BlockSize,
inter: &Av1BlockInter,
bw4: usize,
bh4: usize,
) {
assert!(bw4 >= 2 && bh4 >= 2);
let mode = inter.inter_mode;
let tmpl = Aligned(RefMvsBlock {
mv: RefMvsMvPair {
mv: inter.nd.one_d.mv,
},
r#ref: RefMvsRefPair {
r#ref: [inter.r#ref[0] + 1, inter.r#ref[1] + 1],
},
bs,
mf: (mode == GLOBALMV_GLOBALMV) as u8 | (1 << mode & 0xbc != 0) as u8 * 2,
});
c.dsp.refmvs.splat_mv.call(rf, &t.rt, &tmpl, t.b, bw4, bh4);
}
#[inline]
fn splat_intraref(
c: &Rav1dContext,
t: &Rav1dTaskContext,
rf: &RefMvsFrame,
bs: BlockSize,
bw4: usize,
bh4: usize,
) {
let tmpl = Aligned(RefMvsBlock {
mv: RefMvsMvPair {
mv: [Mv::INVALID, Mv::ZERO],
},
r#ref: RefMvsRefPair { r#ref: [0, -1] },
bs,
mf: 0,
});
c.dsp.refmvs.splat_mv.call(rf, &t.rt, &tmpl, t.b, bw4, bh4);
}
fn mc_lowest_px(
dst: &mut c_int,
by4: c_int,
bh4: c_int,
mvy: i16,
ss_ver: c_int,
smp: &ScalableMotionParams,
) {
let mvy = mvy as c_int;
let v_mul = 4 >> ss_ver;
if smp.scale == 0 {
let my = mvy >> 3 + ss_ver;
let dy = mvy & 15 >> (ss_ver == 0) as c_int;
*dst = cmp::max(*dst, (by4 + bh4) * v_mul + my + 4 * (dy != 0) as c_int);
} else {
let mut y = (by4 * v_mul << 4) + mvy * (1 << (ss_ver == 0) as c_int);
let tmp = y as i64 * smp.scale as i64 + ((smp.scale - 0x4000) * 8) as i64;
y = apply_sign64((tmp.abs() + 128 >> 8) as c_int, tmp) + 32;
let bottom = (y + (bh4 * v_mul - 1) * smp.step >> 10) + 1 + 4;
*dst = cmp::max(*dst, bottom);
};
}
#[inline(always)]
fn affine_lowest_px(
t: &Rav1dTaskContext,
dst: &mut c_int,
b_dim: &[u8; 4],
wmp: &Rav1dWarpedMotionParams,
ss_ver: c_int,
ss_hor: c_int,
) {
let h_mul = 4 >> ss_hor;
let v_mul = 4 >> ss_ver;
assert!(b_dim[0] as c_int * h_mul & 7 == 0 && b_dim[1] as c_int * v_mul & 7 == 0);
let mat = &wmp.matrix;
let y = b_dim[1] as c_int * v_mul - 8;
let src_y = t.b.y * 4 + ((y + 4) << ss_ver);
let mat5_y = mat[5] as i64 * src_y as i64 + mat[1] as i64;
let mut x = 0;
while x < b_dim[0] as c_int * h_mul {
let src_x = t.b.x * 4 + ((x + 4) << ss_hor);
let mvy = mat[4] as i64 * src_x as i64 + mat5_y >> ss_ver;
let dy = (mvy >> 16) as c_int - 4;
*dst = cmp::max(*dst, dy + 4 + 8);
x += cmp::max(8, b_dim[0] as c_int * h_mul - 8);
}
}
#[inline(never)]
fn affine_lowest_px_luma(
t: &Rav1dTaskContext,
dst: &mut c_int,
b_dim: &[u8; 4],
wmp: &Rav1dWarpedMotionParams,
) {
affine_lowest_px(t, dst, b_dim, wmp, 0, 0);
}
#[inline(never)]
fn affine_lowest_px_chroma(
t: &Rav1dTaskContext,
layout: Rav1dPixelLayout,
dst: &mut c_int,
b_dim: &[u8; 4],
wmp: &Rav1dWarpedMotionParams,
) {
assert!(layout != Rav1dPixelLayout::I400);
if layout == Rav1dPixelLayout::I444 {
affine_lowest_px_luma(t, dst, b_dim, wmp);
} else {
affine_lowest_px(
t,
dst,
b_dim,
wmp,
(layout & Rav1dPixelLayout::I420) as c_int,
1,
);
};
}
fn obmc_lowest_px(
r: &DisjointMut<AlignedVec64<RefMvsBlock>>,
t: &mut Rav1dTaskContext,
ts: &Rav1dTileState,
layout: Rav1dPixelLayout,
svc: &[[ScalableMotionParams; 2]; 7],
dst: &mut [[c_int; 2]; 7],
is_chroma: bool,
b_dim: &[u8; 4],
_bx4: c_int,
_by4: c_int,
w4: c_int,
h4: c_int,
) {
assert!(t.b.x & 1 == 0 && t.b.y & 1 == 0);
let ri = &t.rt.r[(t.b.y as usize & 31) + 5 - 1..];
let ss_ver = (is_chroma && layout == Rav1dPixelLayout::I420) as c_int;
let ss_hor = (is_chroma && layout != Rav1dPixelLayout::I444) as c_int;
let h_mul = 4 >> ss_hor;
let v_mul = 4 >> ss_ver;
if t.b.y > ts.tiling.row_start
&& (!is_chroma || b_dim[0] as c_int * h_mul + b_dim[1] as c_int * v_mul >= 16)
{
let mut i = 0;
let mut x = 0;
while x < w4 && i < cmp::min(b_dim[2] as c_int, 4) {
let a_r = *r.index(ri[0] + t.b.x as usize + x as usize + 1);
let a_b_dim = a_r.bs.dimensions();
if a_r.r#ref.r#ref[0] as c_int > 0 {
let oh4 = cmp::min(b_dim[1] as c_int, 16) >> 1;
mc_lowest_px(
&mut dst[a_r.r#ref.r#ref[0] as usize - 1][is_chroma as usize],
t.b.y,
oh4 * 3 + 3 >> 2,
a_r.mv.mv[0].y,
ss_ver,
&svc[a_r.r#ref.r#ref[0] as usize - 1][1],
);
i += 1;
}
x += cmp::max(a_b_dim[0] as c_int, 2);
}
}
if t.b.x > ts.tiling.col_start {
let mut i = 0;
let mut y = 0;
while y < h4 && i < cmp::min(b_dim[3] as c_int, 4) {
let l_r = *r.index(ri[y as usize + 1 + 1] + t.b.x as usize - 1);
let l_b_dim = l_r.bs.dimensions();
if l_r.r#ref.r#ref[0] as c_int > 0 {
let oh4 = iclip(l_b_dim[1] as c_int, 2, b_dim[1] as c_int);
mc_lowest_px(
&mut dst[l_r.r#ref.r#ref[0] as usize - 1][is_chroma as usize],
t.b.y + y,
oh4,
l_r.mv.mv[0].y,
ss_ver,
&svc[l_r.r#ref.r#ref[0] as usize - 1][1],
);
i += 1;
}
y += cmp::max(l_b_dim[1] as c_int, 2);
}
}
}
fn decode_b(
c: &Rav1dContext,
t: &mut Rav1dTaskContext,
f: &Rav1dFrameData,
pass: &mut FrameThreadPassState,
bl: BlockLevel,
bs: BlockSize,
bp: BlockPartition,
intra_edge_flags: EdgeFlags,
) -> Result<(), ()> {
let seq_hdr = &***f.seq_hdr.as_ref().unwrap();
use std::fmt;
struct SignAbs(i32);
impl fmt::Display for SignAbs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sign = if self.0 < 0 { "-" } else { " " };
write!(f, "{}{:x}", sign, self.0.abs())
}
}
let mut b_mem = Av1Block::default();
let b = if t.frame_thread.pass != 0 {
&mut *f
.frame_thread
.b
.index_mut((t.b.y as isize * f.b4_stride + t.b.x as isize) as usize)
} else {
&mut b_mem
};
let ts = &f.ts[t.ts];
let ta = &f.a[t.a];
let bd_fn = f.bd_fn();
let b_dim = bs.dimensions();
let bx4 = t.b.x & 31;
let by4 = t.b.y & 31;
let ss_ver = (f.cur.p.layout == Rav1dPixelLayout::I420) as c_int;
let ss_hor = (f.cur.p.layout != Rav1dPixelLayout::I444) as c_int;
let cbx4 = bx4 >> ss_hor;
let cby4 = by4 >> ss_ver;
let bw4 = b_dim[0] as c_int;
let bh4 = b_dim[1] as c_int;
let w4 = cmp::min(bw4, f.bw - t.b.x);
let h4 = cmp::min(bh4, f.bh - t.b.y);
let cbw4 = bw4 + ss_hor >> ss_hor;
let cbh4 = bh4 + ss_ver >> ss_ver;
let have_left = t.b.x > ts.tiling.col_start;
let have_top = t.b.y > ts.tiling.row_start;
let has_chroma = f.cur.p.layout != Rav1dPixelLayout::I400
&& (bw4 > ss_hor || t.b.x & 1 != 0)
&& (bh4 > ss_ver || t.b.y & 1 != 0);
let frame_type = f.frame_hdr.as_ref().unwrap().frame_type;
let FrameThreadPassState::First(ts_c) = pass else {
match &b.ii {
Av1BlockIntraInter::Intra(intra) => {
(bd_fn.recon_b_intra)(f, t, None, bs, intra_edge_flags, b, intra);
let y_mode = intra.y_mode;
let y_mode_nofilt = if y_mode == FILTER_PRED {
DC_PRED
} else {
y_mode
};
CaseSet::<32, false>::many(
[&t.l, ta],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, dir| {
case.set_disjoint(&dir.mode, y_mode_nofilt);
case.set_disjoint(&dir.intra, 1);
},
);
if frame_type.is_inter_or_switch() {
let ri = t.rt.r[(t.b.y as usize & 31) + 5 + bh4 as usize - 1] + t.b.x as usize;
let r = &mut *f.rf.r.index_mut(ri..ri + bw4 as usize);
for block in r {
block.r#ref.r#ref[0] = 0;
block.bs = bs;
}
let rr = &t.rt.r[(t.b.y as usize & 31) + 5..][..bh4 as usize - 1];
for r in rr {
let block = &mut f.rf.r.index_mut(r + t.b.x as usize + bw4 as usize - 1);
block.r#ref.r#ref[0] = 0;
block.bs = bs;
}
}
if has_chroma {
CaseSet::<32, false>::many(
[&t.l, ta],
[cbh4 as usize, cbw4 as usize],
[cby4 as usize, cbx4 as usize],
|case, dir| {
case.set_disjoint(&dir.uvmode, intra.uv_mode);
},
);
}
}
Av1BlockIntraInter::Inter(inter) => {
if frame_type.is_inter_or_switch()
&& inter.comp_type.is_none()
&& inter.motion_mode == MotionMode::Warp
{
let two_d = inter.nd.two_d();
if two_d.matrix[0] == i16::MIN {
t.warpmv.r#type = Rav1dWarpedMotionType::Identity;
} else {
t.warpmv.r#type = Rav1dWarpedMotionType::Affine;
t.warpmv.matrix[2] = two_d.matrix[0] as i32 + 0x10000;
t.warpmv.matrix[3] = two_d.matrix[1] as i32;
t.warpmv.matrix[4] = two_d.matrix[2] as i32;
t.warpmv.matrix[5] = two_d.matrix[3] as i32 + 0x10000;
rav1d_set_affine_mv2d(bw4, bh4, two_d.mv2d, &mut t.warpmv, t.b.x, t.b.y);
rav1d_get_shear_params(&t.warpmv);
if debug_block_info!(f, t.b) {
println!(
"[ {} {} {}\n {} {} {} ]\n\
alpha={}, beta={}, gamma={}, deta={}, mv=y:{},x:{}",
SignAbs(t.warpmv.matrix[0]),
SignAbs(t.warpmv.matrix[1]),
SignAbs(t.warpmv.matrix[2]),
SignAbs(t.warpmv.matrix[3]),
SignAbs(t.warpmv.matrix[4]),
SignAbs(t.warpmv.matrix[5]),
SignAbs(t.warpmv.alpha().into()),
SignAbs(t.warpmv.beta().into()),
SignAbs(t.warpmv.gamma().into()),
SignAbs(t.warpmv.delta().into()),
two_d.mv2d.y,
two_d.mv2d.x,
);
}
}
}
(bd_fn.recon_b_inter)(f, t, None, bs, b, inter)?;
let filter = &dav1d_filter_dir[inter.filter2d as usize];
CaseSet::<32, false>::many(
[&t.l, ta],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, dir| {
case.set_disjoint(&dir.filter[0], filter[0]);
case.set_disjoint(&dir.filter[1], filter[1]);
case.set_disjoint(&dir.intra, 0);
},
);
if frame_type.is_inter_or_switch() {
let ri = t.rt.r[(t.b.y as usize & 31) + 5 + bh4 as usize - 1] + t.b.x as usize;
let r = &mut *f.rf.r.index_mut(ri..ri + bw4 as usize);
for block in r {
block.r#ref.r#ref[0] = inter.r#ref[0] + 1;
block.mv.mv[0] = inter.nd.one_d.mv[0];
block.bs = bs;
}
let rr = &t.rt.r[(t.b.y as usize & 31) + 5..][..bh4 as usize - 1];
for r in rr {
let block = &mut f.rf.r.index_mut(r + t.b.x as usize + bw4 as usize - 1);
block.r#ref.r#ref[0] = inter.r#ref[0] + 1;
block.mv.mv[0] = inter.nd.one_d.mv[0];
block.bs = bs;
}
}
if has_chroma {
CaseSet::<32, false>::many(
[&t.l, ta],
[cbh4 as usize, cbw4 as usize],
[cby4 as usize, cbx4 as usize],
|case, dir| {
case.set_disjoint(&dir.uvmode, DC_PRED);
},
);
}
}
}
return Ok(());
};
let ts_c = &mut **ts_c;
let cw4 = w4 + ss_hor >> ss_hor;
let ch4 = h4 + ss_ver >> ss_ver;
b.bl = bl;
b.bp = bp;
b.bs = bs as u8;
let mut seg = None;
let mut seg_pred = false;
let frame_hdr: &Rav1dFrameHeader = &f.frame_hdr.as_ref().unwrap();
if frame_hdr.segmentation.enabled != 0 {
if frame_hdr.segmentation.update_map == 0 {
b.seg_id = f
.prev_segmap
.as_ref()
.map(|prev_segmap| {
get_prev_frame_segid(frame_hdr, t.b, w4, h4, &prev_segmap.inner, f.b4_stride)
})
.unwrap_or_default();
seg = Some(&frame_hdr.segmentation.seg_data.d[b.seg_id.get()]);
} else if frame_hdr.segmentation.seg_data.preskip != 0 {
if frame_hdr.segmentation.temporal != 0 && {
let index = *ta.seg_pred.index(bx4 as usize) + *t.l.seg_pred.index(by4 as usize);
seg_pred = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.seg_pred[index as usize],
);
seg_pred
} {
b.seg_id = f
.prev_segmap
.as_ref()
.map(|prev_segmap| {
get_prev_frame_segid(
frame_hdr,
t.b,
w4,
h4,
&prev_segmap.inner,
f.b4_stride,
)
})
.unwrap_or_default();
} else {
let (pred_seg_id, seg_ctx) = get_cur_frame_segid(
t.b,
have_top,
have_left,
&f.cur_segmap.as_ref().unwrap().inner,
f.b4_stride as usize,
);
let diff = rav1d_msac_decode_symbol_adapt8(
&mut ts_c.msac,
&mut ts_c.cdf.m.seg_id[seg_ctx as usize],
SegmentId::COUNT as u8 - 1,
);
let last_active_seg_id_plus1 =
(frame_hdr.segmentation.seg_data.last_active_segid + 1) as u8;
let mut seg_id =
neg_deinterleave(diff as u8, pred_seg_id, last_active_seg_id_plus1);
if seg_id >= last_active_seg_id_plus1 {
seg_id = 0; }
b.seg_id = SegmentId::new(seg_id).unwrap_or_default(); }
if debug_block_info!(f, t.b) {
println!("Post-segid[preskip;{}]: r={}", b.seg_id, ts_c.msac.rng);
}
seg = Some(&frame_hdr.segmentation.seg_data.d[b.seg_id.get()]);
}
} else {
b.seg_id = Default::default();
}
if seg
.map(|seg| seg.globalmv == 0 && seg.r#ref == -1 && seg.skip == 0)
.unwrap_or(true)
&& frame_hdr.skip_mode.enabled != 0
&& cmp::min(bw4, bh4) > 1
{
let smctx = *ta.skip_mode.index(bx4 as usize) + *t.l.skip_mode.index(by4 as usize);
b.skip_mode = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.skip_mode[smctx as usize],
) as u8;
if debug_block_info!(f, t.b) {
println!("Post-skipmode[{}]: r={}", b.skip_mode, ts_c.msac.rng);
}
} else {
b.skip_mode = 0;
}
if b.skip_mode != 0 || seg.map(|seg| seg.skip != 0).unwrap_or(false) {
b.skip = 1;
} else {
let sctx = *ta.skip.index(bx4 as usize) + *t.l.skip.index(by4 as usize);
b.skip =
rav1d_msac_decode_bool_adapt(&mut ts_c.msac, &mut ts_c.cdf.m.skip[sctx as usize]) as u8;
if debug_block_info!(f, t.b) {
println!("Post-skip[{}]: r={}", b.skip, ts_c.msac.rng);
}
}
if frame_hdr.segmentation.enabled != 0
&& frame_hdr.segmentation.update_map != 0
&& frame_hdr.segmentation.seg_data.preskip == 0
{
if b.skip == 0 && frame_hdr.segmentation.temporal != 0 && {
let index = *ta.seg_pred.index(bx4 as usize) + *t.l.seg_pred.index(by4 as usize);
seg_pred = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.seg_pred[index as usize],
);
seg_pred
} {
b.seg_id = f
.prev_segmap
.as_ref()
.map(|prev_segmap| {
get_prev_frame_segid(frame_hdr, t.b, w4, h4, &prev_segmap.inner, f.b4_stride)
})
.unwrap_or_default();
} else {
let (pred_seg_id, seg_ctx) = get_cur_frame_segid(
t.b,
have_top,
have_left,
&f.cur_segmap.as_ref().unwrap().inner,
f.b4_stride as usize,
);
b.seg_id = if b.skip != 0 {
pred_seg_id
} else {
let diff = rav1d_msac_decode_symbol_adapt8(
&mut ts_c.msac,
&mut ts_c.cdf.m.seg_id[seg_ctx as usize],
SegmentId::COUNT as u8 - 1,
);
let last_active_seg_id_plus1 =
(frame_hdr.segmentation.seg_data.last_active_segid + 1) as u8;
let mut seg_id =
neg_deinterleave(diff as u8, pred_seg_id, last_active_seg_id_plus1);
if seg_id >= last_active_seg_id_plus1 {
seg_id = 0; }
SegmentId::new(seg_id).unwrap_or_default() };
}
seg = Some(&frame_hdr.segmentation.seg_data.d[b.seg_id.get()]);
if debug_block_info!(f, t.b) {
println!("Post-segid[postskip;{}]: r={}", b.seg_id, ts_c.msac.rng);
}
}
if b.skip == 0 {
let idx = if seq_hdr.sb128 != 0 {
((t.b.x & 16) >> 4) + ((t.b.y & 16) >> 3)
} else {
0
} as usize;
let cdef_idx = &f.lf.mask[t.lf_mask.unwrap()].cdef_idx;
let cur_idx = t.cur_sb_cdef_idx + idx;
if cdef_idx[cur_idx].get() == -1 {
let v = rav1d_msac_decode_bools(&mut ts_c.msac, frame_hdr.cdef.n_bits) as i8;
cdef_idx[cur_idx].set(v);
if bw4 > 16 {
cdef_idx[cur_idx + 1].set(v)
}
if bh4 > 16 {
cdef_idx[cur_idx + 2].set(v)
}
if bw4 == 32 && bh4 == 32 {
cdef_idx[cur_idx + 3].set(v)
}
if debug_block_info!(f, t.b) {
println!(
"Post-cdef_idx[{}]: r={}",
cdef_idx[t.cur_sb_cdef_idx].get(),
ts_c.msac.rng
);
}
}
}
let not_sb128 = (seq_hdr.sb128 == 0) as c_int;
if t.b.x & (31 >> not_sb128) == 0 && t.b.y & (31 >> not_sb128) == 0 {
let prev_qidx = ts.last_qidx.get();
let have_delta_q = frame_hdr.delta.q.present != 0
&& (bs
!= (if seq_hdr.sb128 != 0 {
BlockSize::Bs128x128
} else {
BlockSize::Bs64x64
})
|| b.skip == 0);
let prev_delta_lf = ts.last_delta_lf.get();
if have_delta_q {
let mut delta_q =
rav1d_msac_decode_symbol_adapt4(&mut ts_c.msac, &mut *ts_c.cdf.m.delta_q, 3)
as c_int;
if delta_q == 3 {
let n_bits = 1 + rav1d_msac_decode_bools(&mut ts_c.msac, 3) as u8;
delta_q =
(rav1d_msac_decode_bools(&mut ts_c.msac, n_bits) + 1 + (1 << n_bits)) as c_int;
}
if delta_q != 0 {
if rav1d_msac_decode_bool_equi(&mut ts_c.msac) {
delta_q = -delta_q;
}
delta_q *= 1 << frame_hdr.delta.q.res_log2;
}
let last_qidx = clip(ts.last_qidx.get() as c_int + delta_q, 1, 255);
ts.last_qidx.set(last_qidx);
if have_delta_q && debug_block_info!(f, t.b) {
println!(
"Post-delta_q[{}->{}]: r={}",
delta_q, last_qidx, ts_c.msac.rng
);
}
if frame_hdr.delta.lf.present != 0 {
let n_lfs = if frame_hdr.delta.lf.multi != 0 {
if f.cur.p.layout != Rav1dPixelLayout::I400 {
4
} else {
2
}
} else {
1
};
let mut last_delta_lf = ts.last_delta_lf.get();
for i in 0..n_lfs as usize {
let delta_lf_index = i + frame_hdr.delta.lf.multi as usize;
let mut delta_lf = rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut ts_c.cdf.m.delta_lf[delta_lf_index],
3,
) as c_int;
if delta_lf == 3 {
let n_bits = 1 + rav1d_msac_decode_bools(&mut ts_c.msac, 3) as u8;
delta_lf = (rav1d_msac_decode_bools(&mut ts_c.msac, n_bits)
+ 1
+ (1 << n_bits)) as c_int;
}
if delta_lf != 0 {
if rav1d_msac_decode_bool_equi(&mut ts_c.msac) {
delta_lf = -delta_lf;
}
delta_lf *= 1 << frame_hdr.delta.lf.res_log2;
}
last_delta_lf[i] = clip(last_delta_lf[i] as c_int + delta_lf, -63, 63);
if have_delta_q && debug_block_info!(f, t.b) {
println!("Post-delta_lf[{}:{}]: r={}", i, delta_lf, ts_c.msac.rng);
}
}
ts.last_delta_lf.set(last_delta_lf);
}
}
let last_qidx = ts.last_qidx.get();
if last_qidx == frame_hdr.quant.yac {
ts.dq.set(TileStateRef::Frame);
} else if last_qidx != prev_qidx {
init_quant_tables(seq_hdr, frame_hdr, last_qidx, &ts.dqmem);
ts.dq.set(TileStateRef::Local);
}
let last_delta_lf = ts.last_delta_lf.get();
if last_delta_lf == [0, 0, 0, 0] {
ts.lflvl.set(TileStateRef::Frame);
} else if last_delta_lf != prev_delta_lf {
rav1d_calc_lf_values(
&mut (*ts.lflvlmem.try_write().unwrap()),
frame_hdr,
&last_delta_lf,
);
ts.lflvl.set(TileStateRef::Local);
}
}
let intra = if b.skip_mode != 0 {
false
} else if frame_hdr.frame_type.is_inter_or_switch() {
if let Some(seg) = seg.filter(|seg| seg.r#ref >= 0 || seg.globalmv != 0) {
seg.r#ref == 0
} else {
let ictx = get_intra_ctx(&ta, &t.l, by4, bx4, have_top, have_left);
let intra = !rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.intra[ictx as usize],
);
if debug_block_info!(f, t.b) {
println!("Post-intra[{}]: r={}", intra, ts_c.msac.rng);
}
intra
}
} else if frame_hdr.allow_intrabc {
let intra = !rav1d_msac_decode_bool_adapt(&mut ts_c.msac, &mut *ts_c.cdf.m.intrabc);
if debug_block_info!(f, t.b) {
println!("Post-intrabcflag[{}]: r={}", intra, ts_c.msac.rng);
}
intra
} else {
true
};
if intra {
let ymode_cdf = if frame_hdr.frame_type.is_inter_or_switch() {
&mut ts_c.cdf.mi.y_mode[dav1d_ymode_size_context[bs as usize] as usize]
} else {
&mut ts_c.cdf.kfym
[dav1d_intra_mode_context[*ta.mode.index(bx4 as usize) as usize] as usize]
[dav1d_intra_mode_context[*t.l.mode.index(by4 as usize) as usize] as usize]
};
let y_mode = rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
ymode_cdf,
N_INTRA_PRED_MODES as u8 - 1,
);
if debug_block_info!(f, t.b) {
println!("Post-ymode[{}]: r={}", y_mode, ts_c.msac.rng);
}
let y_angle = if b_dim[2] + b_dim[3] >= 2 && (VERT_PRED..=VERT_LEFT_PRED).contains(&y_mode)
{
let acdf = &mut ts_c.cdf.m.angle_delta[y_mode as usize - VERT_PRED as usize];
let angle = rav1d_msac_decode_symbol_adapt8(&mut ts_c.msac, acdf, 6);
angle as i8 - 3
} else {
0
};
let uv_mode;
let uv_angle;
let cfl_alpha;
if has_chroma {
let cfl_allowed = if frame_hdr.segmentation.lossless[b.seg_id.get()] {
cbw4 == 1 && cbh4 == 1
} else {
(cfl_allowed_mask & (1 << bs as u8)) != 0
};
let uvmode_cdf = &mut ts_c.cdf.m.uv_mode[cfl_allowed as usize][y_mode as usize];
uv_mode = rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
uvmode_cdf,
(N_UV_INTRA_PRED_MODES as u8) - 1 - (!cfl_allowed as u8),
);
if debug_block_info!(f, t.b) {
println!("Post-uvmode[{}]: r={}", uv_mode, ts_c.msac.rng);
}
if uv_mode == CFL_PRED {
let sign =
rav1d_msac_decode_symbol_adapt8(&mut ts_c.msac, &mut *ts_c.cdf.m.cfl_sign, 7)
+ 1;
let sign_u = (sign as u16 * 0x56 >> 8) as u8;
let sign_v = sign - sign_u * 3;
assert!(sign_u == sign / 3);
let sign_uv = [sign_u, sign_v];
cfl_alpha = array::from_fn(|i| {
if sign_uv[i] == 0 {
return 0;
}
let ctx = (sign_uv[i] == 2) as usize * 3 + sign_uv[1 - i] as usize;
let cfl_alpha = rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
&mut ts_c.cdf.m.cfl_alpha[ctx],
15,
) as i8
+ 1;
if sign_uv[i] == 1 {
-cfl_alpha
} else {
cfl_alpha
}
});
if debug_block_info!(f, t.b) {
println!(
"Post-uvalphas[{}/{}]: r={}",
cfl_alpha[0], cfl_alpha[1], ts_c.msac.rng,
);
}
uv_angle = 0;
} else if b_dim[2] + b_dim[3] >= 2 && (VERT_PRED..=VERT_LEFT_PRED).contains(&uv_mode) {
let acdf = &mut ts_c.cdf.m.angle_delta[uv_mode as usize - VERT_PRED as usize];
let angle = rav1d_msac_decode_symbol_adapt8(&mut ts_c.msac, acdf, 6);
uv_angle = angle as i8 - 3;
cfl_alpha = Default::default();
} else {
uv_angle = 0;
cfl_alpha = Default::default();
}
} else {
uv_mode = Default::default();
uv_angle = Default::default();
cfl_alpha = Default::default();
}
let mut pal_sz = [0; 2];
if frame_hdr.allow_screen_content_tools && cmp::max(bw4, bh4) <= 16 && bw4 + bh4 >= 4 {
let sz_ctx = b_dim[2] + b_dim[3] - 2;
if y_mode == DC_PRED {
let pal_ctx = (*ta.pal_sz.index(bx4 as usize) > 0) as usize
+ (*t.l.pal_sz.index(by4 as usize) > 0) as usize;
let use_y_pal = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.m.pal_y[sz_ctx as usize][pal_ctx],
);
if debug_block_info!(f, t.b) {
println!("Post-y_pal[{}]: r={}", use_y_pal, ts_c.msac.rng);
}
if use_y_pal {
pal_sz[0] = (bd_fn.read_pal_plane)(
t,
f,
ts_c,
false,
sz_ctx,
bx4 as usize,
by4 as usize,
);
}
}
if has_chroma && uv_mode == DC_PRED {
let pal_ctx = pal_sz[0] > 0;
let use_uv_pal = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.m.pal_uv[pal_ctx as usize],
);
if debug_block_info!(f, t.b) {
println!("Post-uv_pal[{}]: r={}", use_uv_pal, ts_c.msac.rng);
}
if use_uv_pal {
pal_sz[1] = (bd_fn.read_pal_uv)(t, f, ts_c, sz_ctx, bx4 as usize, by4 as usize);
}
}
}
let pal_sz = pal_sz;
let mut y_mode = y_mode;
let mut y_angle = y_angle;
let seq_hdr = f.seq_hdr();
if y_mode == DC_PRED
&& pal_sz[0] == 0
&& cmp::max(b_dim[2], b_dim[3]) <= 3
&& seq_hdr.filter_intra != 0
{
let is_filter = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.m.use_filter_intra[bs as usize],
);
if is_filter {
y_mode = FILTER_PRED as u8;
y_angle = rav1d_msac_decode_symbol_adapt8(
&mut ts_c.msac,
&mut *ts_c.cdf.m.filter_intra,
4,
) as i8;
}
if debug_block_info!(f, t.b) {
println!(
"Post-filterintramode[{}/{}]: r={}",
y_mode, y_angle, ts_c.msac.rng,
);
}
}
let y_mode = y_mode;
let y_angle = y_angle;
if pal_sz[0] != 0 {
let scratch = t.scratch.inter_intra_mut();
let pal_idx = if t.frame_thread.pass != 0 {
let p = t.frame_thread.pass & 1;
let frame_thread = &ts.frame_thread[p as usize];
let len = (bw4 * bh4 * 8) as u32;
let pal_idx = frame_thread.pal_idx.get_update(|i| i + len);
&mut *f
.frame_thread
.pal_idx
.index_mut((pal_idx as usize.., ..len as usize))
} else {
&mut scratch.pal_idx_y
};
read_pal_indices(
ts_c,
&c.dsp.pal,
scratch.levels_pal.pal_mut(),
&mut scratch.pal_idx_uv,
Some(pal_idx),
pal_sz[0],
false,
w4,
h4,
bw4,
bh4,
);
if debug_block_info!(f, t.b) {
println!("Post-y-pal-indices: r={}", ts_c.msac.rng);
}
}
if has_chroma && pal_sz[1] != 0 {
let scratch = t.scratch.inter_intra_mut();
let mut pal_idx = if t.frame_thread.pass != 0 {
let p = t.frame_thread.pass & 1;
let frame_thread = &ts.frame_thread[p as usize];
let len = (cbw4 * cbh4 * 8) as u32;
let pal_idx = frame_thread.pal_idx.get_update(|i| i + len);
Some(
f.frame_thread
.pal_idx
.index_mut((pal_idx as usize.., ..len as usize)),
)
} else {
None
};
let pal_idx = pal_idx.as_deref_mut();
read_pal_indices(
ts_c,
&c.dsp.pal,
scratch.levels_pal.pal_mut(),
&mut scratch.pal_idx_uv,
pal_idx,
pal_sz[1],
true,
cw4,
ch4,
cbw4,
cbh4,
);
if debug_block_info!(f, t.b) {
println!("Post-uv-pal-indices: r={}", ts_c.msac.rng);
}
}
let frame_hdr = f.frame_hdr();
let tx = if frame_hdr.segmentation.lossless[b.seg_id.get()] {
b.uvtx = TxfmSize::S4x4;
b.uvtx
} else {
let mut tx = dav1d_max_txfm_size_for_bs[bs as usize][0];
b.uvtx = dav1d_max_txfm_size_for_bs[bs as usize][f.cur.p.layout as usize];
let mut t_dim = &dav1d_txfm_dimensions[tx as usize];
if frame_hdr.txfm_mode == Rav1dTxfmMode::Switchable && t_dim.max > TxfmSize::S4x4 as _ {
let tctx = get_tx_ctx(ta, &t.l, t_dim, by4, bx4);
let tx_cdf = &mut ts_c.cdf.m.txsz[(t_dim.max - 1) as usize][tctx as usize];
let depth =
rav1d_msac_decode_symbol_adapt4(&mut ts_c.msac, tx_cdf, cmp::min(t_dim.max, 2))
as c_int;
for _ in 0..depth {
tx = t_dim.sub;
t_dim = &dav1d_txfm_dimensions[tx as usize];
}
}
if debug_block_info!(f, t.b) {
println!("Post-tx[{:?}]: r={}", tx, ts_c.msac.rng);
}
tx
};
let t_dim = &dav1d_txfm_dimensions[tx as usize];
let intra = Av1BlockIntra {
y_mode,
uv_mode,
tx,
pal_sz,
y_angle,
uv_angle,
cfl_alpha,
};
b.ii = Av1BlockIntraInter::Intra(intra);
if t.frame_thread.pass == 1 {
(bd_fn.read_coef_blocks)(f, t, ts_c, bs, b);
} else {
(bd_fn.recon_b_intra)(f, t, Some(ts_c), bs, intra_edge_flags, b, &intra);
}
if f.frame_hdr().loopfilter.level_y != [0, 0] {
let lflvl = match ts.lflvl.get() {
TileStateRef::Frame => &f.lf.lvl,
TileStateRef::Local => &*ts.lflvlmem.try_read().unwrap(),
};
let mut a_uv_guard;
let mut l_uv_guard;
rav1d_create_lf_mask_intra(
&f.lf.mask[t.lf_mask.unwrap()],
&f.lf.level,
f.b4_stride,
&lflvl[b.seg_id.get()],
t.b,
f.w4,
f.h4,
bs,
tx,
b.uvtx,
f.cur.p.layout,
&mut ta.tx_lpf_y.index_mut((bx4 as usize.., ..bw4 as usize)),
&mut t.l.tx_lpf_y.index_mut((by4 as usize.., ..bh4 as usize)),
if has_chroma {
a_uv_guard = ta.tx_lpf_uv.index_mut((cbx4 as usize.., ..cbw4 as usize));
l_uv_guard = t.l.tx_lpf_uv.index_mut((cby4 as usize.., ..cbh4 as usize));
Some((&mut a_uv_guard, &mut l_uv_guard))
} else {
None
},
);
}
let y_mode_nofilt = if y_mode == FILTER_PRED {
DC_PRED
} else {
y_mode
};
let is_inter_or_switch = f.frame_hdr().frame_type.is_inter_or_switch();
CaseSet::<32, false>::many(
[(&t.l, t_dim.lh, 1), (ta, t_dim.lw, 0)],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, (dir, lw_lh, dir_index)| {
case.set_disjoint(&dir.tx_intra, lw_lh as i8);
case.set_disjoint(&dir.tx, TxfmSize::from_repr(lw_lh as _).unwrap());
case.set_disjoint(&dir.mode, y_mode_nofilt);
case.set_disjoint(&dir.pal_sz, pal_sz[0]);
case.set_disjoint(&dir.seg_pred, seg_pred.into());
case.set_disjoint(&dir.skip_mode, 0);
case.set_disjoint(&dir.intra, 1);
case.set_disjoint(&dir.skip, b.skip);
case.set(
&mut t.pal_sz_uv[dir_index],
if has_chroma { pal_sz[1] } else { 0 },
);
if is_inter_or_switch {
case.set_disjoint(&dir.comp_type, None);
case.set_disjoint(&dir.r#ref[0], -1);
case.set_disjoint(&dir.r#ref[1], -1);
case.set_disjoint(&dir.filter[0], Rav1dFilterMode::N_SWITCHABLE_FILTERS);
case.set_disjoint(&dir.filter[1], Rav1dFilterMode::N_SWITCHABLE_FILTERS);
}
},
);
if pal_sz[0] != 0 {
(bd_fn.copy_pal_block_y)(t, f, bx4 as usize, by4 as usize, bw4 as usize, bh4 as usize);
}
if has_chroma {
CaseSet::<32, false>::many(
[&t.l, ta],
[cbh4 as usize, cbw4 as usize],
[cby4 as usize, cbx4 as usize],
|case, dir| {
case.set_disjoint(&dir.uvmode, uv_mode);
},
);
if pal_sz[1] != 0 {
(bd_fn.copy_pal_block_uv)(
t,
f,
bx4 as usize,
by4 as usize,
bw4 as usize,
bh4 as usize,
);
}
}
let frame_hdr = f.frame_hdr();
if frame_hdr.frame_type.is_inter_or_switch() || frame_hdr.allow_intrabc {
splat_intraref(c, t, &f.rf, bs, bw4 as usize, bh4 as usize);
}
} else if frame_hdr.frame_type.is_key_or_intra() {
let mut mvstack = [Default::default(); 8];
let mut n_mvs = 0;
let mut ctx = 0;
rav1d_refmvs_find(
&t.rt,
&f.rf,
&mut mvstack,
&mut n_mvs,
&mut ctx,
[0, -1].into(),
bs,
intra_edge_flags,
t.b.y,
t.b.x,
frame_hdr,
);
let mut r#ref = if mvstack[0].mv.mv[0] != Mv::ZERO {
mvstack[0].mv.mv[0]
} else if mvstack[1].mv.mv[0] != Mv::ZERO {
mvstack[1].mv.mv[0]
} else if t.b.y - (16 << seq_hdr.sb128) < ts.tiling.row_start {
Mv {
y: 0,
x: (-(512 << seq_hdr.sb128) - 2048) as i16,
}
} else {
Mv {
y: -(512 << seq_hdr.sb128) as i16,
x: 0,
}
};
read_mv_residual(ts_c, &mut r#ref, -1);
let mut border_left = ts.tiling.col_start * 4;
let mut border_top = ts.tiling.row_start * 4;
if has_chroma {
if bw4 < 2 && ss_hor != 0 {
border_left += 4;
}
if bh4 < 2 && ss_ver != 0 {
border_top += 4;
}
}
let mut src_left = t.b.x * 4 + (r#ref.x as c_int >> 3);
let mut src_top = t.b.y * 4 + (r#ref.y as c_int >> 3);
let mut src_right = src_left + bw4 * 4;
let mut src_bottom = src_top + bh4 * 4;
let border_right = (ts.tiling.col_end + (bw4 - 1) & !(bw4 - 1)) * 4;
if src_left < border_left {
src_right += border_left - src_left;
src_left += border_left - src_left;
} else if src_right > border_right {
src_left -= src_right - border_right;
src_right -= src_right - border_right;
}
if src_top < border_top {
src_bottom += border_top - src_top;
src_top += border_top - src_top;
}
let sbx = t.b.x >> 4 + seq_hdr.sb128 << 6 + seq_hdr.sb128;
let sby = t.b.y >> 4 + seq_hdr.sb128 << 6 + seq_hdr.sb128;
let sb_size = 1 << 6 + seq_hdr.sb128;
if src_bottom > sby && src_right > sbx {
if src_top - border_top >= src_bottom - sby {
src_top -= src_bottom - sby;
src_bottom -= src_bottom - sby;
} else if src_left - border_left >= src_right - sbx {
src_left -= src_right - sbx;
src_right -= src_right - sbx;
}
}
if src_bottom > sby + sb_size {
src_top -= src_bottom - (sby + sb_size);
src_bottom -= src_bottom - (sby + sb_size);
}
if src_bottom > sby && src_right > sbx {
return Err(());
}
let prev_ref = r#ref;
let r#ref = Mv {
x: ((src_left - t.b.x * 4) * 8) as i16,
y: ((src_top - t.b.y * 4) * 8) as i16,
};
if debug_block_info!(f, t.b) {
println!(
"Post-dmv[{}/{},ref={}/{}|{}/{}]: r={}",
r#ref.y,
r#ref.x,
prev_ref.y,
prev_ref.x,
mvstack[0].mv.mv[0].y,
mvstack[0].mv.mv[0].x,
ts_c.msac.rng,
);
}
let VarTx {
uvtx,
max_ytx,
tx_split0,
tx_split1,
} = read_vartx_tree(t, f, ts_c, b, bs, bx4, by4);
let filter2d = if t.frame_thread.pass == 1 {
Filter2d::Bilinear
} else {
Default::default()
};
b.uvtx = uvtx;
let inter = Av1BlockInter {
nd: Av1BlockInter1d {
mv: [r#ref, Default::default()],
..Default::default()
}
.into(),
comp_type: Default::default(),
inter_mode: Default::default(),
motion_mode: Default::default(),
drl_idx: Default::default(),
r#ref: Default::default(),
max_ytx,
filter2d,
interintra_type: Default::default(),
tx_split0,
tx_split1,
};
b.ii = Av1BlockIntraInter::Inter(inter);
if t.frame_thread.pass == 1 {
(bd_fn.read_coef_blocks)(f, t, ts_c, bs, b);
} else {
(bd_fn.recon_b_inter)(f, t, Some(ts_c), bs, b, &inter)?;
}
splat_intrabc_mv(c, t, &f.rf, bs, r#ref, bw4 as usize, bh4 as usize);
CaseSet::<32, false>::many(
[(&t.l, 1), (ta, 0)],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, (dir, dir_index)| {
case.set_disjoint(&dir.tx_intra, b_dim[2 + dir_index] as i8);
case.set_disjoint(&dir.mode, DC_PRED);
case.set_disjoint(&dir.pal_sz, 0);
case.set(&mut t.pal_sz_uv[dir_index], 0);
case.set_disjoint(&dir.seg_pred, seg_pred.into());
case.set_disjoint(&dir.skip_mode, 0);
case.set_disjoint(&dir.intra, 0);
case.set_disjoint(&dir.skip, b.skip);
},
);
if has_chroma {
CaseSet::<32, false>::many(
[&t.l, ta],
[cbh4 as usize, cbw4 as usize],
[cby4 as usize, cbx4 as usize],
|case, dir| {
case.set_disjoint(&dir.uvmode, DC_PRED);
},
);
}
} else {
let mv_prec = || frame_hdr.hp as i32 - frame_hdr.force_integer_mv as i32;
let mut has_subpel_filter;
let is_comp = if b.skip_mode != 0 {
true
} else if seg
.map(|seg| seg.r#ref == -1 && seg.globalmv == 0 && seg.skip == 0)
.unwrap_or(true)
&& frame_hdr.switchable_comp_refs != 0
&& cmp::min(bw4, bh4) > 1
{
let ctx = get_comp_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let is_comp =
rav1d_msac_decode_bool_adapt(&mut ts_c.msac, &mut ts_c.cdf.mi.comp[ctx as usize]);
if debug_block_info!(f, t.b) {
println!("Post-compflag[{}]: r={}", is_comp, ts_c.msac.rng);
}
is_comp
} else {
false
};
struct Inter {
nd: Av1BlockInterNd,
comp_type: Option<CompInterType>,
inter_mode: u8,
motion_mode: MotionMode,
drl_idx: DrlProximity,
r#ref: [i8; 2],
interintra_type: Option<InterIntraType>,
}
let Inter {
nd,
comp_type,
inter_mode,
motion_mode,
drl_idx,
r#ref,
interintra_type,
} = if b.skip_mode != 0 {
let r#ref = [
frame_hdr.skip_mode.refs[0] as i8,
frame_hdr.skip_mode.refs[1] as i8,
];
let comp_type = CompInterType::Avg;
let inter_mode = NEARESTMV_NEARESTMV;
let drl_idx = DrlProximity::Nearest;
has_subpel_filter = false;
let mut mvstack = [Default::default(); 8];
let mut n_mvs = 0;
let mut ctx = 0;
rav1d_refmvs_find(
&t.rt,
&f.rf,
&mut mvstack,
&mut n_mvs,
&mut ctx,
[r#ref[0] + 1, r#ref[1] + 1].into(),
bs,
intra_edge_flags,
t.b.y,
t.b.x,
frame_hdr,
);
let mut mv1d = mvstack[0].mv.mv;
fix_mv_precision(frame_hdr, &mut mv1d[0]);
fix_mv_precision(frame_hdr, &mut mv1d[1]);
let mv1d = mv1d;
if debug_block_info!(f, t.b) {
println!(
"Post-skipmodeblock[mv=1:y={},x={},2:y={},x={},refs={}+{}",
mv1d[0].y, mv1d[0].x, mv1d[1].y, mv1d[1].x, r#ref[0], r#ref[1],
);
}
Inter {
nd: Av1BlockInter1d {
mv: mv1d,
..Default::default()
}
.into(),
comp_type: Some(comp_type),
inter_mode,
motion_mode: Default::default(),
drl_idx,
r#ref,
interintra_type: None,
}
} else if is_comp {
let dir_ctx = get_comp_dir_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let r#ref = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_dir[dir_ctx as usize],
) {
let ctx1 = av1_get_fwd_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let ref0 = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_fwd_ref[0][ctx1 as usize],
) {
let ctx2 = av1_get_fwd_ref_2_ctx(ta, &t.l, by4, bx4, have_top, have_left);
2 + rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_fwd_ref[2][ctx2 as usize],
) as i8
} else {
let ctx2 = av1_get_fwd_ref_1_ctx(ta, &t.l, by4, bx4, have_top, have_left);
rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_fwd_ref[1][ctx2 as usize],
) as i8
};
let ctx3 = av1_get_bwd_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let ref1 = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_bwd_ref[0][ctx3 as usize],
) {
6
} else {
let ctx4 = av1_get_bwd_ref_1_ctx(ta, &t.l, by4, bx4, have_top, have_left);
4 + rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_bwd_ref[1][ctx4 as usize],
) as i8
};
[ref0, ref1]
} else {
let uctx_p = av1_get_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_uni_ref[0][uctx_p as usize],
) {
[4, 6]
} else {
let uctx_p1 = av1_get_uni_p1_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let mut r#ref = [
0,
1 + rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_uni_ref[1][uctx_p1 as usize],
) as i8,
];
if r#ref[1] == 2 {
let uctx_p2 =
av1_get_fwd_ref_2_ctx(ta, &t.l, by4, bx4, have_top, have_left);
r#ref[1] += rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_uni_ref[2][uctx_p2 as usize],
) as i8;
}
r#ref
}
};
if debug_block_info!(f, t.b) {
println!("Post-refs[{}/{}]: r={}", r#ref[0], r#ref[1], ts_c.msac.rng,);
}
let mut mvstack = [Default::default(); 8];
let mut n_mvs = 0;
let mut ctx = 0;
rav1d_refmvs_find(
&t.rt,
&f.rf,
&mut mvstack,
&mut n_mvs,
&mut ctx,
[r#ref[0] + 1, r#ref[1] + 1].into(),
bs,
intra_edge_flags,
t.b.y,
t.b.x,
frame_hdr,
);
let inter_mode = rav1d_msac_decode_symbol_adapt8(
&mut ts_c.msac,
&mut ts_c.cdf.mi.comp_inter_mode[ctx as usize],
N_COMP_INTER_PRED_MODES as u8 - 1,
);
if debug_block_info!(f, t.b) {
println!(
"Post-compintermode[{},ctx={},n_mvs={}]: r={}",
inter_mode, ctx, n_mvs, ts_c.msac.rng,
);
}
let im = &dav1d_comp_inter_pred_modes[inter_mode as usize];
let mut drl_idx = DrlProximity::Nearest;
if inter_mode == NEWMV_NEWMV {
if n_mvs > 1 {
let drl_ctx_v1 = get_drl_context(&mvstack, 0);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v1 as usize],
) {
drl_idx = DrlProximity::Nearer;
if n_mvs > 2 {
let drl_ctx_v2 = get_drl_context(&mvstack, 1);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v2 as usize],
) {
drl_idx = DrlProximity::Near;
}
}
}
if debug_block_info!(f, t.b) {
println!(
"Post-drlidx[{:?},n_mvs={}]: r={}",
drl_idx, n_mvs, ts_c.msac.rng,
);
}
}
} else if im[0] == NEARMV || im[1] == NEARMV {
drl_idx = DrlProximity::Nearer;
if n_mvs > 2 {
let drl_ctx_v2 = get_drl_context(&mvstack, 1);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v2 as usize],
) {
drl_idx = DrlProximity::Near;
if n_mvs > 3 {
let drl_ctx_v3 = get_drl_context(&mvstack, 2);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v3 as usize],
) {
drl_idx = DrlProximity::Nearish;
}
}
}
if debug_block_info!(f, t.b) {
println!(
"Post-drlidx[{:?},n_mvs={}]: r={}",
drl_idx, n_mvs, ts_c.msac.rng,
);
}
}
}
let drl_idx = drl_idx;
has_subpel_filter = cmp::min(bw4, bh4) == 1 || inter_mode != GLOBALMV_GLOBALMV;
let mv1d = array::from_fn(|i| match im[i] {
NEARMV | NEARESTMV => {
let mut mv1d = mvstack[drl_idx as usize].mv.mv[i];
fix_mv_precision(frame_hdr, &mut mv1d);
mv1d
}
GLOBALMV => {
has_subpel_filter |= frame_hdr.gmv[r#ref[i] as usize].r#type
== Rav1dWarpedMotionType::Translation;
get_gmv_2d(
&frame_hdr.gmv[r#ref[i] as usize],
t.b.x,
t.b.y,
bw4,
bh4,
frame_hdr,
)
}
NEWMV => {
let mut mv1d = mvstack[drl_idx as usize].mv.mv[i];
read_mv_residual(ts_c, &mut mv1d, mv_prec());
mv1d
}
_ => unreachable!(),
});
if debug_block_info!(f, t.b) {
println!(
"Post-residual_mv[1:y={},x={},2:y={},x={}]: r={}",
mv1d[0].y, mv1d[0].x, mv1d[1].y, mv1d[1].x, ts_c.msac.rng,
);
}
let is_segwedge;
if seq_hdr.masked_compound != 0 {
let mask_ctx = get_mask_comp_ctx(ta, &t.l, by4, bx4);
is_segwedge = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.mask_comp[mask_ctx as usize],
);
if debug_block_info!(f, t.b) {
println!(
"Post-segwedge_vs_jntavg[{},ctx={}]: r={}",
is_segwedge, mask_ctx, ts_c.msac.rng,
);
}
} else {
is_segwedge = false;
}
let comp_type;
let mask_sign;
let mut wedge_idx = Default::default();
if !is_segwedge {
if seq_hdr.jnt_comp != 0 {
let [ref0poc, ref1poc] = r#ref.map(|r#ref| {
f.refp[r#ref as usize]
.p
.frame_hdr
.as_ref()
.unwrap()
.frame_offset as c_uint
});
let jnt_ctx = get_jnt_comp_ctx(
seq_hdr.order_hint_n_bits,
f.cur.frame_hdr.as_ref().unwrap().frame_offset as c_uint,
ref0poc,
ref1poc,
ta,
&t.l,
by4,
bx4,
);
comp_type = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.jnt_comp[jnt_ctx as usize],
) {
CompInterType::Avg
} else {
CompInterType::WeightedAvg
};
if debug_block_info!(f, t.b) {
let a = ta;
let l = &t.l;
println!(
"Post-jnt_comp[{},ctx={}[ac:{:?},ar:{},lc:{:?},lr:{}]]: r={}",
comp_type == CompInterType::Avg,
jnt_ctx,
*a.comp_type.index(bx4 as usize),
*a.r#ref[0].index(bx4 as usize),
*l.comp_type.index(by4 as usize),
*l.r#ref[0].index(by4 as usize),
ts_c.msac.rng,
);
}
} else {
comp_type = CompInterType::Avg;
}
mask_sign = Default::default();
} else {
comp_type = if wedge_allowed_mask & (1 << bs as u8) != 0 {
let ctx = dav1d_wedge_ctx_lut[bs as usize] as usize;
let comp_type = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.wedge_comp[ctx],
) {
CompInterType::Seg
} else {
CompInterType::Wedge
};
if comp_type == CompInterType::Wedge {
wedge_idx = rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
&mut ts_c.cdf.mi.wedge_idx[ctx],
15,
) as u8;
}
comp_type
} else {
CompInterType::Seg
};
mask_sign = rav1d_msac_decode_bool_equi(&mut ts_c.msac);
if debug_block_info!(f, t.b) {
println!(
"Post-seg/wedge[{},wedge_idx={},sign={}]: r={}",
comp_type == CompInterType::Wedge,
wedge_idx,
mask_sign,
ts_c.msac.rng,
);
}
}
let wedge_idx = wedge_idx;
Inter {
nd: Av1BlockInter1d {
mv: mv1d,
wedge_idx,
mask_sign: mask_sign as u8,
..Default::default()
}
.into(),
comp_type: Some(comp_type),
inter_mode,
motion_mode: Default::default(),
drl_idx,
r#ref,
interintra_type: None,
}
} else {
let ref0 = if let Some(seg) = seg.filter(|seg| seg.r#ref > 0) {
seg.r#ref as i8 - 1
} else if seg
.filter(|seg| seg.globalmv != 0 || seg.skip != 0)
.is_some()
{
0
} else {
let ctx1 = av1_get_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
let ref0 = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[0][ctx1 as usize],
) {
let ctx2 = av1_get_bwd_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[1][ctx2 as usize],
) {
6
} else {
let ctx3 = av1_get_bwd_ref_1_ctx(ta, &t.l, by4, bx4, have_top, have_left);
4 + rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[5][ctx3 as usize],
) as i8
}
} else {
let ctx2 = av1_get_fwd_ref_ctx(ta, &t.l, by4, bx4, have_top, have_left);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[2][ctx2 as usize],
) {
let ctx3 = av1_get_fwd_ref_2_ctx(ta, &t.l, by4, bx4, have_top, have_left);
2 + rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[4][ctx3 as usize],
) as i8
} else {
let ctx3 = av1_get_fwd_ref_1_ctx(ta, &t.l, by4, bx4, have_top, have_left);
rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.r#ref[3][ctx3 as usize],
) as i8
}
};
if debug_block_info!(f, t.b) {
println!("Post-ref[{}]: r={}", ref0, ts_c.msac.rng);
}
ref0
};
let r#ref = [ref0, -1];
let mut mvstack = [Default::default(); 8];
let mut n_mvs = 0;
let mut ctx = 0;
rav1d_refmvs_find(
&t.rt,
&f.rf,
&mut mvstack,
&mut n_mvs,
&mut ctx,
RefMvsRefPair {
r#ref: [r#ref[0] + 1, -1],
},
bs,
intra_edge_flags,
t.b.y,
t.b.x,
frame_hdr,
);
let inter_mode;
let mut mv1d0;
let mut drl_idx;
if seg
.map(|seg| seg.skip != 0 || seg.globalmv != 0)
.unwrap_or(false)
|| rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.newmv_mode[(ctx & 7) as usize],
)
{
if seg
.map(|seg| seg.skip != 0 || seg.globalmv != 0)
.unwrap_or(false)
|| !rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.globalmv_mode[(ctx >> 3 & 1) as usize],
)
{
inter_mode = GLOBALMV;
mv1d0 = get_gmv_2d(
&frame_hdr.gmv[r#ref[0] as usize],
t.b.x,
t.b.y,
bw4,
bh4,
frame_hdr,
);
has_subpel_filter = cmp::min(bw4, bh4) == 1
|| frame_hdr.gmv[r#ref[0] as usize].r#type
== Rav1dWarpedMotionType::Translation;
drl_idx = Default::default();
} else {
has_subpel_filter = true;
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.refmv_mode[(ctx >> 4 & 15) as usize],
) {
inter_mode = NEARMV;
drl_idx = DrlProximity::Nearer;
if n_mvs > 2 {
let drl_ctx_v2 = get_drl_context(&mvstack, 1);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v2 as usize],
) {
drl_idx = DrlProximity::Near;
if n_mvs > 3 {
let drl_ctx_v3 = get_drl_context(&mvstack, 2);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v3 as usize],
) {
drl_idx = DrlProximity::Nearish;
}
}
}
}
} else {
inter_mode = NEARESTMV;
drl_idx = DrlProximity::Nearest;
}
mv1d0 = mvstack[drl_idx as usize].mv.mv[0];
if drl_idx < DrlProximity::Near {
fix_mv_precision(frame_hdr, &mut mv1d0);
}
}
if debug_block_info!(f, t.b) {
println!(
"Post-intermode[{},drl={:?},mv=y:{},x:{},n_mvs={}]: r={}",
inter_mode, drl_idx, mv1d0.y, mv1d0.x, n_mvs, ts_c.msac.rng,
);
}
} else {
has_subpel_filter = true;
inter_mode = NEWMV;
drl_idx = DrlProximity::Nearest;
if n_mvs > 1 {
let drl_ctx_v1 = get_drl_context(&mvstack, 0);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v1 as usize],
) {
drl_idx = DrlProximity::Nearer;
if n_mvs > 2 {
let drl_ctx_v2 = get_drl_context(&mvstack, 1);
if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.drl_bit[drl_ctx_v2 as usize],
) {
drl_idx = DrlProximity::Near;
}
}
}
}
if n_mvs > 1 {
mv1d0 = mvstack[drl_idx as usize].mv.mv[0];
} else {
assert_eq!(drl_idx, DrlProximity::Nearest);
mv1d0 = mvstack[0].mv.mv[0];
fix_mv_precision(frame_hdr, &mut mv1d0);
}
if debug_block_info!(f, t.b) {
println!(
"Post-intermode[{},drl={:?}]: r={}",
inter_mode, drl_idx, ts_c.msac.rng,
);
}
read_mv_residual(ts_c, &mut mv1d0, mv_prec());
if debug_block_info!(f, t.b) {
println!(
"Post-residualmv[mv=y:{},x:{}]: r={}",
mv1d0.y, mv1d0.x, ts_c.msac.rng,
);
}
}
let drl_idx = drl_idx;
let mv1d0 = mv1d0;
let interintra_mode;
let interintra_type;
let mut wedge_idx = Default::default();
let ii_sz_grp = dav1d_ymode_size_context[bs as usize] as c_int;
if seq_hdr.inter_intra != 0
&& interintra_allowed_mask & (1 << bs as u8) != 0
&& rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.interintra[ii_sz_grp as usize],
)
{
interintra_mode = InterIntraPredMode::from_repr(rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut ts_c.cdf.mi.interintra_mode[ii_sz_grp as usize],
InterIntraPredMode::COUNT as u8 - 1,
) as usize)
.expect("valid variant");
let wedge_ctx = dav1d_wedge_ctx_lut[bs as usize] as c_int;
let ii_type = if rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
&mut ts_c.cdf.mi.interintra_wedge[wedge_ctx as usize],
) {
InterIntraType::Wedge
} else {
InterIntraType::Blend
};
interintra_type = Some(ii_type);
if ii_type == InterIntraType::Wedge {
wedge_idx = rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
&mut ts_c.cdf.mi.wedge_idx[wedge_ctx as usize],
15,
) as u8;
}
} else {
interintra_mode = Default::default();
interintra_type = None;
}
let wedge_idx = wedge_idx;
if debug_block_info!(f, t.b)
&& seq_hdr.inter_intra != 0
&& interintra_allowed_mask & (1 << bs as u8) != 0
{
println!(
"Post-interintra[t={:?},m={:?},w={}]: r={}",
interintra_type, interintra_mode, wedge_idx, ts_c.msac.rng,
);
}
let motion_mode;
let mut matrix = None;
if frame_hdr.switchable_motion_mode != 0
&& interintra_type.is_none()
&& cmp::min(bw4, bh4) >= 2
&& !(!frame_hdr.force_integer_mv
&& inter_mode == GLOBALMV
&& frame_hdr.gmv[r#ref[0] as usize].r#type > Rav1dWarpedMotionType::Translation)
&& (have_left && findoddzero(&t.l.intra.index(by4 as usize..(by4 + h4) as usize))
|| have_top && findoddzero(&ta.intra.index(bx4 as usize..(bx4 + w4) as usize)))
{
let mut mask = [0, 0];
find_matching_ref(
f,
t,
intra_edge_flags,
bw4,
bh4,
w4,
h4,
have_left,
have_top,
r#ref[0],
&mut mask,
);
let allow_warp = (f.svc[r#ref[0] as usize][0].scale == 0
&& !frame_hdr.force_integer_mv
&& frame_hdr.warp_motion != 0
&& mask[0] | mask[1] != 0) as c_int;
motion_mode = MotionMode::from_repr(if allow_warp != 0 {
rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut ts_c.cdf.mi.motion_mode[bs as usize],
2,
) as usize
} else {
rav1d_msac_decode_bool_adapt(&mut ts_c.msac, &mut ts_c.cdf.mi.obmc[bs as usize])
as usize
})
.expect("valid variant");
if motion_mode == MotionMode::Warp {
has_subpel_filter = false;
t.warpmv = derive_warpmv(&f.rf.r, t, bw4, bh4, &mask, mv1d0, t.warpmv.clone());
if debug_block_info!(f, t.b) {
println!(
"[ {} {} {}\n {} {} {} ]\n\
alpha={}, beta={}, gamma={}, deta={}, mv=y:{},x:{}",
SignAbs(t.warpmv.matrix[0]),
SignAbs(t.warpmv.matrix[1]),
SignAbs(t.warpmv.matrix[2]),
SignAbs(t.warpmv.matrix[3]),
SignAbs(t.warpmv.matrix[4]),
SignAbs(t.warpmv.matrix[5]),
SignAbs(t.warpmv.alpha().into()),
SignAbs(t.warpmv.beta().into()),
SignAbs(t.warpmv.gamma().into()),
SignAbs(t.warpmv.delta().into()),
mv1d0.y,
mv1d0.x,
);
}
if t.frame_thread.pass != 0 {
matrix = Some(if t.warpmv.r#type == Rav1dWarpedMotionType::Affine {
[
t.warpmv.matrix[2] - 0x10000,
t.warpmv.matrix[3],
t.warpmv.matrix[4],
t.warpmv.matrix[5] - 0x10000,
]
.map(|coef| {
let coef = coef as i16;
debug_assert!(coef < (1 << 13));
debug_assert!(coef >= -(1 << 13));
coef
})
} else {
[i16::MIN, 0, 0, 0]
});
}
}
if debug_block_info!(f, t.b) {
println!(
"Post-motionmode[{:?}]: r={} [mask: 0x{:x}/0x{:x}]",
motion_mode, ts_c.msac.rng, mask[0], mask[1],
);
}
} else {
motion_mode = MotionMode::Translation;
}
let matrix = matrix;
Inter {
nd: match matrix {
None => Av1BlockInter1d {
mv: [mv1d0, Default::default()],
wedge_idx,
interintra_mode: interintra_mode.into(),
..Default::default()
}
.into(),
Some(matrix) => Av1BlockInter2d {
mv2d: mv1d0,
matrix,
}
.into(),
},
comp_type: None,
inter_mode,
motion_mode,
drl_idx,
r#ref,
interintra_type,
}
};
let filter = if frame_hdr.subpel_filter_mode == Rav1dFilterMode::Switchable {
if has_subpel_filter {
let comp = comp_type.is_some();
let ctx1 = get_filter_ctx(ta, &t.l, comp, false, r#ref[0], by4, bx4);
let filter0 = Rav1dFilterMode::from_repr(rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut ts_c.cdf.mi.filter[0][ctx1 as usize],
Rav1dFilterMode::N_SWITCHABLE_FILTERS as u8 - 1,
) as usize)
.unwrap();
if seq_hdr.dual_filter != 0 {
let ctx2 = get_filter_ctx(ta, &t.l, comp, true, r#ref[0], by4, bx4);
if debug_block_info!(f, t.b) {
println!(
"Post-subpel_filter1[{:?},ctx={}]: r={}",
filter0, ctx1, ts_c.msac.rng,
);
}
let filter1 = Rav1dFilterMode::from_repr(rav1d_msac_decode_symbol_adapt4(
&mut ts_c.msac,
&mut ts_c.cdf.mi.filter[1][ctx2 as usize],
Rav1dFilterMode::N_SWITCHABLE_FILTERS as u8 - 1,
) as usize)
.unwrap();
if debug_block_info!(f, t.b) {
println!(
"Post-subpel_filter2[{:?},ctx={}]: r={}",
filter1, ctx2, ts_c.msac.rng,
);
}
[filter0, filter1]
} else {
if debug_block_info!(f, t.b) {
println!(
"Post-subpel_filter[{:?},ctx={}]: r={}",
filter0, ctx1, ts_c.msac.rng
);
}
[filter0; 2]
}
} else {
[Rav1dFilterMode::Regular8Tap; 2]
}
} else {
[frame_hdr.subpel_filter_mode; 2]
};
let filter2d = dav1d_filter_2d[filter[1] as usize][filter[0] as usize];
let VarTx {
uvtx,
max_ytx,
tx_split0,
tx_split1,
} = read_vartx_tree(t, f, ts_c, b, bs, bx4, by4);
b.uvtx = uvtx;
let inter = Av1BlockInter {
nd,
comp_type,
inter_mode,
motion_mode,
drl_idx,
r#ref,
max_ytx,
filter2d,
interintra_type,
tx_split0,
tx_split1,
};
b.ii = Av1BlockIntraInter::Inter(inter);
if t.frame_thread.pass == 1 {
(bd_fn.read_coef_blocks)(f, t, ts_c, bs, b);
} else {
(bd_fn.recon_b_inter)(f, t, Some(ts_c), bs, b, &inter)?;
}
let frame_hdr = f.frame_hdr();
if frame_hdr.loopfilter.level_y != [0, 0] {
let is_globalmv =
(inter_mode == if is_comp { GLOBALMV_GLOBALMV } else { GLOBALMV }) as c_int;
let tx_split = [tx_split0 as u16, tx_split1];
let mut ytx = max_ytx;
let mut uvtx = b.uvtx;
if frame_hdr.segmentation.lossless[b.seg_id.get()] {
ytx = TxfmSize::S4x4;
uvtx = TxfmSize::S4x4;
}
let lflvl = match ts.lflvl.get() {
TileStateRef::Frame => &f.lf.lvl,
TileStateRef::Local => &*ts.lflvlmem.try_read().unwrap(),
};
let mut a_uv_guard;
let mut l_uv_guard;
rav1d_create_lf_mask_inter(
&f.lf.mask[t.lf_mask.unwrap()],
&f.lf.level,
f.b4_stride,
&lflvl[b.seg_id.get()],
(r#ref[0] + 1) as usize,
is_globalmv == 0,
t.b,
f.w4,
f.h4,
b.skip != 0,
bs,
ytx,
&tx_split,
uvtx,
f.cur.p.layout,
&mut ta.tx_lpf_y.index_mut((bx4 as usize.., ..bw4 as usize)),
&mut t.l.tx_lpf_y.index_mut((by4 as usize.., ..bh4 as usize)),
if has_chroma {
a_uv_guard = ta.tx_lpf_uv.index_mut((cbx4 as usize.., ..cbw4 as usize));
l_uv_guard = t.l.tx_lpf_uv.index_mut((cby4 as usize.., ..cbh4 as usize));
Some((&mut *a_uv_guard, &mut *l_uv_guard))
} else {
None
},
);
}
if is_comp {
splat_tworef_mv(c, t, &f.rf, bs, &inter, bw4 as usize, bh4 as usize);
} else {
splat_oneref_mv(c, t, &f.rf, bs, &inter, bw4 as usize, bh4 as usize);
}
CaseSet::<32, false>::many(
[(&t.l, 1), (ta, 0)],
[bh4 as usize, bw4 as usize],
[by4 as usize, bx4 as usize],
|case, (dir, dir_index)| {
case.set_disjoint(&dir.seg_pred, seg_pred.into());
case.set_disjoint(&dir.skip_mode, b.skip_mode);
case.set_disjoint(&dir.intra, 0);
case.set_disjoint(&dir.skip, b.skip);
case.set_disjoint(&dir.pal_sz, 0);
case.set(&mut t.pal_sz_uv[dir_index], 0);
case.set_disjoint(&dir.tx_intra, b_dim[2 + dir_index] as i8);
case.set_disjoint(&dir.comp_type, comp_type);
case.set_disjoint(&dir.filter[0], filter[0]);
case.set_disjoint(&dir.filter[1], filter[1]);
case.set_disjoint(&dir.mode, inter_mode);
case.set_disjoint(&dir.r#ref[0], r#ref[0]);
case.set_disjoint(&dir.r#ref[1], r#ref[1]);
},
);
if has_chroma {
CaseSet::<32, false>::many(
[&t.l, ta],
[cbh4 as usize, cbw4 as usize],
[cby4 as usize, cbx4 as usize],
|case, dir| {
case.set_disjoint(&dir.uvmode, DC_PRED);
},
);
}
}
let frame_hdr = &***f.frame_hdr.as_ref().unwrap();
if frame_hdr.segmentation.enabled != 0 && frame_hdr.segmentation.update_map != 0 {
let [by, bx, bh4, bw4] = [t.b.y, t.b.x, bh4, bw4].map(|it| usize::try_from(it).unwrap());
let b4_stride = usize::try_from(f.b4_stride).unwrap();
let cur_segmap = &f.cur_segmap.as_ref().unwrap().inner;
let offset = by * b4_stride + bx;
CaseSet::<32, false>::one((), bw4, 0, |case, ()| {
for i in 0..bh4 {
let i = offset + i * b4_stride;
case.set(&mut cur_segmap.index_mut((i.., ..bw4)), b.seg_id);
}
});
}
if b.skip == 0 {
let mask = !0u32 >> 32 - bw4 << (bx4 & 15);
let bx_idx = (bx4 & 16) >> 4;
for noskip_mask in &f.lf.mask[t.lf_mask.unwrap()].noskip_mask[by4 as usize >> 1..]
[..(bh4 as usize).div_ceil(2)]
{
noskip_mask[bx_idx as usize].update(|it| it | mask as u16);
if bw4 == 32 {
noskip_mask[1].update(|it| it | mask as u16);
}
}
}
match &b.ii {
Av1BlockIntraInter::Inter(inter)
if t.frame_thread.pass == 1 && frame_hdr.frame_type.is_inter_or_switch() =>
{
let sby = t.b.y - ts.tiling.row_start >> f.sb_shift;
let mut lowest_px = f.lowest_pixel_mem.index_mut(ts.lowest_pixel + sby as usize);
if inter.comp_type.is_none() {
if cmp::min(bw4, bh4) > 1
&& (inter.inter_mode == GLOBALMV
&& f.gmv_warp_allowed[inter.r#ref[0] as usize] != 0
|| inter.motion_mode == MotionMode::Warp
&& t.warpmv.r#type > Rav1dWarpedMotionType::Translation)
{
affine_lowest_px_luma(
t,
&mut lowest_px[inter.r#ref[0] as usize][0],
b_dim,
if inter.motion_mode == MotionMode::Warp {
&t.warpmv
} else {
&frame_hdr.gmv[inter.r#ref[0] as usize]
},
);
} else {
mc_lowest_px(
&mut lowest_px[inter.r#ref[0] as usize][0],
t.b.y,
bh4,
inter.nd.one_d.mv[0].y,
0,
&f.svc[inter.r#ref[0] as usize][1],
);
if inter.motion_mode == MotionMode::Obmc {
obmc_lowest_px(
&f.rf.r,
t,
&f.ts[t.ts],
f.cur.p.layout,
&f.svc,
&mut lowest_px,
false,
b_dim,
bx4,
by4,
w4,
h4,
);
}
}
if has_chroma {
let mut is_sub8x8 = bw4 == ss_hor || bh4 == ss_ver;
let r = if is_sub8x8 {
assert!(ss_hor == 1);
let r = <[_; 2]>::try_from(&t.rt.r[(t.b.y as usize & 31) + 5 - 1..][..2])
.unwrap();
if bw4 == 1 {
is_sub8x8 &= f.rf.r.index(r[1] + t.b.x as usize - 1).r#ref.r#ref[0] > 0;
}
if bh4 == ss_ver {
is_sub8x8 &= f.rf.r.index(r[0] + t.b.x as usize).r#ref.r#ref[0] > 0;
}
if bw4 == 1 && bh4 == ss_ver {
is_sub8x8 &= f.rf.r.index(r[0] + t.b.x as usize - 1).r#ref.r#ref[0] > 0;
}
r
} else {
Default::default() };
if is_sub8x8 {
if bw4 == 1 && bh4 == ss_ver {
let rr = *f.rf.r.index(r[0] + t.b.x as usize - 1);
mc_lowest_px(
&mut lowest_px[rr.r#ref.r#ref[0] as usize - 1][1],
t.b.y - 1,
bh4,
rr.mv.mv[0].y,
ss_ver,
&f.svc[rr.r#ref.r#ref[0] as usize - 1][1],
);
}
if bw4 == 1 {
let rr = *f.rf.r.index(r[1] + t.b.x as usize - 1);
mc_lowest_px(
&mut lowest_px[rr.r#ref.r#ref[0] as usize - 1][1],
t.b.y,
bh4,
rr.mv.mv[0].y,
ss_ver,
&f.svc[rr.r#ref.r#ref[0] as usize - 1][1],
);
}
if bh4 == ss_ver {
let rr = *f.rf.r.index(r[0] + t.b.x as usize);
mc_lowest_px(
&mut lowest_px[rr.r#ref.r#ref[0] as usize - 1][1],
t.b.y - 1,
bh4,
rr.mv.mv[0].y,
ss_ver,
&f.svc[rr.r#ref.r#ref[0] as usize - 1][1],
);
}
mc_lowest_px(
&mut lowest_px[inter.r#ref[0] as usize][1],
t.b.y,
bh4,
inter.nd.one_d.mv[0].y,
ss_ver,
&f.svc[inter.r#ref[0] as usize][1],
);
} else if cmp::min(cbw4, cbh4) > 1
&& (inter.inter_mode == GLOBALMV
&& f.gmv_warp_allowed[inter.r#ref[0] as usize] != 0
|| inter.motion_mode == MotionMode::Warp
&& t.warpmv.r#type > Rav1dWarpedMotionType::Translation)
{
affine_lowest_px_chroma(
t,
f.cur.p.layout,
&mut lowest_px[inter.r#ref[0] as usize][1],
b_dim,
if inter.motion_mode == MotionMode::Warp {
&t.warpmv
} else {
&frame_hdr.gmv[inter.r#ref[0] as usize]
},
);
} else {
mc_lowest_px(
&mut lowest_px[inter.r#ref[0] as usize][1],
t.b.y & !ss_ver,
bh4 << (bh4 == ss_ver) as c_int,
inter.nd.one_d.mv[0].y,
ss_ver,
&f.svc[inter.r#ref[0] as usize][1],
);
if inter.motion_mode == MotionMode::Obmc {
obmc_lowest_px(
&f.rf.r,
t,
&f.ts[t.ts],
f.cur.p.layout,
&f.svc,
&mut lowest_px,
true,
b_dim,
bx4,
by4,
w4,
h4,
);
}
}
}
} else {
let refmvs = || {
std::iter::zip(inter.r#ref, inter.nd.one_d.mv)
.map(|(r#ref, mv)| (r#ref as usize, mv))
};
for (r#ref, mv) in refmvs() {
if inter.inter_mode == GLOBALMV_GLOBALMV && f.gmv_warp_allowed[r#ref] != 0 {
affine_lowest_px_luma(
t,
&mut lowest_px[r#ref][0],
b_dim,
&frame_hdr.gmv[r#ref],
);
} else {
mc_lowest_px(
&mut lowest_px[r#ref][0],
t.b.y,
bh4,
mv.y,
0,
&f.svc[r#ref][1],
);
}
}
for (r#ref, mv) in refmvs() {
if inter.inter_mode == GLOBALMV_GLOBALMV && f.gmv_warp_allowed[r#ref] != 0 {
affine_lowest_px_luma(
t,
&mut lowest_px[r#ref][0],
b_dim,
&frame_hdr.gmv[r#ref],
);
} else {
mc_lowest_px(
&mut lowest_px[r#ref][0],
t.b.y,
bh4,
mv.y,
0,
&f.svc[r#ref][1],
);
}
}
if has_chroma {
for (r#ref, mv) in refmvs() {
if inter.inter_mode == GLOBALMV_GLOBALMV
&& cmp::min(cbw4, cbh4) > 1
&& f.gmv_warp_allowed[r#ref] != 0
{
affine_lowest_px_chroma(
t,
f.cur.p.layout,
&mut lowest_px[r#ref][1],
b_dim,
&frame_hdr.gmv[r#ref],
);
} else {
mc_lowest_px(
&mut lowest_px[r#ref][1],
t.b.y,
bh4,
mv.y,
ss_ver,
&f.svc[r#ref][1],
);
}
}
}
}
}
_ => {}
}
Ok(())
}
enum FrameThreadPassState<'a> {
First(&'a mut Rav1dTileStateContext),
Second,
}
fn decode_sb(
c: &Rav1dContext,
t: &mut Rav1dTaskContext,
f: &Rav1dFrameData,
pass: &mut FrameThreadPassState,
bl: BlockLevel,
edge_index: EdgeIndex,
) -> Result<(), ()> {
let ts = &f.ts[t.ts];
let hsz = 16 >> bl as u8;
let have_h_split = f.bw > t.b.x + hsz;
let have_v_split = f.bh > t.b.y + hsz;
let sb128 = f.seq_hdr().sb128 != 0;
let intra_edge = &IntraEdges::DEFAULT;
if !have_h_split && !have_v_split {
let next_bl = bl
.decrease()
.expect("BlockLevel::BL_8X8 should never make it here");
return decode_sb(
c,
t,
f,
pass,
next_bl,
intra_edge.branch(sb128, edge_index).split[0],
);
}
let frame_hdr = &***f.frame_hdr.as_ref().unwrap();
let bp;
let mut bx8 = 0;
let mut by8 = 0;
let ctx = match pass {
FrameThreadPassState::First(ts_c) => {
if false && bl == BlockLevel::Bl64x64 {
println!(
"poc={},y={},x={},bl={:?},r={}",
frame_hdr.frame_offset, t.b.y, t.b.x, bl, ts_c.msac.rng,
);
}
bx8 = (t.b.x & 31) >> 1;
by8 = (t.b.y & 31) >> 1;
Some((
get_partition_ctx(&f.a[t.a], &t.l, bl, by8, bx8),
&mut **ts_c,
))
}
FrameThreadPassState::Second => None,
};
if have_h_split && have_v_split {
if let Some((ctx, ts_c)) = ctx {
let pc = &mut ts_c.cdf.m.partition[bl as usize][ctx as usize];
bp = BlockPartition::from_repr(rav1d_msac_decode_symbol_adapt16(
&mut ts_c.msac,
pc,
dav1d_partition_type_count[bl as usize],
) as usize)
.expect("valid variant");
if f.cur.p.layout == Rav1dPixelLayout::I422
&& matches!(
bp,
BlockPartition::V
| BlockPartition::V4
| BlockPartition::LeftSplit
| BlockPartition::RightSplit
)
{
return Err(());
}
if debug_block_info!(f, t.b) {
println!(
"poc={},y={},x={},bl={:?},ctx={},bp={:?}: r={}",
frame_hdr.frame_offset, t.b.y, t.b.x, bl, ctx, bp, ts_c.msac.rng,
);
}
} else {
let b = f
.frame_thread
.b
.index((t.b.y as isize * f.b4_stride + t.b.x as isize) as usize);
bp = if b.bl == bl {
b.bp
} else {
BlockPartition::Split
};
}
let b = &dav1d_block_sizes[bl as usize][bp as usize];
match bp {
BlockPartition::None => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, node.o)?;
}
BlockPartition::H => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, node.h[0])?;
t.b.y += hsz;
decode_b(c, t, f, pass, bl, b[0], bp, node.h[1])?;
t.b.y -= hsz;
}
BlockPartition::V => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, node.v[0])?;
t.b.x += hsz;
decode_b(c, t, f, pass, bl, b[0], bp, node.v[1])?;
t.b.x -= hsz;
}
BlockPartition::Split => {
match bl.decrease() {
None => {
let tip = intra_edge.tip(sb128, edge_index);
assert!(hsz == 1);
decode_b(
c,
t,
f,
pass,
bl,
BlockSize::Bs4x4,
bp,
EdgeFlags::ALL_TR_AND_BL,
)?;
let tl_filter = t.tl_4x4_filter;
t.b.x += 1;
decode_b(c, t, f, pass, bl, BlockSize::Bs4x4, bp, tip.split[0])?;
t.b.x -= 1;
t.b.y += 1;
decode_b(c, t, f, pass, bl, BlockSize::Bs4x4, bp, tip.split[1])?;
t.b.x += 1;
t.tl_4x4_filter = tl_filter;
decode_b(c, t, f, pass, bl, BlockSize::Bs4x4, bp, tip.split[2])?;
t.b.x -= 1;
t.b.y -= 1;
if cfg!(target_arch = "x86_64") && t.frame_thread.pass != 0 {
let p = (t.frame_thread.pass & 1) as usize;
ts.frame_thread[p].cf.update(|cf| (cf + 31) & !31);
}
}
Some(next_bl) => {
let branch = intra_edge.branch(sb128, edge_index);
decode_sb(c, t, f, pass, next_bl, branch.split[0])?;
t.b.x += hsz;
decode_sb(c, t, f, pass, next_bl, branch.split[1])?;
t.b.x -= hsz;
t.b.y += hsz;
decode_sb(c, t, f, pass, next_bl, branch.split[2])?;
t.b.x += hsz;
decode_sb(c, t, f, pass, next_bl, branch.split[3])?;
t.b.x -= hsz;
t.b.y -= hsz;
}
}
}
BlockPartition::TopSplit => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, EdgeFlags::ALL_TR_AND_BL)?;
t.b.x += hsz;
decode_b(c, t, f, pass, bl, b[0], bp, node.v[1])?;
t.b.x -= hsz;
t.b.y += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, node.h[1])?;
t.b.y -= hsz;
}
BlockPartition::BottomSplit => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, node.h[0])?;
t.b.y += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, node.v[0])?;
t.b.x += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, EdgeFlags::empty())?;
t.b.x -= hsz;
t.b.y -= hsz;
}
BlockPartition::LeftSplit => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, EdgeFlags::ALL_TR_AND_BL)?;
t.b.y += hsz;
decode_b(c, t, f, pass, bl, b[0], bp, node.h[1])?;
t.b.y -= hsz;
t.b.x += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, node.v[1])?;
t.b.x -= hsz;
}
BlockPartition::RightSplit => {
let node = intra_edge.node(sb128, edge_index);
decode_b(c, t, f, pass, bl, b[0], bp, node.v[0])?;
t.b.x += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, node.h[0])?;
t.b.y += hsz;
decode_b(c, t, f, pass, bl, b[1], bp, EdgeFlags::empty())?;
t.b.y -= hsz;
t.b.x -= hsz;
}
BlockPartition::H4 => {
let branch = intra_edge.branch(sb128, edge_index);
let node = &branch.node;
decode_b(c, t, f, pass, bl, b[0], bp, node.h[0])?;
t.b.y += hsz >> 1;
decode_b(c, t, f, pass, bl, b[0], bp, branch.h4)?;
t.b.y += hsz >> 1;
decode_b(c, t, f, pass, bl, b[0], bp, EdgeFlags::ALL_LEFT_HAS_BOTTOM)?;
t.b.y += hsz >> 1;
if t.b.y < f.bh {
decode_b(c, t, f, pass, bl, b[0], bp, node.h[1])?;
}
t.b.y -= hsz * 3 >> 1;
}
BlockPartition::V4 => {
let branch = intra_edge.branch(sb128, edge_index);
let node = &branch.node;
decode_b(c, t, f, pass, bl, b[0], bp, node.v[0])?;
t.b.x += hsz >> 1;
decode_b(c, t, f, pass, bl, b[0], bp, branch.v4)?;
t.b.x += hsz >> 1;
decode_b(c, t, f, pass, bl, b[0], bp, EdgeFlags::ALL_TOP_HAS_RIGHT)?;
t.b.x += hsz >> 1;
if t.b.x < f.bw {
decode_b(c, t, f, pass, bl, b[0], bp, node.v[1])?;
}
t.b.x -= hsz * 3 >> 1;
}
}
} else if have_h_split {
let is_split;
if let Some((ctx, ts_c)) = ctx {
let pc = &mut ts_c.cdf.m.partition[bl as usize][ctx as usize];
is_split = rav1d_msac_decode_bool(&mut ts_c.msac, gather_top_partition_prob(pc, bl));
if debug_block_info!(f, t.b) {
println!(
"poc={},y={},x={},bl={:?},ctx={},bp={:?}: r={}",
frame_hdr.frame_offset,
t.b.y,
t.b.x,
bl,
ctx,
if is_split {
BlockPartition::Split
} else {
BlockPartition::H
},
ts_c.msac.rng,
);
}
} else {
let b = &f
.frame_thread
.b
.index((t.b.y as isize * f.b4_stride + t.b.x as isize) as usize);
is_split = b.bl != bl;
}
let next_bl = bl
.decrease()
.expect("BlockLevel::BL_8X8 should never make it here");
if is_split {
let branch = intra_edge.branch(sb128, edge_index);
bp = BlockPartition::Split;
decode_sb(c, t, f, pass, next_bl, branch.split[0])?;
t.b.x += hsz;
decode_sb(c, t, f, pass, next_bl, branch.split[1])?;
t.b.x -= hsz;
} else {
let node = intra_edge.node(sb128, edge_index);
bp = BlockPartition::H;
decode_b(
c,
t,
f,
pass,
bl,
dav1d_block_sizes[bl as usize][bp as usize][0],
bp,
node.h[0],
)?;
}
} else {
assert!(have_v_split);
let is_split;
if let Some((ctx, ts_c)) = ctx {
let pc = &mut ts_c.cdf.m.partition[bl as usize][ctx as usize];
is_split = rav1d_msac_decode_bool(&mut ts_c.msac, gather_left_partition_prob(pc, bl));
if f.cur.p.layout == Rav1dPixelLayout::I422 && !is_split {
return Err(());
}
if debug_block_info!(f, t.b) {
println!(
"poc={},y={},x={},bl={:?},ctx={},bp={:?}: r={}",
frame_hdr.frame_offset,
t.b.y,
t.b.x,
bl,
ctx,
if is_split {
BlockPartition::Split
} else {
BlockPartition::V
},
ts_c.msac.rng,
);
}
} else {
let b = &f
.frame_thread
.b
.index((t.b.y as isize * f.b4_stride + t.b.x as isize) as usize);
is_split = b.bl != bl;
}
let next_bl = bl
.decrease()
.expect("BlockLevel::BL_8X8 should never make it here");
if is_split {
let branch = intra_edge.branch(sb128, edge_index);
bp = BlockPartition::Split;
decode_sb(c, t, f, pass, next_bl, branch.split[0])?;
t.b.y += hsz;
decode_sb(c, t, f, pass, next_bl, branch.split[2])?;
t.b.y -= hsz;
} else {
let node = intra_edge.node(sb128, edge_index);
bp = BlockPartition::V;
decode_b(
c,
t,
f,
pass,
bl,
dav1d_block_sizes[bl as usize][bp as usize][0],
bp,
node.v[0],
)?;
}
}
if matches!(pass, FrameThreadPassState::First(_))
&& (bp != BlockPartition::Split || bl == BlockLevel::Bl8x8)
{
CaseSet::<16, false>::many(
[(&f.a[t.a], 0), (&t.l, 1)],
[hsz as usize; 2],
[bx8 as usize, by8 as usize],
|case, (dir, dir_index)| {
case.set_disjoint(
&dir.partition,
dav1d_al_part_ctx[dir_index][bl as usize][bp as usize],
);
},
);
}
Ok(())
}
fn reset_context(ctx: &mut BlockContext, keyframe: bool, pass: c_int) {
ctx.intra.get_mut().fill(keyframe.into());
ctx.uvmode.get_mut().fill(DC_PRED);
if keyframe {
ctx.mode.get_mut().fill(DC_PRED);
}
if pass == 2 {
return;
}
ctx.partition.get_mut().fill(0);
ctx.skip.get_mut().fill(0);
ctx.skip_mode.get_mut().fill(0);
ctx.tx_lpf_y.get_mut().fill(2);
ctx.tx_lpf_uv.get_mut().fill(1);
ctx.tx_intra.get_mut().fill(-1);
ctx.tx.get_mut().fill(TxfmSize::S64x64);
if !keyframe {
for r#ref in &mut ctx.r#ref {
r#ref.get_mut().fill(-1);
}
ctx.comp_type.get_mut().fill(None);
ctx.mode.get_mut().fill(NEARESTMV);
}
ctx.lcoef.get_mut().fill(0x40);
for ccoef in &mut ctx.ccoef {
ccoef.get_mut().fill(0x40);
}
for filter in &mut ctx.filter {
filter.get_mut().fill(Rav1dFilterMode::N_SWITCHABLE_FILTERS);
}
ctx.seg_pred.get_mut().fill(0);
ctx.pal_sz.get_mut().fill(0);
}
impl DefaultValue for [u8; 2] {
const DEFAULT: Self = [0; 2];
}
static ss_size_mul: enum_map_ty!(Rav1dPixelLayout, [u8; 2]) = enum_map!(Rav1dPixelLayout => [u8; 2]; match key {
I400 => [4, 4],
I420 => [6, 5],
I422 => [8, 6],
I444 => [12, 8],
});
fn setup_tile(
c: &Rav1dContext,
ts: &mut Rav1dTileState,
seq_hdr: &Rav1dSequenceHeader,
frame_hdr: &Rav1dFrameHeader,
bitdepth_max: i32,
sb_shift: i32,
cur: &Rav1dPicture,
bw: i32,
bh: i32,
frame_thread: &Rav1dFrameContextFrameThread,
sr_sb128w: i32,
sb128w: i32,
lf: &mut Rav1dFrameContextLf,
in_cdf: &CdfThreadContext,
data: CArc<[u8]>,
tile_row: usize,
tile_col: usize,
tile_start_off: u32,
) {
let col_sb_start = frame_hdr.tiling.col_start_sb[tile_col] as c_int;
let col_sb128_start = col_sb_start >> (seq_hdr.sb128 == 0) as c_int;
let col_sb_end = frame_hdr.tiling.col_start_sb[tile_col + 1] as c_int;
let row_sb_start = frame_hdr.tiling.row_start_sb[tile_row] as c_int;
let row_sb_end = frame_hdr.tiling.row_start_sb[tile_row + 1] as c_int;
let size_mul = &ss_size_mul[cur.p.layout];
for p in 0..2 {
ts.frame_thread[p]
.pal_idx
.set(if !frame_thread.pal_idx.is_empty() {
tile_start_off * size_mul[1] as u32 / 8
} else {
0
});
ts.frame_thread[p]
.cbi_idx
.set(if !frame_thread.cbi.is_empty() {
tile_start_off * size_mul[0] as u32 / 64
} else {
0
});
ts.frame_thread[p].cf.set(if !frame_thread.cf.is_empty() {
let bpc = BPC::from_bitdepth_max(bitdepth_max);
bpc.coef_stride(tile_start_off * size_mul[0] as u32 >> (seq_hdr.hbd == 0) as c_int)
} else {
0
});
}
let ts_c = &mut *ts.context.try_lock().unwrap();
ts_c.cdf = rav1d_cdf_thread_copy(in_cdf);
ts.last_qidx = frame_hdr.quant.yac.into();
ts.last_delta_lf = Default::default();
ts_c.msac = MsacContext::new(data, frame_hdr.disable_cdf_update != 0, &c.dsp.msac);
ts.tiling.row = tile_row as i32;
ts.tiling.col = tile_col as i32;
ts.tiling.col_start = col_sb_start << sb_shift;
ts.tiling.col_end = cmp::min(col_sb_end << sb_shift, bw);
ts.tiling.row_start = row_sb_start << sb_shift;
ts.tiling.row_end = cmp::min(row_sb_end << sb_shift, bh);
let diff_width = frame_hdr.size.width[0] != frame_hdr.size.width[1];
let (sb_idx, unit_idx) = if diff_width {
(
(ts.tiling.row_start >> 5) * sr_sb128w,
(ts.tiling.row_start & 16) >> 3,
)
} else {
(
(ts.tiling.row_start >> 5) * sb128w + col_sb128_start,
((ts.tiling.row_start & 16) >> 3) + ((ts.tiling.col_start & 16) >> 4),
)
};
for p in 0..3 {
if !((lf.restore_planes.bits() >> p) & 1 != 0) {
continue;
}
let lr_ref = if diff_width {
let ss_hor = (p != 0 && cur.p.layout != Rav1dPixelLayout::I444) as u8;
let d = frame_hdr.size.super_res.width_scale_denominator as c_int;
let unit_size_log2 = frame_hdr.restoration.unit_size[(p != 0) as usize];
let rnd = (8 << unit_size_log2) - 1;
let shift = unit_size_log2 + 3;
let x = (4 * ts.tiling.col_start * d >> ss_hor) + rnd >> shift;
let px_x = x << unit_size_log2 + ss_hor;
let u_idx = unit_idx + ((px_x & 64) >> 6);
let sb128x = px_x >> 7;
if sb128x >= sr_sb128w {
continue;
}
&mut lf.lr_mask[(sb_idx + sb128x) as usize].lr[p][u_idx as usize]
} else {
&mut lf.lr_mask[sb_idx as usize].lr[p][unit_idx as usize]
};
let lr = lr_ref.get_mut();
*lr = Av1RestorationUnit {
filter_v: [3, -7, 15],
filter_h: [3, -7, 15],
sgr_weights: [-32, 31],
..*lr
};
ts.lr_ref.get_mut()[p] = *lr;
}
if c.tc.len() > 1 {
ts.progress.fill_with(|| AtomicI32::new(row_sb_start));
}
}
fn read_restoration_info(
ts: &Rav1dTileState,
lr: &mut Av1RestorationUnit,
p: usize,
frame_type: Rav1dRestorationType,
debug_block_info: bool,
) {
let ts_c = &mut *ts.context.try_lock().unwrap();
let lr_ref = ts.lr_ref.try_read().unwrap()[p];
if frame_type == Rav1dRestorationType::Switchable {
let filter =
rav1d_msac_decode_symbol_adapt4(&mut ts_c.msac, &mut *ts_c.cdf.m.restore_switchable, 2);
lr.r#type = if filter != 0 {
if filter == 2 {
Rav1dRestorationType::SgrProj(SgrIdx::I0)
} else {
Rav1dRestorationType::Wiener
}
} else {
Rav1dRestorationType::None
};
} else {
let r#type = rav1d_msac_decode_bool_adapt(
&mut ts_c.msac,
if frame_type == Rav1dRestorationType::Wiener {
&mut *ts_c.cdf.m.restore_wiener
} else {
&mut *ts_c.cdf.m.restore_sgrproj
},
);
lr.r#type = if r#type {
frame_type
} else {
Rav1dRestorationType::None
};
}
fn msac_decode_lr_subexp(
ts_c: &mut Rav1dTileStateContext,
r#ref: i8,
k: u8,
adjustment: i8,
) -> i8 {
(rav1d_msac_decode_subexp(&mut ts_c.msac, (r#ref + adjustment) as c_uint, 8 << k, k)
- adjustment as c_int) as i8
}
match lr.r#type {
Rav1dRestorationType::Wiener => {
lr.filter_v[0] = if p != 0 {
0
} else {
msac_decode_lr_subexp(ts_c, lr_ref.filter_v[0], 1, 5)
};
lr.filter_v[1] = msac_decode_lr_subexp(ts_c, lr_ref.filter_v[1], 2, 23);
lr.filter_v[2] = msac_decode_lr_subexp(ts_c, lr_ref.filter_v[2], 3, 17);
lr.filter_h[0] = if p != 0 {
0
} else {
msac_decode_lr_subexp(ts_c, lr_ref.filter_h[0], 1, 5)
};
lr.filter_h[1] = msac_decode_lr_subexp(ts_c, lr_ref.filter_h[1], 2, 23);
lr.filter_h[2] = msac_decode_lr_subexp(ts_c, lr_ref.filter_h[2], 3, 17);
lr.sgr_weights = lr_ref.sgr_weights;
ts.lr_ref.try_write().unwrap()[p] = *lr;
if debug_block_info {
println!(
"Post-lr_wiener[pl={},v[{},{},{}],h[{},{},{}]]: r={}",
p,
lr.filter_v[0],
lr.filter_v[1],
lr.filter_v[2],
lr.filter_h[0],
lr.filter_h[1],
lr.filter_h[2],
ts_c.msac.rng,
);
}
}
Rav1dRestorationType::SgrProj(_) => {
let sgr_idx =
SgrIdx::from_repr(rav1d_msac_decode_bools(&mut ts_c.msac, 4) as usize).unwrap();
let sgr_params = &dav1d_sgr_params[sgr_idx as usize];
lr.r#type = Rav1dRestorationType::SgrProj(sgr_idx);
lr.sgr_weights[0] = if sgr_params[0] != 0 {
msac_decode_lr_subexp(ts_c, lr_ref.sgr_weights[0], 4, 96)
} else {
0
};
lr.sgr_weights[1] = if sgr_params[1] != 0 {
msac_decode_lr_subexp(ts_c, lr_ref.sgr_weights[1], 4, 32)
} else {
95
};
lr.filter_v = lr_ref.filter_v;
lr.filter_h = lr_ref.filter_h;
ts.lr_ref.try_write().unwrap()[p] = *lr;
if debug_block_info {
println!(
"Post-lr_sgrproj[pl={},idx={},w[{},{}]]: r={}",
p, sgr_idx, lr.sgr_weights[0], lr.sgr_weights[1], ts_c.msac.rng,
);
}
}
_ => {}
}
}
fn check_trailing_bits_after_symbol_coder(msac: &MsacContext) -> Result<(), ()> {
let n_bits = -(msac.cnt + 14);
assert!(n_bits <= 0); let n_bytes = (n_bits + 7) >> 3;
let trailing_bytes_offset = msac.buf_index().wrapping_add_signed(n_bytes as isize - 1);
let trailing_bytes = &msac.data()[trailing_bytes_offset..];
let pattern = 128 >> ((n_bits - 1) & 7);
if (trailing_bytes[0] & (pattern + (pattern - 1))) != pattern {
return Err(());
}
if trailing_bytes[1..].iter().any(|&x| x != 0) {
return Err(());
}
return Ok(());
}
pub(crate) fn rav1d_decode_tile_sbrow(
c: &Rav1dContext,
t: &mut Rav1dTaskContext,
f: &Rav1dFrameData,
) -> Result<(), ()> {
let seq_hdr = &***f.seq_hdr.as_ref().ok_or(())?;
let root_bl = if seq_hdr.sb128 != 0 {
BlockLevel::Bl128x128
} else {
BlockLevel::Bl64x64
};
let ts = &f.ts[t.ts];
let sb_step = f.sb_step;
let tile_row = ts.tiling.row;
let tile_col = ts.tiling.col;
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(())?;
let col_sb_start = frame_hdr.tiling.col_start_sb[tile_col as usize] as c_int;
let col_sb128_start = col_sb_start >> (seq_hdr.sb128 == 0) as c_int;
if frame_hdr.frame_type.is_inter_or_switch() || frame_hdr.allow_intrabc {
t.rt = rav1d_refmvs_tile_sbrow_init(
&f.rf,
ts.tiling.col_start,
ts.tiling.col_end,
ts.tiling.row_start,
ts.tiling.row_end,
t.b.y >> f.sb_shift,
ts.tiling.row,
t.frame_thread.pass,
);
}
if frame_hdr.frame_type.is_inter_or_switch() && c.fc.len() > 1 {
let sby = t.b.y - ts.tiling.row_start >> f.sb_shift;
*f.lowest_pixel_mem.index_mut(ts.lowest_pixel + sby as usize) = [[i32::MIN; 2]; 7];
}
reset_context(
&mut t.l,
frame_hdr.frame_type.is_key_or_intra(),
t.frame_thread.pass,
);
if t.frame_thread.pass == 2 {
let off_2pass = if c.tc.len() > 1 {
f.sb128w * frame_hdr.tiling.rows as c_int
} else {
0
};
t.a = (off_2pass + col_sb128_start + tile_row * f.sb128w) as usize;
for bx in (ts.tiling.col_start..ts.tiling.col_end).step_by(sb_step as usize) {
t.b.x = bx;
if c.flush.load(Ordering::Acquire) {
return Err(());
}
decode_sb(
c,
t,
f,
&mut FrameThreadPassState::Second,
root_bl,
EdgeIndex::root(),
)?;
if t.b.x & 16 != 0 || f.seq_hdr().sb128 != 0 {
t.a += 1;
}
}
(f.bd_fn().backup_ipred_edge)(f, t);
return Ok(());
}
if c.tc.len() > 1 && frame_hdr.use_ref_frame_mvs != 0 {
c.dsp.refmvs.load_tmvs.call(
&f.rf,
&f.mvs,
&f.ref_mvs,
ts.tiling.row,
ts.tiling.col_start >> 1,
ts.tiling.col_end >> 1,
t.b.y >> 1,
t.b.y + sb_step >> 1,
);
}
t.pal_sz_uv[1] = Default::default();
let sb128y = t.b.y >> 5;
t.a = (col_sb128_start + tile_row * f.sb128w) as usize;
t.lf_mask = Some((sb128y * f.sb128w + col_sb128_start) as usize);
for bx in (ts.tiling.col_start..ts.tiling.col_end).step_by(sb_step as usize) {
t.b.x = bx;
if c.flush.load(Ordering::Acquire) {
return Err(());
}
let cdef_idx = &f.lf.mask[t.lf_mask.unwrap()].cdef_idx;
if root_bl == BlockLevel::Bl128x128 {
for cdef_idx in cdef_idx {
cdef_idx.set(-1);
}
t.cur_sb_cdef_idx = 0;
} else {
t.cur_sb_cdef_idx = (((t.b.x & 16) >> 4) + ((t.b.y & 16) >> 3)) as usize;
let cdef_idx = &cdef_idx[t.cur_sb_cdef_idx..];
cdef_idx[0].set(-1);
}
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(())?;
for p in 0..3 {
if (f.lf.restore_planes.bits() >> p) & 1 == 0 {
continue;
}
let ss_ver = (p != 0 && f.cur.p.layout == Rav1dPixelLayout::I420) as c_int;
let ss_hor = (p != 0 && f.cur.p.layout != Rav1dPixelLayout::I444) as c_int;
let unit_size_log2 = frame_hdr.restoration.unit_size[(p != 0) as usize];
let y = t.b.y * 4 >> ss_ver;
let h = f.cur.p.h + ss_ver >> ss_ver;
let unit_size = 1 << unit_size_log2;
let mask = (unit_size - 1) as c_uint;
if y as c_uint & mask != 0 {
continue;
}
let half_unit = unit_size >> 1;
if y != 0 && y + half_unit > h {
continue;
}
let frame_type = frame_hdr.restoration.r#type[p as usize];
if frame_hdr.size.width[0] != frame_hdr.size.width[1] {
let w = f.sr_cur.p.p.w + ss_hor >> ss_hor;
let n_units = cmp::max(1, w + half_unit >> unit_size_log2);
let d = frame_hdr.size.super_res.width_scale_denominator as c_int;
let rnd = unit_size * 8 - 1;
let shift = unit_size_log2 + 3;
let x0 = (4 * t.b.x * d >> ss_hor) + rnd >> shift;
let x1 = (4 * (t.b.x + sb_step) * d >> ss_hor) + rnd >> shift;
for x in x0..cmp::min(x1, n_units) {
let px_x = x << unit_size_log2 + ss_hor as u8;
let sb_idx = (t.b.y >> 5) * f.sr_sb128w + (px_x >> 7);
let unit_idx = ((t.b.y & 16) >> 3) + ((px_x & 64) >> 6);
let mut lr = f.lf.lr_mask[sb_idx as usize].lr[p][unit_idx as usize]
.try_write()
.unwrap();
read_restoration_info(ts, &mut lr, p, frame_type, debug_block_info!(f, t.b));
}
} else {
let x = 4 * t.b.x >> ss_hor;
if x as c_uint & mask != 0 {
continue;
}
let w = f.cur.p.w + ss_hor >> ss_hor;
if x != 0 && x + half_unit > w {
continue;
}
let sb_idx = (t.b.y >> 5) * f.sr_sb128w + (t.b.x >> 5);
let unit_idx = ((t.b.y & 16) >> 3) + ((t.b.x & 16) >> 4);
let mut lr = f.lf.lr_mask[sb_idx as usize].lr[p][unit_idx as usize]
.try_write()
.unwrap();
read_restoration_info(ts, &mut lr, p, frame_type, debug_block_info!(f, t.b));
}
}
decode_sb(
c,
t,
f,
&mut FrameThreadPassState::First(&mut f.ts[t.ts].context.try_lock().unwrap()),
root_bl,
EdgeIndex::root(),
)?;
if t.b.x & 16 != 0 || f.seq_hdr().sb128 != 0 {
t.a += 1;
t.lf_mask = t.lf_mask.map(|i| i + 1);
}
}
if f.seq_hdr().ref_frame_mvs != 0
&& c.tc.len() > 1
&& f.frame_hdr().frame_type.is_inter_or_switch()
{
c.dsp.refmvs.save_tmvs.call(
&t.rt,
&f.rf,
&f.mvs,
ts.tiling.col_start >> 1,
ts.tiling.col_end >> 1,
t.b.y >> 1,
t.b.y + sb_step >> 1,
);
}
if t.frame_thread.pass != 1 {
(f.bd_fn().backup_ipred_edge)(f, t);
}
let mut align_h = f.bh + 31 & !31;
let start_y = (align_h * tile_col + t.b.y) as usize;
let len_y = sb_step as usize;
let start_lpf_y = (t.b.y & 16) as usize;
f.lf.tx_lpf_right_edge.copy_from_slice_y(
start_y..start_y + len_y,
&t.l.tx_lpf_y.index(start_lpf_y..start_lpf_y + len_y),
);
let ss_ver = (f.cur.p.layout == Rav1dPixelLayout::I420) as c_int;
align_h >>= ss_ver;
let start_uv = (align_h * tile_col + (t.b.y >> ss_ver)) as usize;
let len_uv = (sb_step >> ss_ver) as usize;
let lpf_uv_start = ((t.b.y & 16) >> ss_ver) as usize;
f.lf.tx_lpf_right_edge.copy_from_slice_uv(
start_uv..start_uv + len_uv,
&t.l.tx_lpf_uv.index(lpf_uv_start..lpf_uv_start + len_uv),
);
if ts.context.try_lock().unwrap().msac.cnt <= -15 {
return Err(());
}
if c.strict_std_compliance
&& (t.b.y >> f.sb_shift) + 1
>= f.frame_hdr().tiling.row_start_sb[tile_row as usize + 1].into()
{
return check_trailing_bits_after_symbol_coder(&ts.context.try_lock().unwrap().msac);
}
Ok(())
}
pub(crate) fn rav1d_decode_frame_init(c: &Rav1dContext, fc: &Rav1dFrameContext) -> Rav1dResult {
let mut f = fc.data.try_write().unwrap();
let f = &mut *f;
f.lf.start_of_tile_row
.try_resize(f.sbh as usize, 0)
.map_err(|_| ENOMEM)?;
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(EINVAL)?;
let mut sby = 0;
for tile_row in 0..frame_hdr.tiling.rows {
f.lf.start_of_tile_row[sby as usize] = tile_row;
sby += 1;
while sby < frame_hdr.tiling.row_start_sb[(tile_row + 1) as usize] as c_int {
f.lf.start_of_tile_row[sby as usize] = 0;
sby += 1;
}
}
let n_ts = frame_hdr.tiling.cols as c_int * frame_hdr.tiling.rows as c_int;
if c.fc.len() > 1 {
f.frame_thread
.tile_start_off
.try_resize(n_ts as usize, 0)
.map_err(|_| ENOMEM)?;
}
f.ts.try_resize_with(n_ts as usize, Default::default)
.map_err(|_| ENOMEM)?;
let a_sz = f.sb128w
* frame_hdr.tiling.rows as c_int
* (1 + (c.fc.len() > 1 && c.tc.len() > 1) as c_int);
f.a.try_resize_with(a_sz as usize, Default::default)
.map_err(|_| ENOMEM)?;
let num_sb128 = f.sb128w * f.sb128h;
let size_mul = &ss_size_mul[f.cur.p.layout];
let seq_hdr = &***f.seq_hdr.as_ref().ok_or(EINVAL)?;
let hbd = (seq_hdr.hbd != 0) as c_int;
if c.fc.len() > 1 {
let mut tile_idx = 0;
let sb_step4 = f.sb_step as u32 * 4;
for tile_row in 0..frame_hdr.tiling.rows {
let row_off = frame_hdr.tiling.row_start_sb[tile_row as usize] as u32
* sb_step4
* f.sb128w as u32
* 128;
let b_diff = (frame_hdr.tiling.row_start_sb[(tile_row + 1) as usize] as u32
- frame_hdr.tiling.row_start_sb[tile_row as usize] as u32)
* sb_step4;
for tile_col in 0..frame_hdr.tiling.cols {
f.frame_thread.tile_start_off[tile_idx] = row_off
+ b_diff * frame_hdr.tiling.col_start_sb[tile_col as usize] as u32 * sb_step4;
tile_idx += 1;
}
}
let lowest_pixel_mem_sz = frame_hdr.tiling.cols as usize * f.sbh as usize;
f.lowest_pixel_mem
.try_resize(lowest_pixel_mem_sz, Default::default())
.map_err(|_| ENOMEM)?;
let mut lowest_pixel_offset = 0;
for tile_row in 0..frame_hdr.tiling.rows as usize {
let tile_row_base = tile_row * frame_hdr.tiling.cols as usize;
let tile_row_sb_h = frame_hdr.tiling.row_start_sb[tile_row + 1] as usize
- frame_hdr.tiling.row_start_sb[tile_row] as usize;
for tile_col in 0..frame_hdr.tiling.cols as usize {
f.ts[tile_row_base + tile_col].lowest_pixel = lowest_pixel_offset;
lowest_pixel_offset += tile_row_sb_h;
}
}
let cbi_sz = num_sb128 * size_mul[0] as c_int;
f.frame_thread
.cbi
.try_resize_with(cbi_sz as usize * 32 * 32 / 4, Default::default)
.map_err(|_| ENOMEM)?;
let cf_sz = (num_sb128 * size_mul[0] as c_int) << hbd;
f.frame_thread
.cf
.try_resize(cf_sz as usize * 128 * 128 / 2, 0)
.map_err(|_| ENOMEM)?;
if frame_hdr.allow_screen_content_tools {
f.frame_thread
.pal
.try_resize(num_sb128 as usize * 16 * 16 << hbd)
.map_err(|_| ENOMEM)?;
let pal_idx_sz = num_sb128 * size_mul[1] as c_int;
f.frame_thread
.pal_idx
.try_resize(pal_idx_sz as usize * 128 * 128 / 8, Default::default())
.map_err(|_| ENOMEM)?;
} else if !f.frame_thread.pal.is_empty() {
let _ = mem::take(&mut f.frame_thread.pal);
let _ = mem::take(&mut f.frame_thread.pal_idx);
}
}
let mut y_stride = f.cur.stride[0];
let mut uv_stride = f.cur.stride[1];
let has_resize = (frame_hdr.size.width[0] != frame_hdr.size.width[1]) as c_int;
let need_cdef_lpf_copy = (c.tc.len() > 1 && has_resize != 0) as c_int;
let mut alloc_sz: usize = 64;
alloc_sz += (y_stride.unsigned_abs() * 4 * f.sbh as usize) << need_cdef_lpf_copy;
alloc_sz += (uv_stride.unsigned_abs() * 8 * f.sbh as usize) << need_cdef_lpf_copy;
f.lf.cdef_line_buf
.try_resize(alloc_sz, 0)
.map_err(|_| ENOMEM)?;
let bpc = BPC::from_bitdepth_max(f.bitdepth_max);
let y_stride_px = bpc.pxstride(f.cur.stride[0]);
let uv_stride_px = bpc.pxstride(f.cur.stride[1]);
let mut offset = bpc.pxstride(32usize);
if y_stride < 0 {
f.lf.cdef_line[0][0] =
offset.wrapping_add_signed(-(y_stride_px * (f.sbh as isize * 4 - 1)));
f.lf.cdef_line[1][0] =
offset.wrapping_add_signed(-(y_stride_px * (f.sbh as isize * 4 - 3)));
} else {
f.lf.cdef_line[0][0] = offset.wrapping_add_signed(y_stride_px * 0);
f.lf.cdef_line[1][0] = offset.wrapping_add_signed(y_stride_px * 2);
}
offset = offset.wrapping_add_signed(y_stride_px.abs() * f.sbh as isize * 4);
if uv_stride < 0 {
f.lf.cdef_line[0][1] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 8 - 1)));
f.lf.cdef_line[0][2] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 8 - 3)));
f.lf.cdef_line[1][1] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 8 - 5)));
f.lf.cdef_line[1][2] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 8 - 7)));
} else {
f.lf.cdef_line[0][1] = offset.wrapping_add_signed(uv_stride_px * 0);
f.lf.cdef_line[0][2] = offset.wrapping_add_signed(uv_stride_px * 2);
f.lf.cdef_line[1][1] = offset.wrapping_add_signed(uv_stride_px * 4);
f.lf.cdef_line[1][2] = offset.wrapping_add_signed(uv_stride_px * 6);
}
if need_cdef_lpf_copy != 0 {
offset = offset.wrapping_add_signed(uv_stride_px.abs() * f.sbh as isize * 8);
if y_stride < 0 {
f.lf.cdef_lpf_line[0] =
offset.wrapping_add_signed(-(y_stride_px * (f.sbh as isize * 4 - 1)));
} else {
f.lf.cdef_lpf_line[0] = offset;
}
offset = offset.wrapping_add_signed(y_stride_px.abs() * f.sbh as isize * 4);
if uv_stride < 0 {
f.lf.cdef_lpf_line[1] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 4 - 1)));
f.lf.cdef_lpf_line[2] =
offset.wrapping_add_signed(-(uv_stride_px * (f.sbh as isize * 8 - 1)));
} else {
f.lf.cdef_lpf_line[1] = offset;
f.lf.cdef_lpf_line[2] = offset.wrapping_add_signed(uv_stride_px * f.sbh as isize * 4);
}
}
let sb128 = seq_hdr.sb128;
let num_lines = if c.tc.len() > 1 {
(f.sbh * 4) << sb128
} else {
12
};
y_stride = f.sr_cur.p.stride[0];
uv_stride = f.sr_cur.p.stride[1];
let mut alloc_sz: usize = 128;
alloc_sz += y_stride.unsigned_abs() * num_lines as usize;
alloc_sz += uv_stride.unsigned_abs() * num_lines as usize * 2;
f.lf.lr_line_buf
.try_resize(alloc_sz, 0)
.map_err(|_| ENOMEM)?;
let y_stride_px = bpc.pxstride(y_stride);
let uv_stride_px = bpc.pxstride(uv_stride);
let mut offset = bpc.pxstride(64usize);
if y_stride < 0 {
f.lf.lr_lpf_line[0] = offset.wrapping_add_signed(-(y_stride_px * (num_lines as isize - 1)));
} else {
f.lf.lr_lpf_line[0] = offset;
}
offset = offset.wrapping_add_signed(y_stride_px.abs() * num_lines as isize);
if uv_stride < 0 {
f.lf.lr_lpf_line[1] =
offset.wrapping_add_signed(-(uv_stride_px * (num_lines as isize * 1 - 1)));
f.lf.lr_lpf_line[2] =
offset.wrapping_add_signed(-(uv_stride_px * (num_lines as isize * 2 - 1)));
} else {
f.lf.lr_lpf_line[1] = offset;
f.lf.lr_lpf_line[2] = offset.wrapping_add_signed(uv_stride_px * num_lines as isize);
}
f.lf.mask.clear();
f.lf.mask
.try_resize_with(num_sb128 as usize, Default::default)
.map_err(|_| ENOMEM)?;
{
let level_len = 4 * num_sb128 as usize * 32 * 32 + 3;
f.lf.level
.try_reserve(level_len.saturating_sub(f.lf.level.len()))
.map_err(|_| ENOMEM)?;
f.lf.level.resize_with(level_len, || AtomicU8::new(0));
}
if c.fc.len() > 1 {
f.frame_thread
.b
.try_resize_with(num_sb128 as usize * 32 * 32, Default::default)
.map_err(|_| ENOMEM)?;
}
f.sr_sb128w = f.sr_cur.p.p.w + 127 >> 7;
let lr_mask_sz = f.sr_sb128w * f.sb128h;
f.lf.lr_mask
.try_resize_with(lr_mask_sz as usize, Default::default)
.map_err(|_| ENOMEM)?;
f.lf.restore_planes = LrRestorePlanes::from_bits_truncate(
frame_hdr
.restoration
.r#type
.iter()
.enumerate()
.map(|(i, &r#type)| ((r#type != Rav1dRestorationType::None) as u8) << i)
.sum::<u8>(),
);
if frame_hdr.loopfilter.sharpness != f.lf.last_sharpness {
rav1d_calc_eih(&mut *f.lf.lim_lut, frame_hdr.loopfilter.sharpness);
f.lf.last_sharpness = frame_hdr.loopfilter.sharpness;
}
rav1d_calc_lf_values(&mut f.lf.lvl, &frame_hdr, &[0, 0, 0, 0]);
let ipred_edge_sz = f.sbh * f.sb128w << hbd;
f.ipred_edge
.try_resize(ipred_edge_sz as usize * 128 * 3, 0)
.map_err(|_| ENOMEM)?;
f.ipred_edge_off = bpc.pxstride(ipred_edge_sz as usize * 128);
let re_sz = f.sb128h as usize * frame_hdr.tiling.cols as usize;
f.lf.tx_lpf_right_edge
.try_resize(re_sz, 0)
.map_err(|_| ENOMEM)?;
if frame_hdr.frame_type.is_inter_or_switch() || frame_hdr.allow_intrabc {
rav1d_refmvs_init_frame(
&mut f.rf,
seq_hdr,
frame_hdr,
&f.refpoc,
&f.refrefpoc,
&f.ref_mvs,
c.tc.len() as u32,
c.fc.len() as u32,
)?;
}
init_quant_tables(&seq_hdr, &frame_hdr, frame_hdr.quant.yac, &f.dq);
if frame_hdr.quant.qm != 0 {
for i in 0..TxfmSize::COUNT {
f.qm[i][0] = dav1d_qm_tbl[frame_hdr.quant.qm_y as usize][0][i];
f.qm[i][1] = dav1d_qm_tbl[frame_hdr.quant.qm_u as usize][1][i];
f.qm[i][2] = dav1d_qm_tbl[frame_hdr.quant.qm_v as usize][1][i];
}
} else {
f.qm = Default::default();
}
if frame_hdr.switchable_comp_refs != 0 {
let cur_frame_offset = f.cur.frame_hdr.as_ref().ok_or(EINVAL)?.frame_offset as c_int;
let ref_pocs: [_; 7] = array::from_fn(|i| {
f.refp[i]
.p
.frame_hdr
.as_ref()
.map(|h| h.frame_offset)
.unwrap_or(0)
});
for i in 0..ref_pocs.len() {
for j in i + 1..ref_pocs.len() {
let d = [j, i].map(|ij| {
cmp::min(
(get_poc_diff(
seq_hdr.order_hint_n_bits,
ref_pocs[ij] as c_int,
cur_frame_offset,
))
.unsigned_abs(),
31,
) as u8
});
let order = d[0] <= d[1];
static quant_dist_weight: [[u8; 2]; 3] = [[2, 3], [2, 5], [2, 7]];
static quant_dist_lookup_table: [[u8; 2]; 4] = [[9, 7], [11, 5], [12, 4], [13, 3]];
let k = quant_dist_weight
.into_iter()
.position(|weight| {
let c = [order, !order].map(|order| weight[order as usize]);
let dc: [_; 2] = array::from_fn(|i| d[i] * c[i]);
!order && dc[0] < dc[1] || order && dc[0] > dc[1]
})
.unwrap_or(quant_dist_weight.len());
f.jnt_weights[i][j] = quant_dist_lookup_table[k][order as usize];
}
}
}
Ok(())
}
pub(crate) fn rav1d_decode_frame_init_cdf(
c: &Rav1dContext,
fc: &Rav1dFrameContext,
f: &mut Rav1dFrameData,
in_cdf: &CdfThreadContext,
) -> Rav1dResult {
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(EINVAL)?;
if frame_hdr.refresh_context != 0 {
*f.out_cdf.cdf_write() = rav1d_cdf_thread_copy(in_cdf);
}
let uses_2pass = c.fc.len() > 1;
let tiling = &frame_hdr.tiling;
let n_bytes = tiling.n_bytes.into();
let rows: usize = tiling.rows.into();
let cols = tiling.cols.into();
let sb128w: usize = f.sb128w.try_into().unwrap();
let mut tile_row = 0;
let mut tile_col = 0;
fc.task_thread.update_set.set(false);
for tile in &f.tiles {
let start = tile.hdr.start.try_into().unwrap();
let end: usize = tile.hdr.end.try_into().unwrap();
let mut data = tile.data.data.clone().unwrap();
for (j, (ts, tile_start_off)) in iter::zip(
&mut f.ts[..end + 1],
if uses_2pass {
&f.frame_thread.tile_start_off[..end + 1]
} else {
&[]
}
.iter()
.copied()
.chain(iter::repeat(0)),
)
.enumerate()
.skip(start)
{
let tile_sz = if j == end {
data.len()
} else {
if n_bytes > data.len() {
return Err(EINVAL);
}
let (cur_data, rest_data) = CArc::split_at(data, n_bytes);
let tile_sz = cur_data
.iter()
.enumerate()
.map(|(k, &data)| (data as usize) << (k * 8))
.fold(0, |tile_sz, data_k| tile_sz | data_k)
+ 1;
data = rest_data;
if tile_sz > data.len() {
return Err(EINVAL);
}
tile_sz
};
let (cur_data, rest_data) = CArc::split_at(data, tile_sz);
setup_tile(
c,
ts,
&***f.seq_hdr.as_ref().ok_or(EINVAL)?,
frame_hdr,
f.bitdepth_max,
f.sb_shift,
&f.cur,
f.bw,
f.bh,
&f.frame_thread,
f.sr_sb128w,
f.sb128w,
&mut f.lf,
in_cdf,
cur_data,
tile_row,
tile_col,
tile_start_off,
);
tile_col += 1;
if tile_col == cols {
tile_col = 0;
tile_row += 1;
}
if j == tiling.update as usize && frame_hdr.refresh_context != 0 {
fc.task_thread.update_set.set(true);
}
data = rest_data;
}
}
if c.tc.len() > 1 {
for (n, ctx) in f.a[..sb128w * rows * (1 + uses_2pass as usize)]
.iter_mut()
.enumerate()
{
reset_context(
ctx,
frame_hdr.frame_type.is_key_or_intra(),
if uses_2pass {
1 + (n >= sb128w * rows) as c_int
} else {
0
},
);
}
}
Ok(())
}
fn rav1d_decode_frame_main(c: &Rav1dContext, f: &mut Rav1dFrameData) -> Rav1dResult {
assert!(c.tc.len() == 1);
let Rav1dContextTaskType::Single(t) = &c.tc[0].task else {
panic!("Expected a single-threaded context");
};
let mut t = t.lock();
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(EINVAL)?;
for ctx in &mut f.a[..f.sb128w as usize * frame_hdr.tiling.rows as usize] {
reset_context(ctx, frame_hdr.frame_type.is_key_or_intra(), 0);
}
let Rav1dFrameHeaderTiling { rows, cols, .. } = frame_hdr.tiling;
let [rows, cols] = [rows, cols].map(|it| it.into());
let row_start_sb = frame_hdr.tiling.row_start_sb;
for (tile_row, sbh_start_end) in row_start_sb[..rows + 1].windows(2).take(rows).enumerate() {
let [sbh_start, sbh_end] = <[u16; 2]>::try_from(sbh_start_end).unwrap();
let sbh_end = cmp::min(sbh_end.into(), f.sbh);
for sby in sbh_start.into()..sbh_end {
let seq_hdr = &***f.seq_hdr.as_ref().ok_or(EINVAL)?;
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(EINVAL)?;
t.b.y = sby << 4 + seq_hdr.sb128;
let by_end = t.b.y + f.sb_step >> 1;
if frame_hdr.use_ref_frame_mvs != 0 {
c.dsp.refmvs.load_tmvs.call(
&f.rf,
&f.mvs,
&f.ref_mvs,
tile_row as c_int,
0,
f.bw >> 1,
t.b.y >> 1,
by_end,
);
}
for col in 0..cols {
t.ts = tile_row * cols + col;
rav1d_decode_tile_sbrow(c, &mut t, f).map_err(|()| EINVAL)?;
}
if f.frame_hdr().frame_type.is_inter_or_switch() {
c.dsp
.refmvs
.save_tmvs
.call(&t.rt, &f.rf, &f.mvs, 0, f.bw >> 1, t.b.y >> 1, by_end);
}
(f.bd_fn().filter_sbrow)(c, f, &mut t, sby);
}
}
Ok(())
}
pub(crate) fn rav1d_decode_frame_exit(
c: &Rav1dContext,
fc: &Rav1dFrameContext,
mut retval: Rav1dResult,
) -> Rav1dResult {
let task_thread = &fc.task_thread;
let mut f = fc.data.write();
if f.sr_cur.p.data.is_some() {
task_thread.error.store(0, Ordering::Relaxed);
}
let cf = f.frame_thread.cf.get_mut();
if c.fc.len() > 1 && retval.is_err() {
cf.fill_with(Default::default);
}
if retval.is_ok() && c.fc.len() > 1 && c.strict_std_compliance {
if f.refp.iter().any(|rf| {
rf.p.frame_hdr.is_some()
&& rf.progress.as_ref().unwrap()[1].load(Ordering::SeqCst) == FRAME_ERROR
}) {
retval = Err(EINVAL);
task_thread.error.store(1, Ordering::SeqCst);
f.sr_cur.progress.as_mut().unwrap()[1].store(FRAME_ERROR, Ordering::SeqCst);
}
}
let _ = mem::take(&mut f.refp);
let _ = mem::take(&mut f.ref_mvs);
let _ = mem::take(&mut f.cur);
let _ = mem::take(&mut f.sr_cur);
let _ = mem::take(&mut *fc.in_cdf.try_write().unwrap());
if let Some(frame_hdr) = &f.frame_hdr {
if frame_hdr.refresh_context != 0 {
if let Some(progress) = f.out_cdf.progress() {
progress.store(
if retval.is_ok() { 1 } else { TILE_ERROR as u32 },
Ordering::SeqCst,
);
}
let _ = mem::take(&mut f.out_cdf);
}
}
let _ = mem::take(&mut f.cur_segmap);
let _ = mem::take(&mut f.prev_segmap);
let _ = mem::take(&mut f.mvs);
let _ = mem::take(&mut f.seq_hdr);
let _ = mem::take(&mut f.frame_hdr);
f.tiles.clear();
task_thread.finished.store(true, Ordering::SeqCst);
*task_thread.retval.try_lock().unwrap() = retval.err();
retval
}
pub(crate) fn rav1d_decode_frame(c: &Rav1dContext, fc: &Rav1dFrameContext) -> Rav1dResult {
assert!(c.fc.len() == 1);
let mut res = rav1d_decode_frame_init(c, fc);
{
let mut f = fc.data.try_write().unwrap();
if res.is_ok() {
res = rav1d_decode_frame_init_cdf(c, fc, &mut f, &fc.in_cdf());
}
if res.is_ok() {
if c.tc.len() > 1 {
res = rav1d_task_create_tile_sbrow(fc, &f, 0, 1);
drop(f); let mut task_thread_lock = (*fc.task_thread.ttd).lock.lock();
(*fc.task_thread.ttd).cond.notify_one();
if res.is_ok() {
while fc.task_thread.done[0].load(Ordering::SeqCst) == 0
|| fc.task_thread.task_counter.load(Ordering::SeqCst) > 0
{
fc.task_thread.cond.wait(&mut task_thread_lock);
}
}
drop(task_thread_lock);
res = fc.task_thread.retval.try_lock().unwrap().err_or(());
} else {
res = rav1d_decode_frame_main(c, &mut f);
let frame_hdr = &***f.frame_hdr.as_ref().ok_or(EINVAL)?;
if res.is_ok() && frame_hdr.refresh_context != 0 && fc.task_thread.update_set.get()
{
rav1d_cdf_thread_update(
frame_hdr,
&mut f.out_cdf.cdf_write(),
&f.ts[frame_hdr.tiling.update as usize]
.context
.try_lock()
.unwrap()
.cdf,
);
}
}
}
}
rav1d_decode_frame_exit(c, fc, res)
}
fn get_upscale_x0(in_w: c_int, out_w: c_int, step: c_int) -> c_int {
let err = out_w * step - (in_w << 14);
let x0 = (-(out_w - in_w << 13) + (out_w >> 1)) / out_w + 128 - err / 2;
x0 & 0x3fff
}
pub fn rav1d_submit_frame(c: &Rav1dContext, state: &mut Rav1dState) -> Rav1dResult {
let (fc, out, _task_thread_lock) = if c.fc.len() > 1 {
let mut task_thread_lock = c.task_thread.lock.lock();
let next = state.frame_thread.next;
state.frame_thread.next = (state.frame_thread.next + 1) % c.fc.len() as u32;
let fc = &c.fc[next as usize];
while !fc.task_thread.finished.load(Ordering::SeqCst) {
fc.task_thread.cond.wait(&mut task_thread_lock);
}
let out_delayed = &mut state.frame_thread.out_delayed[next as usize];
if out_delayed.p.data.is_some() || fc.task_thread.error.load(Ordering::SeqCst) != 0 {
let first = c.task_thread.first.load(Ordering::SeqCst);
if first as usize + 1 < c.fc.len() {
c.task_thread.first.fetch_add(1, Ordering::SeqCst);
} else {
c.task_thread.first.store(0, Ordering::SeqCst);
}
let _ = c.task_thread.reset_task_cur.compare_exchange(
first,
u32::MAX,
Ordering::SeqCst,
Ordering::SeqCst,
);
let cur = c.task_thread.cur.get();
if cur != 0 && (cur as usize) < c.fc.len() {
c.task_thread.cur.update(|cur| cur - 1);
}
}
let error = &mut *fc.task_thread.retval.try_lock().unwrap();
if error.is_some() {
state.cached_error = mem::take(&mut *error);
state.cached_error_props = out_delayed.p.m.clone();
let _ = mem::take(out_delayed);
} else if out_delayed.p.data.is_some() {
let progress = out_delayed.progress.as_ref().unwrap()[1].load(Ordering::Relaxed);
if (out_delayed.visible || c.output_invisible_frames) && progress != FRAME_ERROR {
state.out = out_delayed.clone();
state.event_flags |= out_delayed.flags.into();
}
let _ = mem::take(out_delayed);
}
(fc, out_delayed, Some(task_thread_lock))
} else {
(&c.fc[0], &mut state.out, None)
};
let mut f = fc.data.try_write().unwrap();
f.seq_hdr = state.seq_hdr.clone();
f.frame_hdr = mem::take(&mut state.frame_hdr);
let seq_hdr = f.seq_hdr.clone().unwrap();
fn on_error(
fc: &Rav1dFrameContext,
f: &mut Rav1dFrameData,
out: &mut Rav1dThreadPicture,
cached_error_props: &mut Rav1dDataProps,
m: &Rav1dDataProps,
) {
fc.task_thread.error.store(1, Ordering::Relaxed);
let _ = mem::take(&mut *fc.in_cdf.try_write().unwrap());
if f.frame_hdr
.as_ref()
.is_some_and(|hdr| hdr.refresh_context != 0)
{
let _ = mem::take(&mut f.out_cdf);
}
for i in 0..7 {
if f.refp[i].p.frame_hdr.is_some() {
let _ = mem::take(&mut f.refp[i]);
}
let _ = mem::take(&mut f.ref_mvs[i]);
}
let _ = mem::take(out);
let _ = mem::take(&mut f.cur);
let _ = mem::take(&mut f.sr_cur);
let _ = mem::take(&mut f.mvs);
let _ = mem::take(&mut f.seq_hdr);
let _ = mem::take(&mut f.frame_hdr);
*cached_error_props = m.clone();
f.tiles.clear();
fc.task_thread.finished.store(true, Ordering::SeqCst);
}
let bpc = 8 + 2 * seq_hdr.hbd;
match Rav1dBitDepthDSPContext::get(bpc) {
Some(dsp) => f.dsp = dsp,
None => {
writeln!(c.logger, "Compiled without support for {bpc}-bit decoding",);
on_error(
fc,
&mut f,
out,
&mut state.cached_error_props,
&state.in_0.m,
);
return Err(ENOPROTOOPT);
}
};
fn scale_fac(ref_sz: i32, this_sz: i32) -> i32 {
((ref_sz << 14) + (this_sz >> 1)) / this_sz
}
let mut ref_coded_width = <[i32; 7]>::default();
let frame_hdr = f.frame_hdr.as_ref().ok_or(EINVAL)?.clone();
if frame_hdr.frame_type.is_inter_or_switch() {
if frame_hdr.primary_ref_frame != RAV1D_PRIMARY_REF_NONE {
let pri_ref = frame_hdr.refidx[frame_hdr.primary_ref_frame as usize] as usize;
if state.refs[pri_ref].p.p.data.is_none() {
on_error(
fc,
&mut f,
out,
&mut state.cached_error_props,
&state.in_0.m,
);
return Err(EINVAL);
}
}
for i in 0..7 {
let refidx = frame_hdr.refidx[i] as usize;
if state.refs[refidx].p.p.data.is_none()
|| (frame_hdr.size.width[0] * 2) < state.refs[refidx].p.p.p.w
|| (frame_hdr.size.height * 2) < state.refs[refidx].p.p.p.h
|| frame_hdr.size.width[0] > state.refs[refidx].p.p.p.w * 16
|| frame_hdr.size.height > state.refs[refidx].p.p.p.h * 16
|| seq_hdr.layout != state.refs[refidx].p.p.p.layout
|| bpc != state.refs[refidx].p.p.p.bpc
{
for j in 0..i {
let _ = mem::take(&mut f.refp[j]);
}
on_error(
fc,
&mut f,
out,
&mut state.cached_error_props,
&state.in_0.m,
);
return Err(EINVAL);
}
f.refp[i] = state.refs[refidx].p.clone();
ref_coded_width[i] = state.refs[refidx]
.p
.p
.frame_hdr
.as_ref()
.unwrap()
.size
.width[0];
if frame_hdr.size.width[0] != state.refs[refidx].p.p.p.w
|| frame_hdr.size.height != state.refs[refidx].p.p.p.h
{
f.svc[i][0].scale = scale_fac(state.refs[refidx].p.p.p.w, frame_hdr.size.width[0]);
f.svc[i][1].scale = scale_fac(state.refs[refidx].p.p.p.h, frame_hdr.size.height);
f.svc[i][0].step = f.svc[i][0].scale + 8 >> 4;
f.svc[i][1].step = f.svc[i][1].scale + 8 >> 4;
} else {
f.svc[i][1].scale = 0;
f.svc[i][0].scale = f.svc[i][1].scale;
}
f.gmv_warp_allowed[i] = (frame_hdr.gmv[i].r#type > Rav1dWarpedMotionType::Translation
&& !frame_hdr.force_integer_mv
&& !rav1d_get_shear_params(&frame_hdr.gmv[i])
&& f.svc[i][0].scale == 0) as u8;
}
}
if frame_hdr.primary_ref_frame == RAV1D_PRIMARY_REF_NONE {
*fc.in_cdf.try_write().unwrap() = rav1d_cdf_thread_init_static(frame_hdr.quant.yac);
} else {
let pri_ref = frame_hdr.refidx[frame_hdr.primary_ref_frame as usize] as usize;
*fc.in_cdf.try_write().unwrap() = state.cdf[pri_ref].clone();
}
if frame_hdr.refresh_context != 0 {
let res = rav1d_cdf_thread_alloc(c.fc.len() > 1);
match res {
Err(e) => {
on_error(
fc,
&mut f,
out,
&mut state.cached_error_props,
&state.in_0.m,
);
return Err(e);
}
Ok(res) => {
f.out_cdf = res;
}
}
}
f.tiles.clear();
mem::swap(&mut f.tiles, &mut state.tiles);
fc.task_thread
.finished
.store(f.tiles.is_empty(), Ordering::SeqCst);
let itut_t35 = mem::take(&mut state.itut_t35);
let res = rav1d_thread_picture_alloc(
&c.fc,
&c.logger,
&c.allocator,
state.content_light.clone(),
state.mastering_display.clone(),
c.output_invisible_frames,
state.max_spatial_id,
&mut state.frame_flags,
&mut f,
bpc,
itut_t35,
);
if res.is_err() {
on_error(
fc,
&mut f,
out,
&mut state.cached_error_props,
&state.in_0.m,
);
return res;
}
let seq_hdr = f.seq_hdr.as_ref().ok_or(EINVAL)?.clone();
let frame_hdr = f.frame_hdr.as_ref().ok_or(EINVAL)?.clone();
if frame_hdr.size.width[0] != frame_hdr.size.width[1] {
let f = &mut *f;
let res =
rav1d_picture_alloc_copy(&c.logger, &mut f.cur, frame_hdr.size.width[0], &f.sr_cur.p);
if res.is_err() {
on_error(fc, f, out, &mut state.cached_error_props, &state.in_0.m);
return res;
}
} else {
f.cur = f.sr_cur.p.clone();
}
if frame_hdr.size.width[0] != frame_hdr.size.width[1] {
f.resize_step[0] = scale_fac(f.cur.p.w, f.sr_cur.p.p.w);
let ss_hor = (f.cur.p.layout != Rav1dPixelLayout::I444) as c_int;
let in_cw = f.cur.p.w + ss_hor >> ss_hor;
let out_cw = f.sr_cur.p.p.w + ss_hor >> ss_hor;
f.resize_step[1] = scale_fac(in_cw, out_cw);
f.resize_start[0] = get_upscale_x0(f.cur.p.w, f.sr_cur.p.p.w, f.resize_step[0]);
f.resize_start[1] = get_upscale_x0(in_cw, out_cw, f.resize_step[1]);
}
if c.fc.len() == 1 {
if frame_hdr.show_frame != 0 || c.output_invisible_frames {
*out = f.sr_cur.clone();
state.event_flags |= f.sr_cur.flags.into();
}
} else {
*out = f.sr_cur.clone();
}
f.w4 = frame_hdr.size.width[0] + 3 >> 2;
f.h4 = frame_hdr.size.height + 3 >> 2;
f.bw = (frame_hdr.size.width[0] + 7 >> 3) << 1;
f.bh = (frame_hdr.size.height + 7 >> 3) << 1;
f.sb128w = f.bw + 31 >> 5;
f.sb128h = f.bh + 31 >> 5;
f.sb_shift = 4 + seq_hdr.sb128 as c_int;
f.sb_step = 16 << seq_hdr.sb128;
f.sbh = f.bh + f.sb_step - 1 >> f.sb_shift;
f.b4_stride = (f.bw + 31 & !31) as ptrdiff_t;
f.bitdepth_max = (1 << f.cur.p.bpc) - 1;
fc.task_thread.error.store(0, Ordering::Relaxed);
let uses_2pass = (c.fc.len() > 1) as c_int;
let cols = frame_hdr.tiling.cols;
let rows = frame_hdr.tiling.rows;
fc.task_thread.task_counter.store(
cols as c_int * rows as c_int + f.sbh << uses_2pass,
Ordering::SeqCst,
);
if frame_hdr.frame_type.is_inter_or_switch() || frame_hdr.allow_intrabc {
let mvs_sz = f.sb128h as usize * 16 * (f.b4_stride >> 1) as usize;
f.mvs = Some(
crate::src::disjoint_mut::dm_arc_try_new(mvs_sz, Default::default())
.map_err(|_| ENOMEM)?,
);
if !frame_hdr.allow_intrabc {
for i in 0..7 {
f.refpoc[i] = f.refp[i].p.frame_hdr.as_ref().ok_or(EINVAL)?.frame_offset as c_uint;
}
} else {
f.refpoc.fill(0);
}
if frame_hdr.use_ref_frame_mvs != 0 {
for i in 0..7 {
let refidx = frame_hdr.refidx[i] as usize;
let ref_w = (ref_coded_width[i] + 7 >> 3) << 1;
let ref_h = (f.refp[i].p.p.h + 7 >> 3) << 1;
if ref_w == f.bw && ref_h == f.bh {
f.ref_mvs[i] = state.refs[refidx].refmvs.clone();
} else {
f.ref_mvs[i] = None;
}
f.refrefpoc[i] = state.refs[refidx].refpoc;
}
} else {
f.ref_mvs.fill_with(Default::default);
}
} else {
f.mvs = None;
f.ref_mvs.fill_with(Default::default);
}
if frame_hdr.segmentation.enabled != 0 {
f.prev_segmap = None;
if frame_hdr.segmentation.temporal != 0 || frame_hdr.segmentation.update_map == 0 {
let pri_ref = frame_hdr.primary_ref_frame as usize;
assert!(pri_ref != RAV1D_PRIMARY_REF_NONE as usize);
let ref_w = (ref_coded_width[pri_ref] + 7 >> 3) << 1;
let ref_h = (f.refp[pri_ref].p.p.h + 7 >> 3) << 1;
if ref_w == f.bw && ref_h == f.bh {
f.prev_segmap = state.refs[frame_hdr.refidx[pri_ref] as usize]
.segmap
.clone();
}
}
f.cur_segmap = Some(
match (
frame_hdr.segmentation.update_map != 0,
f.prev_segmap.as_mut(),
) {
(true, _) | (false, None) => {
let segmap_size = f.b4_stride as usize * 32 * f.sb128h as usize;
crate::src::disjoint_mut::dm_arc_try_new(segmap_size, Default::default())
.map_err(|_| ENOMEM)?
}
(_, Some(prev_segmap)) => {
prev_segmap.clone()
}
},
);
} else {
f.cur_segmap = None;
f.prev_segmap = None;
}
let refresh_frame_flags = frame_hdr.refresh_frame_flags as c_uint;
for i in 0..8 {
if refresh_frame_flags & (1 << i) != 0 {
if state.refs[i].p.p.frame_hdr.is_some() {
let _ = mem::take(&mut state.refs[i].p);
}
state.refs[i].p = f.sr_cur.clone();
if frame_hdr.refresh_context != 0 {
state.cdf[i] = f.out_cdf.clone();
} else {
state.cdf[i] = fc.in_cdf.try_read().unwrap().clone();
}
state.refs[i].segmap = f.cur_segmap.clone();
let _ = mem::take(&mut state.refs[i].refmvs);
if !frame_hdr.allow_intrabc {
state.refs[i].refmvs = f.mvs.clone();
}
state.refs[i].refpoc = f.refpoc;
}
}
drop(f);
if c.fc.len() == 1 {
let res = rav1d_decode_frame(c, &fc);
if res.is_err() {
let _ = mem::take(&mut state.out);
for i in 0..8 {
if refresh_frame_flags & (1 << i) != 0 {
if state.refs[i].p.p.frame_hdr.is_some() {
let _ = mem::take(&mut state.refs[i].p);
}
let _ = mem::take(&mut state.cdf[i]);
let _ = mem::take(&mut state.refs[i].segmap);
let _ = mem::take(&mut state.refs[i].refmvs);
}
}
let mut f = fc.data.try_write().unwrap();
on_error(
fc,
&mut f,
&mut state.out,
&mut state.cached_error_props,
&state.in_0.m,
);
return res;
}
} else {
rav1d_task_frame_init(c, fc);
}
Ok(())
}