From 0ba021388e7d56d4ef0af231ce673f3bbc64e4ff Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 28 Oct 2026 02:05:37 +0000 Subject: [PATCH] Refactor mpeg2v for strict Clippy checks --- crates/mpeg2v/src/mc.rs | 25 +++- crates/mpeg2v/src/slice.rs | 234 ++++++++++++++++++------------- crates/mpeg2v/src/synth_tests.rs | 92 +++++++----- 3 files changed, 213 insertions(+), 138 deletions(-) diff --git a/crates/mpeg2v/src/mc.rs b/crates/mpeg2v/src/mc.rs index 937b4bc9a..2d39508e2 100644 --- a/crates/mpeg2v/src/mc.rs +++ b/crates/mpeg2v/src/mc.rs @@ -38,13 +38,24 @@ pub(crate) struct RefPlane<'a> { pub h: usize, } +/// A block to predict: integer position, half-sample flags and size. +#[derive(Clone, Copy)] +pub(crate) struct Block { + pub(crate) x: i32, + pub(crate) y: i32, + pub(crate) hx: bool, + pub(crate) hy: bool, + pub(crate) bw: usize, + pub(crate) bh: usize, +} + /// Form the `bw`×`bh` prediction at integer position (`x`, `y`) with half-sample flags into /// `dst` (row `r` at `dst[doff + r·dstride..]`), or average it with what is there (`avg`). /// Positions outside the reference are clamped to its edges (not allowed in conforming streams; /// this keeps corrupt ones safe). -#[allow(clippy::too_many_arguments)] #[inline] -pub(crate) fn predict(dst: &mut [u8], doff: usize, dstride: usize, src: RefPlane, x: i32, y: i32, hx: bool, hy: bool, bw: usize, bh: usize, avg: bool) { +pub(crate) fn predict(dst: &mut [u8], doff: usize, dstride: usize, src: RefPlane, blk: Block, avg: bool) { + let Block { x, y, hx, hy, bw, bh } = blk; let (ex, ey) = (hx as i32, hy as i32); let inside = x >= 0 && y >= 0 && (x + bw as i32 + ex) as usize <= src.w && (y + bh as i32 + ey) as usize <= src.h; let mut tmp = [0u8; 16]; @@ -129,10 +140,10 @@ mod tests { let f = frame(); let p = f.plane(0, None); let mut d = [0u8; 4]; - predict(&mut d, 0, 2, p, 1, 1, true, true, 2, 2, false); + predict(&mut d, 0, 2, p, Block { x: 1, y: 1, hx: true, hy: true, bw: 2, bh: 2 }, false); let s = |x: usize, y: usize| f.planes[0][y * 32 + x] as u16; assert_eq!(d[0] as u16, (s(1, 1) + s(2, 1) + s(1, 2) + s(2, 2) + 2) >> 2); - predict(&mut d, 0, 2, p, 1, 1, true, false, 2, 2, false); + predict(&mut d, 0, 2, p, Block { x: 1, y: 1, hx: true, hy: false, bw: 2, bh: 2 }, false); assert_eq!(d[3] as u16, (s(2, 2) + s(3, 2) + 1) >> 1); } @@ -141,14 +152,14 @@ mod tests { let f = frame(); let mut d = [0u8; 4]; // bottom field row 0 = frame row 1 - predict(&mut d, 0, 2, f.plane(0, Some(1)), 0, 0, false, false, 2, 2, false); + predict(&mut d, 0, 2, f.plane(0, Some(1)), Block { x: 0, y: 0, hx: false, hy: false, bw: 2, bh: 2 }, false); assert_eq!(d, [f.planes[0][32], f.planes[0][33], f.planes[0][96], f.planes[0][97]]); // outside: clamped to the corner - predict(&mut d, 0, 2, f.plane(0, None), -10, -10, false, false, 2, 2, false); + predict(&mut d, 0, 2, f.plane(0, None), Block { x: -10, y: -10, hx: false, hy: false, bw: 2, bh: 2 }, false); assert_eq!(d, [f.planes[0][0]; 4]); // averaging let mut d = [10u8; 4]; - predict(&mut d, 0, 2, f.plane(0, None), -10, -10, false, false, 2, 2, true); + predict(&mut d, 0, 2, f.plane(0, None), Block { x: -10, y: -10, hx: false, hy: false, bw: 2, bh: 2 }, true); assert_eq!(d[0], ((10 + f.planes[0][0] as u16 + 1) >> 1) as u8); } } diff --git a/crates/mpeg2v/src/slice.rs b/crates/mpeg2v/src/slice.rs index 5f3eb24eb..6947f44ec 100644 --- a/crates/mpeg2v/src/slice.rs +++ b/crates/mpeg2v/src/slice.rs @@ -4,7 +4,7 @@ use crate::bits::Bits; use crate::headers::{PictureCodingExtension, PictureType, SCAN}; use crate::idct::idct; -use crate::mc::{Frame, predict}; +use crate::mc::{Block, Frame, predict}; use crate::vlc::{DCT_EOB, DCT_ESCAPE, MB_BWD, MB_FWD, MB_INTRA, MB_PATTERN, MB_QUANT, MBA_ESCAPE, MBA_STUFFING, tables}; /// Non-linear quantiser_scale (Table 7-6), indexed by quantiser_scale_code. @@ -232,7 +232,6 @@ fn skipped_mb(p: &PicParams, st: &mut SliceState, addr: usize, buf: &mut MbBuf, Ok(()) } -#[allow(clippy::too_many_arguments)] fn macroblock(p: &PicParams, st: &mut SliceState, b: &mut Bits, addr: usize, buf: &mut MbBuf, blk: &mut [i32; 64], t: &mut Target) -> R<()> { let tb = tables(); let ti = match p.ptype { @@ -257,15 +256,81 @@ fn macroblock(p: &PicParams, st: &mut SliceState, b: &mut Bits, addr: usize, buf if flags & MB_QUANT != 0 { st.qscale = qscale(p, b.read(5) as usize); } - // motion vectors - let (count, field_fmt, dual) = match (frame_pic, m.mtype) { - (true, MT_FIELD) => (2, true, false), - (true, MT_DUAL) | (false, MT_DUAL) => (1, true, true), - (true, _) => (1, false, false), - (false, MT_16X8) => (2, true, false), - (false, _) => (1, true, false), - }; let concealment = intra && p.pce.concealment_motion_vectors; + read_motion_vectors(p, st, b, &mut m, concealment)?; + if concealment { + b.skip(1); // marker_bit + } + // coded_block_pattern + let nblocks = 4 + p.chroma_blocks(); + let cbp = read_cbp(p, b, flags, intra)?; + let (mbx, mby) = (addr % p.mb_width, addr / p.mb_width); + if intra { + if !concealment { + st.pmv = [[[0; 2]; 2]; 2]; + } + } else { + st.dc_pred = [dc_reset(p); 3]; + if p.ptype == PictureType::P && flags & MB_FWD == 0 { + // "No MC": zero vector from the same position (same-parity field in field pictures) + st.pmv = [[[0; 2]; 2]; 2]; + m.flags |= MB_FWD; + m.mtype = if frame_pic { MT_FRAME } else { MT_FIELD }; + m.select[0][0] = p.parity; + } + predict_mb(p, &m, mbx, mby, buf); + } + // blocks + let (cbw, cbh) = p.cmb(); + for i in 0..nblocks { + if cbp & (1 << (nblocks - 1 - i)) == 0 { + continue; + } + let cc = block_component(i); + let dc_only = block(p, st, b, cc, intra, blk)?; + idct(blk, dc_only); + place_block(buf, blk, i, (cbw, cbh), dct_type, intra); + } + if p.ptype == PictureType::D { + b.skip(1); // end_of_macroblock + } + t.put(mbx, mby, buf, (cbw, cbh)); + st.last = m; + Ok(()) +} + +/// Colour component (0 luma, 1 Cb, 2 Cr) of block `i` of a macroblock. +fn block_component(i: usize) -> usize { + if i < 4 { 0 } else { 1 + (i & 1) } +} + +/// How a macroblock's motion vectors are sent. +struct MvLayout { + /// Vectors per direction: 1, or 2 for field/16x8 prediction. + count: usize, + field_fmt: bool, + dual: bool, +} + +impl MvLayout { + fn of(frame_pic: bool, mtype: u8) -> MvLayout { + let (count, field_fmt, dual) = match (frame_pic, mtype) { + (true, MT_FIELD) => (2, true, false), + (true, MT_DUAL) | (false, MT_DUAL) => (1, true, true), + (true, _) => (1, false, false), + (false, MT_16X8) => (2, true, false), + (false, _) => (1, true, false), + }; + MvLayout { count, field_fmt, dual } + } +} + +/// Read the motion vectors (and dual-prime vectors) of a macroblock, updating the predictors. +fn read_motion_vectors(p: &PicParams, st: &mut SliceState, b: &mut Bits, m: &mut Motion, concealment: bool) -> R<()> { + let tb = tables(); + let frame_pic = p.frame_picture(); + let MvLayout { count, field_fmt, dual } = MvLayout::of(frame_pic, m.mtype); + let flags = m.flags; for s in 0..2 { let present = if s == 0 { flags & MB_FWD != 0 || concealment } else { flags & MB_BWD != 0 }; if !present { @@ -301,75 +366,49 @@ fn macroblock(p: &PicParams, st: &mut SliceState, b: &mut Bits, addr: usize, buf } } } - if concealment { - b.skip(1); // marker_bit - } - // coded_block_pattern + Ok(()) +} + +/// coded_block_pattern: one bit per block, first block in the most significant bit. +fn read_cbp(p: &PicParams, b: &mut Bits, flags: i16, intra: bool) -> R { let nblocks = 4 + p.chroma_blocks(); - let cbp: u32 = if flags & MB_PATTERN != 0 { - let v = tb.cbp.decode(b).ok_or(SliceError("bad coded_block_pattern"))? as u32; + Ok(if flags & MB_PATTERN != 0 { + let v = tables().cbp.decode(b).ok_or(SliceError("bad coded_block_pattern"))? as u32; if nblocks == 8 { (v << 2) | b.read(2) } else { v } } else if intra { (1 << nblocks) - 1 } else { 0 - }; - let (mbx, mby) = (addr % p.mb_width, addr / p.mb_width); - if intra { - if !concealment { - st.pmv = [[[0; 2]; 2]; 2]; - } + }) +} + +/// Write (intra) or add (inter) the decoded block `i` into the macroblock buffer. +fn place_block(buf: &mut MbBuf, blk: &[i32; 64], i: usize, cmb: (usize, usize), dct_type: bool, intra: bool) { + let (cbw, cbh) = cmb; + let cc = block_component(i); + let (dst, stride, x0, y0, step) = if i < 4 { + let x0 = (i & 1) * 8; + let (y0, step) = if dct_type { (i >> 1, 2) } else { ((i >> 1) * 8, 1) }; + (&mut buf.y[..], 16, x0, y0, step) } else { - st.dc_pred = [dc_reset(p); 3]; - if p.ptype == PictureType::P && flags & MB_FWD == 0 { - // "No MC": zero vector from the same position (same-parity field in field pictures) - st.pmv = [[[0; 2]; 2]; 2]; - m.flags |= MB_FWD; - m.mtype = if frame_pic { MT_FRAME } else { MT_FIELD }; - m.select[0][0] = p.parity; - } - predict_mb(p, &m, mbx, mby, buf); - } - // blocks - let (cbw, cbh) = p.cmb(); - for i in 0..nblocks { - if cbp & (1 << (nblocks - 1 - i)) == 0 { - continue; - } - let cc = if i < 4 { 0 } else { 1 + (i & 1) }; - let dc_only = block(p, st, b, cc, intra, blk)?; - idct(blk, dc_only); - // placement - let (dst, stride, x0, y0, step) = if i < 4 { - let x0 = (i & 1) * 8; - let (y0, step) = if dct_type { (i >> 1, 2) } else { ((i >> 1) * 8, 1) }; - (&mut buf.y[..], 16, x0, y0, step) + let k = (i - 4) >> 1; // 0 for 4:2:0; 0/1 (top/bottom) for 4:2:2 + let (y0, step) = if cbh == 16 && dct_type { (k, 2) } else { (k * 8, 1) }; + (&mut buf.c[cc - 1][..], cbw, 0, y0, step) + }; + for r in 0..8 { + let at = (y0 + r * step) * stride + x0; + let row = &mut dst[at..at + 8]; + let src = &blk[r * 8..r * 8 + 8]; + if intra { + for (o, &v) in row.iter_mut().zip(src) { + *o = v.clamp(0, 255) as u8; + } } else { - let k = (i - 4) >> 1; // 0 for 4:2:0; 0/1 (top/bottom) for 4:2:2 - let (y0, step) = if cbh == 16 && dct_type { (k, 2) } else { (k * 8, 1) }; - (&mut buf.c[cc - 1][..], cbw, 0, y0, step) - }; - for r in 0..8 { - let at = (y0 + r * step) * stride + x0; - let row = &mut dst[at..at + 8]; - let src = &blk[r * 8..r * 8 + 8]; - if intra { - for (o, &v) in row.iter_mut().zip(src) { - *o = v.clamp(0, 255) as u8; - } - } else { - for (o, &v) in row.iter_mut().zip(src) { - *o = (*o as i32 + v).clamp(0, 255) as u8; - } + for (o, &v) in row.iter_mut().zip(src) { + *o = (*o as i32 + v).clamp(0, 255) as u8; } } } - if p.ptype == PictureType::D { - b.skip(1); // end_of_macroblock - } - t.put(mbx, mby, buf, (cbw, cbh)); - st.last = m; - Ok(()) } /// Decode and dequantise one block into `blk` (raster order). Returns whether only the DC @@ -504,6 +543,7 @@ fn reference<'a>(p: &PicParams<'a>, s: usize, sel: usize) -> Option<&'a Frame> { /// Form the prediction of a non-intra macroblock in `buf` (§7.6). fn predict_mb(p: &PicParams, m: &Motion, mbx: usize, mby: usize, buf: &mut MbBuf) { let (cbw, cbh) = p.cmb(); + let mb = Pred { mv: [0; 2], mbx, mby, cbw, cbh, avg: false }; let frame_pic = p.frame_picture(); let mut avg = false; for s in 0..2 { @@ -516,7 +556,7 @@ fn predict_mb(p: &PicParams, m: &Motion, mbx: usize, mby: usize, buf: &mut MbBuf MT_FIELD => { for r in 0..2 { let Some(f) = reference(p, s, m.select[r][s]) else { return gray(buf) }; - pred_block(p, buf, f, Some(m.select[r][s]), m.mv[r][s], mbx, mby, 8, r, 2, (cbw, cbh), avg); + pred_block(p, buf, f, Some(m.select[r][s]), Pred { mv: m.mv[r][s], avg, ..mb }, (8, r, 2)); } } MT_DUAL => { @@ -525,13 +565,13 @@ fn predict_mb(p: &PicParams, m: &Motion, mbx: usize, mby: usize, buf: &mut MbBuf let opp = 1 - par; let (mm, e) = if par == 0 { (if p.pce.top_field_first { 1 } else { 3 }, -1) } else { (if p.pce.top_field_first { 3 } else { 1 }, 1) }; let d = dual_vector(m.mv[0][s], m.dmv, mm, e); - pred_block(p, buf, f, Some(par), m.mv[0][s], mbx, mby, 8, par, 2, (cbw, cbh), avg); - pred_block(p, buf, f, Some(opp), d, mbx, mby, 8, par, 2, (cbw, cbh), true); + pred_block(p, buf, f, Some(par), Pred { mv: m.mv[0][s], avg, ..mb }, (8, par, 2)); + pred_block(p, buf, f, Some(opp), Pred { mv: d, avg: true, ..mb }, (8, par, 2)); } } _ => { let Some(f) = reference(p, s, 0) else { return gray(buf) }; - pred_block(p, buf, f, None, m.mv[0][s], mbx, mby, 16, 0, 1, (cbw, cbh), avg); + pred_block(p, buf, f, None, Pred { mv: m.mv[0][s], avg, ..mb }, (16, 0, 1)); } } } else { @@ -539,7 +579,7 @@ fn predict_mb(p: &PicParams, m: &Motion, mbx: usize, mby: usize, buf: &mut MbBuf MT_16X8 => { for r in 0..2 { let Some(f) = reference(p, s, m.select[r][s]) else { return gray(buf) }; - pred_half(p, buf, f, m.select[r][s], m.mv[r][s], mbx, mby, r, (cbw, cbh), avg); + pred_half(p, buf, f, m.select[r][s], Pred { mv: m.mv[r][s], avg, ..mb }, r); } } MT_DUAL => { @@ -549,12 +589,12 @@ fn predict_mb(p: &PicParams, m: &Motion, mbx: usize, mby: usize, buf: &mut MbBuf let Some(fo) = reference(p, s, opp) else { return gray(buf) }; let e = if same == 1 { 1 } else { -1 }; let d = dual_vector(m.mv[0][s], m.dmv, 1, e); - pred_block(p, buf, fs, Some(same), m.mv[0][s], mbx, mby, 16, 0, 1, (cbw, cbh), avg); - pred_block(p, buf, fo, Some(opp), d, mbx, mby, 16, 0, 1, (cbw, cbh), true); + pred_block(p, buf, fs, Some(same), Pred { mv: m.mv[0][s], avg, ..mb }, (16, 0, 1)); + pred_block(p, buf, fo, Some(opp), Pred { mv: d, avg: true, ..mb }, (16, 0, 1)); } _ => { let Some(f) = reference(p, s, m.select[0][s]) else { return gray(buf) }; - pred_block(p, buf, f, Some(m.select[0][s]), m.mv[0][s], mbx, mby, 16, 0, 1, (cbw, cbh), avg); + pred_block(p, buf, f, Some(m.select[0][s]), Pred { mv: m.mv[0][s], avg, ..mb }, (16, 0, 1)); } } } @@ -574,47 +614,49 @@ fn dual_vector(v: [i32; 2], dmv: [i32; 2], m: i32, e: i32) -> [i32; 2] { [scale(v[0]) + dmv[0], scale(v[1]) + e + dmv[1]] } -/// Predict a 16-wide luma block of `lh` lines (plus chroma) from `f` (one field when `field`), -/// into `buf` lines `first + k·step`. `lh` is 16 (frame or field-picture prediction) or 8 (one -/// field of a frame macroblock). -#[allow(clippy::too_many_arguments)] -fn pred_block( - p: &PicParams, - buf: &mut MbBuf, - f: &Frame, - field: Option, +/// One motion-compensated prediction: vector, macroblock position, chroma block size, and +/// whether to average with what the buffer already holds. +#[derive(Clone, Copy)] +struct Pred { mv: [i32; 2], mbx: usize, mby: usize, - lh: usize, - first: usize, - step: usize, - (cbw, cbh): (usize, usize), + cbw: usize, + cbh: usize, avg: bool, -) { +} + +/// Predict a 16-wide luma block of `lh` lines (plus chroma) from `f` (one field when `field`), +/// into `buf` lines `first + k·step`; `lines` is `(lh, first, step)`. `lh` is 16 (frame or +/// field-picture prediction) or 8 (one field of a frame macroblock). +fn pred_block(p: &PicParams, buf: &mut MbBuf, f: &Frame, field: Option, pr: Pred, lines: (usize, usize, usize)) { + let Pred { mv, mbx, mby, cbw, cbh, avg } = pr; + let (lh, first, step) = lines; // luma: base position in the reference plane's own (frame or field) lines let by = if lh == 8 { mby * 8 } else { mby * 16 }; let (x, y) = ((mbx * 16) as i32 + (mv[0] >> 1), by as i32 + (mv[1] >> 1)); - predict(&mut buf.y, first * 16, 16 * step, f.plane(0, field), x, y, mv[0] & 1 != 0, mv[1] & 1 != 0, 16, lh, avg); + predict(&mut buf.y, first * 16, 16 * step, f.plane(0, field), Block { x, y, hx: mv[0] & 1 != 0, hy: mv[1] & 1 != 0, bw: 16, bh: lh }, avg); let cmv = [if p.shx == 1 { mv[0] / 2 } else { mv[0] }, if p.shy == 1 { mv[1] / 2 } else { mv[1] }]; let clh = if lh == 8 { cbh / 2 } else { cbh }; let cby = mby * clh; let (cx, cy) = ((mbx * cbw) as i32 + (cmv[0] >> 1), cby as i32 + (cmv[1] >> 1)); + let cb = Block { x: cx, y: cy, hx: cmv[0] & 1 != 0, hy: cmv[1] & 1 != 0, bw: cbw, bh: clh }; for c in 0..2 { - predict(&mut buf.c[c], first * cbw, cbw * step, f.plane(1 + c, field), cx, cy, cmv[0] & 1 != 0, cmv[1] & 1 != 0, cbw, clh, avg); + predict(&mut buf.c[c], first * cbw, cbw * step, f.plane(1 + c, field), cb, avg); } } /// 16x8 motion compensation in a field picture: half `r` (0 upper, 1 lower) of the macroblock. -#[allow(clippy::too_many_arguments)] -fn pred_half(p: &PicParams, buf: &mut MbBuf, f: &Frame, field: usize, mv: [i32; 2], mbx: usize, mby: usize, r: usize, (cbw, cbh): (usize, usize), avg: bool) { +fn pred_half(p: &PicParams, buf: &mut MbBuf, f: &Frame, field: usize, pr: Pred, r: usize) { + let Pred { mv, mbx, mby, cbw, cbh, avg } = pr; let (x, y) = ((mbx * 16) as i32 + (mv[0] >> 1), (mby * 16 + r * 8) as i32 + (mv[1] >> 1)); - predict(&mut buf.y, r * 8 * 16, 16, f.plane(0, Some(field)), x, y, mv[0] & 1 != 0, mv[1] & 1 != 0, 16, 8, avg); + predict(&mut buf.y, r * 8 * 16, 16, f.plane(0, Some(field)), Block { x, y, hx: mv[0] & 1 != 0, hy: mv[1] & 1 != 0, bw: 16, bh: 8 }, avg); let cmv = [if p.shx == 1 { mv[0] / 2 } else { mv[0] }, if p.shy == 1 { mv[1] / 2 } else { mv[1] }]; let ch = cbh / 2; let (cx, cy) = ((mbx * cbw) as i32 + (cmv[0] >> 1), (mby * cbh + r * ch) as i32 + (cmv[1] >> 1)); + let cb = Block { x: cx, y: cy, hx: cmv[0] & 1 != 0, hy: cmv[1] & 1 != 0, bw: cbw, bh: ch }; for c in 0..2 { - predict(&mut buf.c[c], r * ch * cbw, cbw, f.plane(1 + c, Some(field)), cx, cy, cmv[0] & 1 != 0, cmv[1] & 1 != 0, cbw, ch, avg); + predict(&mut buf.c[c], r * ch * cbw, cbw, f.plane(1 + c, Some(field)), cb, avg); } } diff --git a/crates/mpeg2v/src/synth_tests.rs b/crates/mpeg2v/src/synth_tests.rs index 33baf11a8..414f6c7ef 100644 --- a/crates/mpeg2v/src/synth_tests.rs +++ b/crates/mpeg2v/src/synth_tests.rs @@ -334,9 +334,46 @@ impl Enc { fn macroblock(&mut self, p: &Pic, st: &mut St, mbx: usize, mby: usize) { let frame_pic = p.structure == 3; - // macroblock_type + let (table, flags) = self.pick_mb_type(p); + let intra = flags & MB_INTRA != 0; + let concealment = intra && self.cfg.concealment; + let mut pmv = st.pmv; + let moving = flags & (MB_FWD | MB_BWD) != 0; + let mut m = self.pick_motion(p, flags, concealment, (mbx, mby), pmv); + self.w.code(code_of(table, flags)); + if moving { + self.w.put(m.mtype as u32, 2); + } + let dct_type = frame_pic && !p.fpfd && (intra || flags & MB_PATTERN != 0); + if dct_type { + self.w.put(self.rng.below(2), 1); + } + if flags & MB_QUANT != 0 { + let q = self.rng.range(1, 31); + self.set_q(q); + self.w.put(q as u32, 5); + } + self.put_vectors(p, &m, concealment, &mut pmv); + // predictor resets + if intra { + if !concealment { + pmv = [[[0; 2]; 2]; 2]; + } + } else { + st.dc = [self.dc_reset(); 3]; + if p.ptype == PictureType::P && flags & MB_FWD == 0 { + pmv = [[[0; 2]; 2]; 2]; + m.select[0][0] = p.parity; + } + } + st.pmv = pmv; + self.put_blocks(st, flags, intra); + st.last = m; + } + + fn pick_mb_type(&mut self, p: &Pic) -> (&'static [(&'static str, i16)], i16) { let quant = self.rng.chance(25); - let (table, mut flags): (&[(&str, i16)], i16) = match p.ptype { + let (table, mut flags): (&'static [(&'static str, i16)], i16) = match p.ptype { PictureType::I => (MBTYPE_I, MB_INTRA), PictureType::P => ( MBTYPE_P, @@ -364,12 +401,15 @@ impl Enc { if quant && (flags & (MB_INTRA | MB_PATTERN) != 0) { flags |= MB_QUANT; } - let intra = flags & MB_INTRA != 0; - let concealment = intra && self.cfg.concealment; - // motion description: pick vectors until the prediction fits + (table, flags) + } + + /// Pick vectors until the prediction fits the picture and the predictors can reach them. + fn pick_motion(&mut self, p: &Pic, flags: i16, concealment: bool, pos: (usize, usize), pmv: [[[i32; 2]; 2]; 2]) -> M { + let (mbx, mby) = pos; + let frame_pic = p.structure == 3; let mut m = M { flags, ..Default::default() }; let moving = flags & (MB_FWD | MB_BWD) != 0; - let mut pmv = st.pmv; if moving || concealment { let mut ok = false; for _ in 0..40 { @@ -431,20 +471,13 @@ impl Enc { assert!(representable(p, &m, concealment, pmv)); } } - self.w.code(code_of(table, flags)); - if moving { - self.w.put(m.mtype as u32, 2); - } - let dct_type = frame_pic && !p.fpfd && (intra || flags & MB_PATTERN != 0); - if dct_type { - self.w.put(self.rng.below(2), 1); - } - if flags & MB_QUANT != 0 { - let q = self.rng.range(1, 31); - self.set_q(q); - self.w.put(q as u32, 5); - } - // vectors (differentially against the predictors, as the decoder forms them) + m + } + + /// Vectors, coded differentially against the predictors as the decoder forms them. + fn put_vectors(&mut self, p: &Pic, m: &M, concealment: bool, pmv: &mut [[[i32; 2]; 2]; 2]) { + let frame_pic = p.structure == 3; + let flags = m.flags; let (count, field_fmt, dualp) = match (frame_pic, m.mtype) { (true, 1) => (2, true, false), (_, 3) => (1, true, true), @@ -479,20 +512,10 @@ impl Enc { if concealment { self.w.put(1, 1); } - // predictor resets - if intra { - if !concealment { - pmv = [[[0; 2]; 2]; 2]; - } - } else { - st.dc = [self.dc_reset(); 3]; - if p.ptype == PictureType::P && flags & MB_FWD == 0 { - pmv = [[[0; 2]; 2]; 2]; - m.select[0][0] = p.parity; - } - } - st.pmv = pmv; - // coded_block_pattern and blocks + } + + /// coded_block_pattern and the blocks it selects. + fn put_blocks(&mut self, st: &mut St, flags: i16, intra: bool) { let nblocks = if self.cfg.chroma == 2 { 8 } else { 6 }; let cbp: u32 = if flags & MB_PATTERN != 0 { // the coded_block_pattern code for 0 is only for 4:2:2 and 4:4:4 (Table B.9) @@ -513,7 +536,6 @@ impl Enc { self.block(st, cc, intra); } } - st.last = m; } fn motion_code(&mut self, delta: i32) {