Browse / github.com/storytold/filmcraft / patch
perf(h264enc): diamond sub-pel refinement and ordered P partition search
perf(h264enc): diamond sub-pel refinement and ordered P partition search Stacked on #3203: review after it. Two changes to P/B motion search in `crates/h264enc/src/slice.rs`, one commit each. Both change the bitstream (encoder-side decisions only; the syntax is unchanged). 1. Sub-pel refinement (half-pel and every quarter-pel round) tests a 4-point diamond instead of the 8-point square. 2. P partitions: 8x8 is searched first, and 16x8 / 8x16 are searched only when 8x8 beat 16x16 (x264-style ordering). Previously all three got a full search whenever the 16x16 cost was above the threshold. Numbers (balanced preset, export-like settings, 1080p, 60 frames, RAYON_NUM
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- vangel76 (imported from pull request #3207, open)
- Base
7428957ae0ece1139ae3af7ea76e97cacdb69570- Size
- +10 −16 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
26c74c5db82eb4935997f9b7
How it went
No other operator has reported using it yet.
Diff
raw · crates/h264enc/src/slice/motion.rs crates/h264enc/tests/it/pinned_decisions.rs
@@ -127,7 +127,7 @@ impl<'a, 'b> SliceEnc<'a, 'b> { let rounds = if step == 1 { 1 + p.subpel_rounds as usize } else { 1 }; for _ in 0..rounds { let c = best;- for (dx, dy) in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (1, -1), (-1, 1), (1, 1)] {+ for (dx, dy) in [(-1, 0), (1, 0), (0, -1), (0, 1)] { let m = Mv::new(c.x as i32 + dx * step, c.y as i32 + dy * step); if !self.mv_ok(bx, by, w, h, m) || !seen.first(m) { continue;@@ -278,16 +278,7 @@ impl<'a, 'b> SliceEnc<'a, 'b> { skip_pred = Some((y, u, v)); } // --- 16x16 search- let mut cands = vec![skip_mv, Mv::ZERO];- let colo = r.mbs[my * f.p.mbw + mx];- if colo.ref_idx[0][0] >= 0 {- cands.push(colo.mv[0][0]);- }- let (mv16, mvp16, cost16) = {- let (m, p, c) = self.search_part(mx, my, r, Part::P16x16, 0, src, lam, skip_mv);- (m, p, c)- };- let _ = cands;+ let (mv16, mvp16, cost16) = self.search_part(mx, my, r, Part::P16x16, 0, src, lam, skip_mv); let mut best_part = Part::P16x16; let mut best_mvs = mv16; let mut best_mvps = mvp16;@@ -295,7 +286,10 @@ impl<'a, 'b> SliceEnc<'a, 'b> { if f.p.partitions { let big = cost16 as u64 > (256 * 4) as u64; if big {- for part in [Part::P16x8, Part::P8x16, Part::P8x8] {+ for part in [Part::P8x8, Part::P16x8, Part::P8x16] {+ if part != Part::P8x8 && best_part == Part::P16x16 {+ continue;+ } let (m, p, c) = self.search_part(mx, my, r, part, 0, src, lam, mv16[0]); let extra = match part { Part::P8x8 => 10,@@ -44,10 +44,10 @@ fn cfg(profile: Profile, preset: Preset, rate: RateControl) -> EncoderConfig { #[test] fn coded_slices_are_pinned() { let cases = [- ("high balanced crf", cfg(Profile::High, Preset::Balanced, RateControl::Crf(23.0)), 0xecd1_35a9_3a46_f7d8u64),- ("high quality vbr", cfg(Profile::High, Preset::Quality, RateControl::Vbr { target_kbps: 800, max_kbps: 1200 }), 0x251e_c302_fd8a_ed38),- ("main speed qp", cfg(Profile::Main, Preset::Speed, RateControl::Qp(30)), 0xa123_355d_d580_4e7b),- ("baseline balanced cbr", cfg(Profile::Baseline, Preset::Balanced, RateControl::Cbr { kbps: 600 }), 0x13cb_e982_aee0_13f8),+ ("high balanced crf", cfg(Profile::High, Preset::Balanced, RateControl::Crf(23.0)), 0x6223_db82_41eb_7da1u64),+ ("high quality vbr", cfg(Profile::High, Preset::Quality, RateControl::Vbr { target_kbps: 800, max_kbps: 1200 }), 0x196d_593c_b754_622f),+ ("main speed qp", cfg(Profile::Main, Preset::Speed, RateControl::Qp(30)), 0x7772_91d5_4c75_c320),+ ("baseline balanced cbr", cfg(Profile::Baseline, Preset::Balanced, RateControl::Cbr { kbps: 600 }), 0x73f3_1918_3ea8_80be), ]; let got: Vec<u64> = cases.iter().map(|(_, c, _)| slices_hash(c.clone(), 20)).collect(); for ((name, _, _), got) in cases.iter().zip(&got) {