1#![allow(clippy::needless_range_loop)]
7
8use rusty_h264_common::bit_reader::OutOfData;
9use rusty_h264_common::cavlc::{
10 decode_residual_block, read_cbp_inter, read_cbp_intra, un_scan_4x4_ac_into, un_scan_4x4_dcac,
11};
12use rusty_h264_common::inter::{
13 inter_partitions, mc_chroma_padded, mc_luma_padded, predict_mv, predict_partition_mv,
14 MvNeighbor,
15};
16use rusty_h264_common::predict::{
17 add_residual_8x8, chroma8x8_pred, chroma_qp, intra4x4_pred, intra8x8_pred, luma16x16_pred,
18 reconstruct_4x4, reconstruct_4x4_dc, reconstruct_4x4_dc_into, reconstruct_4x4_into, I16Mode,
19 CHROMA_4X4_SCAN_XY, LUMA_4X4_SCAN_XY,
20};
21use rusty_h264_common::transform::{
22 dequant_scatter_4x4, dequantize, dequantize_weighted, inverse_quant_8x8,
23 inverse_quant_chroma_dc,
24 inverse_quant_chroma_dc_weighted, inverse_quant_luma_dc, inverse_quant_luma_dc_weighted,
25};
26use rusty_h264_common::{BitReader, YuvFrame};
27
28pub struct MvField {
34 pub mb_w: usize,
35 pub mb_h: usize,
36 pub mv: Vec<(i32, i32)>,
37 pub ref_idx: Vec<i32>,
38 pub inter: Vec<bool>,
39}
40
41pub static MV_DUMP: std::sync::Mutex<Vec<MvField>> = std::sync::Mutex::new(Vec::new());
43
44pub fn mv_dump_on() -> bool {
45 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
46 *ON.get_or_init(|| std::env::var("RFF_MV_DUMP").map_or(false, |v| v != "0"))
47}
48
49pub struct FrameDecoder {
51 mb_w: usize,
52 mb_h: usize,
53 qp: u8,
55 cur_qp: u8,
58 chroma_qp_offset: i32,
60 cw: usize,
61 ch: usize,
62 ccw: usize,
63 cch: usize,
64 rec_y: Vec<u8>,
65 rec_u: Vec<u8>,
66 rec_v: Vec<u8>,
67 mb_qp: Vec<u8>,
69 slice_first_mb: usize,
74 nnz_y: Vec<u8>,
75 nnz_c: [Vec<u8>; 2],
76 modes_y: Vec<u8>,
77 coded_y: Vec<bool>,
78 mv_y: Vec<(i32, i32)>,
81 inter_y: Vec<bool>,
82 ref_idx_y: Vec<i32>,
83 mv1: Vec<(i32, i32)>,
85 ref_idx1: Vec<i32>,
86 refs1: Vec<crate::Ref>,
88 num_ref_active1: usize,
89 is_b: bool,
90 b_possible: bool,
94 direct_spatial: bool,
95 nnz_l_cache: [u8; 25],
96 nnz_c_cache: [[u8; 9]; 2],
97 refs: Vec<crate::Ref>,
100 num_ref_active: usize,
104 constrained_intra: bool,
107 scaling: Option<[[i32; 16]; 6]>,
110 scaling8: Option<[[i32; 64]; 2]>,
113 transform_8x8_mode: bool,
115 mb_t8x8: Vec<bool>,
118 bs_frame: Vec<rusty_h264_common::deblock::MbBs>,
121 bs_rows: usize,
123 flt_rows: usize,
125 pk_prev: Vec<rusty_h264_common::deblock::MbPack>,
127 pk_cur: Vec<rusty_h264_common::deblock::MbPack>,
128 nnz_dbr: Vec<u8>,
130 bak_y: Vec<u8>,
132 bak_u: Vec<u8>,
133 bak_v: Vec<u8>,
134 edc_jobs: Vec<EdcJob>,
137 edc_active: bool,
138 edc_tx: Option<std::sync::mpsc::SyncSender<EdcMsg>>,
140 edc_ctx_rx: Option<std::sync::mpsc::Receiver<PixelCtx>>,
141 edc_back_tx: Option<std::sync::mpsc::Sender<PixelCtx>>,
142 edc_parked: Option<PixelCtx>,
145 edc_regions: Option<Vec<BRegion>>,
148 edc_batch: Vec<EdcJob>,
150 bits_per_mb: f64,
152 db_ena: bool,
154 db_oa: i32,
155 db_ob: i32,
156 mb_kind: Vec<u8>,
163 weights: Option<WeightTable>,
165 cur_poc: i32,
167 weighted_bipred_idc: u8,
169 direct_8x8_inference: bool,
171}
172
173#[derive(Clone, Default)]
177pub struct WeightTable {
178 pub luma_log2_denom: i32,
179 pub chroma_log2_denom: i32,
180 pub luma: [Vec<(i32, i32)>; 2],
182 pub chroma: [Vec<[(i32, i32); 2]>; 2],
184}
185
186impl WeightTable {
187 fn apply_luma(&self, sample: u8, list: usize, refi: usize) -> u8 {
189 let (w, o) = self.luma[list][refi];
190 let lwd = self.luma_log2_denom;
191 let v = if lwd >= 1 {
192 ((sample as i32 * w + (1 << (lwd - 1))) >> lwd) + o
193 } else {
194 sample as i32 * w + o
195 };
196 v.clamp(0, 255) as u8
197 }
198
199 fn apply_chroma(&self, sample: u8, list: usize, refi: usize, cc: usize) -> u8 {
201 let (w, o) = self.chroma[list][refi][cc];
202 let cwd = self.chroma_log2_denom;
203 let v = if cwd >= 1 {
204 ((sample as i32 * w + (1 << (cwd - 1))) >> cwd) + o
205 } else {
206 sample as i32 * w + o
207 };
208 v.clamp(0, 255) as u8
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq)]
214pub enum MbError {
215 Truncated,
216 Unsupported(&'static str),
217}
218
219impl From<OutOfData> for MbError {
220 fn from(_: OutOfData) -> Self {
221 MbError::Truncated
222 }
223}
224
225#[derive(Default)]
247pub struct GridPool {
248 bits_per_mb: f64,
252 mb_qp: Vec<u8>,
253 bs_frame: Vec<rusty_h264_common::deblock::MbBs>,
254 pk_prev: Vec<rusty_h264_common::deblock::MbPack>,
255 pk_cur: Vec<rusty_h264_common::deblock::MbPack>,
256 nnz_dbr: Vec<u8>,
257 bak_y: Vec<u8>,
258 bak_u: Vec<u8>,
259 bak_v: Vec<u8>,
260 nnz_y: Vec<u8>,
261 nnz_c0: Vec<u8>,
262 nnz_c1: Vec<u8>,
263 modes_y: Vec<u8>,
264 coded_y: Vec<bool>,
265 mv_y: Vec<(i32, i32)>,
266 inter_y: Vec<bool>,
267 ref_idx_y: Vec<i32>,
268 mv1: Vec<(i32, i32)>,
269 ref_idx1: Vec<i32>,
270 mb_t8x8: Vec<bool>,
271 mb_kind: Vec<u8>,
272}
273
274#[inline]
278fn refill<T: Clone>(mut v: Vec<T>, n: usize, val: T) -> Vec<T> {
279 v.clear();
280 v.resize(n, val);
281 v
282}
283
284impl FrameDecoder {
285 pub fn new(
286 mb_w: usize,
287 mb_h: usize,
288 qp: u8,
289 chroma_qp_offset: i32,
290 refs: Vec<crate::Ref>,
291 num_ref_active: usize,
292 constrained_intra: bool,
293 transform_8x8_mode: bool,
294 b_possible: bool,
295 ) -> Self {
296 Self::with_pool(
297 mb_w,
298 mb_h,
299 qp,
300 chroma_qp_offset,
301 refs,
302 num_ref_active,
303 constrained_intra,
304 transform_8x8_mode,
305 b_possible,
306 GridPool::default(),
307 )
308 }
309
310 #[allow(clippy::too_many_arguments)]
312 pub fn with_pool(
313 mb_w: usize,
314 mb_h: usize,
315 qp: u8,
316 chroma_qp_offset: i32,
317 refs: Vec<crate::Ref>,
318 num_ref_active: usize,
319 constrained_intra: bool,
320 transform_8x8_mode: bool,
321 b_possible: bool,
322 pool: GridPool,
323 ) -> Self {
324 let (cw, ch) = (mb_w * 16, mb_h * 16);
325 let (ccw, cch) = (cw / 2, ch / 2);
326 let bits_per_mb = pool.bits_per_mb;
327 Self {
328 mb_w,
329 mb_h,
330 qp,
331 cur_qp: qp,
332 chroma_qp_offset,
333 cw,
334 ch,
335 ccw,
336 cch,
337 rec_y: vec![0; cw * ch],
338 rec_u: vec![0; ccw * cch],
339 rec_v: vec![0; ccw * cch],
340 mb_qp: refill(pool.mb_qp, mb_w * mb_h, qp),
341 slice_first_mb: 0,
342 nnz_y: refill(pool.nnz_y, (mb_w * 4) * (mb_h * 4), 0),
343 nnz_c: [
344 refill(pool.nnz_c0, (mb_w * 2) * (mb_h * 2), 0),
345 refill(pool.nnz_c1, (mb_w * 2) * (mb_h * 2), 0),
346 ],
347 modes_y: refill(pool.modes_y, (mb_w * 4) * (mb_h * 4), 2),
348 coded_y: refill(pool.coded_y, (mb_w * 4) * (mb_h * 4), false),
349 mv_y: refill(pool.mv_y, (mb_w * 4) * (mb_h * 4), (0, 0)),
350 inter_y: refill(pool.inter_y, (mb_w * 4) * (mb_h * 4), false),
351 ref_idx_y: refill(pool.ref_idx_y, (mb_w * 4) * (mb_h * 4), -1),
352 mv1: refill(pool.mv1, (mb_w * 4) * (mb_h * 4), (0, 0)),
353 ref_idx1: refill(pool.ref_idx1, (mb_w * 4) * (mb_h * 4), -1),
354 refs1: Vec::new(),
355 num_ref_active1: 0,
356 is_b: false,
357 b_possible,
358 direct_spatial: true,
359 nnz_l_cache: [0x80; 25],
360 nnz_c_cache: [[0x80; 9]; 2],
361 refs,
362 num_ref_active,
363 constrained_intra,
364 scaling: None,
365 scaling8: None,
366 transform_8x8_mode,
367 mb_t8x8: refill(pool.mb_t8x8, mb_w * mb_h, false),
368 bs_frame: refill(pool.bs_frame, mb_w * mb_h, Default::default()),
369 bs_rows: 0,
370 flt_rows: 0,
371 pk_prev: {
372 let mut v = pool.pk_prev;
373 v.clear();
374 v
375 },
376 pk_cur: {
377 let mut v = pool.pk_cur;
378 v.clear();
379 v
380 },
381 nnz_dbr: refill(pool.nnz_dbr, (mb_w * 4) * (mb_h * 4), 0),
382 bak_y: refill(pool.bak_y, cw, 0),
383 bak_u: refill(pool.bak_u, ccw, 0),
384 bak_v: refill(pool.bak_v, ccw, 0),
385 edc_jobs: Vec::new(),
386 edc_active: false,
387 edc_tx: None,
388 edc_ctx_rx: None,
389 edc_back_tx: None,
390 edc_parked: None,
391 edc_regions: None,
392 edc_batch: Vec::new(),
393 bits_per_mb,
394 db_ena: false,
395 db_oa: 0,
396 db_ob: 0,
397 mb_kind: refill(
398 pool.mb_kind,
399 mb_w * mb_h,
400 rusty_h264_common::deblock::MB_KIND_UNSET,
401 ),
402 weights: None,
403 cur_poc: 0,
404 weighted_bipred_idc: 0,
405 direct_8x8_inference: false,
406 }
407 }
408
409 pub fn set_weights(&mut self, weights: WeightTable) {
411 self.weights = Some(weights);
412 }
413
414 fn weight_partition(
418 &self,
419 pred_y: &mut [u8; 256],
420 c_pred: &mut [[u8; 64]; 2],
421 list: usize,
422 refi: usize,
423 rx: usize,
424 ry: usize,
425 rw: usize,
426 rh: usize,
427 ) {
428 let Some(wt) = &self.weights else { return };
429 for dy in 0..rh {
430 for dx in 0..rw {
431 let i = (ry + dy) * 16 + (rx + dx);
432 pred_y[i] = wt.apply_luma(pred_y[i], list, refi);
433 }
434 }
435 let (crx, cry, crw, crh) = (rx / 2, ry / 2, rw / 2, rh / 2);
436 for cc in 0..2 {
437 for dy in 0..crh {
438 for dx in 0..crw {
439 let i = (cry + dy) * 8 + (crx + dx);
440 c_pred[cc][i] = wt.apply_chroma(c_pred[cc][i], list, refi, cc);
441 }
442 }
443 }
444 }
445
446 pub fn set_scaling(&mut self, scaling: [[i32; 16]; 6], scaling8: [[i32; 64]; 2]) {
449 self.scaling = Some(scaling);
450 self.scaling8 = Some(scaling8);
451 }
452
453 fn dequant(&self, levels: &[i32; 16], qp: u8, list: usize) -> [i32; 16] {
455 match &self.scaling {
456 Some(s) => dequantize_weighted(levels, qp, &s[list]),
457 None => dequantize(levels, qp),
458 }
459 }
460
461 fn dequant_dc4(&self, level: i32, qp: u8, list: usize) -> i32 {
463 rusty_h264_common::transform::dequantize_dc4(
464 level,
465 qp,
466 self.scaling.as_ref().map(|s| s[list][0]),
467 )
468 }
469
470 fn dequant_luma_dc(&self, levels: &[i32; 16], qp: u8, list: usize) -> [i32; 16] {
472 match &self.scaling {
473 Some(s) => inverse_quant_luma_dc_weighted(levels, qp, s[list][0]),
474 None => inverse_quant_luma_dc(levels, qp),
475 }
476 }
477
478 fn dequant_chroma_dc(&self, levels: &[i32; 4], qp: u8, list: usize) -> [i32; 4] {
480 match &self.scaling {
481 Some(s) => inverse_quant_chroma_dc_weighted(levels, qp, s[list][0]),
482 None => inverse_quant_chroma_dc(levels, qp),
483 }
484 }
485
486 #[allow(clippy::too_many_arguments)]
489 pub fn set_b_context(
490 &mut self,
491 refs1: Vec<crate::Ref>,
492 num_ref_active1: usize,
493 direct_spatial: bool,
494 cur_poc: i32,
495 weighted_bipred_idc: u8,
496 direct_8x8_inference: bool,
497 ) {
498 self.is_b = true;
499 self.refs1 = refs1;
500 self.num_ref_active1 = num_ref_active1;
501 self.direct_spatial = direct_spatial;
502 self.cur_poc = cur_poc;
503 self.weighted_bipred_idc = weighted_bipred_idc;
504 self.direct_8x8_inference = direct_8x8_inference;
505 }
506
507 fn step_qp(&mut self, delta: i32) {
510 self.cur_qp = (self.cur_qp as i32 + delta + 52).rem_euclid(52) as u8;
511 }
512
513 fn chroma_qp_for(&self, qp_y: u8) -> u8 {
516 let qpi = (qp_y as i32 + self.chroma_qp_offset).clamp(0, 51) as u8;
517 chroma_qp(qpi)
518 }
519
520 pub fn begin_slice(&mut self, slice_qp: u8, refs: Vec<crate::Ref>, num_ref_active: usize) {
524 self.cur_qp = slice_qp;
525 self.qp = slice_qp;
526 self.refs = refs;
527 self.num_ref_active = num_ref_active;
528 self.weights = None; }
530
531 #[inline]
535 fn nbr_in_slice(&self, nbx: usize, nby: usize) -> bool {
536 nby * self.mb_w + nbx >= self.slice_first_mb
537 }
538
539 #[inline]
543 fn intra_nbr_ok(&self, nbx: usize, nby: usize) -> bool {
544 !self.constrained_intra || !self.inter_y[nby * (self.mb_w * 4) + nbx]
545 }
546
547 fn mv_neighbors(&self, mb_x: usize, mb_y: usize) -> [MvNeighbor; 3] {
548 let w4 = self.mb_w * 4;
549 let get = |avail: bool, bx: isize, by: isize| {
550 if avail {
551 let idx = by as usize * w4 + bx as usize;
552 MvNeighbor {
553 available: true,
554 mv: self.mv_y[idx],
555 ref_idx: self.ref_idx_y[idx],
556 }
557 } else {
558 MvNeighbor::NONE
559 }
560 };
561 let (bx, by) = (mb_x as isize * 4, mb_y as isize * 4);
562 let a = get(mb_x > 0 && self.nbr_in_slice(mb_x - 1, mb_y), bx - 1, by);
563 let b = get(mb_y > 0 && self.nbr_in_slice(mb_x, mb_y - 1), bx, by - 1);
564 let c = if mb_y > 0 && mb_x + 1 < self.mb_w && self.nbr_in_slice(mb_x + 1, mb_y - 1) {
565 get(true, bx + 4, by - 1)
566 } else {
567 get(mb_x > 0 && mb_y > 0 && self.nbr_in_slice(mb_x - 1, mb_y - 1), bx - 1, by - 1)
568 };
569 [a, b, c]
570 }
571
572 fn mv_neighbors_block(&self, pbx: isize, pby: isize, pwb: isize) -> [MvNeighbor; 3] {
573 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Neighbors);
574 let (w4, h4) = ((self.mb_w * 4) as isize, (self.mb_h * 4) as isize);
575 let get = |bx: isize, by: isize| -> MvNeighbor {
576 if bx < 0
578 || by < 0
579 || bx >= w4
580 || by >= h4
581 || !self.coded_y[(by * w4 + bx) as usize]
582 || !self.nbr_in_slice(bx as usize / 4, by as usize / 4)
583 {
584 MvNeighbor::NONE
585 } else {
586 let idx = (by * w4 + bx) as usize;
587 MvNeighbor { available: true, mv: self.mv_y[idx], ref_idx: self.ref_idx_y[idx] }
588 }
589 };
590 let a = get(pbx - 1, pby);
591 let b = get(pbx, pby - 1);
592 let mut c = get(pbx + pwb, pby - 1);
593 if !c.available {
594 c = get(pbx - 1, pby - 1);
595 }
596 [a, b, c]
597 }
598
599 fn skip_mv(&self, mb_x: usize, mb_y: usize) -> (i32, i32) {
600 let [a, b, c] = self.mv_neighbors(mb_x, mb_y);
601 if !a.available
602 || !b.available
603 || (a.ref_idx == 0 && a.mv == (0, 0))
604 || (b.ref_idx == 0 && b.mv == (0, 0))
605 {
606 (0, 0)
607 } else {
608 predict_mv(a, b, c, 0)
609 }
610 }
611
612 fn set_mb_mv(&mut self, mb_x: usize, mb_y: usize, mv: (i32, i32), inter: bool, refi: i32) {
613 let w4 = self.mb_w * 4;
614 for dy in 0..4 {
615 for dx in 0..4 {
616 let idx = (mb_y * 4 + dy) * w4 + (mb_x * 4 + dx);
617 self.mv_y[idx] = mv;
618 self.inter_y[idx] = inter;
619 self.ref_idx_y[idx] = if inter { refi } else { -1 };
620 }
621 }
622 }
623
624 fn commit_inter_grid(&mut self, mb_x: usize, mb_y: usize, rx: usize, ry: usize, rw: usize, rh: usize, mv: (i32, i32), refi: i8) {
628 let w4 = self.mb_w * 4;
629 for by in ry / 4..ry / 4 + rh / 4 {
630 for bx in rx / 4..rx / 4 + rw / 4 {
631 let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
632 self.mv_y[idx] = mv;
633 self.inter_y[idx] = true;
634 self.ref_idx_y[idx] = refi as i32;
635 self.coded_y[idx] = true;
636 }
637 }
638 }
639
640 pub fn set_deblock_params(&mut self, ena: bool, oa: i32, ob: i32) {
643 self.db_ena = ena && (self.flt_rows == 0 || self.db_ena);
647 self.db_oa = oa;
648 self.db_ob = ob;
649 }
650
651 fn derive_bs_row(&mut self, r: usize) {
655 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DebDerive);
658 use rusty_h264_common::deblock::{derive_mb_records, pack_mb, BlockInfo, MbBs};
659 let (mb_w, w4) = (self.mb_w, self.mb_w * 4);
660 for br in r * 4..r * 4 + 4 {
663 let a = br * w4;
664 self.nnz_dbr[a..a + w4].copy_from_slice(&self.nnz_y[a..a + w4]);
665 }
666 for mb_x in 0..mb_w {
667 if !self.mb_t8x8[r * mb_w + mb_x] {
668 continue;
669 }
670 for b8 in 0..4usize {
671 let (bx, by) = (mb_x * 4 + (b8 % 2) * 2, r * 4 + (b8 / 2) * 2);
672 let any = (0..2).any(|sy| (0..2).any(|sx| self.nnz_y[(by + sy) * w4 + bx + sx] > 0));
673 for sy in 0..2 {
674 for sx in 0..2 {
675 self.nnz_dbr[(by + sy) * w4 + bx + sx] = any as u8;
676 }
677 }
678 }
679 }
680 let poc0: Vec<i32> = self.refs.iter().map(|f| f.poc).collect();
681 let poc1: Vec<i32> = self.refs1.iter().map(|f| f.poc).collect();
682 let info = BlockInfo {
683 inter: &self.inter_y,
684 nnz: &self.nnz_dbr,
685 mv: &self.mv_y,
686 ref_id: &self.ref_idx_y,
687 mv1: &self.mv1,
688 ref_id1: if poc1.is_empty() { &[] } else { &self.ref_idx1 },
689 w4,
690 t8x8: &self.mb_t8x8,
691 bs: &[],
692 poc0: &poc0,
693 poc1: &poc1,
694 kind: &[],
695 };
696 let has1 = !info.ref_id1.is_empty();
697 std::mem::swap(&mut self.pk_prev, &mut self.pk_cur);
698 self.pk_cur.clear();
699 for mb_x in 0..mb_w {
700 self.pk_cur.push(pack_mb(&info, has1, mb_x, r));
701 let cur = &self.pk_cur[mb_x];
702 let left = if mb_x > 0 { Some(&self.pk_cur[mb_x - 1]) } else { None };
703 let top = if r > 0 { Some(&self.pk_prev[mb_x]) } else { None };
704 let mb_t8 = self.mb_t8x8[r * mb_w + mb_x];
705 let (mut bv, mut bh) = ([[0i32; 4]; 4], [[0i32; 4]; 4]);
706 derive_mb_records(cur, left, top, mb_t8, &mut bv, &mut bh);
707 let mut m = MbBs::default();
708 for e in 0..4 {
709 for sg in 0..4 {
710 m.v[e][sg] = bv[e][sg] as u8;
711 m.h[e][sg] = bh[e][sg] as u8;
712 }
713 }
714 self.bs_frame[r * mb_w + mb_x] = m;
715 }
716 }
717
718 #[inline]
724 fn row_hook(&mut self, addr: usize) {
725 let _rh = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecRowHook);
726 edcstat::bump(&edcstat::MBS, 1); if !rowdb_on() {
728 self.edc_flush();
732 return;
733 }
734 let done = addr / self.mb_w;
735 if self.edc_tx.is_some() {
736 if self.bs_rows < done {
740 self.edc_giveback();
741 }
742 while self.bs_rows < done {
743 let r = self.bs_rows;
744 self.derive_bs_row(r);
745 self.bs_rows += 1;
746 let base = r * self.mb_w;
747 self.edc_flush_batch();
750 edcstat::bump(&edcstat::ROWS, 1);
751 edcstat::bump(
752 &edcstat::ROWBYTES,
753 (self.mb_w
754 * (std::mem::size_of::<rusty_h264_common::deblock::MbBs>() + 2))
755 as u64,
756 );
757 let msg = EdcMsg::Row {
758 r,
759 bs: self.bs_frame[base..base + self.mb_w].to_vec(),
760 qp: self.mb_qp[base..base + self.mb_w].to_vec(),
761 t8: self.mb_t8x8[base..base + self.mb_w].to_vec(),
762 };
763 self.edc_tx.as_ref().unwrap().send(msg).expect("worker alive");
764 }
765 return;
766 }
767 if self.bs_rows < done {
768 self.edc_flush();
769 }
770 while self.bs_rows < done {
771 let r = self.bs_rows;
772 self.derive_bs_row(r);
773 self.bs_rows += 1;
774 if self.db_ena {
779 self.save_bak(r);
780 self.filter_row(r);
781 self.flt_rows = r + 1;
782 }
783 }
784 }
785
786 fn save_bak(&mut self, r: usize) {
792 let y0 = (r * 16 + 15) * self.cw;
793 self.bak_y.copy_from_slice(&self.rec_y[y0..y0 + self.cw]);
794 let c0 = (r * 8 + 7) * self.ccw;
795 self.bak_u.copy_from_slice(&self.rec_u[c0..c0 + self.ccw]);
796 self.bak_v.copy_from_slice(&self.rec_v[c0..c0 + self.ccw]);
797 }
798
799 fn filter_row(&mut self, r: usize) {
804 let info = rusty_h264_common::deblock::BlockInfo {
805 inter: &self.inter_y,
806 nnz: &self.nnz_dbr,
807 mv: &self.mv_y,
808 ref_id: &self.ref_idx_y,
809 mv1: &self.mv1,
810 ref_id1: &self.ref_idx1,
811 w4: self.mb_w * 4,
812 t8x8: &self.mb_t8x8,
813 bs: &self.bs_frame,
814 poc0: &[],
815 poc1: &[],
816 kind: &self.mb_kind,
817 };
818 rusty_h264_common::deblock::filter_frame_rows(
819 &mut self.rec_y,
820 &mut self.rec_u,
821 &mut self.rec_v,
822 self.mb_w,
823 self.mb_h,
824 r..r + 1,
825 &self.mb_qp,
826 self.chroma_qp_offset,
827 self.db_oa,
828 self.db_ob,
829 &info,
830 );
831 }
832
833 #[inline]
838 fn top_y_px(&self, py: usize, x: usize) -> u8 {
839 if py % 16 == 0 && self.flt_rows * 16 >= py {
840 self.bak_y[x]
841 } else {
842 self.rec_y[(py - 1) * self.cw + x]
843 }
844 }
845
846 #[inline]
848 fn top_y_row(&self, py: usize, x: usize, n: usize) -> &[u8] {
849 if py % 16 == 0 && self.flt_rows * 16 >= py {
850 &self.bak_y[x..x + n]
851 } else {
852 &self.rec_y[(py - 1) * self.cw + x..][..n]
853 }
854 }
855
856 #[inline]
858 fn top_c_px(&self, c: usize, cy: usize, x: usize) -> u8 {
859 if cy % 8 == 0 && self.flt_rows * 8 >= cy {
860 if c == 0 { self.bak_u[x] } else { self.bak_v[x] }
861 } else {
862 let rec = if c == 0 { &self.rec_u } else { &self.rec_v };
863 rec[(cy - 1) * self.ccw + x]
864 }
865 }
866
867 #[inline]
869 fn top_c_row(&self, c: usize, cy: usize, x: usize, n: usize) -> &[u8] {
870 if cy % 8 == 0 && self.flt_rows * 8 >= cy {
871 if c == 0 { &self.bak_u[x..x + n] } else { &self.bak_v[x..x + n] }
872 } else {
873 let rec = if c == 0 { &self.rec_u } else { &self.rec_v };
874 &rec[(cy - 1) * self.ccw + x..][..n]
875 }
876 }
877
878 pub fn as_reference(&self) -> crate::RefFrame {
880 self.as_reference_pooled(&mut Vec::new())
881 }
882
883 pub fn as_reference_pooled(&self, pool: &mut Vec<Vec<u8>>) -> crate::RefFrame {
888 if mv_dump_on() {
892 MV_DUMP.lock().unwrap().push(MvField {
893 mb_w: self.mb_w,
894 mb_h: self.mb_h,
895 mv: self.mv_y.clone(),
896 ref_idx: self.ref_idx_y.clone(),
897 inter: self.inter_y.clone(),
898 });
899 }
900
901 let (mv, ref_idx, mv1, ref_idx1, ref_poc, w4) = if self.b_possible {
907 (
908 self.mv_y.clone(),
909 self.ref_idx_y.clone(),
910 self.mv1.clone(),
911 self.ref_idx1.clone(),
912 self.ref_idx_y
915 .iter()
916 .map(|&r| {
917 if r >= 0 {
918 self.refs.get(r as usize).map_or(i32::MIN, |f| f.poc)
919 } else {
920 i32::MIN
921 }
922 })
923 .collect(),
924 self.mb_w * 4,
925 )
926 } else {
927 (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), 0)
928 };
929 let mut take = |len: usize| -> Vec<u8> {
932 match pool.iter().position(|v| v.len() == len) {
933 Some(i) => pool.swap_remove(i),
934 None => Vec::new(),
935 }
936 };
937 let (lpw, lph) = (self.cw + 2 * crate::LPAD, self.ch + 2 * crate::LPAD);
938 let (cpw, cph) = (self.ccw + 2 * crate::CPAD, self.ch / 2 + 2 * crate::CPAD);
939 crate::RefFrame {
940 py: rusty_h264_common::inter::pad_plane_into(take(lpw * lph), &self.rec_y, self.cw, self.ch, crate::LPAD),
943 pu: rusty_h264_common::inter::pad_plane_into(take(cpw * cph), &self.rec_u, self.ccw, self.ch / 2, crate::CPAD),
944 pv: rusty_h264_common::inter::pad_plane_into(take(cpw * cph), &self.rec_v, self.ccw, self.ch / 2, crate::CPAD),
945 cw: self.cw,
946 ch: self.ch,
947 frame_num: 0, poc: 0, mv,
950 ref_idx,
951 mv1,
952 ref_idx1,
953 ref_poc,
954 w4,
955 long_term: false,
956 long_term_idx: 0,
957 }
958 }
959
960 fn nnz_cache_load(&mut self, mb_x: usize, mb_y: usize) {
961 let w4 = self.mb_w * 4;
962 let top_unavail = mb_y == 0 || !self.nbr_in_slice(mb_x, mb_y - 1);
963 let left_unavail = mb_x == 0 || !self.nbr_in_slice(mb_x - 1, mb_y);
964 for lbx in 0..4 {
965 self.nnz_l_cache[1 + lbx] =
966 if top_unavail { 0x80 } else { self.nnz_y[(mb_y * 4 - 1) * w4 + (mb_x * 4 + lbx)] };
967 }
968 for lby in 0..4 {
969 self.nnz_l_cache[(lby + 1) * 5] =
970 if left_unavail { 0x80 } else { self.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 - 1)] };
971 }
972 }
973 #[inline]
974 fn nc_pred(&self, lbx: usize, lby: usize) -> i32 {
975 let left = self.nnz_l_cache[(lby + 1) * 5 + lbx] as i32;
976 let top = self.nnz_l_cache[lby * 5 + (lbx + 1)] as i32;
977 let r = left + top;
978 if r < 0x80 { (r + 1) >> 1 } else { r & 0x7f }
979 }
980 #[inline]
981 fn nnz_cache_set(&mut self, lbx: usize, lby: usize, total: u8) {
982 self.nnz_l_cache[(lby + 1) * 5 + (lbx + 1)] = total;
983 }
984 fn chroma_cache_load(&mut self, mb_x: usize, mb_y: usize) {
985 let w2 = self.mb_w * 2;
986 let top_unavail = mb_y == 0 || !self.nbr_in_slice(mb_x, mb_y - 1);
987 let left_unavail = mb_x == 0 || !self.nbr_in_slice(mb_x - 1, mb_y);
988 for c in 0..2 {
989 for bx in 0..2 {
990 self.nnz_c_cache[c][1 + bx] =
991 if top_unavail { 0x80 } else { self.nnz_c[c][(mb_y * 2 - 1) * w2 + (mb_x * 2 + bx)] };
992 }
993 for by in 0..2 {
994 self.nnz_c_cache[c][(by + 1) * 3] =
995 if left_unavail { 0x80 } else { self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 - 1)] };
996 }
997 }
998 }
999 #[inline]
1000 fn chroma_nc_pred(&self, c: usize, bx: usize, by: usize) -> i32 {
1001 let left = self.nnz_c_cache[c][(by + 1) * 3 + bx] as i32;
1002 let top = self.nnz_c_cache[c][by * 3 + (bx + 1)] as i32;
1003 let r = left + top;
1004 if r < 0x80 { (r + 1) >> 1 } else { r & 0x7f }
1005 }
1006 #[inline]
1007 fn chroma_nnz_cache_set(&mut self, c: usize, bx: usize, by: usize, total: u8) {
1008 self.nnz_c_cache[c][(by + 1) * 3 + (bx + 1)] = total;
1009 }
1010
1011 #[allow(clippy::too_many_arguments)]
1019 pub fn decode_slice_data_cabac(
1020 &mut self,
1021 rbsp: &[u8],
1022 start_byte: usize,
1023 slice_qp: u8,
1024 cabac_init_idc: u32,
1025 is_i: bool,
1026 is_p: bool,
1027 first_mb: usize,
1028 ) -> Result<usize, MbError> {
1029 let eligible = edc_on() && rowdb_on() && !is_i && (is_p || self.is_b);
1034 let threaded = eligible
1035 && edc_mt()
1036 .unwrap_or_else(|| edc_dispatch(self.mb_w, self.mb_h, self.bits_per_mb, true));
1037 edcstat::bump(&edcstat::DISPATCH_ON, threaded as u64);
1038 edcstat::bump(&edcstat::DISPATCH_SEEN, eligible as u64);
1039 if !threaded {
1040 let r = self.decode_slice_cabac_inner(rbsp, start_byte, slice_qp, cabac_init_idc, is_i, is_p, first_mb);
1041 self.note_slice_density(rbsp.len().saturating_sub(start_byte), first_mb, &r);
1042 return r;
1043 }
1044 let ctx = self.edc_take_ctx();
1045 let (tx, rx) = std::sync::mpsc::sync_channel::<EdcMsg>(edc_bound());
1050 let (ctx_tx, ctx_rx) = std::sync::mpsc::channel::<PixelCtx>();
1051 let (back_tx, back_rx) = std::sync::mpsc::channel::<PixelCtx>();
1052 let (res, ctx, panicked) = std::thread::scope(|sc| {
1053 let h = sc.spawn(move || edc_worker(ctx, rx, ctx_tx, back_rx));
1054 self.edc_tx = Some(tx);
1055 self.edc_ctx_rx = Some(ctx_rx);
1056 self.edc_back_tx = Some(back_tx);
1057 let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1065 self.decode_slice_cabac_inner(rbsp, start_byte, slice_qp, cabac_init_idc, is_i, is_p, first_mb)
1066 }));
1067 self.edc_flush_batch(); self.edc_giveback(); self.edc_tx = None; self.edc_ctx_rx = None;
1071 self.edc_back_tx = None;
1072 match (r, h.join()) {
1073 (Ok(res), Ok(ctx)) => (res, Some(ctx), None),
1074 (Err(p), Ok(ctx)) => (Err(MbError::Truncated), Some(ctx), Some(p)),
1075 (Ok(_), Err(p)) | (Err(_), Err(p)) => (Err(MbError::Truncated), None, Some(p)),
1076 }
1077 });
1078 if let Some(ctx) = ctx {
1079 self.edc_restore_ctx(ctx);
1080 }
1081 if let Some(p) = panicked {
1082 std::panic::resume_unwind(p);
1083 }
1084 self.note_slice_density(rbsp.len().saturating_sub(start_byte), first_mb, &res);
1085 res
1086 }
1087
1088 fn note_slice_density(&mut self, bytes: usize, first_mb: usize, r: &Result<usize, MbError>) {
1092 let Ok(end) = r else { return };
1093 let mbs = end.saturating_sub(first_mb);
1094 if mbs == 0 {
1095 return;
1096 }
1097 let bpm = (bytes * 8) as f64 / mbs as f64;
1098 self.bits_per_mb = if self.bits_per_mb == 0.0 {
1099 bpm
1100 } else {
1101 0.75 * self.bits_per_mb + 0.25 * bpm
1102 };
1103 }
1104
1105 fn decode_slice_cabac_inner(
1106 &mut self,
1107 rbsp: &[u8],
1108 start_byte: usize,
1109 slice_qp: u8,
1110 cabac_init_idc: u32,
1111 is_i: bool,
1112 is_p: bool,
1113 first_mb: usize,
1114 ) -> Result<usize, MbError> {
1115 self.edc_active = edc_on();
1116 let mut cab = crate::cabac::Cabac::new(rbsp, start_byte, slice_qp as i32, cabac_init_idc, is_i);
1117 let (range, _offset) = cab.dbg_state();
1118 let trace = std::env::var_os("RH_CABAC_TRACE").is_some();
1119 debug_assert_eq!(range, 510, "CABAC init range must be 510");
1120
1121 const I16_CBP: [u32; 6] = [0, 16, 32, 15, 31, 47];
1122 let mbw = self.mb_w;
1123 let total = self.mb_w * self.mb_h;
1124 let _alloc_g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecSliceAlloc);
1127 let mut cat = vec![255u8; total]; let mut mb_cbp = vec![0u8; total];
1129 let mut cmode = vec![-1i32; total]; let mut mb_nzc = vec![[0u8; 24]; total]; let mut cbf_dc = vec![0u16; total];
1132 let mut mb_skip = vec![false; total];
1133 let mut mb_ref = vec![[-1i8; 16]; total]; let mut mb_mvd = vec![[[0i16; 2]; 16]; total]; let mut mb_ref1 = vec![[-1i8; 16]; total]; let mut mb_mvd1 = vec![[[0i16; 2]; 16]; total]; let mut mb_direct = vec![false; total]; drop(_alloc_g);
1139 let mut last_delta_qp = 0i32;
1140 let mut addr = first_mb;
1141
1142 let _mbloop_g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMbLoop);
1143 loop {
1144 if addr >= total {
1151 return Err(MbError::Truncated);
1152 }
1153 self.row_hook(addr);
1154 let (mbx, mby) = (addr % mbw, addr / mbw);
1155 let left = (mbx > 0).then(|| addr - 1);
1156 let top = (mby > 0).then(|| addr - mbw);
1157
1158 let mb_type;
1161 if is_p {
1162 let sctx = 11
1163 + left.map_or(0, |a| (!mb_skip[a]) as usize)
1164 + top.map_or(0, |a| (!mb_skip[a]) as usize);
1165 if parse_mb_skip_cabac(&mut cab, sctx) {
1166 mb_skip[addr] = true;
1167 cat[addr] = 100; last_delta_qp = 0; self.decode_p_skip(mbx, mby)?;
1173 self.mb_qp[addr] = self.cur_qp; let eos = cab.decode_terminate();
1175 addr += 1;
1176 if eos || addr >= total {
1177 break;
1178 }
1179 continue;
1180 }
1181 let mbt = parse_mb_type_p_cabac(&mut cab);
1182 if mbt == 30 {
1183 return Err(MbError::Unsupported("CABAC I_PCM (WIP)"));
1184 }
1185 if mbt <= 3 {
1186 let _gb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMbP);
1187 let mut allow8 = true;
1190 let mut mvdc = [[0i16; 2]; 30];
1193 let mut refc = [-1i8; 30];
1194 if let Some(l) = left {
1195 for (ci, bi) in [(6usize, 3usize), (12, 7), (18, 11), (24, 15)] {
1196 refc[ci] = mb_ref[l][bi];
1197 mvdc[ci] = mb_mvd[l][bi];
1198 }
1199 }
1200 if let Some(t) = top {
1201 for (ci, bi) in [(1usize, 12usize), (2, 13), (3, 14), (4, 15)] {
1202 refc[ci] = mb_ref[t][bi];
1203 mvdc[ci] = mb_mvd[t][bi];
1204 }
1205 }
1206 if mbx > 0 && mby > 0 {
1207 let a = addr - mbw - 1;
1208 (refc[0], mvdc[0]) = (mb_ref[a][15], mb_mvd[a][15]);
1209 }
1210 if mby > 0 && mbx + 1 < mbw {
1211 let a = addr - mbw + 1;
1212 (refc[5], mvdc[5]) = (mb_ref[a][12], mb_mvd[a][12]);
1213 }
1214 let mut mmvd = [[0i16; 2]; 16];
1215 let mut mref = [0i8; 16];
1216 macro_rules! refidx {
1222 ($pi:expr, $zb:expr) => {{
1223 if self.num_ref_active > 1 {
1224 let s = CACHE30[$pi];
1225 let c0 = (refc[s - 1] > 0) as usize + 2 * (refc[s - 6] > 0) as usize;
1226 let r = parse_ref_idx_cabac(&mut cab, c0);
1227 for &zb in $zb.iter() {
1228 refc[CACHE30[zb]] = r;
1229 }
1230 r
1231 } else {
1232 0i8
1233 }
1234 }};
1235 }
1236 macro_rules! part {
1237 ($pi:expr, $zb:expr, $pred:expr, $rx:expr, $ry:expr, $rw:expr, $rh:expr, $refi:expr) => {{
1238 let (mvx, mvy) = parse_mvd_partition(&mut cab, $pi, $zb, &mut mvdc, &mut refc, &mut mmvd, &mut mref, $refi);
1239 let [na, nb, nc] = self.mv_neighbors_block(
1240 (mbx * 4 + $rx / 4) as isize,
1241 (mby * 4 + $ry / 4) as isize,
1242 ($rw / 4) as isize,
1243 );
1244 let pmv = $pred(na, nb, nc);
1245 self.commit_inter_grid(mbx, mby, $rx, $ry, $rw, $rh, (pmv.0 + mvx, pmv.1 + mvy), $refi);
1246 }};
1247 }
1248 match mbt {
1249 0 => {
1250 let r0 = refidx!(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
1251 part!(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], |a, b, c| predict_partition_mv(0, 0, a, b, c, r0 as i32), 0, 0, 16, 16, r0);
1252 }
1253 1 => {
1254 let r0 = refidx!(0, &[0, 1, 2, 3, 4, 5, 6, 7]);
1255 let r1 = refidx!(8, &[8, 9, 10, 11, 12, 13, 14, 15]);
1256 part!(0, &[0, 1, 2, 3, 4, 5, 6, 7], |a, b, c| predict_partition_mv(1, 0, a, b, c, r0 as i32), 0, 0, 16, 8, r0);
1257 part!(8, &[8, 9, 10, 11, 12, 13, 14, 15], |a, b, c| predict_partition_mv(1, 1, a, b, c, r1 as i32), 0, 8, 16, 8, r1);
1258 }
1259 2 => {
1260 let r0 = refidx!(0, &[0, 1, 2, 3, 8, 9, 10, 11]);
1261 let r1 = refidx!(4, &[4, 5, 6, 7, 12, 13, 14, 15]);
1262 part!(0, &[0, 1, 2, 3, 8, 9, 10, 11], |a, b, c| predict_partition_mv(2, 0, a, b, c, r0 as i32), 0, 0, 8, 16, r0);
1263 part!(4, &[4, 5, 6, 7, 12, 13, 14, 15], |a, b, c| predict_partition_mv(2, 1, a, b, c, r1 as i32), 8, 0, 8, 16, r1);
1264 }
1265 _ => {
1266 let mut subt = [0u32; 4];
1268 for st in &mut subt {
1269 *st = parse_sub_mb_type_p_cabac(&mut cab);
1270 }
1271 allow8 = subt.iter().all(|&t| t == 0);
1272 let mut pr = [0i8; 4];
1273 for (i, r) in pr.iter_mut().enumerate() {
1274 let b = i * 4;
1275 *r = refidx!(b, &[b, b + 1, b + 2, b + 3]);
1276 }
1277 for i in 0..4usize {
1278 let b = i * 4;
1279 let (ox, oy) = ((i % 2) * 8, (i / 2) * 8); let ri = pr[i];
1281 match subt[i] {
1282 0 => part!(b, &[b, b + 1, b + 2, b + 3], |a, b, c| predict_mv(a, b, c, ri as i32), ox, oy, 8, 8, ri),
1283 1 => {
1284 part!(b, &[b, b + 1], |a, b, c| predict_mv(a, b, c, ri as i32), ox, oy, 8, 4, ri);
1285 part!(b + 2, &[b + 2, b + 3], |a, b, c| predict_mv(a, b, c, ri as i32), ox, oy + 4, 8, 4, ri);
1286 }
1287 2 => {
1288 part!(b, &[b, b + 2], |a, b, c| predict_mv(a, b, c, ri as i32), ox, oy, 4, 8, ri);
1289 part!(b + 1, &[b + 1, b + 3], |a, b, c| predict_mv(a, b, c, ri as i32), ox + 4, oy, 4, 8, ri);
1290 }
1291 _ => {
1292 for j in 0..4usize {
1293 let (sx, sy) = ((j % 2) * 4, (j / 2) * 4);
1294 part!(b + j, &[b + j], |a, b, c| predict_mv(a, b, c, ri as i32), ox + sx, oy + sy, 4, 4, ri);
1295 }
1296 }
1297 }
1298 }
1299 }
1300 }
1301 mb_ref[addr] = mref;
1302 mb_mvd[addr] = mmvd;
1303 cat[addr] = 100;
1304
1305 let cbp = parse_cbp_cabac(&mut cab, top.map(|a| mb_cbp[a]), left.map(|a| mb_cbp[a]));
1307 mb_cbp[addr] = cbp as u8;
1308 let t8 = self.transform_8x8_mode && (cbp & 15) != 0 && allow8 && {
1312 let a = left.map_or(0, |x| self.mb_t8x8[x] as usize);
1313 let b = top.map_or(0, |x| self.mb_t8x8[x] as usize);
1314 cab.decode_decision(399 + a + b) != 0
1315 };
1316 self.mb_t8x8[addr] = t8;
1317 let mut luma8 = [[0i32; 64]; 4]; let (cbp_luma, cbp_chroma) = (cbp & 15, cbp >> 4);
1319 let mut nzc = [0xffu8; 48];
1320 if let Some(t) = top {
1321 let tnz = mb_nzc[t];
1322 nzc[1..5].copy_from_slice(&tnz[12..16]);
1323 (nzc[0], nzc[5], nzc[29]) = (0, 0, 0);
1324 (nzc[6], nzc[7], nzc[30], nzc[31]) = (tnz[20], tnz[21], tnz[22], tnz[23]);
1325 }
1326 if let Some(l) = left {
1327 let lnz = mb_nzc[l];
1328 (nzc[8], nzc[16], nzc[24], nzc[32]) = (lnz[3], lnz[7], lnz[11], lnz[15]);
1329 (nzc[13], nzc[21], nzc[37], nzc[45]) = (lnz[17], lnz[21], lnz[19], lnz[23]);
1330 }
1331 let mut cbfdc = 0u16;
1332 let mut nnzs = [0u8; 24]; let mut luma_scan = [[0i32; 16]; 16]; let mut cdc = [[0i32; 4]; 2]; let mut cac = [[[0i32; 16]; 4]; 2]; if cbp == 0 {
1338 last_delta_qp = 0;
1339 }
1340 if cbp != 0 {
1341 let ndc = (top.map(|a| cbf_dc[a]), left.map(|a| cbf_dc[a]));
1342 let qpd = parse_mb_qp_delta_cabac(&mut cab, &mut last_delta_qp);
1343 self.step_qp(qpd);
1344 for id8 in 0..4usize {
1345 if cbp_luma & (1 << id8) != 0 {
1346 if t8 {
1347 let n8 = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, id8 * 4, RP_LUMA_8X8, false, ndc, &mut luma8[id8]) as u8;
1351 for k in 0..4 {
1352 nnzs[id8 * 4 + k] = n8;
1353 }
1354 } else {
1355 for id4 in 0..4usize {
1356 let iz = id8 * 4 + id4;
1357 nnzs[iz] = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, iz, RP_LUMA_4X4, false, ndc, &mut luma_scan[iz]) as u8;
1358 }
1359 }
1360 } else {
1361 for k in 0..4 {
1362 nzc[NZC_CACHE[id8 * 4 + k]] = 0;
1363 }
1364 }
1365 }
1366 if cbp_chroma >= 1 {
1367 for i in 0..2usize {
1368 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4, RP_CHROMA_DC + i, false, ndc, &mut cdc[i]);
1369 }
1370 }
1371 if cbp_chroma == 2 {
1372 for i in 0..2usize {
1373 for id4 in 0..4usize {
1374 nnzs[16 + i * 4 + id4] = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4 + id4, RP_CHROMA_AC + i, false, ndc, &mut cac[i][id4]) as u8;
1375 }
1376 }
1377 }
1378 }
1379 self.mb_qp[addr] = self.cur_qp;
1380 cbf_dc[addr] = cbfdc;
1381 let _sc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecStateCache);
1382 let mut mn = [0u8; 24];
1383 for k in 0..4 {
1384 mn[k] = nzc[9 + k];
1385 mn[4 + k] = nzc[17 + k];
1386 mn[8 + k] = nzc[25 + k];
1387 mn[12 + k] = nzc[33 + k];
1388 }
1389 (mn[16], mn[17], mn[20], mn[21]) = (nzc[14], nzc[15], nzc[22], nzc[23]);
1390 (mn[18], mn[19], mn[22], mn[23]) = (nzc[38], nzc[39], nzc[46], nzc[47]);
1391 for v in mn.iter_mut() {
1395 if *v == 0xff {
1396 *v = 0;
1397 }
1398 }
1399 mb_nzc[addr] = mn;
1400 drop(_sc);
1401
1402 if self.refs.is_empty() {
1403 return Err(MbError::Unsupported("inter without reference"));
1404 }
1405 let (mut jgmv, mut jgref) = ([(0i32, 0i32); 16], [0u8; 16]);
1406 {
1407 let w4r = self.mb_w * 4;
1408 for by in 0..4usize {
1409 for bx in 0..4usize {
1410 let bidx = (mby * 4 + by) * w4r + (mbx * 4 + bx);
1411 jgmv[by * 4 + bx] = self.mv_y[bidx];
1412 jgref[by * 4 + bx] =
1413 self.ref_idx_y[bidx].clamp(0, 15) as u8;
1414 }
1415 }
1416 }
1417 let job = PInterJob {
1418 mbx,
1419 mby,
1420 t8,
1421 qp: self.cur_qp,
1422 cbp_chroma,
1423 gmv: jgmv,
1424 gref: jgref,
1425 luma_scan,
1426 luma8,
1427 cdc,
1428 cac,
1429 nnzs,
1430 };
1431 let nores = cbp == 0 && nores_on();
1439 if self.edc_tx.is_some() {
1440 self.edc_giveback();
1441 self.edc_commit_nnz(mbx, mby, t8, &nnzs, cbp_chroma);
1442 if edcstat::on() {
1443 edcstat::bump(&edcstat::J_INTER, 1);
1444 let nores = job.cbp_chroma == 0
1445 && job.luma_scan.iter().all(|b| b.iter().all(|&c| c == 0))
1446 && job.cdc.iter().all(|p| p.iter().all(|&c| c == 0))
1447 && job.cac.iter().all(|p| p.iter().all(|b| b.iter().all(|&c| c == 0)));
1448 if nores {
1449 edcstat::bump(&edcstat::J_INTER_NORES, 1);
1450 }
1451 }
1452 let job_msg = if nores {
1453 edcstat::bump(&edcstat::J_NORES_SENT, 1);
1454 EdcJob::InterNoRes(Box::new(PInterNoResJob {
1455 mbx: job.mbx,
1456 mby: job.mby,
1457 t8: job.t8,
1458 qp: job.qp,
1459 gmv: job.gmv,
1460 gref: job.gref,
1461 }))
1462 } else {
1463 EdcJob::Inter(Box::new(job))
1464 };
1465 self.edc_send_job(job_msg);
1466 } else if self.edc_active {
1467 if nores {
1468 edcstat::bump(&edcstat::J_NORES_SENT, 1);
1469 self.edc_jobs.push(EdcJob::InterNoRes(Box::new(PInterNoResJob {
1470 mbx: job.mbx,
1471 mby: job.mby,
1472 t8: job.t8,
1473 qp: job.qp,
1474 gmv: job.gmv,
1475 gref: job.gref,
1476 })));
1477 } else {
1478 self.edc_jobs.push(EdcJob::Inter(Box::new(job)));
1479 }
1480 } else {
1481 self.recon_p_inter(&job);
1482 if double_recon() {
1483 self.recon_p_inter(&job);
1484 }
1485 }
1486
1487 let eos = cab.decode_terminate();
1488 addr += 1;
1489 if eos || addr >= total {
1490 break;
1491 }
1492 continue;
1493 }
1494 mb_type = mbt - 5; } else if self.is_b {
1496 self.edc_flush(); if self.edc_tx.is_some() {
1498 self.edc_regions = Some(Vec::with_capacity(8));
1500 }
1501 let _gb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMbB);
1502 let mut allow8 = true;
1505 let sctx = 24
1507 + left.map_or(0, |a| (!mb_skip[a]) as usize)
1508 + top.map_or(0, |a| (!mb_skip[a]) as usize);
1509 if parse_mb_skip_cabac(&mut cab, sctx) {
1510 mb_skip[addr] = true;
1511 cat[addr] = 100;
1512 mb_direct[addr] = true;
1513 last_delta_qp = 0; self.decode_b_skip(mbx, mby)?;
1517 self.mb_qp[addr] = self.cur_qp;
1518 mb_ref[addr] = [0i8; 16];
1521 mb_ref1[addr] = [0i8; 16];
1522 let eos = cab.decode_terminate();
1523 addr += 1;
1524 if eos || addr >= total {
1525 break;
1526 }
1527 continue;
1528 }
1529 let bci = left.map_or(0, |a| (!mb_direct[a]) as usize)
1530 + top.map_or(0, |a| (!mb_direct[a]) as usize);
1531 let bmt = parse_mb_type_b_cabac(&mut cab, bci);
1532 if bmt < 23 {
1533 let mut mvdc0 = [[0i16; 2]; 30];
1536 let mut refc0 = [-1i8; 30];
1537 let mut mvdc1 = [[0i16; 2]; 30];
1538 let mut refc1 = [-1i8; 30];
1539 macro_rules! fill {
1541 ($mrf:expr, $mmv:expr, $rc:expr, $mc:expr) => {{
1542 if let Some(l) = left {
1543 for (ci, bi) in [(6usize, 3usize), (12, 7), (18, 11), (24, 15)] {
1544 $rc[ci] = $mrf[l][bi];
1545 $mc[ci] = $mmv[l][bi];
1546 }
1547 }
1548 if let Some(t) = top {
1549 for (ci, bi) in [(1usize, 12usize), (2, 13), (3, 14), (4, 15)] {
1550 $rc[ci] = $mrf[t][bi];
1551 $mc[ci] = $mmv[t][bi];
1552 }
1553 }
1554 if mbx > 0 && mby > 0 {
1555 let a = addr - mbw - 1;
1556 ($rc[0], $mc[0]) = ($mrf[a][15], $mmv[a][15]);
1557 }
1558 if mby > 0 && mbx + 1 < mbw {
1559 let a = addr - mbw + 1;
1560 ($rc[5], $mc[5]) = ($mrf[a][12], $mmv[a][12]);
1561 }
1562 }};
1563 }
1564 fill!(mb_ref, mb_mvd, refc0, mvdc0);
1565 fill!(mb_ref1, mb_mvd1, refc1, mvdc1);
1566 let mut mmvd0 = [[0i16; 2]; 16];
1567 let mut mref0 = [-1i8; 16];
1568 let mut mmvd1 = [[0i16; 2]; 16];
1569 let mut mref1 = [-1i8; 16];
1570 if self.refs.is_empty() || self.refs1.is_empty() {
1571 return Err(MbError::Unsupported("B without references"));
1572 }
1573 let mut pred_y = [0u8; 256];
1578 let mut c_pred = [[0u8; 64]; 2];
1579
1580 if bmt == 0 {
1581 mb_direct[addr] = true;
1584 allow8 = self.direct_8x8_inference;
1585 (mref0, mref1) = ([0i8; 16], [0i8; 16]);
1586 self.decode_b_direct(mbx, mby, 0, 0, 16, 16, &mut pred_y, &mut c_pred);
1587 } else if bmt == 22 {
1588 let mut subt = [0u32; 4];
1591 for s in &mut subt {
1592 *s = parse_sub_mb_type_b_cabac(&mut cab);
1593 }
1594 allow8 = subt.iter().all(|&t| if t == 0 { self.direct_8x8_inference } else { (1..=3).contains(&t) });
1595 for i in 0..4usize {
1599 if subt[i] == 0 {
1600 let b = i * 4;
1601 for &zb in &[b, b + 1, b + 2, b + 3] {
1602 (mref0[G_SCAN4[zb]], mref1[G_SCAN4[zb]]) = (0, 0);
1603 (refc0[CACHE30[zb]], refc1[CACHE30[zb]]) = (0, 0);
1604 }
1605 }
1606 }
1607 let mut sref = [[0i8; 2]; 4]; for list in 0..2usize {
1612 let active = if list == 0 { self.num_ref_active } else { self.num_ref_active1 };
1613 if active <= 1 {
1614 continue;
1615 }
1616 let rc = if list == 0 { &mut refc0 } else { &mut refc1 };
1617 for i in 0..4usize {
1618 let st = subt[i];
1619 if st == 0 || !b_sub_uses(st, list) {
1620 continue;
1621 }
1622 let b = i * 4;
1623 let s = CACHE30[b];
1624 let c0 = (rc[s - 1] > 0) as usize + 2 * (rc[s - 6] > 0) as usize;
1625 let r = parse_ref_idx_cabac(&mut cab, c0);
1626 for &zb in &[b, b + 1, b + 2, b + 3] {
1627 rc[CACHE30[zb]] = r;
1628 }
1629 sref[i][list] = r;
1630 }
1631 }
1632 for list in 0..2usize {
1633 let (mmv, mrf, mc, rc) = if list == 0 {
1634 (&mut mmvd0, &mut mref0, &mut mvdc0, &mut refc0)
1635 } else {
1636 (&mut mmvd1, &mut mref1, &mut mvdc1, &mut refc1)
1637 };
1638 for i in 0..4usize {
1639 let st = subt[i];
1640 if st == 0 || !b_sub_uses(st, list) {
1641 continue;
1642 }
1643 let b = i * 4;
1644 for &(sx, sy, sw, sh) in b_sub_parts(st) {
1645 let mut zb = [0usize; 4];
1646 let mut n = 0;
1647 for ly in sy / 4..sy / 4 + sh / 4 {
1648 for lx in sx / 4..sx / 4 + sw / 4 {
1649 zb[n] = b + ly * 2 + lx;
1650 n += 1;
1651 }
1652 }
1653 parse_mvd_partition(&mut cab, zb[0], &zb[..n], mc, rc, mmv, mrf, sref[i][list]);
1654 }
1655 }
1656 }
1657 for (p, &st) in subt.iter().enumerate() {
1660 let (b8x, b8y) = ((p % 2) * 8, (p / 2) * 8);
1661 if st == 0 {
1662 self.decode_b_direct(mbx, mby, b8x, b8y, 8, 8, &mut pred_y, &mut c_pred);
1663 continue;
1664 }
1665 for &(sx, sy, sw, sh) in b_sub_parts(st) {
1666 let (px, py) = (b8x + sx, b8y + sy);
1667 let mut mv = [(0i32, 0i32); 2];
1668 for list in 0..2usize {
1669 if b_sub_uses(st, list) {
1670 let d = if list == 0 { mmvd0 } else { mmvd1 }[(py / 4) * 4 + px / 4];
1671 let n = self.mv_neighbors_list((mbx * 4 + px / 4) as isize, (mby * 4 + py / 4) as isize, (sw / 4) as isize, list);
1672 let pmv = predict_mv(n[0], n[1], n[2], sref[p][list] as i32);
1673 mv[list] = (pmv.0 + d[0] as i32, pmv.1 + d[1] as i32);
1674 }
1675 }
1676 let refi0 = if b_sub_uses(st, 0) { sref[p][0] as i32 } else { -1 };
1677 let refi1 = if b_sub_uses(st, 1) { sref[p][1] as i32 } else { -1 };
1678 self.b_set_motion(mbx, mby, px, py, sw, sh, refi0, mv[0], refi1, mv[1]);
1679 self.b_mc_or_record(mbx, mby, px, py, sw, sh, refi0, mv[0], refi1, mv[1], &mut pred_y, &mut c_pred);
1680 }
1681 }
1682 } else {
1683 let (layout, mvmode, preds) = b_inter_layout(bmt);
1684 let parts: &[(usize, &[usize])] = match mvmode {
1685 0 => &[(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])],
1686 1 => &[(0, &[0, 1, 2, 3, 4, 5, 6, 7]), (8, &[8, 9, 10, 11, 12, 13, 14, 15])],
1687 _ => &[(0, &[0, 1, 2, 3, 8, 9, 10, 11]), (4, &[4, 5, 6, 7, 12, 13, 14, 15])],
1688 };
1689 let mut pref = [[0i8; 2]; 2]; for list in 0..2usize {
1697 let active = if list == 0 { self.num_ref_active } else { self.num_ref_active1 };
1698 if active <= 1 {
1699 continue;
1700 }
1701 let rc = if list == 0 { &mut refc0 } else { &mut refc1 };
1702 for (p, &(pidx, zb)) in parts.iter().enumerate() {
1703 if !preds[p].uses(list) {
1704 continue;
1705 }
1706 let s = CACHE30[pidx];
1707 let c0 = (rc[s - 1] > 0) as usize + 2 * (rc[s - 6] > 0) as usize;
1708 let r = parse_ref_idx_cabac(&mut cab, c0);
1709 for &zbi in zb.iter() {
1711 rc[CACHE30[zbi]] = r;
1712 }
1713 pref[p][list] = r;
1714 }
1715 }
1716 for list in 0..2usize {
1719 let (mmv, mrf, mc, rc) = if list == 0 {
1720 (&mut mmvd0, &mut mref0, &mut mvdc0, &mut refc0)
1721 } else {
1722 (&mut mmvd1, &mut mref1, &mut mvdc1, &mut refc1)
1723 };
1724 for (p, &(pidx, zb)) in parts.iter().enumerate() {
1725 if preds[p].uses(list) {
1726 parse_mvd_partition(&mut cab, pidx, zb, mc, rc, mmv, mrf, pref[p][list]);
1727 }
1728 }
1729 }
1730 for (p, &(rx, ry, rw, rh)) in layout.iter().enumerate() {
1732 let mut mv = [(0i32, 0i32); 2];
1733 for list in 0..2usize {
1734 if preds[p].uses(list) {
1735 let d = if list == 0 { mmvd0 } else { mmvd1 }[(ry / 4) * 4 + rx / 4];
1736 let n = self.mv_neighbors_list((mbx * 4 + rx / 4) as isize, (mby * 4 + ry / 4) as isize, (rw / 4) as isize, list);
1737 let pmv = predict_partition_mv(mvmode, p, n[0], n[1], n[2], pref[p][list] as i32);
1738 mv[list] = (pmv.0 + d[0] as i32, pmv.1 + d[1] as i32);
1739 }
1740 }
1741 let refi0 = if preds[p].uses(0) { pref[p][0] as i32 } else { -1 };
1742 let refi1 = if preds[p].uses(1) { pref[p][1] as i32 } else { -1 };
1743 self.b_set_motion(mbx, mby, rx, ry, rw, rh, refi0, mv[0], refi1, mv[1]);
1744 self.b_mc_or_record(mbx, mby, rx, ry, rw, rh, refi0, mv[0], refi1, mv[1], &mut pred_y, &mut c_pred);
1748 }
1749 }
1750 mb_ref[addr] = mref0;
1751 mb_mvd[addr] = mmvd0;
1752 mb_ref1[addr] = mref1;
1753 mb_mvd1[addr] = mmvd1;
1754 cat[addr] = 100;
1755
1756 let cbp = parse_cbp_cabac(&mut cab, top.map(|a| mb_cbp[a]), left.map(|a| mb_cbp[a]));
1758 mb_cbp[addr] = cbp as u8;
1759 let t8 = self.transform_8x8_mode && (cbp & 15) != 0 && allow8 && {
1763 let a = left.map_or(0, |x| self.mb_t8x8[x] as usize);
1764 let b = top.map_or(0, |x| self.mb_t8x8[x] as usize);
1765 cab.decode_decision(399 + a + b) != 0
1766 };
1767 self.mb_t8x8[addr] = t8;
1768 let mut luma8 = [[0i32; 64]; 4]; let (cbp_luma, cbp_chroma) = (cbp & 15, cbp >> 4);
1770 let mut nzc = [0xffu8; 48];
1771 if let Some(t) = top {
1772 let tnz = mb_nzc[t];
1773 nzc[1..5].copy_from_slice(&tnz[12..16]);
1774 (nzc[0], nzc[5], nzc[29]) = (0, 0, 0);
1775 (nzc[6], nzc[7], nzc[30], nzc[31]) = (tnz[20], tnz[21], tnz[22], tnz[23]);
1776 }
1777 if let Some(l) = left {
1778 let lnz = mb_nzc[l];
1779 (nzc[8], nzc[16], nzc[24], nzc[32]) = (lnz[3], lnz[7], lnz[11], lnz[15]);
1780 (nzc[13], nzc[21], nzc[37], nzc[45]) = (lnz[17], lnz[21], lnz[19], lnz[23]);
1781 }
1782 let mut cbfdc = 0u16;
1783 let mut nnzs = [0u8; 24]; let mut luma_scan = [[0i32; 16]; 16];
1785 let mut cdc = [[0i32; 4]; 2];
1786 let mut cac = [[[0i32; 16]; 4]; 2];
1787 if cbp == 0 {
1788 last_delta_qp = 0;
1789 }
1790 if cbp != 0 {
1791 let ndc = (top.map(|a| cbf_dc[a]), left.map(|a| cbf_dc[a]));
1792 let qpd = parse_mb_qp_delta_cabac(&mut cab, &mut last_delta_qp);
1793 self.step_qp(qpd);
1794 for id8 in 0..4usize {
1795 if cbp_luma & (1 << id8) != 0 {
1796 if t8 {
1797 let n8 = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, id8 * 4, RP_LUMA_8X8, false, ndc, &mut luma8[id8]) as u8;
1801 for k in 0..4 {
1802 nnzs[id8 * 4 + k] = n8;
1803 }
1804 } else {
1805 for id4 in 0..4usize {
1806 let iz = id8 * 4 + id4;
1807 nnzs[iz] = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, iz, RP_LUMA_4X4, false, ndc, &mut luma_scan[iz]) as u8;
1808 }
1809 }
1810 } else {
1811 for k in 0..4 {
1812 nzc[NZC_CACHE[id8 * 4 + k]] = 0;
1813 }
1814 }
1815 }
1816 if cbp_chroma >= 1 {
1817 for i in 0..2usize {
1818 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4, RP_CHROMA_DC + i, false, ndc, &mut cdc[i]);
1819 }
1820 }
1821 if cbp_chroma == 2 {
1822 for i in 0..2usize {
1823 for id4 in 0..4usize {
1824 nnzs[16 + i * 4 + id4] = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4 + id4, RP_CHROMA_AC + i, false, ndc, &mut cac[i][id4]) as u8;
1825 }
1826 }
1827 }
1828 }
1829 self.mb_qp[addr] = self.cur_qp;
1830 cbf_dc[addr] = cbfdc;
1831 let _sc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecStateCache);
1832 let mut mn = [0u8; 24];
1833 for k in 0..4 {
1834 mn[k] = nzc[9 + k];
1835 mn[4 + k] = nzc[17 + k];
1836 mn[8 + k] = nzc[25 + k];
1837 mn[12 + k] = nzc[33 + k];
1838 }
1839 (mn[16], mn[17], mn[20], mn[21]) = (nzc[14], nzc[15], nzc[22], nzc[23]);
1840 (mn[18], mn[19], mn[22], mn[23]) = (nzc[38], nzc[39], nzc[46], nzc[47]);
1841 for v in mn.iter_mut() {
1845 if *v == 0xff {
1846 *v = 0;
1847 }
1848 }
1849 mb_nzc[addr] = mn;
1850 drop(_sc);
1851 if let Some(regions) = self.edc_regions.take() {
1852 self.edc_giveback();
1853 self.edc_commit_nnz(mbx, mby, t8, &nnzs, cbp_chroma);
1854 let job = BJob {
1855 mbx,
1856 mby,
1857 t8,
1858 qp: self.cur_qp,
1859 cbp_chroma,
1860 skip: false,
1861 regions,
1862 luma_scan,
1863 luma8,
1864 cdc,
1865 cac,
1866 nnzs,
1867 };
1868 self.edc_send_job(EdcJob::B(Box::new(job)));
1869 } else {
1870 self.add_inter_residual(mbx, mby, &pred_y, &c_pred, &luma_scan, if t8 { Some(&luma8) } else { None }, &cdc, &cac, cbp_chroma, &nnzs);
1871 }
1872
1873 let eos = cab.decode_terminate();
1874 addr += 1;
1875 if eos || addr >= total {
1876 break;
1877 }
1878 continue;
1879 }
1880 mb_type = bmt - 23; if mb_type == 25 {
1882 return Err(MbError::Unsupported("CABAC I_PCM (WIP)"));
1883 }
1884 } else {
1885 let li = left.map_or(0, |a| (cat[a] >= 2) as usize);
1886 let ti = top.map_or(0, |a| (cat[a] >= 2) as usize);
1887 mb_type = parse_mb_type_i_cabac(&mut cab, li + ti);
1888 if mb_type == 25 {
1889 return Err(MbError::Unsupported("CABAC I_PCM (WIP)"));
1890 }
1891 }
1892 self.edc_intra_sync(); let _gi = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMbI);
1899 let cci = left.map_or(0, |a| (1..=3).contains(&cmode[a]) as usize)
1901 + top.map_or(0, |a| (1..=3).contains(&cmode[a]) as usize);
1902
1903 if mb_type != 0 {
1904 let mt = mb_type - 1;
1909 let pred_mode = I16Mode::from_id(mt % 4);
1910 let cbp_chroma = (mt % 12) / 4;
1911 let cbp_luma_15 = mt / 12 == 1;
1912 let chroma_mode = parse_intra_chroma_pred_mode_cabac(&mut cab, cci) as u8;
1913 cmode[addr] = chroma_mode as i32;
1914 cat[addr] = 2;
1915 mb_cbp[addr] = ((cbp_chroma as u8) << 4) | if cbp_luma_15 { 15 } else { 0 };
1916 let w4 = self.mb_w * 4;
1917
1918 let mut nzc = [0xffu8; 48];
1919 if let Some(t) = top {
1920 let tn = mb_nzc[t];
1921 nzc[1..5].copy_from_slice(&tn[12..16]);
1922 (nzc[0], nzc[5], nzc[29]) = (0, 0, 0);
1923 (nzc[6], nzc[7]) = (tn[20], tn[21]);
1924 (nzc[30], nzc[31]) = (tn[22], tn[23]);
1925 }
1926 if let Some(l) = left {
1927 let ln = mb_nzc[l];
1928 (nzc[8], nzc[16], nzc[24], nzc[32]) = (ln[3], ln[7], ln[11], ln[15]);
1929 (nzc[13], nzc[21], nzc[37], nzc[45]) = (ln[17], ln[21], ln[19], ln[23]);
1930 }
1931
1932 let ndc = (top.map(|a| cbf_dc[a]), left.map(|a| cbf_dc[a]));
1933 let qpd = parse_mb_qp_delta_cabac(&mut cab, &mut last_delta_qp);
1934 self.step_qp(qpd);
1935 let qp = self.cur_qp;
1936 let mut cbfdc = 0u16;
1937
1938 let mut dc_scan = [0i32; 16];
1940 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 0, RP_I16_DC, true, ndc, &mut dc_scan);
1941 let recon_dc = self.dequant_luma_dc(&un_scan_4x4_dcac(&dc_scan), qp, 0);
1942
1943 let mut q_blocks = [[0i32; 16]; 16];
1945 for (iz, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
1946 let total = if cbp_luma_15 {
1947 let mut ac = [0i32; 16];
1948 let t = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, iz, RP_I16_AC, true, ndc, &mut ac);
1949 un_scan_4x4_ac_into(&ac, &mut q_blocks[lby * 4 + lbx]);
1950 t as u8
1951 } else {
1952 nzc[NZC_CACHE[iz]] = 0;
1953 0
1954 };
1955 self.nnz_y[(mby * 4 + lby) * w4 + (mbx * 4 + lbx)] = total;
1956 }
1957
1958 let mut cdc = [[0i32; 4]; 2];
1959 let mut cac = [[[0i32; 16]; 4]; 2];
1960 if cbp_chroma >= 1 {
1961 for i in 0..2usize {
1962 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4, RP_CHROMA_DC + i, true, ndc, &mut cdc[i]);
1963 }
1964 }
1965 if cbp_chroma == 2 {
1966 for i in 0..2usize {
1967 for id4 in 0..4usize {
1968 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4 + id4, RP_CHROMA_AC + i, true, ndc, &mut cac[i][id4]);
1969 }
1970 }
1971 }
1972
1973 let top_ok = mby > 0 && self.nbr_in_slice(mbx, mby - 1) && self.intra_nbr_ok(mbx * 4, mby * 4 - 1);
1975 let left_ok = mbx > 0 && self.nbr_in_slice(mbx - 1, mby) && self.intra_nbr_ok(mbx * 4 - 1, mby * 4);
1976 let (lx, ly) = (mbx * 16, mby * 16);
1977 let mut t16 = [0u8; 16];
1978 let mut l16 = [0u8; 16];
1979 if top_ok {
1980 t16.copy_from_slice(self.top_y_row(ly, lx, 16));
1981 }
1982 if left_ok {
1983 for i in 0..16 {
1984 l16[i] = self.rec_y[(ly + i) * self.cw + lx - 1];
1985 }
1986 }
1987 let corner = if top_ok && left_ok { self.top_y_px(ly, lx - 1) } else { 0 };
1988 let pred_l = luma16x16_pred(pred_mode, top_ok, left_ok, &t16, &l16, corner);
1989 for by in 0..4 {
1990 for bx in 0..4 {
1991 let mut deq = self.dequant(&q_blocks[by * 4 + bx], qp, 0);
1992 deq[0] = recon_dc[by * 4 + bx];
1993 let predb: [i32; 16] = std::array::from_fn(|i| pred_l[(by * 4 + i / 4) * 16 + (bx * 4 + i % 4)] as i32);
1994 let s = reconstruct_4x4(&deq, &predb);
1995 store(&mut self.rec_y, self.cw, lx + bx * 4, ly + by * 4, &s);
1996 self.modes_y[(mby * 4 + by) * w4 + (mbx * 4 + bx)] = 2;
2000 self.coded_y[(mby * 4 + by) * w4 + (mbx * 4 + bx)] = true;
2001 }
2002 }
2003 self.recon_chroma_cabac(mbx, mby, chroma_mode, &cdc, &cac, cbp_chroma, top_ok, left_ok);
2004
2005 self.mb_qp[addr] = self.cur_qp;
2006 cbf_dc[addr] = cbfdc;
2007 let mut mn = [0u8; 24];
2008 for k in 0..4 {
2009 mn[k] = nzc[9 + k];
2010 mn[4 + k] = nzc[17 + k];
2011 mn[8 + k] = nzc[25 + k];
2012 mn[12 + k] = nzc[33 + k];
2013 }
2014 (mn[16], mn[17], mn[20], mn[21]) = (nzc[14], nzc[15], nzc[22], nzc[23]);
2015 (mn[18], mn[19], mn[22], mn[23]) = (nzc[38], nzc[39], nzc[46], nzc[47]);
2016 for v in mn.iter_mut() {
2017 if *v == 0xff {
2018 *v = 0;
2019 }
2020 }
2021 mb_nzc[addr] = mn;
2022
2023 let eos = cab.decode_terminate();
2024 addr += 1;
2025 if eos || addr >= total {
2026 break;
2027 }
2028 continue;
2029 }
2030 cat[addr] = 0;
2031 let w4 = self.mb_w * 4;
2032 let t8 = self.transform_8x8_mode && {
2037 let a = left.map_or(0, |x| self.mb_t8x8[x] as usize);
2038 let b = top.map_or(0, |x| self.mb_t8x8[x] as usize);
2039 cab.decode_decision(399 + a + b) != 0
2040 };
2041 self.mb_t8x8[addr] = t8;
2042 let mut modes = [2u8; 16]; let mut modes8 = [2u8; 4]; if t8 {
2047 for b8 in 0..4usize {
2050 let (b8x, b8y) = (b8 % 2, b8 / 2);
2051 let (bx, by) = (mbx * 4 + b8x * 2, mby * 4 + b8y * 2);
2052 let predicted = self.predict_i4_mode(bx, by);
2053 let rr = parse_intra4x4_pred_mode_cabac(&mut cab);
2054 let actual = if rr < 0 {
2055 predicted
2056 } else {
2057 let rem = rr as u8;
2058 if rem < predicted { rem } else { rem + 1 }
2059 };
2060 modes8[b8] = actual;
2061 for dy in 0..2 {
2062 for dx in 0..2 {
2063 self.modes_y[(by + dy) * w4 + (bx + dx)] = actual;
2064 modes[(b8y * 2 + dy) * 4 + (b8x * 2 + dx)] = actual;
2065 }
2066 }
2067 }
2068 } else {
2069 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
2070 let (bx, by) = (mbx * 4 + lbx, mby * 4 + lby);
2071 let predicted = self.predict_i4_mode(bx, by);
2072 let rr = parse_intra4x4_pred_mode_cabac(&mut cab);
2073 let actual = if rr < 0 {
2074 predicted
2075 } else {
2076 let rem = rr as u8;
2077 if rem < predicted { rem } else { rem + 1 }
2078 };
2079 self.modes_y[by * w4 + bx] = actual;
2080 modes[lby * 4 + lbx] = actual;
2081 }
2082 }
2083 let chroma_mode = parse_intra_chroma_pred_mode_cabac(&mut cab, cci) as u8;
2084 cmode[addr] = chroma_mode as i32;
2085 let cbp = parse_cbp_cabac(&mut cab, top.map(|a| mb_cbp[a]), left.map(|a| mb_cbp[a]));
2086 mb_cbp[addr] = cbp as u8;
2087 let (cbp_luma, cbp_chroma) = (cbp & 15, cbp >> 4);
2088
2089 let mut nzc = [0xffu8; 48];
2091 if let Some(t) = top {
2092 let tn = mb_nzc[t];
2093 nzc[1..5].copy_from_slice(&tn[12..16]);
2094 (nzc[0], nzc[5], nzc[29]) = (0, 0, 0);
2095 (nzc[6], nzc[7]) = (tn[20], tn[21]);
2096 (nzc[30], nzc[31]) = (tn[22], tn[23]);
2097 }
2098 if let Some(l) = left {
2099 let ln = mb_nzc[l];
2100 (nzc[8], nzc[16], nzc[24], nzc[32]) = (ln[3], ln[7], ln[11], ln[15]);
2101 (nzc[13], nzc[21], nzc[37], nzc[45]) = (ln[17], ln[21], ln[19], ln[23]);
2102 }
2103
2104 let mut cbfdc = 0u16;
2107 let mut luma_scan = [[0i32; 16]; 16]; let mut luma8 = [[0i32; 64]; 4]; let mut cdc = [[0i32; 4]; 2]; let mut cac = [[[0i32; 16]; 4]; 2]; if cbp == 0 {
2112 last_delta_qp = 0;
2113 }
2114 if cbp != 0 {
2115 let ndc = (top.map(|a| cbf_dc[a]), left.map(|a| cbf_dc[a]));
2116 let qpd = parse_mb_qp_delta_cabac(&mut cab, &mut last_delta_qp);
2117 self.step_qp(qpd);
2118 for id8 in 0..4usize {
2119 if cbp_luma & (1 << id8) != 0 {
2120 if t8 {
2121 let n = parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, id8 * 4, RP_LUMA_8X8, true, ndc, &mut luma8[id8]);
2124 let (b8x, b8y) = (id8 % 2, id8 / 2);
2125 for sy in 0..2 {
2126 for sx in 0..2 {
2127 self.nnz_y[(mby * 4 + b8y * 2 + sy) * w4 + (mbx * 4 + b8x * 2 + sx)] = n as u8;
2128 }
2129 }
2130 } else {
2131 for id4 in 0..4usize {
2132 let iz = id8 * 4 + id4;
2133 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, iz, RP_LUMA_4X4, true, ndc, &mut luma_scan[iz]);
2134 }
2135 }
2136 } else {
2137 for k in 0..4 {
2138 nzc[NZC_CACHE[id8 * 4 + k]] = 0;
2139 }
2140 if t8 {
2141 let (b8x, b8y) = (id8 % 2, id8 / 2);
2142 for sy in 0..2 {
2143 for sx in 0..2 {
2144 self.nnz_y[(mby * 4 + b8y * 2 + sy) * w4 + (mbx * 4 + b8x * 2 + sx)] = 0;
2145 }
2146 }
2147 }
2148 }
2149 }
2150 if cbp_chroma >= 1 {
2151 for i in 0..2usize {
2152 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4, RP_CHROMA_DC + i, true, ndc, &mut cdc[i]);
2153 }
2154 }
2155 if cbp_chroma == 2 {
2156 for i in 0..2usize {
2157 for id4 in 0..4usize {
2158 parse_residual_cabac(&mut cab, &mut nzc, &mut cbfdc, 16 + i * 4 + id4, RP_CHROMA_AC + i, true, ndc, &mut cac[i][id4]);
2159 }
2160 }
2161 }
2162 }
2163 self.mb_qp[addr] = self.cur_qp;
2164 cbf_dc[addr] = cbfdc;
2165 let mut mn = [0u8; 24];
2167 for k in 0..4 {
2168 mn[k] = nzc[9 + k];
2169 mn[4 + k] = nzc[17 + k];
2170 mn[8 + k] = nzc[25 + k];
2171 mn[12 + k] = nzc[33 + k];
2172 }
2173 (mn[16], mn[17], mn[20], mn[21]) = (nzc[14], nzc[15], nzc[22], nzc[23]);
2174 (mn[18], mn[19], mn[22], mn[23]) = (nzc[38], nzc[39], nzc[46], nzc[47]);
2175 for v in mn.iter_mut() {
2176 if *v == 0xff {
2177 *v = 0;
2178 }
2179 }
2180 mb_nzc[addr] = mn;
2181
2182 let qp = self.cur_qp;
2184 let top_ok = mby > 0 && self.nbr_in_slice(mbx, mby - 1) && self.intra_nbr_ok(mbx * 4, mby * 4 - 1);
2185 let left_ok = mbx > 0 && self.nbr_in_slice(mbx - 1, mby) && self.intra_nbr_ok(mbx * 4 - 1, mby * 4);
2186 if t8 {
2187 for b8 in 0..4usize {
2191 let (b8x, b8y) = (b8 % 2, b8 / 2);
2192 let (bx, by) = (mbx * 4 + b8x * 2, mby * 4 + b8y * 2);
2193 let (px, py) = (bx * 4, by * 4);
2194 let res8 = if cbp_luma & (1 << b8) != 0 {
2195 let raster = un_scan_8x8(&luma8[b8]);
2196 self.inv_quant8(&raster, qp, 0)
2197 } else {
2198 [0i32; 64]
2199 };
2200 let avail_top = b8y > 0 || top_ok;
2201 let avail_left = b8x > 0 || left_ok;
2202 let (t, l, corner, avail_corner) =
2203 self.gather_i8(px, py, avail_top, avail_left, bx, by);
2204 let pred =
2205 intra8x8_pred(modes8[b8], avail_top, avail_left, avail_corner, &t, &l, corner);
2206 let mut predb = [0i32; 64];
2207 for i in 0..64 {
2208 predb[i] = pred[i] as i32;
2209 }
2210 let recon = add_residual_8x8(&res8, &predb);
2211 for dy in 0..8 {
2212 for dx in 0..8 {
2213 self.rec_y[(py + dy) * self.cw + (px + dx)] = recon[dy * 8 + dx];
2214 }
2215 }
2216 for sy in 0..2 {
2217 for sx in 0..2 {
2218 self.coded_y[(by + sy) * w4 + (bx + sx)] = true;
2219 }
2220 }
2221 }
2222 }
2223 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
2224 if t8 {
2225 break;
2226 }
2227 let (bx, by) = (mbx * 4 + lbx, mby * 4 + lby);
2228 let (px, py) = (bx * 4, by * 4);
2229 let at = lby > 0 || top_ok;
2230 let al = lbx > 0 || left_ok;
2231 let qb = un_scan_4x4_dcac(&luma_scan[blk]);
2232 self.nnz_y[by * w4 + bx] = luma_scan[blk].iter().filter(|&&v| v != 0).count() as u8;
2233 let (t, l, corner) = self.gather_i4(px, py, at, al, bx, by);
2234 let pred = intra4x4_pred(modes[lby * 4 + lbx], at, al, &t, &l, corner);
2235 let predb = std::array::from_fn(|i| pred[i] as i32);
2236 let s = reconstruct_4x4(&self.dequant(&qb, qp, 0), &predb);
2237 store(&mut self.rec_y, self.cw, px, py, &s);
2238 self.coded_y[by * w4 + bx] = true;
2239 }
2240 self.recon_chroma_cabac(mbx, mby, chroma_mode, &cdc, &cac, cbp_chroma, top_ok, left_ok);
2241
2242 let eos = cab.decode_terminate();
2244 addr += 1;
2245 if eos || addr >= total {
2246 break;
2247 }
2248 }
2249 if trace {
2250 eprintln!("# CABAC decoded {} MBs (of {total})", addr - first_mb);
2251 }
2252 self.edc_flush(); Ok(addr)
2254 }
2255
2256 #[allow(clippy::too_many_arguments)]
2260 #[allow(clippy::too_many_arguments)]
2266 fn add_inter_residual(
2267 &mut self,
2268 mb_x: usize,
2269 mb_y: usize,
2270 pred_y: &[u8; 256],
2271 c_pred: &[[u8; 64]; 2],
2272 luma_scan: &[[i32; 16]; 16],
2273 luma8: Option<&[[i32; 64]; 4]>,
2276 cdc: &[[i32; 4]; 2],
2277 cac: &[[[i32; 16]; 4]; 2],
2278 cbp_chroma: u32,
2279 nnzs: &[u8; 24],
2286 ) {
2287 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecResidAdd);
2288 let qp = self.cur_qp;
2289 let qpc = self.chroma_qp_for(qp);
2290 let (w4r, w2r) = (self.mb_w * 4, self.mb_w * 2);
2291 if let Some(l8) = luma8 {
2292 for b8 in 0..4usize {
2294 let (b8x, b8y) = (b8 % 2, b8 / 2);
2295 let nnz: u32 = (0..4).map(|k| nnzs[b8 * 4 + k] as u32).sum();
2304 for sy in 0..2 {
2305 for sx in 0..2 {
2306 self.nnz_y[(mb_y * 4 + b8y * 2 + sy) * w4r + (mb_x * 4 + b8x * 2 + sx)] =
2307 nnzs[b8 * 4 + sy * 2 + sx];
2308 }
2309 }
2310 let res8 = if nnz == 0 {
2311 [0i32; 64]
2312 } else {
2313 let raster = un_scan_8x8(&l8[b8]);
2314 self.inv_quant8(&raster, qp, 1)
2316 };
2317 for sy in 0..2 {
2320 for sx in 0..2 {
2321 self.coded_y[(mb_y * 4 + b8y * 2 + sy) * w4r + (mb_x * 4 + b8x * 2 + sx)] = true;
2322 }
2323 }
2324 let predb: [i32; 64] =
2325 std::array::from_fn(|i| pred_y[(b8y * 8 + i / 8) * 16 + (b8x * 8 + i % 8)] as i32);
2326 let recon = add_residual_8x8(&res8, &predb);
2327 let (px, py) = (mb_x * 16 + b8x * 8, mb_y * 16 + b8y * 8);
2328 for dy in 0..8 {
2329 for dx in 0..8 {
2330 self.rec_y[(py + dy) * self.cw + (px + dx)] = recon[dy * 8 + dx];
2331 }
2332 }
2333 }
2334 }
2335 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
2336 if luma8.is_some() {
2337 break;
2338 }
2339 let nnz = nnzs[blk];
2340 self.nnz_y[(mb_y * 4 + lby) * w4r + (mb_x * 4 + lbx)] = nnz;
2341 let cw = self.cw;
2342 let p_off = (lby * 4) * 16 + lbx * 4;
2343 let r_off = (mb_y * 4 + lby) * 4 * cw + (mb_x * 4 + lbx) * 4;
2344 if nnz == 0 {
2345 for r in 0..4 {
2350 self.rec_y[r_off + r * cw..r_off + r * cw + 4]
2351 .copy_from_slice(&pred_y[p_off + r * 16..p_off + r * 16 + 4]);
2352 }
2353 continue;
2354 }
2355 if nnz == 1 && luma_scan[blk][0] != 0 {
2359 let f = self.dequant_dc4(luma_scan[blk][0], qp, 3);
2360 reconstruct_4x4_dc_into((f + 32) >> 6, pred_y, p_off, 16, &mut self.rec_y, r_off, cw);
2361 } else {
2362 let deq = if nnz <= 6 {
2372 dequant_scatter_4x4(&luma_scan[blk], nnz, 0, qp, self.scaling.as_ref().map(|sc| &sc[3]))
2373 } else {
2374 self.dequant(&un_scan_4x4_dcac(&luma_scan[blk]), qp, 3)
2375 };
2376 reconstruct_4x4_into(&deq, pred_y, p_off, 16, &mut self.rec_y, r_off, cw);
2377 }
2378 }
2379 let mut c_dc = [[0i32; 4]; 2];
2380 if cbp_chroma != 0 {
2381 for c in 0..2 {
2382 c_dc[c] = self.dequant_chroma_dc(&cdc[c], qpc, 4 + c);
2383 }
2384 }
2385 let ccw = self.ccw;
2386 for c in 0..2 {
2387 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
2388 let mut ac_nz = false;
2389 if cbp_chroma == 2 {
2390 let n = nnzs[16 + c * 4 + by * 2 + bx];
2391 self.nnz_c[c][(mb_y * 2 + by) * w2r + (mb_x * 2 + bx)] = n;
2392 ac_nz = n != 0;
2393 }
2394 let dc = c_dc[c][by * 2 + bx];
2395 let p_off = (by * 4) * 8 + bx * 4;
2396 let r_off = (mb_y * 2 + by) * 4 * ccw + (mb_x * 2 + bx) * 4;
2397 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
2398 if dc == 0 && !ac_nz {
2399 for r in 0..4 {
2401 plane[r_off + r * ccw..r_off + r * ccw + 4]
2402 .copy_from_slice(&c_pred[c][p_off + r * 8..p_off + r * 8 + 4]);
2403 }
2404 continue;
2405 }
2406 if !ac_nz {
2410 reconstruct_4x4_dc_into((dc + 32) >> 6, &c_pred[c], p_off, 8, plane, r_off, ccw);
2411 continue;
2412 }
2413 let n = nnzs[16 + c * 4 + by * 2 + bx];
2416 let mut deq = if n <= 6 {
2417 dequant_scatter_4x4(&cac[c][by * 2 + bx], n, 1, qpc, self.scaling.as_ref().map(|sc| &sc[4 + c]))
2418 } else {
2419 let mut ac = [0i32; 16];
2420 un_scan_4x4_ac_into(&cac[c][by * 2 + bx], &mut ac);
2421 match &self.scaling {
2424 Some(sc) => dequantize_weighted(&ac, qpc, &sc[4 + c]),
2425 None => dequantize(&ac, qpc),
2426 }
2427 };
2428 deq[0] = dc;
2429 reconstruct_4x4_into(&deq, &c_pred[c], p_off, 8, plane, r_off, ccw);
2430 }
2431 }
2432 }
2433
2434 fn recon_chroma_cabac(
2435 &mut self,
2436 mb_x: usize,
2437 mb_y: usize,
2438 chroma_mode: u8,
2439 cdc: &[[i32; 4]; 2],
2440 cac: &[[[i32; 16]; 4]; 2],
2441 cbp_chroma: u32,
2442 avail_top: bool,
2443 avail_left: bool,
2444 ) {
2445 let qpc = self.chroma_qp_for(self.cur_qp);
2446 let (cx, cy) = (mb_x * 8, mb_y * 8);
2447 let mut c_dc = [[0i32; 4]; 2];
2448 if cbp_chroma != 0 {
2449 for c in 0..2 {
2450 c_dc[c] = self.dequant_chroma_dc(&cdc[c], qpc, 1 + c);
2451 }
2452 }
2453 let w2 = self.mb_w * 2;
2454 for c in 0..2 {
2455 let mut ctop = [0u8; 8];
2456 let mut cleft = [0u8; 8];
2457 let mut ccorner = 0u8;
2458 {
2459 let rec_c = if c == 0 { &self.rec_u } else { &self.rec_v };
2460 if avail_top {
2461 ctop.copy_from_slice(self.top_c_row(c, cy, cx, 8));
2462 }
2463 if avail_left {
2464 for i in 0..8 {
2465 cleft[i] = rec_c[(cy + i) * self.ccw + cx - 1];
2466 }
2467 }
2468 if avail_top && avail_left {
2469 ccorner = self.top_c_px(c, cy, cx - 1);
2470 }
2471 }
2472 let pred8 = chroma8x8_pred(chroma_mode, avail_top, avail_left, &ctop, &cleft, ccorner);
2473 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
2474 let mut ac = [0i32; 16];
2475 if cbp_chroma == 2 {
2476 un_scan_4x4_ac_into(&cac[c][by * 2 + bx], &mut ac);
2477 self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] =
2478 cac[c][by * 2 + bx].iter().filter(|&&v| v != 0).count() as u8;
2479 }
2480 let mut deq = self.dequant(&ac, qpc, 1 + c);
2481 deq[0] = c_dc[c][by * 2 + bx];
2482 let predb: [i32; 16] =
2483 std::array::from_fn(|i| pred8[(by * 4 + i / 4) * 8 + (bx * 4 + i % 4)] as i32);
2484 let s = reconstruct_4x4(&deq, &predb);
2485 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
2486 store(plane, self.ccw, cx + bx * 4, cy + by * 4, &s);
2487 }
2488 }
2489 }
2490
2491 pub fn decode_slice_data(
2497 &mut self,
2498 r: &mut BitReader,
2499 is_p: bool,
2500 first_mb: usize,
2501 ) -> Result<usize, MbError> {
2502 let eligible = edc_on() && rowdb_on() && (is_p || self.is_b);
2503 let threaded = eligible
2504 && edc_mt().unwrap_or_else(|| edc_dispatch(self.mb_w, self.mb_h, self.bits_per_mb, false));
2505 edcstat::bump(&edcstat::DISPATCH_ON, threaded as u64);
2506 edcstat::bump(&edcstat::DISPATCH_SEEN, eligible as u64);
2507 if !threaded {
2508 return self.decode_slice_cavlc_inner(r, is_p, first_mb);
2509 }
2510 let ctx = self.edc_take_ctx();
2511 let (tx, rx) = std::sync::mpsc::sync_channel::<EdcMsg>(edc_bound());
2512 let (ctx_tx, ctx_rx) = std::sync::mpsc::channel::<PixelCtx>();
2513 let (back_tx, back_rx) = std::sync::mpsc::channel::<PixelCtx>();
2514 let (res, ctx, panicked) = std::thread::scope(|sc| {
2515 let h = sc.spawn(move || edc_worker(ctx, rx, ctx_tx, back_rx));
2516 self.edc_tx = Some(tx);
2517 self.edc_ctx_rx = Some(ctx_rx);
2518 self.edc_back_tx = Some(back_tx);
2519 let r2 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
2525 self.decode_slice_cavlc_inner(r, is_p, first_mb)
2526 }));
2527 self.edc_flush_batch();
2528 self.edc_giveback();
2529 self.edc_tx = None;
2530 self.edc_ctx_rx = None;
2531 self.edc_back_tx = None;
2532 match (r2, h.join()) {
2533 (Ok(res), Ok(ctx)) => (res, Some(ctx), None),
2534 (Err(pn), Ok(ctx)) => (Err(MbError::Truncated), Some(ctx), Some(pn)),
2535 (Ok(_), Err(pn)) | (Err(_), Err(pn)) => (Err(MbError::Truncated), None, Some(pn)),
2536 }
2537 });
2538 if let Some(ctx) = ctx {
2539 self.edc_restore_ctx(ctx);
2540 }
2541 if let Some(pn) = panicked {
2542 std::panic::resume_unwind(pn);
2543 }
2544 res
2545 }
2546
2547 fn decode_slice_cavlc_inner(
2548 &mut self,
2549 r: &mut BitReader,
2550 is_p: bool,
2551 first_mb: usize,
2552 ) -> Result<usize, MbError> {
2553 let total = self.mb_w * self.mb_h;
2554 self.slice_first_mb = first_mb;
2555 self.edc_active = edc_on();
2556 let mut addr = first_mb;
2557 while addr < total {
2558 self.row_hook(addr);
2559 if is_p || self.is_b {
2560 let skip_run = {
2561 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
2562 r.read_ue()?
2563 } as usize;
2564 for _ in 0..skip_run {
2565 if addr >= total {
2566 break;
2567 }
2568 if self.is_b {
2569 self.decode_b_skip(addr % self.mb_w, addr / self.mb_w)?;
2570 } else {
2571 self.decode_p_skip(addr % self.mb_w, addr / self.mb_w)?;
2572 }
2573 self.mb_qp[addr] = self.cur_qp; addr += 1;
2575 }
2576 if addr >= total {
2577 break;
2578 }
2579 if skip_run > 0 && !r.more_rbsp_data() {
2581 break;
2582 }
2583 }
2584 if self.is_b {
2585 self.edc_intra_sync();
2587 self.decode_b_mb(r, addr % self.mb_w, addr / self.mb_w)?;
2588 } else {
2589 self.decode_mb(r, addr % self.mb_w, addr / self.mb_w, is_p)?;
2590 }
2591 self.mb_qp[addr] = self.cur_qp;
2592 addr += 1;
2593 if !r.more_rbsp_data() {
2595 break;
2596 }
2597 }
2598 self.edc_flush(); Ok(addr)
2600 }
2601
2602 fn decode_mb(
2603 &mut self,
2604 r: &mut BitReader,
2605 mb_x: usize,
2606 mb_y: usize,
2607 is_p: bool,
2608 ) -> Result<(), MbError> {
2609 let mut mb_type = {
2610 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
2611 r.read_ue()?
2612 };
2613 if is_p {
2614 if mb_type <= 2 {
2617 return self.decode_inter(r, mb_x, mb_y, mb_type as u8);
2618 }
2619 if mb_type == 3 || mb_type == 4 {
2620 return self.decode_p8x8(r, mb_x, mb_y, mb_type == 4);
2621 }
2622 mb_type -= 5;
2623 }
2624 self.edc_intra_sync();
2627 self.decode_intra_mb(r, mb_x, mb_y, mb_type)
2628 }
2629
2630 fn decode_intra_mb(
2633 &mut self,
2634 r: &mut BitReader,
2635 mb_x: usize,
2636 mb_y: usize,
2637 mb_type: u32,
2638 ) -> Result<(), MbError> {
2639 let _gi = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMbI);
2643 if mb_type == 0 {
2644 if self.transform_8x8_mode && r.read_bit()? {
2646 self.decode_i8x8(r, mb_x, mb_y)?;
2647 } else {
2648 self.decode_i4x4(r, mb_x, mb_y)?;
2649 }
2650 } else if (1..=24).contains(&mb_type) {
2651 self.decode_i16(r, mb_x, mb_y, mb_type - 1)?;
2652 } else if mb_type == 25 {
2653 self.edc_intra_sync();
2655 self.decode_ipcm(r, mb_x, mb_y)?;
2656 } else {
2657 return Err(MbError::Unsupported("only I_4x4 / I_16x16 / I_PCM macroblocks"));
2658 }
2659 let w4 = self.mb_w * 4;
2661 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
2662 self.coded_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = true;
2663 }
2664 Ok(())
2665 }
2666
2667 fn decode_inter(
2671 &mut self,
2672 r: &mut BitReader,
2673 mb_x: usize,
2674 mb_y: usize,
2675 mode: u8,
2676 ) -> Result<(), MbError> {
2677 if self.refs.is_empty() {
2678 return Err(MbError::Unsupported("inter without reference"));
2679 }
2680 if mode == 0 {
2687 self.mb_kind[mb_y * self.mb_w + mb_x] =
2688 rusty_h264_common::deblock::MB_KIND_INTER_UNIFORM;
2689 }
2690 let w4 = self.mb_w * 4;
2692 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
2693 let num_refs = self.refs.len();
2694 let layout = inter_partitions(mode);
2695
2696 let nparts = layout.len();
2699 let mut ref_idxs = [0i32; 4];
2700 if self.num_ref_active > 1 {
2701 for ri in ref_idxs[..nparts].iter_mut() {
2702 *ri = read_ref_idx(r, self.num_ref_active)?;
2703 if *ri as usize >= num_refs {
2704 return Err(MbError::Truncated); }
2706 }
2707 }
2708
2709 let mut part_mv = [(0i32, (0i32, 0i32)); 4];
2712 {
2713 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MvGrid);
2714 for (part, &(rx, ry, rw, rh)) in layout.iter().enumerate() {
2715 let refi = ref_idxs[part];
2716 let (pbx, pby) = ((mb_x * 4 + rx / 4) as isize, (mb_y * 4 + ry / 4) as isize);
2717 let [a, b, c] = self.mv_neighbors_block(pbx, pby, (rw / 4) as isize);
2718 let pmv = predict_partition_mv(mode, part, a, b, c, refi);
2719 let mvd_x = r.read_se()?;
2720 let mvd_y = r.read_se()?;
2721 let mv = (pmv.0 + mvd_x, pmv.1 + mvd_y);
2722 part_mv[part] = (refi, mv);
2723 for by in ry / 4..ry / 4 + rh / 4 {
2724 for bx in rx / 4..rx / 4 + rw / 4 {
2725 let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
2726 self.mv_y[idx] = mv;
2727 self.inter_y[idx] = true;
2728 self.ref_idx_y[idx] = refi;
2729 self.coded_y[idx] = true;
2730 }
2731 }
2732 }
2733 }
2734
2735 let mut pred_y = [0u8; 256];
2737 let mut c_pred = [[0u8; 64]; 2];
2738 let defer = self.edc_tx.is_some() || self.edc_active;
2751 let mc_passes = if defer { 0 } else if double_recon() { 2 } else { 1 };
2752 for _pass in 0..mc_passes {
2753 if _pass > 0 {
2754 edcstat::bump(&edcstat::DOUBLED, 1);
2755 }
2756 for (part, &(rx, ry, rw, rh)) in layout.iter().enumerate() {
2757 let (refi, mv) = part_mv[part];
2758 let reference = &self.refs[refi as usize];
2759 let mut tmp = [0u8; 256];
2760 mc_luma_padded(&reference.py, reference.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + rx, mb_y * 16 + ry, rw, rh, mv.0, mv.1, &mut tmp);
2761 {
2762 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
2763 restride(&mut pred_y, 16, rx, ry, &tmp, rw, rh);
2764 }
2765 let (crx, cry, crw, crh) = (rx / 2, ry / 2, rw / 2, rh / 2);
2766 for cc in 0..2 {
2767 let rc = if cc == 0 { &reference.pu } else { &reference.pv };
2768 let mut tc = [0u8; 64];
2769 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv.0, mv.1, &mut tc);
2770 {
2771 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
2772 restride(&mut c_pred[cc], 8, crx, cry, &tc, crw, crh);
2773 }
2774 }
2775 self.weight_partition(&mut pred_y, &mut c_pred, 0, refi as usize, rx, ry, rw, rh);
2776 }
2777 }
2778
2779 self.inter_finish(r, mb_x, mb_y, &pred_y, &c_pred, true, defer)
2781 }
2782
2783 fn inter_finish(
2787 &mut self,
2788 r: &mut BitReader,
2789 mb_x: usize,
2790 mb_y: usize,
2791 pred_y: &[u8; 256],
2792 c_pred: &[[u8; 64]; 2],
2793 allow_8x8: bool,
2794 defer: bool,
2797 ) -> Result<(), MbError> {
2798 let w4 = self.mb_w * 4;
2799 let cbp = {
2800 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
2801 read_cbp_inter(r)?
2802 };
2803 let cbp_luma = cbp & 15;
2804 let cbp_chroma = cbp >> 4;
2805 let t8x8 = cbp_luma > 0 && self.transform_8x8_mode && allow_8x8 && r.read_bit()?;
2808 if t8x8 {
2809 self.mb_t8x8[mb_y * self.mb_w + mb_x] = true;
2810 }
2811 if cbp != 0 {
2812 self.step_qp(r.read_se()?);
2813 }
2814 let (qp, qpc) = (self.cur_qp, self.chroma_qp_for(self.cur_qp));
2815
2816 self.nnz_cache_load(mb_x, mb_y);
2818 let mut luma_scan = [[0i32; 16]; 16];
2819 let mut nnzs = [0u8; 24];
2820 let mut luma8 = [[0i32; 64]; 4]; if t8x8 {
2822 for b8 in 0..4 {
2823 let (b8x, b8y) = (b8 % 2, b8 / 2);
2824 let (bx, by) = (mb_x * 4 + b8x * 2, mb_y * 4 + b8y * 2);
2825 if cbp_luma & (1 << b8) != 0 {
2826 let mut scan8 = [0i32; 64];
2827 for sub in 0..4 {
2828 let (sx, sy) = (sub % 2, sub / 2);
2829 let (cx, cy) = (b8x * 2 + sx, b8y * 2 + sy);
2830 let nc = self.nc_pred(cx, cy);
2831 let blk = decode_residual_block(r, 16, nc)?;
2832 let total = blk.iter().filter(|&&v| v != 0).count() as u8;
2833 self.nnz_cache_set(cx, cy, total);
2834 self.nnz_y[(by + sy) * w4 + (bx + sx)] = total;
2835 nnzs[b8 * 4 + sub] = total;
2839 for k in 0..16 {
2840 scan8[4 * k + sub] = blk[k];
2841 }
2842 }
2843 luma8[b8] = scan8;
2846 } else {
2847 for sub in 0..4 {
2848 let (sx, sy) = (sub % 2, sub / 2);
2849 self.nnz_cache_set(b8x * 2 + sx, b8y * 2 + sy, 0);
2850 self.nnz_y[(by + sy) * w4 + (bx + sx)] = 0;
2851 }
2852 }
2853 }
2854 } else {
2855 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
2856 let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
2857 let total = if cbp_luma & (1 << (blk / 4)) != 0 {
2858 let nc = self.nc_pred(lbx, lby);
2859 let scan16 = decode_residual_block(r, 16, nc)?;
2860 luma_scan[blk] = scan16; scan16.iter().filter(|&&v| v != 0).count() as u8
2862 } else {
2863 0
2864 };
2865 self.nnz_cache_set(lbx, lby, total);
2866 self.nnz_y[by * w4 + bx] = total;
2867 nnzs[blk] = total;
2868 }
2869 }
2870
2871 let mut c_recon_dc = [[0i32; 4]; 2];
2873 if cbp_chroma != 0 {
2874 for (c, slot) in c_recon_dc.iter_mut().enumerate() {
2875 let dc = decode_residual_block(r, 4, -1)?;
2876 *slot = [dc[0], dc[1], dc[2], dc[3]]; }
2878 }
2879 let mut c_q = [[[0i32; 16]; 4]; 2];
2880 if cbp_chroma == 2 {
2881 self.chroma_cache_load(mb_x, mb_y);
2882 let w2 = self.mb_w * 2;
2883 for c in 0..2 {
2884 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
2885 let nc = self.chroma_nc_pred(c, bx, by);
2886 let ac = decode_residual_block(r, 15, nc)?;
2887 let total = ac.iter().filter(|&&v| v != 0).count() as u8;
2888 self.chroma_nnz_cache_set(c, bx, by, total);
2889 self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total;
2890 c_q[c][by * 2 + bx] = ac; nnzs[16 + c * 4 + by * 2 + bx] = total;
2892 }
2893 }
2894 }
2895
2896 if defer {
2908 let (mut gmv, mut gref) = ([(0i32, 0i32); 16], [0u8; 16]);
2913 let w4r = self.mb_w * 4;
2914 for by in 0..4usize {
2915 for bx in 0..4usize {
2916 let bi = (mb_y * 4 + by) * w4r + (mb_x * 4 + bx);
2917 gmv[by * 4 + bx] = self.mv_y[bi];
2918 gref[by * 4 + bx] = self.ref_idx_y[bi].clamp(0, 15) as u8;
2919 }
2920 }
2921 let ej = if cbp == 0 && nores_on() {
2926 edcstat::bump(&edcstat::J_NORES_SENT, 1);
2927 EdcJob::InterNoRes(Box::new(PInterNoResJob {
2928 mbx: mb_x, mby: mb_y, t8: t8x8, qp, gmv, gref,
2929 }))
2930 } else {
2931 EdcJob::Inter(Box::new(PInterJob {
2932 mbx: mb_x, mby: mb_y, t8: t8x8, qp,
2933 cbp_chroma, gmv, gref,
2934 luma_scan, luma8, cdc: c_recon_dc, cac: c_q, nnzs,
2935 }))
2936 };
2937 if self.edc_tx.is_some() {
2938 self.edc_giveback();
2939 self.edc_send_job(ej);
2940 } else {
2941 self.edc_jobs.push(ej);
2942 }
2943 } else {
2944 self.add_inter_residual(
2945 mb_x, mb_y, pred_y, c_pred, &luma_scan,
2946 if t8x8 { Some(&luma8) } else { None },
2947 &c_recon_dc, &c_q, cbp_chroma, &nnzs,
2948 );
2949 }
2950
2951 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
2953 self.modes_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 2;
2954 }
2955 Ok(())
2956 }
2957
2958 fn mv_neighbors_list(&self, pbx: isize, pby: isize, pwb: isize, list: usize) -> [MvNeighbor; 3] {
2966 let (w4, h4) = ((self.mb_w * 4) as isize, (self.mb_h * 4) as isize);
2967 let (mvg, refg) = if list == 0 {
2968 (&self.mv_y, &self.ref_idx_y)
2969 } else {
2970 (&self.mv1, &self.ref_idx1)
2971 };
2972 let get = |bx: isize, by: isize| -> MvNeighbor {
2973 if bx < 0
2974 || by < 0
2975 || bx >= w4
2976 || by >= h4
2977 || !self.coded_y[(by * w4 + bx) as usize]
2978 || !self.nbr_in_slice(bx as usize / 4, by as usize / 4)
2979 {
2980 MvNeighbor::NONE
2981 } else {
2982 let idx = (by * w4 + bx) as usize;
2983 MvNeighbor { available: true, mv: mvg[idx], ref_idx: refg[idx] }
2984 }
2985 };
2986 let a = get(pbx - 1, pby);
2987 let b = get(pbx, pby - 1);
2988 let mut c = get(pbx + pwb, pby - 1);
2989 if !c.available {
2990 c = get(pbx - 1, pby - 1);
2991 }
2992 [a, b, c]
2993 }
2994
2995 #[inline]
3009 fn col_block(&self, bx4: usize, by4: usize) -> (usize, usize) {
3010 if self.direct_8x8_inference {
3011 ((bx4 / 2) * 3, (by4 / 2) * 3)
3012 } else {
3013 (bx4, by4)
3014 }
3015 }
3016
3017 fn col_zero(&self, bx: usize, by: usize) -> bool {
3018 let Some(col) = self.refs1.first() else { return false };
3019 if col.long_term || col.w4 == 0 {
3020 return false;
3021 }
3022 let idx = by * col.w4 + bx;
3023 if idx >= col.ref_idx.len() {
3024 return false;
3025 }
3026 let (cref, cmv) = if col.ref_idx[idx] >= 0 {
3034 (col.ref_idx[idx], col.mv[idx])
3035 } else if idx < col.ref_idx1.len() && col.ref_idx1[idx] >= 0 {
3036 (col.ref_idx1[idx], col.mv1[idx])
3037 } else {
3038 return false;
3039 };
3040 cref == 0 && cmv.0.abs() <= 1 && cmv.1.abs() <= 1
3041 }
3042
3043 fn implicit_weights(&self, refi0: i32, refi1: i32) -> Option<(i32, i32)> {
3047 if self.weighted_bipred_idc != 2 || refi0 < 0 || refi1 < 0 {
3048 return None;
3049 }
3050 let r0 = &self.refs[refi0 as usize];
3051 let r1 = &self.refs1[refi1 as usize];
3052 let td = (r1.poc - r0.poc).clamp(-128, 127);
3053 let tb = (self.cur_poc - r0.poc).clamp(-128, 127);
3054 if td == 0 || r0.long_term || r1.long_term {
3055 return None; }
3057 let tx = (16384 + td.abs() / 2) / td;
3058 let dsf = ((tb * tx + 32) >> 6).clamp(-1024, 1023);
3059 let w1 = dsf >> 2;
3060 if !(-64..=128).contains(&w1) {
3061 return None; }
3063 Some((64 - w1, w1))
3064 }
3065
3066 #[allow(clippy::too_many_arguments)]
3070 fn b_mc(
3071 &self,
3072 mb_x: usize,
3073 mb_y: usize,
3074 px: usize,
3075 py: usize,
3076 rw: usize,
3077 rh: usize,
3078 refi0: i32,
3079 mv0: (i32, i32),
3080 refi1: i32,
3081 mv1: (i32, i32),
3082 pred_y: &mut [u8; 256],
3083 c_pred: &mut [[u8; 64]; 2],
3084 ) {
3085 let _gb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBMc);
3086 let refi0 = if refi0 >= 0 { (refi0 as usize).min(self.refs.len().saturating_sub(1)) as i32 } else { -1 };
3092 let refi1 = if refi1 >= 0 { (refi1 as usize).min(self.refs1.len().saturating_sub(1)) as i32 } else { -1 };
3093 if (refi0 >= 0 && self.refs.is_empty()) || (refi1 >= 0 && self.refs1.is_empty()) {
3094 return;
3095 }
3096 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
3097 let weights = {
3098 let _gw = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBWeights);
3099 self.implicit_weights(refi0, refi1)
3100 };
3101 let full = px == 0 && rw == 16;
3113 let _gl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBLuma);
3114 let chroma_done = rusty_h264_common::inter::with_mc_scratch(|scr| match (refi0 >= 0, refi1 >= 0, full) {
3119 (true, false, true) => {
3120 let rf = &self.refs[refi0 as usize];
3121 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
3122 false
3123 }
3124 (false, true, true) => {
3125 let rf = &self.refs1[refi1 as usize];
3126 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
3127 false
3128 }
3129 (true, true, true) => {
3130 let rf = &self.refs[refi0 as usize];
3131 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
3132 let mut b = [0u8; 256];
3133 let rf = &self.refs1[refi1 as usize];
3134 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut b[..rw * rh]);
3135 drop(_gl);
3136 let _gbl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBBlend);
3137 let dst = &mut pred_y[py * 16..py * 16 + rw * rh];
3143 match weights {
3144 None => {
3145 for (d, s) in dst.iter_mut().zip(&b[..rw * rh]) {
3146 *d = ((*d as u16 + *s as u16 + 1) >> 1) as u8;
3147 }
3148 }
3149 Some((w0, w1)) => {
3150 for (d, s) in dst.iter_mut().zip(&b[..rw * rh]) {
3151 *d = ((*d as i32 * w0 + *s as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
3152 }
3153 }
3154 }
3155 let _gc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBChroma);
3156 self.b_mc_chroma(mb_x, mb_y, px, py, rw, rh, refi0, mv0, refi1, mv1, c_pred, weights, cch);
3157 true
3158 }
3159 _ => {
3160 let (mut a, mut b) = ([0u8; 256], [0u8; 256]);
3162 if refi0 >= 0 {
3163 let rf = &self.refs[refi0 as usize];
3164 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut a[..rw * rh]);
3165 }
3166 if refi1 >= 0 {
3167 let rf = &self.refs1[refi1 as usize];
3168 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut b[..rw * rh]);
3169 }
3170 drop(_gl);
3171 let _gbl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBBlend);
3172 match (refi0 >= 0, refi1 >= 0) {
3173 (true, true) => {
3174 for dy in 0..rh {
3175 let (ar, br) = (&a[dy * rw..dy * rw + rw], &b[dy * rw..dy * rw + rw]);
3176 let base = (py + dy) * 16 + px;
3177 let dst = &mut pred_y[base..base + rw];
3178 match weights {
3179 None => {
3180 for ((d, p), q) in dst.iter_mut().zip(ar).zip(br) {
3181 *d = ((*p as u16 + *q as u16 + 1) >> 1) as u8;
3182 }
3183 }
3184 Some((w0, w1)) => {
3185 for ((d, p), q) in dst.iter_mut().zip(ar).zip(br) {
3186 *d = ((*p as i32 * w0 + *q as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
3187 }
3188 }
3189 }
3190 }
3191 }
3192 (true, false) => {
3193 for dy in 0..rh {
3194 let d = (py + dy) * 16 + px;
3195 pred_y[d..d + rw].copy_from_slice(&a[dy * rw..dy * rw + rw]);
3196 }
3197 }
3198 _ => {
3199 for dy in 0..rh {
3200 let d = (py + dy) * 16 + px;
3201 pred_y[d..d + rw].copy_from_slice(&b[dy * rw..dy * rw + rw]);
3202 }
3203 }
3204 }
3205 false
3206 }
3207 });
3208 if chroma_done {
3209 return;
3210 }
3211 let _gc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBChroma);
3212 self.b_mc_chroma(mb_x, mb_y, px, py, rw, rh, refi0, mv0, refi1, mv1, c_pred, weights, cch);
3213 }
3214
3215 #[allow(clippy::too_many_arguments)]
3218 fn b_mc_chroma(
3219 &self,
3220 mb_x: usize,
3221 mb_y: usize,
3222 px: usize,
3223 py: usize,
3224 rw: usize,
3225 rh: usize,
3226 refi0: i32,
3227 mv0: (i32, i32),
3228 refi1: i32,
3229 mv1: (i32, i32),
3230 c_pred: &mut [[u8; 64]; 2],
3231 weights: Option<(i32, i32)>,
3232 cch: usize,
3233 ) {
3234 let (crx, cry, crw, crh) = (px / 2, py / 2, rw / 2, rh / 2);
3235 let full = crx == 0 && crw == 8;
3236 for c in 0..2 {
3237 match (refi0 >= 0, refi1 >= 0, full) {
3238 (true, false, true) => {
3239 let rf = &self.refs[refi0 as usize];
3240 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3241 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
3242 }
3243 (false, true, true) => {
3244 let rf = &self.refs1[refi1 as usize];
3245 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3246 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
3247 }
3248 (true, true, true) => {
3249 let rf = &self.refs[refi0 as usize];
3250 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3251 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
3252 let mut cb = [0u8; 64];
3253 let rf = &self.refs1[refi1 as usize];
3254 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3255 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut cb[..crw * crh]);
3256 let dst = &mut c_pred[c][cry * 8..cry * 8 + crw * crh];
3257 match weights {
3258 None => {
3259 for (d, s) in dst.iter_mut().zip(&cb[..crw * crh]) {
3260 *d = ((*d as u16 + *s as u16 + 1) >> 1) as u8;
3261 }
3262 }
3263 Some((w0, w1)) => {
3264 for (d, s) in dst.iter_mut().zip(&cb[..crw * crh]) {
3265 *d = ((*d as i32 * w0 + *s as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
3266 }
3267 }
3268 }
3269 }
3270 _ => {
3271 let (mut ca, mut cb) = ([0u8; 64], [0u8; 64]);
3272 if refi0 >= 0 {
3273 let rf = &self.refs[refi0 as usize];
3274 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3275 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut ca[..crw * crh]);
3276 }
3277 if refi1 >= 0 {
3278 let rf = &self.refs1[refi1 as usize];
3279 let pl = if c == 0 { &rf.pu } else { &rf.pv };
3280 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut cb[..crw * crh]);
3281 }
3282 match (refi0 >= 0, refi1 >= 0) {
3283 (true, true) => {
3284 for dy in 0..crh {
3285 let (pr, qr) = (&ca[dy * crw..dy * crw + crw], &cb[dy * crw..dy * crw + crw]);
3286 let base = (cry + dy) * 8 + crx;
3287 let dst = &mut c_pred[c][base..base + crw];
3288 match weights {
3289 None => {
3290 for ((d, p), q) in dst.iter_mut().zip(pr).zip(qr) {
3291 *d = ((*p as u16 + *q as u16 + 1) >> 1) as u8;
3292 }
3293 }
3294 Some((w0, w1)) => {
3295 for ((d, p), q) in dst.iter_mut().zip(pr).zip(qr) {
3296 *d = ((*p as i32 * w0 + *q as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
3297 }
3298 }
3299 }
3300 }
3301 }
3302 (true, false) => {
3303 for dy in 0..crh {
3304 let d = (cry + dy) * 8 + crx;
3305 c_pred[c][d..d + crw].copy_from_slice(&ca[dy * crw..dy * crw + crw]);
3306 }
3307 }
3308 _ => {
3309 for dy in 0..crh {
3310 let d = (cry + dy) * 8 + crx;
3311 c_pred[c][d..d + crw].copy_from_slice(&cb[dy * crw..dy * crw + crw]);
3312 }
3313 }
3314 }
3315 }
3316 }
3317 }
3318 }
3319
3320 #[allow(clippy::too_many_arguments)]
3322 fn b_set_motion(&mut self, mb_x: usize, mb_y: usize, px: usize, py: usize, rw: usize, rh: usize, refi0: i32, mv0: (i32, i32), refi1: i32, mv1: (i32, i32)) {
3323 let _gs = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBSet);
3324 let w4 = self.mb_w * 4;
3325 for by in py / 4..(py + rh) / 4 {
3326 for bx in px / 4..(px + rw) / 4 {
3327 let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
3328 self.ref_idx_y[idx] = refi0;
3329 self.mv_y[idx] = if refi0 >= 0 { mv0 } else { (0, 0) };
3330 self.ref_idx1[idx] = refi1;
3331 self.mv1[idx] = if refi1 >= 0 { mv1 } else { (0, 0) };
3332 self.inter_y[idx] = true;
3333 self.coded_y[idx] = true;
3334 self.modes_y[idx] = 2;
3335 }
3336 }
3337 }
3338
3339 #[allow(clippy::too_many_arguments)]
3343 fn coalesce_region(
3348 x: usize,
3349 y: usize,
3350 w: usize,
3351 h: usize,
3352 uniform: &dyn Fn(usize, usize, usize, usize) -> bool,
3353 emit: &mut dyn FnMut(usize, usize, usize, usize),
3354 ) {
3355 if uniform(x, y, w, h) {
3356 emit(x, y, w, h);
3357 return;
3358 }
3359 if h > 1 && uniform(x, y, w, h / 2) && uniform(x, y + h / 2, w, h / 2) {
3360 emit(x, y, w, h / 2);
3361 emit(x, y + h / 2, w, h / 2);
3362 return;
3363 }
3364 if w > 1 && uniform(x, y, w / 2, h) && uniform(x + w / 2, y, w / 2, h) {
3365 emit(x, y, w / 2, h);
3366 emit(x + w / 2, y, w / 2, h);
3367 return;
3368 }
3369 match (w > 1, h > 1) {
3370 (true, true) => {
3371 for q in 0..4usize {
3372 Self::coalesce_region(x + (q % 2) * (w / 2), y + (q / 2) * (h / 2), w / 2, h / 2, uniform, emit);
3373 }
3374 }
3375 (true, false) => {
3376 Self::coalesce_region(x, y, w / 2, h, uniform, emit);
3377 Self::coalesce_region(x + w / 2, y, w / 2, h, uniform, emit);
3378 }
3379 (false, true) => {
3380 Self::coalesce_region(x, y, w, h / 2, uniform, emit);
3381 Self::coalesce_region(x, y + h / 2, w, h / 2, uniform, emit);
3382 }
3383 (false, false) => emit(x, y, 1, 1),
3384 }
3385 }
3386
3387 fn decode_b_direct(&mut self, mb_x: usize, mb_y: usize, px: usize, py: usize, rw: usize, rh: usize, pred_y: &mut [u8; 256], c_pred: &mut [[u8; 64]; 2]) {
3388 let _gb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBDirect);
3389 if !self.direct_spatial {
3390 return self.decode_b_direct_temporal(mb_x, mb_y, px, py, rw, rh, pred_y, c_pred);
3391 }
3392 let gd = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBDeriv);
3397 let (nbx, nby) = ((mb_x * 4) as isize, (mb_y * 4) as isize);
3399 let n0 = self.mv_neighbors_list(nbx, nby, 4, 0);
3400 let n1 = self.mv_neighbors_list(nbx, nby, 4, 1);
3401 let min_pos = |a: i32, b: i32| if a < 0 { b } else if b < 0 { a } else { a.min(b) };
3402 let rid = |n: &[MvNeighbor; 3]| min_pos(min_pos(n[0].ref_idx, n[1].ref_idx), n[2].ref_idx);
3403 let (mut refi0, mut refi1) = (rid(&n0), rid(&n1));
3404 let direct_zero = refi0 < 0 && refi1 < 0;
3405 if direct_zero {
3406 refi0 = 0;
3407 refi1 = 0;
3408 }
3409 let mv0 = if refi0 >= 0 && !direct_zero { predict_mv(n0[0], n0[1], n0[2], refi0) } else { (0, 0) };
3410 let mv1 = if refi1 >= 0 && !direct_zero { predict_mv(n1[0], n1[1], n1[2], refi1) } else { (0, 0) };
3411 let (bx0, by0, bw, bh) = (px / 4, py / 4, rw / 4, rh / 4);
3417 let mut czg = [[false; 4]; 4]; for dy in 0..bh {
3419 for dx in 0..bw {
3420 let (colx, coly) = self.col_block(bx0 + dx, by0 + dy);
3421 czg[dy][dx] = !direct_zero && self.col_zero(mb_x * 4 + colx, mb_y * 4 + coly);
3422 }
3423 }
3424 let uniform = |x: usize, y: usize, w: usize, h: usize| -> bool {
3425 let t = czg[y][x];
3426 (y..y + h).all(|dy| (x..x + w).all(|dx| czg[dy][dx] == t))
3427 };
3428 let mut rects: [(usize, usize, usize, usize); 16] = [(0, 0, 0, 0); 16];
3429 let mut n = 0usize;
3430 Self::coalesce_region(0, 0, bw, bh, &uniform, &mut |x, y, w, h| {
3431 rects[n] = (x, y, w, h);
3432 n += 1;
3433 });
3434 drop(gd); for &(x, y, w, h) in &rects[..n] {
3436 let cz = czg[y][x];
3437 let m0 = if refi0 == 0 && cz { (0, 0) } else { mv0 };
3438 let m1 = if refi1 == 0 && cz { (0, 0) } else { mv1 };
3439 let (lx, ly, lw, lh) = ((bx0 + x) * 4, (by0 + y) * 4, w * 4, h * 4);
3440 self.b_mc_or_record(mb_x, mb_y, lx, ly, lw, lh, refi0, m0, refi1, m1, pred_y, c_pred);
3441 self.b_set_motion(mb_x, mb_y, lx, ly, lw, lh, refi0, m0, refi1, m1);
3442 }
3443 }
3444
3445 #[allow(clippy::too_many_arguments)]
3450 fn decode_b_direct_temporal(&mut self, mb_x: usize, mb_y: usize, px: usize, py: usize, rw: usize, rh: usize, pred_y: &mut [u8; 256], c_pred: &mut [[u8; 64]; 2]) {
3451 let poc1 = self.refs1.first().map_or(0, |f| f.poc);
3452 let infer = self.direct_8x8_inference;
3453 let step = if infer { 8 } else { 4 };
3459 let mut sy = py;
3460 while sy < py + rh {
3461 let mut sx = px;
3462 while sx < px + rw {
3463 let (colx, coly) = self.col_block(sx / 4, sy / 4);
3466 let (mvcol, refpoc) = {
3467 let col = &self.refs1[0];
3468 let idx = (mb_y * 4 + coly) * col.w4 + (mb_x * 4 + colx);
3469 if col.w4 != 0 && idx < col.mv.len() && col.ref_poc[idx] != i32::MIN {
3470 (col.mv[idx], col.ref_poc[idx])
3471 } else {
3472 ((0, 0), i32::MIN) }
3474 };
3475 let (refi0, mvc) = if refpoc == i32::MIN {
3477 (0, (0, 0))
3478 } else {
3479 let r = self.refs.iter().position(|f| f.poc == refpoc).unwrap_or(0) as i32;
3480 (r, mvcol)
3481 };
3482 let poc0 = self.refs[refi0 as usize].poc;
3483 let td = (poc1 - poc0).clamp(-128, 127);
3484 let tb = (self.cur_poc - poc0).clamp(-128, 127);
3485 let (mv0, mv1) = if td == 0 || self.refs[refi0 as usize].long_term {
3486 (mvc, (0, 0))
3487 } else {
3488 let tx = (16384 + td.abs() / 2) / td;
3489 let dsf = ((tb * tx + 32) >> 6).clamp(-1024, 1023);
3490 let m0 = ((dsf * mvc.0 + 128) >> 8, (dsf * mvc.1 + 128) >> 8);
3491 (m0, (m0.0 - mvc.0, m0.1 - mvc.1))
3492 };
3493 self.b_mc_or_record(mb_x, mb_y, sx, sy, step, step, refi0, mv0, 0, mv1, pred_y, c_pred);
3494 self.b_set_motion(mb_x, mb_y, sx, sy, step, step, refi0, mv0, 0, mv1);
3495 sx += step;
3496 }
3497 sy += step;
3498 }
3499 }
3500
3501 fn read_b_ref(&self, r: &mut BitReader, list: usize) -> Result<i32, MbError> {
3504 let (active, avail) = if list == 0 {
3505 (self.num_ref_active, self.refs.len())
3506 } else {
3507 (self.num_ref_active1, self.refs1.len())
3508 };
3509 let v = if active > 1 { read_ref_idx(r, active)? } else { 0 };
3510 if v as usize >= avail {
3511 return Err(MbError::Truncated);
3512 }
3513 Ok(v)
3514 }
3515
3516 fn decode_b_skip(&mut self, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
3518 if self.refs.is_empty() || self.refs1.is_empty() {
3519 return Err(MbError::Unsupported("B without references"));
3520 }
3521 if self.edc_tx.is_some() {
3522 self.edc_regions = Some(Vec::with_capacity(4));
3523 }
3524 let mut pred_y = [0u8; 256];
3525 let mut c_pred = [[0u8; 64]; 2];
3526 self.decode_b_direct(mb_x, mb_y, 0, 0, 16, 16, &mut pred_y, &mut c_pred);
3527 if let Some(regions) = self.edc_regions.take() {
3528 let w4 = self.mb_w * 4;
3530 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
3531 self.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 0;
3532 }
3533 self.edc_giveback();
3534 self.edc_send_job(EdcJob::BSkip { mbx: mb_x, mby: mb_y, regions });
3535 return Ok(());
3536 }
3537 for dy in 0..16 {
3539 let d = (mb_y * 16 + dy) * self.cw + mb_x * 16;
3540 self.rec_y[d..d + 16].copy_from_slice(&pred_y[dy * 16..dy * 16 + 16]);
3541 }
3542 for c in 0..2 {
3543 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
3544 for dy in 0..8 {
3545 let d = (mb_y * 8 + dy) * self.ccw + mb_x * 8;
3546 plane[d..d + 8].copy_from_slice(&c_pred[c][dy * 8..dy * 8 + 8]);
3547 }
3548 }
3549 let w4 = self.mb_w * 4;
3551 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
3552 self.nnz_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 0;
3553 }
3554 Ok(())
3555 }
3556
3557 fn decode_b_mb(&mut self, r: &mut BitReader, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
3560 let mb_type = r.read_ue()?;
3561 if mb_type >= 23 {
3562 return self.decode_intra_mb(r, mb_x, mb_y, mb_type - 23);
3563 }
3564 if self.refs.is_empty() || self.refs1.is_empty() {
3565 return Err(MbError::Unsupported("B without references"));
3566 }
3567 let mut pred_y = [0u8; 256];
3568 let mut c_pred = [[0u8; 64]; 2];
3569
3570 if mb_type == 0 {
3571 self.decode_b_direct(mb_x, mb_y, 0, 0, 16, 16, &mut pred_y, &mut c_pred);
3573 return self.inter_finish(r, mb_x, mb_y, &pred_y, &c_pred, self.direct_8x8_inference, false);
3574 }
3575 if mb_type == 22 {
3576 return self.decode_b_8x8(r, mb_x, mb_y);
3577 }
3578
3579 let (layout, mvmode, preds) = b_inter_layout(mb_type);
3581 let mut refi = [[-1i32; 2]; 2]; for (p, &(_, _, _, _)) in layout.iter().enumerate() {
3584 if preds[p].uses(0) {
3585 refi[p][0] = self.read_b_ref(r, 0)?;
3586 }
3587 }
3588 for (p, _) in layout.iter().enumerate() {
3589 if preds[p].uses(1) {
3590 refi[p][1] = self.read_b_ref(r, 1)?;
3591 }
3592 }
3593 let mut mvd = [[(0i32, 0i32); 2]; 2];
3594 for (p, _) in layout.iter().enumerate() {
3595 if preds[p].uses(0) {
3596 mvd[p][0] = (r.read_se()?, r.read_se()?);
3597 }
3598 }
3599 for (p, _) in layout.iter().enumerate() {
3600 if preds[p].uses(1) {
3601 mvd[p][1] = (r.read_se()?, r.read_se()?);
3602 }
3603 }
3604 for (p, &(rx, ry, rw, rh)) in layout.iter().enumerate() {
3606 let (pbx, pby) = ((mb_x * 4 + rx / 4) as isize, (mb_y * 4 + ry / 4) as isize);
3607 let pwb = (rw / 4) as isize;
3608 let mut mv = [(0i32, 0i32); 2];
3609 for list in 0..2 {
3610 if refi[p][list] >= 0 {
3611 let n = self.mv_neighbors_list(pbx, pby, pwb, list);
3612 let pmv = predict_partition_mv(mvmode, p, n[0], n[1], n[2], refi[p][list]);
3613 mv[list] = (pmv.0 + mvd[p][list].0, pmv.1 + mvd[p][list].1);
3614 }
3615 }
3616 self.b_set_motion(mb_x, mb_y, rx, ry, rw, rh, refi[p][0], mv[0], refi[p][1], mv[1]);
3617 self.b_mc_or_record(mb_x, mb_y, rx, ry, rw, rh, refi[p][0], mv[0], refi[p][1], mv[1], &mut pred_y, &mut c_pred);
3627 }
3628 self.inter_finish(r, mb_x, mb_y, &pred_y, &c_pred, true, false)
3629 }
3630
3631 fn decode_b_8x8(&mut self, r: &mut BitReader, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
3634 let mut sub = [0u32; 4];
3635 for s in sub.iter_mut() {
3636 let v = r.read_ue()?;
3637 if v > 12 {
3638 return Err(MbError::Unsupported("invalid B sub_mb_type"));
3639 }
3640 *s = v;
3641 }
3642 let mut pred_y = [0u8; 256];
3643 let mut c_pred = [[0u8; 64]; 2];
3644 let mut refi = [[-1i32; 2]; 4];
3647 for (p, &st) in sub.iter().enumerate() {
3648 if st != 0 && b_sub_uses(st, 0) {
3649 refi[p][0] = self.read_b_ref(r, 0)?;
3650 }
3651 }
3652 for (p, &st) in sub.iter().enumerate() {
3653 if st != 0 && b_sub_uses(st, 1) {
3654 refi[p][1] = self.read_b_ref(r, 1)?;
3655 }
3656 }
3657 const MAX_MVD: usize = 16;
3667 let mut mvd0 = [(0i32, 0i32); MAX_MVD];
3668 let mut mvd1 = [(0i32, 0i32); MAX_MVD];
3669 let (mut n0, mut n1) = (0usize, 0usize);
3670 for &st in &sub {
3671 if st != 0 && b_sub_uses(st, 0) {
3672 for _ in b_sub_parts(st) {
3673 mvd0[n0] = (r.read_se()?, r.read_se()?);
3674 n0 += 1;
3675 }
3676 }
3677 }
3678 for &st in &sub {
3679 if st != 0 && b_sub_uses(st, 1) {
3680 for _ in b_sub_parts(st) {
3681 mvd1[n1] = (r.read_se()?, r.read_se()?);
3682 n1 += 1;
3683 }
3684 }
3685 }
3686 let (mut i0, mut i1) = (0usize, 0usize);
3688 for (p, &st) in sub.iter().enumerate() {
3689 let (b8x, b8y) = ((p % 2) * 8, (p / 2) * 8);
3690 if st == 0 {
3691 self.decode_b_direct(mb_x, mb_y, b8x, b8y, 8, 8, &mut pred_y, &mut c_pred);
3692 continue;
3693 }
3694 for &(sx, sy, sw, sh) in b_sub_parts(st) {
3695 let (px, py) = (b8x + sx, b8y + sy);
3696 let (pbx, pby) = ((mb_x * 4 + px / 4) as isize, (mb_y * 4 + py / 4) as isize);
3697 let pwb = (sw / 4) as isize;
3698 let mut mv = [(0i32, 0i32); 2];
3699 if b_sub_uses(st, 0) {
3700 let n = self.mv_neighbors_list(pbx, pby, pwb, 0);
3701 let pmv = predict_mv(n[0], n[1], n[2], refi[p][0]);
3702 let d = mvd0[i0];
3703 i0 += 1;
3704 mv[0] = (pmv.0 + d.0, pmv.1 + d.1);
3705 }
3706 if b_sub_uses(st, 1) {
3707 let n = self.mv_neighbors_list(pbx, pby, pwb, 1);
3708 let pmv = predict_mv(n[0], n[1], n[2], refi[p][1]);
3709 let d = mvd1[i1];
3710 i1 += 1;
3711 mv[1] = (pmv.0 + d.0, pmv.1 + d.1);
3712 }
3713 self.b_set_motion(mb_x, mb_y, px, py, sw, sh, refi[p][0], mv[0], refi[p][1], mv[1]);
3714 self.b_mc_or_record(mb_x, mb_y, px, py, sw, sh, refi[p][0], mv[0], refi[p][1], mv[1], &mut pred_y, &mut c_pred);
3715 }
3716 }
3717 let allow_8x8 = sub
3720 .iter()
3721 .all(|&st| if st == 0 { self.direct_8x8_inference } else { st <= 3 });
3722 self.inter_finish(r, mb_x, mb_y, &pred_y, &c_pred, allow_8x8, false)
3723 }
3724
3725 fn decode_p8x8(
3729 &mut self,
3730 r: &mut BitReader,
3731 mb_x: usize,
3732 mb_y: usize,
3733 ref0: bool,
3734 ) -> Result<(), MbError> {
3735 if self.refs.is_empty() {
3736 return Err(MbError::Unsupported("inter without reference"));
3737 }
3738 let w4 = self.mb_w * 4;
3739 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
3740 let num_refs = self.refs.len();
3741
3742 let mut sub_types = [0u32; 4];
3745 for st in sub_types.iter_mut() {
3746 let v = r.read_ue()?;
3747 if v > 3 {
3748 return Err(MbError::Unsupported("B-slice / invalid sub_mb_type"));
3749 }
3750 *st = v;
3751 }
3752 let mut ref_idxs = [0i32; 4];
3753 if self.num_ref_active > 1 && !ref0 {
3754 for ri in ref_idxs.iter_mut() {
3755 *ri = read_ref_idx(r, self.num_ref_active)?;
3756 if *ri as usize >= num_refs {
3757 return Err(MbError::Truncated); }
3759 }
3760 }
3761
3762 let defer = self.edc_tx.is_some() || self.edc_active;
3773
3774 let mut regions: [(usize, usize, usize, usize, i32, (i32, i32)); 16] =
3789 [(0, 0, 0, 0, 0, (0, 0)); 16];
3790 let mut nreg = 0usize;
3791 for part in 0..4usize {
3792 let refi = ref_idxs[part];
3793 let (b8x, b8y) = ((part % 2) * 8, (part / 2) * 8);
3794 for &(srx, sry, srw, srh) in sub_mb_partitions(sub_types[part]) {
3795 let (px, py) = (b8x + srx, b8y + sry);
3796 let (pbx, pby) = ((mb_x * 4 + px / 4) as isize, (mb_y * 4 + py / 4) as isize);
3797 let [a, b, c] = self.mv_neighbors_block(pbx, pby, (srw / 4) as isize);
3798 let pmv = predict_mv(a, b, c, refi);
3799 let mvd_x = r.read_se()?;
3800 let mvd_y = r.read_se()?;
3801 let mv = (pmv.0 + mvd_x, pmv.1 + mvd_y);
3802 for by in py / 4..py / 4 + srh / 4 {
3803 for bx in px / 4..px / 4 + srw / 4 {
3804 let idx = (mb_y * 4 + by) * w4 + (mb_x * 4 + bx);
3805 self.mv_y[idx] = mv;
3806 self.inter_y[idx] = true;
3807 self.ref_idx_y[idx] = refi;
3808 self.coded_y[idx] = true;
3809 }
3810 }
3811 regions[nreg] = (px, py, srw, srh, refi, mv);
3812 nreg += 1;
3813 }
3814 }
3815
3816 let mut pred_y = [0u8; 256];
3818 let mut c_pred = [[0u8; 64]; 2];
3819 if !defer {
3820 for &(px, py, srw, srh, refi, mv) in ®ions[..nreg] {
3821 let reference = &self.refs[refi as usize];
3822 let mut tmp = [0u8; 256];
3823 mc_luma_padded(&reference.py, reference.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, srw, srh, mv.0, mv.1, &mut tmp);
3824 restride(&mut pred_y, 16, px, py, &tmp, srw, srh);
3825 let (crx, cry, crw, crh) = (px / 2, py / 2, srw / 2, srh / 2);
3826 for cc in 0..2 {
3827 let rc = if cc == 0 { &reference.pu } else { &reference.pv };
3828 let mut tc = [0u8; 64];
3829 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv.0, mv.1, &mut tc);
3830 restride(&mut c_pred[cc], 8, crx, cry, &tc, crw, crh);
3831 }
3832 self.weight_partition(
3833 &mut pred_y, &mut c_pred, 0, refi as usize, px, py, srw, srh,
3834 );
3835 }
3836 }
3837
3838 let allow_8x8 = sub_types.iter().all(|&t| t == 0);
3840 self.inter_finish(r, mb_x, mb_y, &pred_y, &c_pred, allow_8x8, defer)
3841 }
3842
3843 #[allow(clippy::too_many_arguments)]
3849 fn b_mc_or_record(&mut self, mb_x: usize, mb_y: usize, px: usize, py: usize, rw: usize, rh: usize, refi0: i32, mv0: (i32, i32), refi1: i32, mv1: (i32, i32), pred_y: &mut [u8; 256], c_pred: &mut [[u8; 64]; 2]) {
3850 if self.edc_regions.is_some() {
3851 let cr0 = if refi0 >= 0 { (refi0 as usize).min(self.refs.len().saturating_sub(1)) as i32 } else { -1 };
3858 let cr1 = if refi1 >= 0 { (refi1 as usize).min(self.refs1.len().saturating_sub(1)) as i32 } else { -1 };
3859 let w = if (cr0 >= 0 && self.refs.is_empty()) || (cr1 >= 0 && self.refs1.is_empty()) {
3860 None } else {
3862 self.implicit_weights(cr0, cr1)
3863 };
3864 self.edc_regions.as_mut().unwrap().push(BRegion { px, py, rw, rh, refi0, refi1, mv0, mv1, w });
3865 return;
3866 }
3867 self.b_mc(mb_x, mb_y, px, py, rw, rh, refi0, mv0, refi1, mv1, pred_y, c_pred);
3868 }
3869
3870 fn edc_take_ctx(&mut self) -> PixelCtx {
3873 PixelCtx {
3874 rec_y: std::mem::take(&mut self.rec_y),
3875 rec_u: std::mem::take(&mut self.rec_u),
3876 rec_v: std::mem::take(&mut self.rec_v),
3877 bak_y: std::mem::take(&mut self.bak_y),
3878 bak_u: std::mem::take(&mut self.bak_u),
3879 bak_v: std::mem::take(&mut self.bak_v),
3880 refs: self.refs.clone(),
3881 refs1: self.refs1.clone(),
3882 weights: self.weights.clone(),
3883 scaling: self.scaling,
3884 scaling8: self.scaling8,
3885 cw: self.cw,
3886 ccw: self.ccw,
3887 mb_w: self.mb_w,
3888 mb_h: self.mb_h,
3889 chroma_qp_offset: self.chroma_qp_offset,
3890 flt_rows: self.flt_rows,
3891 db_ena: self.db_ena,
3892 db_oa: self.db_oa,
3893 db_ob: self.db_ob,
3894 cur_qp: self.cur_qp,
3895 qp_grid: self.mb_qp.clone(),
3896 t8_grid: self.mb_t8x8.clone(),
3897 bs_store: self.bs_frame.clone(),
3898 }
3899 }
3900
3901 fn edc_restore_ctx(&mut self, ctx: PixelCtx) {
3903 self.rec_y = ctx.rec_y;
3904 self.rec_u = ctx.rec_u;
3905 self.rec_v = ctx.rec_v;
3906 self.bak_y = ctx.bak_y;
3907 self.bak_u = ctx.bak_u;
3908 self.bak_v = ctx.bak_v;
3909 self.flt_rows = ctx.flt_rows;
3910 }
3911
3912 #[inline]
3919 fn edc_send_job(&mut self, job: EdcJob) {
3920 edcstat::bump(&edcstat::JOBS, 1);
3921 if !batch_on() {
3922 self.edc_tx
3923 .as_ref()
3924 .unwrap()
3925 .send(EdcMsg::Job(job))
3926 .expect("worker alive");
3927 return;
3928 }
3929 self.edc_batch.push(job);
3930 }
3931
3932 fn edc_flush_batch(&mut self) {
3936 if self.edc_batch.is_empty() {
3937 return;
3938 }
3939 let cap = self.edc_batch.capacity().max(self.mb_w);
3943 let jobs = std::mem::replace(&mut self.edc_batch, Vec::with_capacity(cap));
3944 edcstat::bump(&edcstat::BATCHES, 1);
3945 self.edc_tx
3946 .as_ref()
3947 .unwrap()
3948 .send(EdcMsg::Batch(jobs))
3949 .expect("worker alive");
3950 }
3951
3952 fn edc_intra_sync(&mut self) {
3953 if self.edc_tx.is_none() {
3954 self.edc_flush();
3955 return;
3956 }
3957 if self.edc_parked.is_some() {
3958 return; }
3960 self.edc_flush_batch();
3963 edcstat::bump(&edcstat::NEEDCTX, 1);
3964 self.edc_tx.as_ref().unwrap().send(EdcMsg::NeedCtx).expect("worker alive");
3965 let mut ctx = self.edc_ctx_rx.as_ref().unwrap().recv().expect("worker ctx");
3966 self.rec_y = std::mem::take(&mut ctx.rec_y);
3967 self.rec_u = std::mem::take(&mut ctx.rec_u);
3968 self.rec_v = std::mem::take(&mut ctx.rec_v);
3969 self.bak_y = std::mem::take(&mut ctx.bak_y);
3970 self.bak_u = std::mem::take(&mut ctx.bak_u);
3971 self.bak_v = std::mem::take(&mut ctx.bak_v);
3972 self.flt_rows = ctx.flt_rows;
3973 self.edc_parked = Some(ctx);
3974 }
3975
3976 fn edc_giveback(&mut self) {
3983 if let Some(mut parked) = self.edc_parked.take() {
3984 parked.rec_y = std::mem::take(&mut self.rec_y);
3985 parked.rec_u = std::mem::take(&mut self.rec_u);
3986 parked.rec_v = std::mem::take(&mut self.rec_v);
3987 parked.bak_y = std::mem::take(&mut self.bak_y);
3988 parked.bak_u = std::mem::take(&mut self.bak_u);
3989 parked.bak_v = std::mem::take(&mut self.bak_v);
3990 parked.flt_rows = self.flt_rows;
3991 let _ = self.edc_back_tx.as_ref().unwrap().send(parked);
3995 }
3996 }
3997
3998 fn edc_commit_nnz(&mut self, mbx: usize, mby: usize, t8: bool, nnzs: &[u8; 24], cbp_chroma: u32) {
4004 let (w4r, w2r) = (self.mb_w * 4, self.mb_w * 2);
4005 if t8 {
4006 for b8 in 0..4usize {
4007 let (b8x, b8y) = (b8 % 2, b8 / 2);
4008 let n = nnzs[b8 * 4];
4009 for sy in 0..2 {
4010 for sx in 0..2 {
4011 self.nnz_y[(mby * 4 + b8y * 2 + sy) * w4r + (mbx * 4 + b8x * 2 + sx)] = n;
4012 }
4013 }
4014 }
4015 } else {
4016 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4017 self.nnz_y[(mby * 4 + lby) * w4r + (mbx * 4 + lbx)] = nnzs[blk];
4018 }
4019 }
4020 if cbp_chroma == 2 {
4021 for c in 0..2usize {
4022 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
4023 self.nnz_c[c][(mby * 2 + by) * w2r + (mbx * 2 + bx)] = nnzs[16 + c * 4 + by * 2 + bx];
4024 }
4025 }
4026 }
4027 }
4028
4029 fn edc_flush(&mut self) {
4034 if self.edc_jobs.is_empty() {
4035 return;
4036 }
4037 let jobs = std::mem::take(&mut self.edc_jobs);
4038 for j in &jobs {
4039 match j {
4040 EdcJob::Skip { mbx, mby, mv } => {
4041 self.recon_p_skip(*mbx, *mby, *mv);
4042 if double_recon() {
4043 edcstat::bump(&edcstat::DOUBLED, 1);
4044 self.recon_p_skip(*mbx, *mby, *mv);
4045 }
4046 }
4047 EdcJob::Inter(job) => {
4048 self.recon_p_inter(job);
4049 if double_recon() {
4050 edcstat::bump(&edcstat::DOUBLED, 1);
4051 self.recon_p_inter(job);
4052 }
4053 }
4054 EdcJob::InterNoRes(job) => {
4055 let full = job.to_full();
4056 self.recon_p_inter(&full);
4057 if double_recon() {
4058 edcstat::bump(&edcstat::DOUBLED, 1);
4059 self.recon_p_inter(&full);
4060 }
4061 }
4062 EdcJob::B(_) | EdcJob::BSkip { .. } => unreachable!("B jobs are worker-only"),
4066 }
4067 }
4068 self.edc_jobs = jobs;
4070 self.edc_jobs.clear();
4071 }
4072
4073 fn recon_p_inter(&mut self, j: &PInterJob) {
4083 let mbw = self.mb_w;
4084 let saved_qp = self.cur_qp;
4089 self.cur_qp = j.qp;
4090 let qp = j.qp;
4095 let qpc = self.chroma_qp_for(qp);
4096 let (w4r, w2r) = (mbw * 4, mbw * 2);
4097 let mut pred_y = [0u8; 256];
4098 let mut c_pred = [[0u8; 64]; 2];
4099 {
4100 let _ms = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMcStage);
4108 let (rh16, cch) = (self.mb_h * 16, self.mb_h * 8);
4109 let mut gmv = [(0i32, 0i32); 16];
4110 let mut gref = [0usize; 16];
4111 let _gg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::MvGrid);
4112 for by in 0..4usize {
4113 for bx in 0..4usize {
4114 let bidx = (j.mby * 4 + by) * w4r + (j.mbx * 4 + bx);
4115 gmv[by * 4 + bx] = self.mv_y[bidx];
4116 gref[by * 4 + bx] =
4119 (self.ref_idx_y[bidx].max(0) as usize).min(self.refs.len() - 1);
4120 }
4121 }
4122 drop(_gg);
4123 let rect_eq = |x4: usize, y4: usize, w4: usize, h4: usize| -> bool {
4125 let t = y4 * 4 + x4;
4126 (0..h4).all(|dy| {
4127 (0..w4).all(|dx| {
4128 let b = (y4 + dy) * 4 + (x4 + dx);
4129 gmv[b] == gmv[t] && gref[b] == gref[t]
4130 })
4131 })
4132 };
4133 let refs = &self.refs;
4134 let (cw, ccw) = (self.cw, self.ccw);
4135 let mut mc_rect = |x4: usize,
4136 y4: usize,
4137 w4: usize,
4138 h4: usize,
4139 pred_y: &mut [u8; 256],
4140 c_pred: &mut [[u8; 64]; 2]| {
4141 let b = y4 * 4 + x4;
4142 let (mv, reference) = (gmv[b], &refs[gref[b]]);
4143 let (w, h) = (w4 * 4, h4 * 4);
4144 if w == 16 {
4153 rusty_h264_common::inter::with_mc_scratch(|scr| rusty_h264_common::inter::mc_luma_padded_pre(scr, &reference.py, reference.lstride(), crate::LPAD, cw, rh16, j.mbx * 16, j.mby * 16 + y4 * 4, w, h, mv.0, mv.1, &mut pred_y[y4 * 64..y4 * 64 + w * h]));
4154 } else {
4155 let mut t = [0u8; 256];
4156 rusty_h264_common::inter::with_mc_scratch(|scr| rusty_h264_common::inter::mc_luma_padded_pre(scr, &reference.py, reference.lstride(), crate::LPAD, cw, rh16, j.mbx * 16 + x4 * 4, j.mby * 16 + y4 * 4, w, h, mv.0, mv.1, &mut t[..w * h]));
4157 let _pb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
4158 for dy in 0..h {
4159 pred_y[(y4 * 4 + dy) * 16 + x4 * 4..][..w]
4160 .copy_from_slice(&t[dy * w..dy * w + w]);
4161 }
4162 }
4163 let (cw4, ch4) = (w4 * 2, h4 * 2);
4164 for cc in 0..2 {
4165 let rc = if cc == 0 { &reference.pu } else { &reference.pv };
4166 if cw4 == 8 {
4169 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, ccw, cch, j.mbx * 8, j.mby * 8 + y4 * 2, cw4, ch4, mv.0, mv.1, &mut c_pred[cc][y4 * 16..y4 * 16 + cw4 * ch4]);
4170 continue;
4171 }
4172 let mut tc = [0u8; 64];
4173 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, ccw, cch, j.mbx * 8 + x4 * 2, j.mby * 8 + y4 * 2, cw4, ch4, mv.0, mv.1, &mut tc[..cw4 * ch4]);
4174 let _pb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
4175 for dy in 0..ch4 {
4176 c_pred[cc][(y4 * 2 + dy) * 8 + x4 * 2..][..cw4]
4177 .copy_from_slice(&tc[dy * cw4..dy * cw4 + cw4]);
4178 }
4179 }
4180 };
4181 if rect_eq(0, 0, 4, 4) {
4182 mc_rect(0, 0, 4, 4, &mut pred_y, &mut c_pred);
4183 } else if rect_eq(0, 0, 4, 2) && rect_eq(0, 2, 4, 2) {
4184 mc_rect(0, 0, 4, 2, &mut pred_y, &mut c_pred);
4185 mc_rect(0, 2, 4, 2, &mut pred_y, &mut c_pred);
4186 } else if rect_eq(0, 0, 2, 4) && rect_eq(2, 0, 2, 4) {
4187 mc_rect(0, 0, 2, 4, &mut pred_y, &mut c_pred);
4188 mc_rect(2, 0, 2, 4, &mut pred_y, &mut c_pred);
4189 } else {
4190 for q in 0..4usize {
4191 let (qx, qy) = ((q % 2) * 2, (q / 2) * 2);
4192 if rect_eq(qx, qy, 2, 2) {
4193 mc_rect(qx, qy, 2, 2, &mut pred_y, &mut c_pred);
4194 } else if rect_eq(qx, qy, 2, 1) && rect_eq(qx, qy + 1, 2, 1) {
4195 mc_rect(qx, qy, 2, 1, &mut pred_y, &mut c_pred);
4196 mc_rect(qx, qy + 1, 2, 1, &mut pred_y, &mut c_pred);
4197 } else if rect_eq(qx, qy, 1, 2) && rect_eq(qx + 1, qy, 1, 2) {
4198 mc_rect(qx, qy, 1, 2, &mut pred_y, &mut c_pred);
4199 mc_rect(qx + 1, qy, 1, 2, &mut pred_y, &mut c_pred);
4200 } else {
4201 for j in 0..4usize {
4202 mc_rect(qx + (j % 2), qy + (j / 2), 1, 1, &mut pred_y, &mut c_pred);
4203 }
4204 }
4205 }
4206 }
4207 if self.weights.is_some() {
4221 for by in 0..4usize {
4222 for bx in 0..4usize {
4223 let refi = gref[by * 4 + bx];
4224 self.weight_partition(
4225 &mut pred_y, &mut c_pred, 0, refi, bx * 4, by * 4, 4, 4,
4226 );
4227 }
4228 }
4229 }
4230 }
4231 self.add_inter_residual(j.mbx, j.mby, &pred_y, &c_pred, &j.luma_scan, if j.t8 { Some(&j.luma8) } else { None }, &j.cdc, &j.cac, j.cbp_chroma, &j.nnzs);
4235 self.cur_qp = saved_qp;
4236 }
4237
4238 fn decode_p_skip(&mut self, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
4239 self.mb_kind[mb_y * self.mb_w + mb_x] = rusty_h264_common::deblock::MB_KIND_SKIP;
4251 if self.refs.is_empty() {
4255 return Err(MbError::Unsupported("P_Skip without reference"));
4256 }
4257 let mv = self.skip_mv(mb_x, mb_y);
4258 {
4262 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::SkipRecon);
4263 self.set_mb_mv(mb_x, mb_y, mv, true, 0);
4264 let w4 = self.mb_w * 4;
4265 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4266 self.coded_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = true;
4267 self.modes_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 2;
4268 }
4269 }
4270 if self.edc_tx.is_some() {
4271 self.edc_giveback();
4272 self.edc_send_job(EdcJob::Skip { mbx: mb_x, mby: mb_y, mv });
4273 return Ok(());
4274 }
4275 if self.edc_active {
4276 self.edc_jobs.push(EdcJob::Skip { mbx: mb_x, mby: mb_y, mv });
4277 return Ok(());
4278 }
4279 self.recon_p_skip(mb_x, mb_y, mv);
4280 if double_recon() {
4281 self.recon_p_skip(mb_x, mb_y, mv);
4282 }
4283 Ok(())
4284 }
4285
4286 fn recon_p_skip(&mut self, mb_x: usize, mb_y: usize, mv: (i32, i32)) {
4288 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
4289
4290 let mut pred = [0u8; 256];
4291 let rf0 = &self.refs[0];
4292 mc_luma_padded(&rf0.py, rf0.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16, 16, 16, mv.0, mv.1, &mut pred);
4293 if let Some(wt) = &self.weights {
4294 for p in pred.iter_mut() {
4295 *p = wt.apply_luma(*p, 0, 0);
4296 }
4297 }
4298 {
4299 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::SkipRecon);
4300 for dy in 0..16 {
4301 let d = (mb_y * 16 + dy) * self.cw + mb_x * 16;
4302 self.rec_y[d..d + 16].copy_from_slice(&pred[dy * 16..dy * 16 + 16]);
4303 }
4304 }
4305 for c in 0..2 {
4306 let mut pc = [0u8; 64];
4307 let rf0 = &self.refs[0];
4308 let rc = if c == 0 { &rf0.pu } else { &rf0.pv };
4309 mc_chroma_padded(rc, rf0.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8, 8, 8, mv.0, mv.1, &mut pc);
4310 if let Some(wt) = &self.weights {
4311 for p in pc.iter_mut() {
4312 *p = wt.apply_chroma(*p, 0, 0, c);
4313 }
4314 }
4315 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
4316 for dy in 0..8 {
4317 let d = (mb_y * 8 + dy) * self.ccw + mb_x * 8;
4318 plane[d..d + 8].copy_from_slice(&pc[dy * 8..dy * 8 + 8]);
4319 }
4320 }
4321 }
4322
4323 fn predict_i4_mode(&self, bx: usize, by: usize) -> u8 {
4327 if bx == 0 || by == 0 {
4328 return 2;
4329 }
4330 if !self.nbr_in_slice((bx - 1) / 4, by / 4)
4334 || !self.nbr_in_slice(bx / 4, (by - 1) / 4)
4335 || !self.intra_nbr_ok(bx - 1, by)
4336 || !self.intra_nbr_ok(bx, by - 1)
4337 {
4338 return 2;
4339 }
4340 let w4 = self.mb_w * 4;
4341 self.modes_y[by * w4 + (bx - 1)].min(self.modes_y[(by - 1) * w4 + bx])
4342 }
4343
4344 fn gather_i4(
4346 &self,
4347 px: usize,
4348 py: usize,
4349 avail_top: bool,
4350 avail_left: bool,
4351 bx: usize,
4352 by: usize,
4353 ) -> ([u8; 8], [u8; 4], u8) {
4354 let (cw, w4) = (self.cw, self.mb_w * 4);
4355 let mut top = [0u8; 8];
4356 let mut left = [0u8; 4];
4357 let mut corner = 0;
4358 if avail_top {
4359 for i in 0..4 {
4360 top[i] = self.top_y_px(py, px + i);
4361 }
4362 let tr_avail = bx + 1 < w4
4363 && self.coded_y[(by - 1) * w4 + (bx + 1)]
4364 && self.nbr_in_slice((bx + 1) / 4, (by - 1) / 4)
4365 && self.intra_nbr_ok(bx + 1, by - 1);
4366 for i in 0..4 {
4367 top[4 + i] = if tr_avail {
4368 self.top_y_px(py, px + 4 + i)
4369 } else {
4370 top[3]
4371 };
4372 }
4373 }
4374 if avail_left {
4375 for i in 0..4 {
4376 left[i] = self.rec_y[(py + i) * cw + px - 1];
4377 }
4378 }
4379 if avail_top && avail_left && self.intra_nbr_ok(bx - 1, by - 1) {
4382 corner = self.top_y_px(py, px - 1);
4383 }
4384 (top, left, corner)
4385 }
4386
4387 fn decode_ipcm(&mut self, r: &mut BitReader, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
4390 r.align_to_byte()?;
4391 let (lx, ly) = (mb_x * 16, mb_y * 16);
4392 for dy in 0..16 {
4393 for dx in 0..16 {
4394 self.rec_y[(ly + dy) * self.cw + (lx + dx)] = r.read_bits(8)? as u8;
4395 }
4396 }
4397 let (cx, cy) = (mb_x * 8, mb_y * 8);
4398 for plane in [&mut self.rec_u, &mut self.rec_v] {
4399 for dy in 0..8 {
4400 for dx in 0..8 {
4401 plane[(cy + dy) * self.ccw + (cx + dx)] = r.read_bits(8)? as u8;
4402 }
4403 }
4404 }
4405 let (w4, w2) = (self.mb_w * 4, self.mb_w * 2);
4408 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4409 let idx = (mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx);
4410 self.nnz_y[idx] = 16;
4411 self.modes_y[idx] = 2;
4412 self.inter_y[idx] = false;
4413 self.ref_idx_y[idx] = -1;
4414 self.mv_y[idx] = (0, 0);
4415 }
4416 for c in 0..2 {
4417 for by in 0..2 {
4418 for bx in 0..2 {
4419 self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = 16;
4420 }
4421 }
4422 }
4423 Ok(())
4424 }
4425
4426 fn decode_i4x4(&mut self, r: &mut BitReader, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
4427 let w4 = self.mb_w * 4;
4428
4429 let mut modes = [2u8; 16]; for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4432 let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
4433 let predicted = self.predict_i4_mode(bx, by);
4434 let actual = if r.read_bit()? {
4435 predicted
4436 } else {
4437 let rem = r.read_bits(3)? as u8;
4438 if rem < predicted {
4439 rem
4440 } else {
4441 rem + 1
4442 }
4443 };
4444 self.modes_y[by * w4 + bx] = actual;
4445 modes[lby * 4 + lbx] = actual;
4446 }
4447
4448 let chroma_mode = r.read_ue()? as u8;
4449 let cbp = read_cbp_intra(r)?;
4450 let cbp_luma = cbp & 15;
4451 let cbp_chroma = cbp >> 4;
4452 if cbp != 0 {
4453 self.step_qp(r.read_se()?);
4454 }
4455 let qp = self.cur_qp;
4456
4457 let top_mb_avail = mb_y > 0
4461 && self.nbr_in_slice(mb_x, mb_y - 1)
4462 && self.intra_nbr_ok(mb_x * 4, mb_y * 4 - 1);
4463 let left_mb_avail = mb_x > 0
4464 && self.nbr_in_slice(mb_x - 1, mb_y)
4465 && self.intra_nbr_ok(mb_x * 4 - 1, mb_y * 4);
4466 self.nnz_cache_load(mb_x, mb_y);
4467 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
4468 let (bx, by) = (mb_x * 4 + lbx, mb_y * 4 + lby);
4469 let (px, py) = (bx * 4, by * 4);
4470 let avail_top = lby > 0 || top_mb_avail;
4471 let avail_left = lbx > 0 || left_mb_avail;
4472 let mut qb = [0i32; 16];
4473 let total = if cbp_luma & (1 << (blk / 4)) != 0 {
4474 let nc = self.nc_pred(lbx, lby);
4475 let scan16 = decode_residual_block(r, 16, nc)?;
4476 qb = un_scan_4x4_dcac(&scan16);
4477 scan16.iter().filter(|&&v| v != 0).count() as u8
4478 } else {
4479 0
4480 };
4481 self.nnz_cache_set(lbx, lby, total);
4482 self.nnz_y[by * w4 + bx] = total;
4483 let (top, left, corner) = self.gather_i4(px, py, avail_top, avail_left, bx, by);
4484 let pred = intra4x4_pred(modes[lby * 4 + lbx], avail_top, avail_left, &top, &left, corner);
4485 let mut predb = [0i32; 16];
4486 for i in 0..16 {
4487 predb[i] = pred[i] as i32;
4488 }
4489 let s = reconstruct_4x4(&self.dequant(&qb, qp, 0), &predb);
4490 store(&mut self.rec_y, self.cw, px, py, &s);
4491 self.coded_y[by * w4 + bx] = true;
4492 }
4493
4494 self.decode_chroma(r, mb_x, mb_y, cbp_chroma, chroma_mode)
4495 }
4496
4497 fn decode_i8x8(&mut self, r: &mut BitReader, mb_x: usize, mb_y: usize) -> Result<(), MbError> {
4501 let w4 = self.mb_w * 4;
4502 self.mb_t8x8[mb_y * self.mb_w + mb_x] = true;
4503
4504 let mut modes8 = [2u8; 4];
4507 for (b8, mode) in modes8.iter_mut().enumerate() {
4508 let (b8x, b8y) = (b8 % 2, b8 / 2);
4509 let (bx, by) = (mb_x * 4 + b8x * 2, mb_y * 4 + b8y * 2);
4510 let predicted = self.predict_i4_mode(bx, by);
4511 let actual = if r.read_bit()? {
4512 predicted
4513 } else {
4514 let rem = r.read_bits(3)? as u8;
4515 if rem < predicted { rem } else { rem + 1 }
4516 };
4517 *mode = actual;
4518 for sy in 0..2 {
4519 for sx in 0..2 {
4520 self.modes_y[(by + sy) * w4 + (bx + sx)] = actual;
4521 }
4522 }
4523 }
4524
4525 let chroma_mode = r.read_ue()? as u8;
4526 let cbp = read_cbp_intra(r)?;
4527 let cbp_luma = cbp & 15;
4528 let cbp_chroma = cbp >> 4;
4529 if cbp != 0 {
4530 self.step_qp(r.read_se()?);
4531 }
4532 let qp = self.cur_qp;
4533
4534 let top_mb_avail = mb_y > 0
4535 && self.nbr_in_slice(mb_x, mb_y - 1)
4536 && self.intra_nbr_ok(mb_x * 4, mb_y * 4 - 1);
4537 let left_mb_avail = mb_x > 0
4538 && self.nbr_in_slice(mb_x - 1, mb_y)
4539 && self.intra_nbr_ok(mb_x * 4 - 1, mb_y * 4);
4540 self.nnz_cache_load(mb_x, mb_y);
4541
4542 for b8 in 0..4 {
4543 let (b8x, b8y) = (b8 % 2, b8 / 2);
4544 let (bx, by) = (mb_x * 4 + b8x * 2, mb_y * 4 + b8y * 2);
4545 let (px, py) = (bx * 4, by * 4);
4546
4547 let mut res8 = [0i32; 64];
4550 if cbp_luma & (1 << b8) != 0 {
4551 let mut scan8 = [0i32; 64];
4552 for sub in 0..4 {
4553 let (sx, sy) = (sub % 2, sub / 2);
4554 let (cx, cy) = (b8x * 2 + sx, b8y * 2 + sy);
4555 let nc = self.nc_pred(cx, cy);
4556 let blk = decode_residual_block(r, 16, nc)?;
4557 let total = blk.iter().filter(|&&v| v != 0).count() as u8;
4558 self.nnz_cache_set(cx, cy, total);
4559 self.nnz_y[(by + sy) * w4 + (bx + sx)] = total;
4560 for k in 0..16 {
4561 scan8[4 * k + sub] = blk[k];
4562 }
4563 }
4564 let raster = un_scan_8x8(&scan8);
4565 res8 = self.inv_quant8(&raster, qp, 0);
4566 } else {
4567 for sub in 0..4 {
4568 let (sx, sy) = (sub % 2, sub / 2);
4569 self.nnz_cache_set(b8x * 2 + sx, b8y * 2 + sy, 0);
4570 self.nnz_y[(by + sy) * w4 + (bx + sx)] = 0;
4571 }
4572 }
4573
4574 let avail_top = b8y > 0 || top_mb_avail;
4575 let avail_left = b8x > 0 || left_mb_avail;
4576 let (top, left, corner, avail_corner) =
4577 self.gather_i8(px, py, avail_top, avail_left, bx, by);
4578 let pred = intra8x8_pred(
4579 modes8[b8], avail_top, avail_left, avail_corner, &top, &left, corner,
4580 );
4581 let mut predb = [0i32; 64];
4582 for i in 0..64 {
4583 predb[i] = pred[i] as i32;
4584 }
4585 let recon = add_residual_8x8(&res8, &predb);
4586 for dy in 0..8 {
4587 for dx in 0..8 {
4588 self.rec_y[(py + dy) * self.cw + (px + dx)] = recon[dy * 8 + dx];
4589 }
4590 }
4591 for sy in 0..2 {
4592 for sx in 0..2 {
4593 self.coded_y[(by + sy) * w4 + (bx + sx)] = true;
4594 }
4595 }
4596 }
4597
4598 self.decode_chroma(r, mb_x, mb_y, cbp_chroma, chroma_mode)
4599 }
4600
4601 fn inv_quant8(&self, raster: &[i32; 64], qp: u8, list: usize) -> [i32; 64] {
4604 match &self.scaling8 {
4605 Some(s) => inverse_quant_8x8(raster, qp, &s[list]),
4606 None => inverse_quant_8x8(raster, qp, &[16i32; 64]),
4607 }
4608 }
4609
4610 #[allow(clippy::too_many_arguments)]
4614 fn gather_i8(
4615 &self,
4616 px: usize,
4617 py: usize,
4618 avail_top: bool,
4619 avail_left: bool,
4620 bx: usize,
4621 by: usize,
4622 ) -> ([u8; 16], [u8; 8], u8, bool) {
4623 let (cw, w4) = (self.cw, self.mb_w * 4);
4624 let mut top = [0u8; 16];
4625 let mut left = [0u8; 8];
4626 let mut corner = 0;
4627 if avail_top {
4628 for i in 0..8 {
4629 top[i] = self.top_y_px(py, px + i);
4630 }
4631 let tr_avail = bx + 2 < w4
4632 && self.coded_y[(by - 1) * w4 + (bx + 2)]
4633 && self.nbr_in_slice((bx + 2) / 4, (by - 1) / 4)
4634 && self.intra_nbr_ok(bx + 2, by - 1);
4635 for i in 0..8 {
4636 top[8 + i] = if tr_avail {
4637 self.top_y_px(py, px + 8 + i)
4638 } else {
4639 top[7]
4640 };
4641 }
4642 }
4643 if avail_left {
4644 for i in 0..8 {
4645 left[i] = self.rec_y[(py + i) * cw + px - 1];
4646 }
4647 }
4648 let avail_corner = avail_top && avail_left && self.intra_nbr_ok(bx - 1, by - 1);
4649 if avail_corner {
4650 corner = self.top_y_px(py, px - 1);
4651 }
4652 (top, left, corner, avail_corner)
4653 }
4654
4655 fn decode_i16(
4656 &mut self,
4657 r: &mut BitReader,
4658 mb_x: usize,
4659 mb_y: usize,
4660 mt: u32,
4661 ) -> Result<(), MbError> {
4662 let pred_mode = I16Mode::from_id(mt % 4);
4663 let cbp_chroma = (mt % 12) / 4;
4664 let cbp_luma_15 = mt / 12 == 1;
4665 let chroma_mode = r.read_ue()? as u8;
4666 self.step_qp(r.read_se()?);
4667 let qp = self.cur_qp;
4668 let w4 = self.mb_w * 4;
4669
4670 self.nnz_cache_load(mb_x, mb_y);
4672 let nc_dc = self.nc_pred(0, 0);
4673 let dc_scan = decode_residual_block(r, 16, nc_dc)?;
4674 let dc_levels = un_scan_4x4_dcac(&dc_scan);
4675 let recon_dc = self.dequant_luma_dc(&dc_levels, qp, 0);
4676
4677 let mut q_blocks = [[0i32; 16]; 16];
4679 for &(bx, by) in &LUMA_4X4_SCAN_XY {
4680 let total = if cbp_luma_15 {
4681 let nc = self.nc_pred(bx, by);
4682 let ac = decode_residual_block(r, 15, nc)?;
4683 un_scan_4x4_ac_into(&ac, &mut q_blocks[by * 4 + bx]);
4684 ac.iter().filter(|&&v| v != 0).count() as u8
4685 } else {
4686 0
4687 };
4688 self.nnz_cache_set(bx, by, total);
4689 self.nnz_y[(mb_y * 4 + by) * w4 + (mb_x * 4 + bx)] = total;
4690 }
4691
4692 let avail_top = mb_y > 0
4694 && self.nbr_in_slice(mb_x, mb_y - 1)
4695 && self.intra_nbr_ok(mb_x * 4, mb_y * 4 - 1);
4696 let avail_left = mb_x > 0
4697 && self.nbr_in_slice(mb_x - 1, mb_y)
4698 && self.intra_nbr_ok(mb_x * 4 - 1, mb_y * 4);
4699 let (lx, ly) = (mb_x * 16, mb_y * 16);
4700 let mut top = [0u8; 16];
4701 let mut left = [0u8; 16];
4702 if avail_top {
4703 for i in 0..16 {
4704 top[i] = self.top_y_px(ly, lx + i);
4705 }
4706 }
4707 if avail_left {
4708 for i in 0..16 {
4709 left[i] = self.rec_y[(ly + i) * self.cw + lx - 1];
4710 }
4711 }
4712 let corner = if avail_top && avail_left {
4713 self.top_y_px(ly, lx - 1)
4714 } else {
4715 0
4716 };
4717 let pred_l = luma16x16_pred(pred_mode, avail_top, avail_left, &top, &left, corner);
4718 for by in 0..4 {
4719 for bx in 0..4 {
4720 let mut deq = self.dequant(&q_blocks[by * 4 + bx], qp, 0);
4721 deq[0] = recon_dc[by * 4 + bx];
4722 let mut predb = [0i32; 16];
4723 for dy in 0..4 {
4724 for dx in 0..4 {
4725 predb[dy * 4 + dx] = pred_l[(by * 4 + dy) * 16 + (bx * 4 + dx)] as i32;
4726 }
4727 }
4728 let s = reconstruct_4x4(&deq, &predb);
4729 store(&mut self.rec_y, self.cw, lx + bx * 4, ly + by * 4, &s);
4730 }
4731 }
4732 for &(lbx, lby) in &LUMA_4X4_SCAN_XY {
4734 self.modes_y[(mb_y * 4 + lby) * w4 + (mb_x * 4 + lbx)] = 2;
4735 }
4736
4737 self.decode_chroma(r, mb_x, mb_y, cbp_chroma, chroma_mode)
4738 }
4739
4740 fn decode_chroma(
4742 &mut self,
4743 r: &mut BitReader,
4744 mb_x: usize,
4745 mb_y: usize,
4746 cbp_chroma: u32,
4747 chroma_mode: u8,
4748 ) -> Result<(), MbError> {
4749 let qpc = self.chroma_qp_for(self.cur_qp);
4750 let (cx, cy) = (mb_x * 8, mb_y * 8);
4751 let avail_top = mb_y > 0
4752 && self.nbr_in_slice(mb_x, mb_y - 1)
4753 && self.intra_nbr_ok(mb_x * 4, mb_y * 4 - 1);
4754 let avail_left = mb_x > 0
4755 && self.nbr_in_slice(mb_x - 1, mb_y)
4756 && self.intra_nbr_ok(mb_x * 4 - 1, mb_y * 4);
4757
4758 let mut c_recon_dc = [[0i32; 4]; 2];
4759 if cbp_chroma != 0 {
4760 for (c, slot) in c_recon_dc.iter_mut().enumerate() {
4761 let dc = decode_residual_block(r, 4, -1)?;
4762 *slot = self.dequant_chroma_dc(&[dc[0], dc[1], dc[2], dc[3]], qpc, 1 + c);
4763 }
4764 }
4765 let mut c_q_blocks = [[[0i32; 16]; 4]; 2];
4766 if cbp_chroma == 2 {
4767 self.chroma_cache_load(mb_x, mb_y);
4768 let w2 = self.mb_w * 2;
4769 for c in 0..2 {
4770 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
4771 let nc = self.chroma_nc_pred(c, bx, by);
4772 let ac = decode_residual_block(r, 15, nc)?;
4773 let total = ac.iter().filter(|&&v| v != 0).count() as u8;
4774 self.chroma_nnz_cache_set(c, bx, by, total);
4775 self.nnz_c[c][(mb_y * 2 + by) * w2 + (mb_x * 2 + bx)] = total;
4776 un_scan_4x4_ac_into(&ac, &mut c_q_blocks[c][by * 2 + bx]);
4777 }
4778 }
4779 }
4780 for c in 0..2 {
4781 let mut ctop = [0u8; 8];
4782 let mut cleft = [0u8; 8];
4783 let mut ccorner = 0u8;
4784 {
4785 let rec_c = if c == 0 { &self.rec_u } else { &self.rec_v };
4786 if avail_top {
4787 for i in 0..8 {
4788 ctop[i] = self.top_c_px(c, cy, cx + i);
4789 }
4790 }
4791 if avail_left {
4792 for i in 0..8 {
4793 cleft[i] = rec_c[(cy + i) * self.ccw + cx - 1];
4794 }
4795 }
4796 if avail_top && avail_left {
4797 ccorner = self.top_c_px(c, cy, cx - 1);
4798 }
4799 }
4800 let pred8 = chroma8x8_pred(chroma_mode, avail_top, avail_left, &ctop, &cleft, ccorner);
4801 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
4802 let mut predb = [0i32; 16];
4803 for dy in 0..4 {
4804 for dx in 0..4 {
4805 predb[dy * 4 + dx] = pred8[(by * 4 + dy) * 8 + (bx * 4 + dx)] as i32;
4806 }
4807 }
4808 let mut deq = self.dequant(&c_q_blocks[c][by * 2 + bx], qpc, 1 + c);
4809 deq[0] = c_recon_dc[c][by * 2 + bx];
4810 let s = reconstruct_4x4(&deq, &predb);
4811 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
4812 store(plane, self.ccw, cx + bx * 4, cy + by * 4, &s);
4813 }
4814 }
4815 Ok(())
4816 }
4817
4818 fn dump_mb_map(&self) {
4827 if std::env::var_os("RH264_DUMP_MB").is_none() {
4828 return;
4829 }
4830 let w4 = self.mb_w * 4;
4831 let mut hist = [0usize; 4];
4832 eprintln!("--- frame poc {} ---", self.cur_poc);
4833 for mb_y in 0..self.mb_h {
4834 let mut row = String::new();
4835 for mb_x in 0..self.mb_w {
4836 let b = (mb_y * 4) * w4 + mb_x * 4;
4837 let r = self.ref_idx_y[b];
4838 if r < 0 {
4839 row.push('i');
4840 } else {
4841 if (r as usize) < 4 {
4842 hist[r as usize] += 1;
4843 }
4844 row.push((b'0' + (r as u8).min(9)) as char);
4845 }
4846 }
4847 eprintln!("{row}");
4848 }
4849 eprintln!(
4850 "ref histogram: {hist:?} num_ref_active={} refs.len()={} OUT-OF-RANGE={}",
4851 self.num_ref_active,
4852 self.refs.len(),
4853 hist.iter().skip(self.refs.len()).sum::<usize>()
4854 );
4855 let list: Vec<String> = self
4856 .refs
4857 .iter()
4858 .enumerate()
4859 .map(|(i, f)| {
4860 let synth = if f.w4 == 0 { " SYNTH-GREY" } else { "" };
4863 format!("[{i}] poc={} fn={}{synth}", f.poc, f.frame_num)
4864 })
4865 .collect();
4866 eprintln!(" RefPicList0: {}", list.join(" "));
4867 }
4868
4869 pub fn deblock(&mut self, offset_a: i32, offset_b: i32) {
4870 self.edc_flush(); self.dump_mb_map();
4872 if rowdb_on() {
4875 while self.bs_rows < self.mb_h {
4876 let r = self.bs_rows;
4877 self.derive_bs_row(r);
4878 self.bs_rows += 1;
4879 }
4880 }
4881 let nnz_db_storage;
4888 let nnz_db: &[u8] = if self.mb_t8x8.iter().any(|&t| t) {
4889 let mut n = self.nnz_y.clone();
4890 let w4 = self.mb_w * 4;
4891 for mb_y in 0..self.mb_h {
4892 for mb_x in 0..self.mb_w {
4893 if !self.mb_t8x8[mb_y * self.mb_w + mb_x] {
4894 continue;
4895 }
4896 for b8 in 0..4 {
4897 let (bx, by) = (mb_x * 4 + (b8 % 2) * 2, mb_y * 4 + (b8 / 2) * 2);
4898 let any = (0..2).any(|sy| (0..2).any(|sx| self.nnz_y[(by + sy) * w4 + (bx + sx)] > 0));
4899 for sy in 0..2 {
4900 for sx in 0..2 {
4901 n[(by + sy) * w4 + (bx + sx)] = u8::from(any);
4902 }
4903 }
4904 }
4905 }
4906 }
4907 nnz_db_storage = n;
4908 &nnz_db_storage
4909 } else {
4910 &self.nnz_y
4911 };
4912 let poc0: Vec<i32> = self.refs.iter().map(|f| f.poc).collect();
4918 let poc1: Vec<i32> = self.refs1.iter().map(|f| f.poc).collect();
4919 let mut info = rusty_h264_common::deblock::BlockInfo {
4920 inter: &self.inter_y,
4921 nnz: nnz_db,
4922 mv: &self.mv_y,
4923 ref_id: &self.ref_idx_y,
4924 mv1: &self.mv1,
4925 ref_id1: if poc1.is_empty() { &[] } else { &self.ref_idx1 },
4926 w4: self.mb_w * 4,
4927 t8x8: &self.mb_t8x8,
4928 bs: &[],
4929 poc0: &poc0,
4930 poc1: &poc1,
4931 kind: &self.mb_kind,
4932 };
4933 let bs_store;
4938 if rowdb_on() {
4939 bs_store = std::mem::take(&mut self.bs_frame);
4940 info.bs = &bs_store;
4941 } else if !std::env::var_os("RS_H264_BS_PRE").is_some_and(|v| v == "0") {
4942 let mut buf = Vec::new();
4943 rusty_h264_common::deblock::precompute_bs_frame(&info, self.mb_w, self.mb_h, &mut buf);
4944 bs_store = buf;
4945 info.bs = &bs_store;
4946 } else {
4947 bs_store = Vec::new();
4948 }
4949 let first_row = if rowdb_on() { self.flt_rows } else { 0 };
4950 rusty_h264_common::deblock::filter_frame_rows(
4951 &mut self.rec_y,
4952 &mut self.rec_u,
4953 &mut self.rec_v,
4954 self.mb_w,
4955 self.mb_h,
4956 first_row..self.mb_h,
4957 &self.mb_qp,
4958 self.chroma_qp_offset,
4959 offset_a,
4960 offset_b,
4961 &info,
4962 );
4963 drop(info);
4964 if rowdb_on() {
4965 self.bs_frame = bs_store;
4966 }
4967 }
4968
4969 pub fn into_frame_recycle(mut self, crop_r: usize, crop_b: usize) -> (YuvFrame, GridPool) {
4973 let [c0, c1] = std::mem::take(&mut self.nnz_c);
4974 let pool = GridPool {
4975 bits_per_mb: self.bits_per_mb,
4976 mb_qp: std::mem::take(&mut self.mb_qp),
4977 bs_frame: std::mem::take(&mut self.bs_frame),
4978 pk_prev: std::mem::take(&mut self.pk_prev),
4979 pk_cur: std::mem::take(&mut self.pk_cur),
4980 nnz_dbr: std::mem::take(&mut self.nnz_dbr),
4981 bak_y: std::mem::take(&mut self.bak_y),
4982 bak_u: std::mem::take(&mut self.bak_u),
4983 bak_v: std::mem::take(&mut self.bak_v),
4984 nnz_y: std::mem::take(&mut self.nnz_y),
4985 nnz_c0: c0,
4986 nnz_c1: c1,
4987 modes_y: std::mem::take(&mut self.modes_y),
4988 coded_y: std::mem::take(&mut self.coded_y),
4989 mv_y: std::mem::take(&mut self.mv_y),
4990 inter_y: std::mem::take(&mut self.inter_y),
4991 ref_idx_y: std::mem::take(&mut self.ref_idx_y),
4992 mv1: std::mem::take(&mut self.mv1),
4993 ref_idx1: std::mem::take(&mut self.ref_idx1),
4994 mb_t8x8: std::mem::take(&mut self.mb_t8x8),
4995 mb_kind: std::mem::take(&mut self.mb_kind),
4996 };
4997 (self.into_frame(crop_r, crop_b), pool)
4998 }
4999
5000 pub fn into_frame(self, crop_r: usize, crop_b: usize) -> YuvFrame {
5001 if crop_r == 0 && crop_b == 0 {
5004 return YuvFrame {
5005 width: self.cw,
5006 height: self.ch,
5007 y: self.rec_y,
5008 u: self.rec_u,
5009 v: self.rec_v,
5010 };
5011 }
5012 let dw = self.cw - 2 * crop_r;
5013 let dh = self.ch - 2 * crop_b;
5014 let mut y = vec![0u8; dw * dh];
5015 for row in 0..dh {
5016 y[row * dw..row * dw + dw].copy_from_slice(&self.rec_y[row * self.cw..row * self.cw + dw]);
5017 }
5018 let (cdw, cdh) = (dw / 2, dh / 2);
5019 let mut u = vec![0u8; cdw * cdh];
5020 let mut v = vec![0u8; cdw * cdh];
5021 for row in 0..cdh {
5022 u[row * cdw..row * cdw + cdw]
5023 .copy_from_slice(&self.rec_u[row * self.ccw..row * self.ccw + cdw]);
5024 v[row * cdw..row * cdw + cdw]
5025 .copy_from_slice(&self.rec_v[row * self.ccw..row * self.ccw + cdw]);
5026 }
5027 let _ = self.cch;
5028 YuvFrame {
5029 width: dw,
5030 height: dh,
5031 y,
5032 u,
5033 v,
5034 }
5035 }
5036}
5037
5038fn cabac_unary(cab: &mut crate::cabac::Cabac, ctx: usize, off: usize) -> u32 {
5045 if cab.decode_decision(ctx) == 0 {
5046 return 0;
5047 }
5048 let mut sym = 0;
5049 loop {
5050 let bin = cab.decode_decision(ctx + off);
5051 sym += 1;
5052 if bin == 0 || sym >= 512 {
5057 break;
5058 }
5059 }
5060 sym
5061}
5062
5063fn cabac_exp_bypass(cab: &mut crate::cabac::Cabac, mut count: i32) -> u32 {
5065 let mut sym = 0u32;
5066 loop {
5067 let c = cab.decode_bypass();
5068 if c == 1 {
5069 sym += 1 << count;
5070 count += 1;
5071 }
5072 if c == 0 || count == 16 {
5073 break;
5074 }
5075 }
5076 let mut sym2 = 0u32;
5077 while count > 0 {
5078 count -= 1;
5079 if cab.decode_bypass() != 0 {
5080 sym2 |= 1 << count;
5081 }
5082 }
5083 sym + sym2
5084}
5085
5086fn cabac_ueg_level(cab: &mut crate::cabac::Cabac, ctx: usize) -> u32 {
5089 if cab.decode_decision(ctx) == 0 {
5090 return 0;
5091 }
5092 let mut code = 0u32;
5093 let mut count = 1;
5094 let mut tmp;
5095 loop {
5096 tmp = cab.decode_decision(ctx);
5097 code += 1;
5098 count += 1;
5099 if tmp == 0 || count == 13 {
5100 break;
5101 }
5102 }
5103 if tmp != 0 {
5104 code += cabac_exp_bypass(cab, 0) + 1;
5105 }
5106 code
5107}
5108
5109fn parse_mb_qp_delta_cabac(cab: &mut crate::cabac::Cabac, last_delta_qp: &mut i32) -> i32 {
5111 const O: usize = 60;
5112 let ctx_inc = (*last_delta_qp != 0) as usize;
5113 let mut qp_delta = 0;
5114 if cab.decode_decision(O + ctx_inc) != 0 {
5115 let code = cabac_unary(cab, O + 2, 1) + 1;
5116 qp_delta = ((code + 1) >> 1) as i32;
5117 if code & 1 == 0 {
5118 qp_delta = -qp_delta;
5119 }
5120 }
5121 *last_delta_qp = qp_delta;
5122 qp_delta
5123}
5124
5125const NZC_CACHE: [usize; 24] = [
5128 9, 10, 17, 18, 11, 12, 19, 20, 25, 26, 33, 34, 27, 28, 35, 36, 14, 15, 22, 23, 38, 39, 46, 47, ];
5132
5133const RES_MAXPOS: [i32; 11] = [0, 15, 14, 15, 3, 14, 63, 3, 3, 14, 14];
5135const RES_MAXC2: [i32; 11] = [0, 4, 4, 4, 3, 4, 4, 3, 3, 4, 4];
5136const RES_CBF: [usize; 11] = [0, 0, 4, 8, 12, 16, 0, 12, 12, 16, 16];
5137const RES_MAP: [usize; 11] = [0, 0, 15, 29, 44, 47, 0, 44, 44, 47, 47];
5138const RES_ONE: [usize; 11] = [0, 0, 10, 20, 30, 39, 199, 30, 30, 39, 39];
5141const RP_I16_DC: usize = 1;
5143const RP_I16_AC: usize = 2;
5144const RP_LUMA_4X4: usize = 3;
5145const RP_CHROMA_DC: usize = 7; const RP_CHROMA_AC: usize = 9; const RP_LUMA_8X8: usize = 6;
5154
5155use rusty_h264_common::cabac_tables::{LAST8X8, SIG8X8};
5158
5159#[allow(clippy::too_many_arguments)]
5164fn parse_residual_cabac(
5165 cab: &mut crate::cabac::Cabac,
5166 nzc: &mut [u8; 48],
5167 cbf_dc: &mut u16,
5168 iz: usize,
5169 rp: usize,
5170 is_intra: bool,
5171 ndc: (Option<u16>, Option<u16>), out: &mut [i32], ) -> u32 {
5174 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Entropy);
5177 let is8 = rp == RP_LUMA_8X8;
5181 let is_dc = rp == RP_I16_DC || rp == RP_CHROMA_DC || rp == RP_CHROMA_DC + 1;
5182 let (mut na, mut nb) = (is_intra as u8, is_intra as u8);
5183 let scan = NZC_CACHE[iz.min(23)];
5184 if is_dc {
5185 if let Some(t) = ndc.0 {
5186 nb = ((t >> rp) & 1) as u8;
5187 }
5188 if let Some(l) = ndc.1 {
5189 na = ((l >> rp) & 1) as u8;
5190 }
5191 } else {
5192 if nzc[scan - 8] != 0xff {
5193 nb = (nzc[scan - 8] != 0) as u8;
5194 }
5195 if nzc[scan - 1] != 0xff {
5196 na = (nzc[scan - 1] != 0) as u8;
5197 }
5198 }
5199 if !is8 {
5200 let _sg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EntCbf);
5201 let cbf = cab.decode_decision(85 + RES_CBF[rp] + (na + (nb << 1)) as usize);
5202 if cbf == 0 {
5203 if !is_dc {
5204 nzc[scan] = 0;
5205 }
5206 return 0;
5207 }
5208 if is_dc {
5209 *cbf_dc |= 1 << rp;
5210 }
5211 }
5212 let maxpos = RES_MAXPOS[rp] as usize;
5214 let (map, last) = if is8 { (402, 417) } else { (105 + RES_MAP[rp], 166 + RES_MAP[rp]) };
5216 let mut pos = [0u8; 64];
5228 let mut n = 0usize;
5229 let mut last_hit = false;
5230 let _sg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EntSig);
5231 for i in 0..maxpos {
5232 let (mi, li) = if is8 { (SIG8X8[i] as usize, LAST8X8[i] as usize) } else { (i, i) };
5234 if cab.decode_decision(map + mi) != 0 {
5235 pos[n] = i as u8;
5236 n += 1;
5237 if cab.decode_decision(last + li) != 0 {
5238 last_hit = true;
5239 break;
5240 }
5241 }
5242 }
5243 if !last_hit {
5244 pos[n] = maxpos as u8;
5245 n += 1;
5246 }
5247 let coeff_num = n as u32;
5248 let one = 227 + RES_ONE[rp];
5250 let abs = 232 + RES_ONE[rp];
5251 let maxc2 = RES_MAXC2[rp];
5252 let (mut c1, mut c2) = (1i32, 0i32);
5253 drop(_sg);
5254 let _lg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::EntLvl);
5255 for k in (0..n).rev() {
5256 let mut level = 1 + cab.decode_decision(one + c1 as usize) as i32;
5257 if level == 2 {
5258 level += cabac_ueg_level(cab, abs + c2 as usize) as i32;
5259 c2 = (c2 + 1).min(maxc2);
5260 c1 = 0;
5261 } else if c1 != 0 {
5262 c1 = (c1 + 1).min(4);
5263 }
5264 if cab.decode_bypass() != 0 {
5265 level = -level;
5266 }
5267 out[pos[k] as usize] = level;
5268 }
5269 if is8 {
5270 for k in 0..4 {
5274 nzc[NZC_CACHE[(iz + k).min(23)]] = coeff_num as u8;
5275 }
5276 } else if !is_dc {
5277 nzc[scan] = coeff_num as u8;
5278 }
5279 coeff_num
5280}
5281
5282
5283enum EdcMsg {
5294 Job(EdcJob),
5295 Batch(Vec<EdcJob>),
5308 Row {
5310 r: usize,
5311 bs: Vec<rusty_h264_common::deblock::MbBs>,
5312 qp: Vec<u8>,
5313 t8: Vec<bool>,
5314 },
5315 NeedCtx,
5318}
5319
5320pub(crate) struct PixelCtx {
5321 rec_y: Vec<u8>,
5322 rec_u: Vec<u8>,
5323 rec_v: Vec<u8>,
5324 bak_y: Vec<u8>,
5325 bak_u: Vec<u8>,
5326 bak_v: Vec<u8>,
5327 refs: Vec<crate::Ref>,
5328 refs1: Vec<crate::Ref>,
5329 weights: Option<WeightTable>,
5330 scaling: Option<[[i32; 16]; 6]>,
5331 scaling8: Option<[[i32; 64]; 2]>,
5332 cw: usize,
5333 ccw: usize,
5334 mb_w: usize,
5335 mb_h: usize,
5336 chroma_qp_offset: i32,
5337 flt_rows: usize,
5338 db_ena: bool,
5339 db_oa: i32,
5340 db_ob: i32,
5341 cur_qp: u8,
5342 qp_grid: Vec<u8>,
5343 t8_grid: Vec<bool>,
5344 bs_store: Vec<rusty_h264_common::deblock::MbBs>,
5345}
5346
5347impl PixelCtx {
5348 fn chroma_qp_for(&self, qp: u8) -> u8 {
5349 rusty_h264_common::predict::chroma_qp(
5350 ((qp as i32 + self.chroma_qp_offset).clamp(0, 51)) as u8,
5351 )
5352 }
5353
5354 fn dequant(&self, levels: &[i32; 16], qp: u8, list: usize) -> [i32; 16] {
5355 match &self.scaling {
5356 Some(sc) => dequantize_weighted(levels, qp, &sc[list]),
5357 None => dequantize(levels, qp),
5358 }
5359 }
5360
5361 fn dequant_dc4(&self, level: i32, qp: u8, list: usize) -> i32 {
5362 rusty_h264_common::transform::dequantize_dc4(
5363 level,
5364 qp,
5365 self.scaling.as_ref().map(|sc| sc[list][0]),
5366 )
5367 }
5368
5369 fn inv_quant8(&self, raster: &[i32; 64], qp: u8, list: usize) -> [i32; 64] {
5370 match &self.scaling8 {
5371 Some(sc) => inverse_quant_8x8(raster, qp, &sc[list]),
5372 None => inverse_quant_8x8(raster, qp, &[16i32; 64]),
5373 }
5374 }
5375
5376 fn dequant_chroma_dc(&self, levels: &[i32; 4], qp: u8, list: usize) -> [i32; 4] {
5377 match &self.scaling {
5378 Some(sc) => inverse_quant_chroma_dc_weighted(levels, qp, sc[list][0]),
5379 None => inverse_quant_chroma_dc(levels, qp),
5380 }
5381 }
5382
5383 fn weight_partition(
5384 &self,
5385 pred_y: &mut [u8; 256],
5386 c_pred: &mut [[u8; 64]; 2],
5387 list: usize,
5388 refi: usize,
5389 rx: usize,
5390 ry: usize,
5391 rw: usize,
5392 rh: usize,
5393 ) {
5394 let Some(wt) = &self.weights else { return };
5395 for dy in 0..rh {
5396 for dx in 0..rw {
5397 let i = (ry + dy) * 16 + (rx + dx);
5398 pred_y[i] = wt.apply_luma(pred_y[i], list, refi);
5399 }
5400 }
5401 let (crx, cry, crw, crh) = (rx / 2, ry / 2, rw / 2, rh / 2);
5402 for cc in 0..2 {
5403 for dy in 0..crh {
5404 for dx in 0..crw {
5405 let i = (cry + dy) * 8 + (crx + dx);
5406 c_pred[cc][i] = wt.apply_chroma(c_pred[cc][i], list, refi, cc);
5407 }
5408 }
5409 }
5410 }
5411
5412 fn recon_p_inter(&mut self, j: &PInterJob) {
5413 let mbw = self.mb_w;
5414 let saved_qp = self.cur_qp;
5419 self.cur_qp = j.qp;
5420 let qp = j.qp;
5425 let qpc = self.chroma_qp_for(qp);
5426 let (w4r, w2r) = (mbw * 4, mbw * 2);
5427 let mut pred_y = [0u8; 256];
5428 let mut c_pred = [[0u8; 64]; 2];
5429 {
5430 let _ms = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecMcStage);
5438 let (rh16, cch) = (self.mb_h * 16, self.mb_h * 8);
5439 let gmv = j.gmv;
5442 let mut gref = [0usize; 16];
5443 for k in 0..16 {
5444 gref[k] = (j.gref[k] as usize).min(self.refs.len() - 1);
5445 }
5446 let rect_eq = |x4: usize, y4: usize, w4: usize, h4: usize| -> bool {
5448 let t = y4 * 4 + x4;
5449 (0..h4).all(|dy| {
5450 (0..w4).all(|dx| {
5451 let b = (y4 + dy) * 4 + (x4 + dx);
5452 gmv[b] == gmv[t] && gref[b] == gref[t]
5453 })
5454 })
5455 };
5456 let refs = &self.refs;
5457 let (cw, ccw) = (self.cw, self.ccw);
5458 let mut mc_rect = |x4: usize,
5459 y4: usize,
5460 w4: usize,
5461 h4: usize,
5462 pred_y: &mut [u8; 256],
5463 c_pred: &mut [[u8; 64]; 2]| {
5464 let b = y4 * 4 + x4;
5465 let (mv, reference) = (gmv[b], &refs[gref[b]]);
5466 let (w, h) = (w4 * 4, h4 * 4);
5467 if w == 16 {
5476 rusty_h264_common::inter::with_mc_scratch(|scr| rusty_h264_common::inter::mc_luma_padded_pre(scr, &reference.py, reference.lstride(), crate::LPAD, cw, rh16, j.mbx * 16, j.mby * 16 + y4 * 4, w, h, mv.0, mv.1, &mut pred_y[y4 * 64..y4 * 64 + w * h]));
5477 } else {
5478 let mut t = [0u8; 256];
5479 rusty_h264_common::inter::with_mc_scratch(|scr| rusty_h264_common::inter::mc_luma_padded_pre(scr, &reference.py, reference.lstride(), crate::LPAD, cw, rh16, j.mbx * 16 + x4 * 4, j.mby * 16 + y4 * 4, w, h, mv.0, mv.1, &mut t[..w * h]));
5480 let _pb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
5481 for dy in 0..h {
5482 pred_y[(y4 * 4 + dy) * 16 + x4 * 4..][..w]
5483 .copy_from_slice(&t[dy * w..dy * w + w]);
5484 }
5485 }
5486 let (cw4, ch4) = (w4 * 2, h4 * 2);
5487 for cc in 0..2 {
5488 let rc = if cc == 0 { &reference.pu } else { &reference.pv };
5489 if cw4 == 8 {
5492 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, ccw, cch, j.mbx * 8, j.mby * 8 + y4 * 2, cw4, ch4, mv.0, mv.1, &mut c_pred[cc][y4 * 16..y4 * 16 + cw4 * ch4]);
5493 continue;
5494 }
5495 let mut tc = [0u8; 64];
5496 mc_chroma_padded(rc, reference.cstride(), crate::CPAD, ccw, cch, j.mbx * 8 + x4 * 2, j.mby * 8 + y4 * 2, cw4, ch4, mv.0, mv.1, &mut tc[..cw4 * ch4]);
5497 let _pb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::PredBuf);
5498 for dy in 0..ch4 {
5499 c_pred[cc][(y4 * 2 + dy) * 8 + x4 * 2..][..cw4]
5500 .copy_from_slice(&tc[dy * cw4..dy * cw4 + cw4]);
5501 }
5502 }
5503 };
5504 if rect_eq(0, 0, 4, 4) {
5505 mc_rect(0, 0, 4, 4, &mut pred_y, &mut c_pred);
5506 } else if rect_eq(0, 0, 4, 2) && rect_eq(0, 2, 4, 2) {
5507 mc_rect(0, 0, 4, 2, &mut pred_y, &mut c_pred);
5508 mc_rect(0, 2, 4, 2, &mut pred_y, &mut c_pred);
5509 } else if rect_eq(0, 0, 2, 4) && rect_eq(2, 0, 2, 4) {
5510 mc_rect(0, 0, 2, 4, &mut pred_y, &mut c_pred);
5511 mc_rect(2, 0, 2, 4, &mut pred_y, &mut c_pred);
5512 } else {
5513 for q in 0..4usize {
5514 let (qx, qy) = ((q % 2) * 2, (q / 2) * 2);
5515 if rect_eq(qx, qy, 2, 2) {
5516 mc_rect(qx, qy, 2, 2, &mut pred_y, &mut c_pred);
5517 } else if rect_eq(qx, qy, 2, 1) && rect_eq(qx, qy + 1, 2, 1) {
5518 mc_rect(qx, qy, 2, 1, &mut pred_y, &mut c_pred);
5519 mc_rect(qx, qy + 1, 2, 1, &mut pred_y, &mut c_pred);
5520 } else if rect_eq(qx, qy, 1, 2) && rect_eq(qx + 1, qy, 1, 2) {
5521 mc_rect(qx, qy, 1, 2, &mut pred_y, &mut c_pred);
5522 mc_rect(qx + 1, qy, 1, 2, &mut pred_y, &mut c_pred);
5523 } else {
5524 for j in 0..4usize {
5525 mc_rect(qx + (j % 2), qy + (j / 2), 1, 1, &mut pred_y, &mut c_pred);
5526 }
5527 }
5528 }
5529 }
5530 if self.weights.is_some() {
5544 for by in 0..4usize {
5545 for bx in 0..4usize {
5546 let refi = gref[by * 4 + bx];
5547 self.weight_partition(
5548 &mut pred_y, &mut c_pred, 0, refi, bx * 4, by * 4, 4, 4,
5549 );
5550 }
5551 }
5552 }
5553 }
5554 self.add_inter_residual(j.mbx, j.mby, &pred_y, &c_pred, &j.luma_scan, if j.t8 { Some(&j.luma8) } else { None }, &j.cdc, &j.cac, j.cbp_chroma, &j.nnzs);
5558 }
5559
5560 fn recon_p_skip(&mut self, mb_x: usize, mb_y: usize, mv: (i32, i32)) {
5561 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
5562
5563 let mut pred = [0u8; 256];
5564 let rf0 = &self.refs[0];
5565 mc_luma_padded(&rf0.py, rf0.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16, 16, 16, mv.0, mv.1, &mut pred);
5566 if let Some(wt) = &self.weights {
5567 for p in pred.iter_mut() {
5568 *p = wt.apply_luma(*p, 0, 0);
5569 }
5570 }
5571 {
5572 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::SkipRecon);
5573 for dy in 0..16 {
5574 let d = (mb_y * 16 + dy) * self.cw + mb_x * 16;
5575 self.rec_y[d..d + 16].copy_from_slice(&pred[dy * 16..dy * 16 + 16]);
5576 }
5577 }
5578 for c in 0..2 {
5579 let mut pc = [0u8; 64];
5580 let rf0 = &self.refs[0];
5581 let rc = if c == 0 { &rf0.pu } else { &rf0.pv };
5582 mc_chroma_padded(rc, rf0.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8, 8, 8, mv.0, mv.1, &mut pc);
5583 if let Some(wt) = &self.weights {
5584 for p in pc.iter_mut() {
5585 *p = wt.apply_chroma(*p, 0, 0, c);
5586 }
5587 }
5588 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
5589 for dy in 0..8 {
5590 let d = (mb_y * 8 + dy) * self.ccw + mb_x * 8;
5591 plane[d..d + 8].copy_from_slice(&pc[dy * 8..dy * 8 + 8]);
5592 }
5593 }
5594 }
5595
5596 fn add_inter_residual(
5597 &mut self,
5598 mb_x: usize,
5599 mb_y: usize,
5600 pred_y: &[u8; 256],
5601 c_pred: &[[u8; 64]; 2],
5602 luma_scan: &[[i32; 16]; 16],
5603 luma8: Option<&[[i32; 64]; 4]>,
5606 cdc: &[[i32; 4]; 2],
5607 cac: &[[[i32; 16]; 4]; 2],
5608 cbp_chroma: u32,
5609 nnzs: &[u8; 24],
5616 ) {
5617 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecResidAdd);
5618 let qp = self.cur_qp;
5619 let qpc = self.chroma_qp_for(qp);
5620 let (w4r, w2r) = (self.mb_w * 4, self.mb_w * 2);
5621 if let Some(l8) = luma8 {
5622 for b8 in 0..4usize {
5624 let (b8x, b8y) = (b8 % 2, b8 / 2);
5625 let nnz: u32 = (0..4).map(|k| nnzs[b8 * 4 + k] as u32).sum();
5628 let res8 = if nnz == 0 {
5629 [0i32; 64]
5630 } else {
5631 let raster = un_scan_8x8(&l8[b8]);
5632 self.inv_quant8(&raster, qp, 1)
5634 };
5635 let predb: [i32; 64] =
5638 std::array::from_fn(|i| pred_y[(b8y * 8 + i / 8) * 16 + (b8x * 8 + i % 8)] as i32);
5639 let recon = add_residual_8x8(&res8, &predb);
5640 let (px, py) = (mb_x * 16 + b8x * 8, mb_y * 16 + b8y * 8);
5641 for dy in 0..8 {
5642 for dx in 0..8 {
5643 self.rec_y[(py + dy) * self.cw + (px + dx)] = recon[dy * 8 + dx];
5644 }
5645 }
5646 }
5647 }
5648 for (blk, &(lbx, lby)) in LUMA_4X4_SCAN_XY.iter().enumerate() {
5649 if luma8.is_some() {
5650 break;
5651 }
5652 let nnz = nnzs[blk];
5653 let cw = self.cw;
5654 let p_off = (lby * 4) * 16 + lbx * 4;
5655 let r_off = (mb_y * 4 + lby) * 4 * cw + (mb_x * 4 + lbx) * 4;
5656 if nnz == 0 {
5657 for r in 0..4 {
5662 self.rec_y[r_off + r * cw..r_off + r * cw + 4]
5663 .copy_from_slice(&pred_y[p_off + r * 16..p_off + r * 16 + 4]);
5664 }
5665 continue;
5666 }
5667 if nnz == 1 && luma_scan[blk][0] != 0 {
5671 let f = self.dequant_dc4(luma_scan[blk][0], qp, 3);
5672 reconstruct_4x4_dc_into((f + 32) >> 6, pred_y, p_off, 16, &mut self.rec_y, r_off, cw);
5673 } else {
5674 let deq = if nnz <= 6 {
5684 dequant_scatter_4x4(&luma_scan[blk], nnz, 0, qp, self.scaling.as_ref().map(|sc| &sc[3]))
5685 } else {
5686 self.dequant(&un_scan_4x4_dcac(&luma_scan[blk]), qp, 3)
5687 };
5688 reconstruct_4x4_into(&deq, pred_y, p_off, 16, &mut self.rec_y, r_off, cw);
5689 }
5690 }
5691 let mut c_dc = [[0i32; 4]; 2];
5692 if cbp_chroma != 0 {
5693 for c in 0..2 {
5694 c_dc[c] = self.dequant_chroma_dc(&cdc[c], qpc, 4 + c);
5695 }
5696 }
5697 let ccw = self.ccw;
5698 for c in 0..2 {
5699 for &(bx, by) in &CHROMA_4X4_SCAN_XY {
5700 let mut ac_nz = false;
5701 if cbp_chroma == 2 {
5702 let n = nnzs[16 + c * 4 + by * 2 + bx];
5703 ac_nz = n != 0;
5704 }
5705 let dc = c_dc[c][by * 2 + bx];
5706 let p_off = (by * 4) * 8 + bx * 4;
5707 let r_off = (mb_y * 2 + by) * 4 * ccw + (mb_x * 2 + bx) * 4;
5708 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
5709 if dc == 0 && !ac_nz {
5710 for r in 0..4 {
5712 plane[r_off + r * ccw..r_off + r * ccw + 4]
5713 .copy_from_slice(&c_pred[c][p_off + r * 8..p_off + r * 8 + 4]);
5714 }
5715 continue;
5716 }
5717 if !ac_nz {
5721 reconstruct_4x4_dc_into((dc + 32) >> 6, &c_pred[c], p_off, 8, plane, r_off, ccw);
5722 continue;
5723 }
5724 let n = nnzs[16 + c * 4 + by * 2 + bx];
5727 let mut deq = if n <= 6 {
5728 dequant_scatter_4x4(&cac[c][by * 2 + bx], n, 1, qpc, self.scaling.as_ref().map(|sc| &sc[4 + c]))
5729 } else {
5730 let mut ac = [0i32; 16];
5731 un_scan_4x4_ac_into(&cac[c][by * 2 + bx], &mut ac);
5732 match &self.scaling {
5735 Some(sc) => dequantize_weighted(&ac, qpc, &sc[4 + c]),
5736 None => dequantize(&ac, qpc),
5737 }
5738 };
5739 deq[0] = dc;
5740 reconstruct_4x4_into(&deq, &c_pred[c], p_off, 8, plane, r_off, ccw);
5741 }
5742 }
5743 }
5744
5745 fn filter_row(&mut self, r: usize) {
5746 let info = rusty_h264_common::deblock::BlockInfo {
5749 inter: &[],
5750 nnz: &[],
5751 mv: &[],
5752 ref_id: &[],
5753 mv1: &[],
5754 ref_id1: &[],
5755 w4: self.mb_w * 4,
5756 t8x8: &self.t8_grid,
5757 bs: &self.bs_store,
5758 poc0: &[],
5759 poc1: &[],
5760 kind: &[],
5761 };
5762 rusty_h264_common::deblock::filter_frame_rows(
5763 &mut self.rec_y,
5764 &mut self.rec_u,
5765 &mut self.rec_v,
5766 self.mb_w,
5767 self.mb_h,
5768 r..r + 1,
5769 &self.qp_grid,
5770 self.chroma_qp_offset,
5771 self.db_oa,
5772 self.db_ob,
5773 &info,
5774 );
5775 }
5776
5777 fn save_bak(&mut self, r: usize) {
5778 let y0 = (r * 16 + 15) * self.cw;
5779 self.bak_y.copy_from_slice(&self.rec_y[y0..y0 + self.cw]);
5780 let c0 = (r * 8 + 7) * self.ccw;
5781 self.bak_u.copy_from_slice(&self.rec_u[c0..c0 + self.ccw]);
5782 self.bak_v.copy_from_slice(&self.rec_v[c0..c0 + self.ccw]);
5783 }
5784}
5785
5786pub(crate) mod edcstat {
5793 use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
5794 pub static NEEDCTX: AtomicU64 = AtomicU64::new(0);
5795 pub static JOBS: AtomicU64 = AtomicU64::new(0);
5796 pub static ROWS: AtomicU64 = AtomicU64::new(0);
5797 pub static ROWBYTES: AtomicU64 = AtomicU64::new(0);
5798 pub static MBS: AtomicU64 = AtomicU64::new(0);
5799 pub static J_INTER: AtomicU64 = AtomicU64::new(0);
5800 pub static DOUBLED: AtomicU64 = AtomicU64::new(0);
5801 pub static J_NORES_SENT: AtomicU64 = AtomicU64::new(0);
5802 pub static BATCHES: AtomicU64 = AtomicU64::new(0);
5803 pub static DISPATCH_ON: AtomicU64 = AtomicU64::new(0);
5804 pub static DISPATCH_SEEN: AtomicU64 = AtomicU64::new(0);
5805 pub static J_INTER_NORES: AtomicU64 = AtomicU64::new(0);
5806 #[inline]
5807 pub fn bump(c: &AtomicU64, n: u64) {
5808 if on() {
5809 c.fetch_add(n, Relaxed);
5810 }
5811 }
5812 pub fn on() -> bool {
5813 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5814 *V.get_or_init(|| std::env::var_os("RS_H264_EDC_STATS").is_some())
5815 }
5816 pub fn report() {
5817 if !on() {
5818 return;
5819 }
5820 eprintln!(
5821 "EDCDISPATCH threaded_slices={} eligible_slices={}",
5822 DISPATCH_ON.load(Relaxed), DISPATCH_SEEN.load(Relaxed)
5823 );
5824 eprintln!(
5825 "EDCSIZE EdcMsg={} EdcJob={} PInterJob={} BJob={}",
5826 std::mem::size_of::<super::EdcMsg>(),
5827 std::mem::size_of::<super::EdcJob>(),
5828 std::mem::size_of::<super::PInterJob>(),
5829 std::mem::size_of::<super::BJob>(),
5830 );
5831 let (n, j, r, b, m) = (
5832 NEEDCTX.load(Relaxed), JOBS.load(Relaxed), ROWS.load(Relaxed),
5833 ROWBYTES.load(Relaxed), MBS.load(Relaxed),
5834 );
5835 eprintln!(
5836 "EDCSTAT needctx={n} jobs={j} rows={r} rowbytes={b} mbs={m} batches={} jobs_per_batch={:.1} needctx_per_1k_mb={:.1} jobs_per_needctx={:.1}",
5837 BATCHES.load(Relaxed),
5838 j as f64 / BATCHES.load(Relaxed).max(1) as f64,
5839 1000.0 * n as f64 / m.max(1) as f64,
5840 j as f64 / n.max(1) as f64
5841 );
5842 let (ji, jn) = (J_INTER.load(Relaxed), J_INTER_NORES.load(Relaxed));
5843 eprintln!(
5844 "EDCMIX doubled={} nores_sent={} inter={ji} inter_no_residual={jn} ({:.1}% of inter) wasted_bytes={:.1} MB of {:.1} MB total inter payload",
5845 DOUBLED.load(Relaxed),
5846 J_NORES_SENT.load(Relaxed),
5847 100.0 * jn as f64 / ji.max(1) as f64,
5848 (jn * 2784) as f64 / 1.048576e6,
5849 (ji * 2784) as f64 / 1.048576e6,
5850 );
5851 }
5852}
5853
5854fn edc_worker(
5855 mut ctx: PixelCtx,
5856 rx: std::sync::mpsc::Receiver<EdcMsg>,
5857 ctx_tx: std::sync::mpsc::Sender<PixelCtx>,
5858 back_rx: std::sync::mpsc::Receiver<PixelCtx>,
5859) -> PixelCtx {
5860 while let Ok(msg) = rx.recv() {
5861 match msg {
5862 EdcMsg::Batch(jobs) => {
5863 for j in jobs {
5864 match j {
5865 EdcJob::Skip { mbx, mby, mv } => ctx.recon_p_skip(mbx, mby, mv),
5866 EdcJob::Inter(j) => ctx.recon_p_inter(&j),
5867 EdcJob::InterNoRes(j) => ctx.recon_p_inter(&j.to_full()),
5868 EdcJob::B(j) => ctx.recon_b(&j),
5869 EdcJob::BSkip { mbx, mby, regions } => ctx.recon_b_skip(mbx, mby, ®ions),
5870 }
5871 }
5872 }
5873 EdcMsg::Job(EdcJob::Skip { mbx, mby, mv }) => ctx.recon_p_skip(mbx, mby, mv),
5874 EdcMsg::Job(EdcJob::Inter(j)) => ctx.recon_p_inter(&j),
5875 EdcMsg::Job(EdcJob::InterNoRes(j)) => ctx.recon_p_inter(&j.to_full()),
5876 EdcMsg::Job(EdcJob::B(j)) => ctx.recon_b(&j),
5877 EdcMsg::Job(EdcJob::BSkip { mbx, mby, regions }) => ctx.recon_b_skip(mbx, mby, ®ions),
5878 EdcMsg::Row { r, bs, qp, t8 } => {
5879 let (w, base) = (ctx.mb_w, r * ctx.mb_w);
5880 ctx.bs_store[base..base + w].copy_from_slice(&bs);
5881 ctx.qp_grid[base..base + w].copy_from_slice(&qp);
5882 ctx.t8_grid[base..base + w].copy_from_slice(&t8);
5883 if ctx.db_ena {
5884 ctx.save_bak(r);
5885 ctx.filter_row(r);
5886 ctx.flt_rows = r + 1;
5887 }
5888 }
5889 EdcMsg::NeedCtx => {
5890 ctx_tx.send(ctx).expect("parse thread alive");
5891 ctx = back_rx.recv().expect("ctx returned after intra");
5892 }
5893 }
5894 }
5895 ctx
5896}
5897
5898
5899pub(crate) struct BRegion {
5903 px: usize,
5904 py: usize,
5905 rw: usize,
5906 rh: usize,
5907 refi0: i32,
5908 refi1: i32,
5909 mv0: (i32, i32),
5910 mv1: (i32, i32),
5911 w: Option<(i32, i32)>,
5912}
5913
5914pub(crate) struct BJob {
5918 mbx: usize,
5919 mby: usize,
5920 t8: bool,
5921 qp: u8,
5922 cbp_chroma: u32,
5923 skip: bool,
5924 regions: Vec<BRegion>,
5925 luma_scan: [[i32; 16]; 16],
5926 luma8: [[i32; 64]; 4],
5927 cdc: [[i32; 4]; 2],
5928 cac: [[[i32; 16]; 4]; 2],
5929 nnzs: [u8; 24],
5930}
5931
5932impl PixelCtx {
5933 fn b_mc(
5934 &self,
5935 mb_x: usize,
5936 mb_y: usize,
5937 px: usize,
5938 py: usize,
5939 rw: usize,
5940 rh: usize,
5941 refi0: i32,
5942 mv0: (i32, i32),
5943 refi1: i32,
5944 mv1: (i32, i32),
5945 pred_y: &mut [u8; 256],
5946 c_pred: &mut [[u8; 64]; 2],
5947 wparam: Option<(i32, i32)>,
5948 ) {
5949 let _gb = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBMc);
5950 let refi0 = if refi0 >= 0 { (refi0 as usize).min(self.refs.len().saturating_sub(1)) as i32 } else { -1 };
5956 let refi1 = if refi1 >= 0 { (refi1 as usize).min(self.refs1.len().saturating_sub(1)) as i32 } else { -1 };
5957 if (refi0 >= 0 && self.refs.is_empty()) || (refi1 >= 0 && self.refs1.is_empty()) {
5958 return;
5959 }
5960 let (ch, cch) = (self.mb_h * 16, self.mb_h * 8);
5961 let weights = wparam;
5964 let full = px == 0 && rw == 16;
5976 let _gl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBLuma);
5977 let chroma_done = rusty_h264_common::inter::with_mc_scratch(|scr| match (refi0 >= 0, refi1 >= 0, full) {
5982 (true, false, true) => {
5983 let rf = &self.refs[refi0 as usize];
5984 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
5985 false
5986 }
5987 (false, true, true) => {
5988 let rf = &self.refs1[refi1 as usize];
5989 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
5990 false
5991 }
5992 (true, true, true) => {
5993 let rf = &self.refs[refi0 as usize];
5994 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut pred_y[py * 16..py * 16 + rw * rh]);
5995 let mut b = [0u8; 256];
5996 let rf = &self.refs1[refi1 as usize];
5997 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut b[..rw * rh]);
5998 drop(_gl);
5999 let _gbl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBBlend);
6000 let dst = &mut pred_y[py * 16..py * 16 + rw * rh];
6006 match weights {
6007 None => {
6008 for (d, s) in dst.iter_mut().zip(&b[..rw * rh]) {
6009 *d = ((*d as u16 + *s as u16 + 1) >> 1) as u8;
6010 }
6011 }
6012 Some((w0, w1)) => {
6013 for (d, s) in dst.iter_mut().zip(&b[..rw * rh]) {
6014 *d = ((*d as i32 * w0 + *s as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
6015 }
6016 }
6017 }
6018 let _gc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBChroma);
6019 self.b_mc_chroma(mb_x, mb_y, px, py, rw, rh, refi0, mv0, refi1, mv1, c_pred, weights, cch);
6020 true
6021 }
6022 _ => {
6023 let (mut a, mut b) = ([0u8; 256], [0u8; 256]);
6025 if refi0 >= 0 {
6026 let rf = &self.refs[refi0 as usize];
6027 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, rw, rh, mv0.0, mv0.1, &mut a[..rw * rh]);
6028 }
6029 if refi1 >= 0 {
6030 let rf = &self.refs1[refi1 as usize];
6031 rusty_h264_common::inter::mc_luma_padded_pre(scr, &rf.py, rf.lstride(), crate::LPAD, self.cw, ch, mb_x * 16 + px, mb_y * 16 + py, rw, rh, mv1.0, mv1.1, &mut b[..rw * rh]);
6032 }
6033 drop(_gl);
6034 let _gbl = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBBlend);
6035 match (refi0 >= 0, refi1 >= 0) {
6036 (true, true) => {
6037 for dy in 0..rh {
6038 let (ar, br) = (&a[dy * rw..dy * rw + rw], &b[dy * rw..dy * rw + rw]);
6039 let base = (py + dy) * 16 + px;
6040 let dst = &mut pred_y[base..base + rw];
6041 match weights {
6042 None => {
6043 for ((d, p), q) in dst.iter_mut().zip(ar).zip(br) {
6044 *d = ((*p as u16 + *q as u16 + 1) >> 1) as u8;
6045 }
6046 }
6047 Some((w0, w1)) => {
6048 for ((d, p), q) in dst.iter_mut().zip(ar).zip(br) {
6049 *d = ((*p as i32 * w0 + *q as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
6050 }
6051 }
6052 }
6053 }
6054 }
6055 (true, false) => {
6056 for dy in 0..rh {
6057 let d = (py + dy) * 16 + px;
6058 pred_y[d..d + rw].copy_from_slice(&a[dy * rw..dy * rw + rw]);
6059 }
6060 }
6061 _ => {
6062 for dy in 0..rh {
6063 let d = (py + dy) * 16 + px;
6064 pred_y[d..d + rw].copy_from_slice(&b[dy * rw..dy * rw + rw]);
6065 }
6066 }
6067 }
6068 false
6069 }
6070 });
6071 if chroma_done {
6072 return;
6073 }
6074 let _gc = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecBChroma);
6075 self.b_mc_chroma(mb_x, mb_y, px, py, rw, rh, refi0, mv0, refi1, mv1, c_pred, weights, cch);
6076 }
6077
6078 fn b_mc_chroma(
6079 &self,
6080 mb_x: usize,
6081 mb_y: usize,
6082 px: usize,
6083 py: usize,
6084 rw: usize,
6085 rh: usize,
6086 refi0: i32,
6087 mv0: (i32, i32),
6088 refi1: i32,
6089 mv1: (i32, i32),
6090 c_pred: &mut [[u8; 64]; 2],
6091 weights: Option<(i32, i32)>,
6092 cch: usize,
6093 ) {
6094 let (crx, cry, crw, crh) = (px / 2, py / 2, rw / 2, rh / 2);
6095 let full = crx == 0 && crw == 8;
6096 for c in 0..2 {
6097 match (refi0 >= 0, refi1 >= 0, full) {
6098 (true, false, true) => {
6099 let rf = &self.refs[refi0 as usize];
6100 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6101 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
6102 }
6103 (false, true, true) => {
6104 let rf = &self.refs1[refi1 as usize];
6105 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6106 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
6107 }
6108 (true, true, true) => {
6109 let rf = &self.refs[refi0 as usize];
6110 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6111 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut c_pred[c][cry * 8..cry * 8 + crw * crh]);
6112 let mut cb = [0u8; 64];
6113 let rf = &self.refs1[refi1 as usize];
6114 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6115 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut cb[..crw * crh]);
6116 let dst = &mut c_pred[c][cry * 8..cry * 8 + crw * crh];
6117 match weights {
6118 None => {
6119 for (d, s) in dst.iter_mut().zip(&cb[..crw * crh]) {
6120 *d = ((*d as u16 + *s as u16 + 1) >> 1) as u8;
6121 }
6122 }
6123 Some((w0, w1)) => {
6124 for (d, s) in dst.iter_mut().zip(&cb[..crw * crh]) {
6125 *d = ((*d as i32 * w0 + *s as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
6126 }
6127 }
6128 }
6129 }
6130 _ => {
6131 let (mut ca, mut cb) = ([0u8; 64], [0u8; 64]);
6132 if refi0 >= 0 {
6133 let rf = &self.refs[refi0 as usize];
6134 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6135 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv0.0, mv0.1, &mut ca[..crw * crh]);
6136 }
6137 if refi1 >= 0 {
6138 let rf = &self.refs1[refi1 as usize];
6139 let pl = if c == 0 { &rf.pu } else { &rf.pv };
6140 mc_chroma_padded(pl, rf.cstride(), crate::CPAD, self.ccw, cch, mb_x * 8 + crx, mb_y * 8 + cry, crw, crh, mv1.0, mv1.1, &mut cb[..crw * crh]);
6141 }
6142 match (refi0 >= 0, refi1 >= 0) {
6143 (true, true) => {
6144 for dy in 0..crh {
6145 let (pr, qr) = (&ca[dy * crw..dy * crw + crw], &cb[dy * crw..dy * crw + crw]);
6146 let base = (cry + dy) * 8 + crx;
6147 let dst = &mut c_pred[c][base..base + crw];
6148 match weights {
6149 None => {
6150 for ((d, p), q) in dst.iter_mut().zip(pr).zip(qr) {
6151 *d = ((*p as u16 + *q as u16 + 1) >> 1) as u8;
6152 }
6153 }
6154 Some((w0, w1)) => {
6155 for ((d, p), q) in dst.iter_mut().zip(pr).zip(qr) {
6156 *d = ((*p as i32 * w0 + *q as i32 * w1 + 32) >> 6).clamp(0, 255) as u8;
6157 }
6158 }
6159 }
6160 }
6161 }
6162 (true, false) => {
6163 for dy in 0..crh {
6164 let d = (cry + dy) * 8 + crx;
6165 c_pred[c][d..d + crw].copy_from_slice(&ca[dy * crw..dy * crw + crw]);
6166 }
6167 }
6168 _ => {
6169 for dy in 0..crh {
6170 let d = (cry + dy) * 8 + crx;
6171 c_pred[c][d..d + crw].copy_from_slice(&cb[dy * crw..dy * crw + crw]);
6172 }
6173 }
6174 }
6175 }
6176 }
6177 }
6178 }
6179
6180 fn recon_b_skip(&mut self, mbx: usize, mby: usize, regions: &[BRegion]) {
6183 let mut pred_y = [0u8; 256];
6184 let mut c_pred = [[0u8; 64]; 2];
6185 for r in regions {
6186 self.b_mc(mbx, mby, r.px, r.py, r.rw, r.rh, r.refi0, r.mv0, r.refi1, r.mv1, &mut pred_y, &mut c_pred, r.w);
6187 }
6188 for dy in 0..16 {
6189 let d = (mby * 16 + dy) * self.cw + mbx * 16;
6190 self.rec_y[d..d + 16].copy_from_slice(&pred_y[dy * 16..dy * 16 + 16]);
6191 }
6192 for c in 0..2 {
6193 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
6194 for dy in 0..8 {
6195 let d = (mby * 8 + dy) * self.ccw + mbx * 8;
6196 plane[d..d + 8].copy_from_slice(&c_pred[c][dy * 8..dy * 8 + 8]);
6197 }
6198 }
6199 }
6200
6201 fn recon_b(&mut self, j: &BJob) {
6205 let mut pred_y = [0u8; 256];
6206 let mut c_pred = [[0u8; 64]; 2];
6207 for r in &j.regions {
6208 self.b_mc(j.mbx, j.mby, r.px, r.py, r.rw, r.rh, r.refi0, r.mv0, r.refi1, r.mv1, &mut pred_y, &mut c_pred, r.w);
6209 }
6210 if j.skip {
6211 for dy in 0..16 {
6212 let d = (j.mby * 16 + dy) * self.cw + j.mbx * 16;
6213 self.rec_y[d..d + 16].copy_from_slice(&pred_y[dy * 16..dy * 16 + 16]);
6214 }
6215 for c in 0..2 {
6216 let plane = if c == 0 { &mut self.rec_u } else { &mut self.rec_v };
6217 for dy in 0..8 {
6218 let d = (j.mby * 8 + dy) * self.ccw + j.mbx * 8;
6219 plane[d..d + 8].copy_from_slice(&c_pred[c][dy * 8..dy * 8 + 8]);
6220 }
6221 }
6222 } else {
6223 self.cur_qp = j.qp;
6224 self.add_inter_residual(j.mbx, j.mby, &pred_y, &c_pred, &j.luma_scan, if j.t8 { Some(&j.luma8) } else { None }, &j.cdc, &j.cac, j.cbp_chroma, &j.nnzs);
6225 }
6226 }
6227}
6228
6229enum EdcJob {
6231 Skip { mbx: usize, mby: usize, mv: (i32, i32) },
6232 Inter(Box<PInterJob>),
6233 B(Box<BJob>),
6234 BSkip { mbx: usize, mby: usize, regions: Vec<BRegion> },
6238 InterNoRes(Box<PInterNoResJob>),
6240}
6241
6242struct PInterNoResJob {
6258 mbx: usize,
6259 mby: usize,
6260 t8: bool,
6261 qp: u8,
6262 gmv: [(i32, i32); 16],
6263 gref: [u8; 16],
6264}
6265
6266impl PInterNoResJob {
6267 #[inline]
6270 fn to_full(&self) -> PInterJob {
6271 PInterJob {
6272 mbx: self.mbx,
6273 mby: self.mby,
6274 t8: self.t8,
6275 qp: self.qp,
6276 cbp_chroma: 0,
6277 gmv: self.gmv,
6278 gref: self.gref,
6279 luma_scan: [[0i32; 16]; 16],
6280 luma8: [[0i32; 64]; 4],
6281 cdc: [[0i32; 4]; 2],
6282 cac: [[[0i32; 16]; 4]; 2],
6283 nnzs: [0u8; 24],
6284 }
6285 }
6286}
6287
6288struct PInterJob {
6290 mbx: usize,
6291 mby: usize,
6292 t8: bool,
6293 qp: u8,
6294 cbp_chroma: u32,
6295 gmv: [(i32, i32); 16],
6299 gref: [u8; 16],
6300 luma_scan: [[i32; 16]; 16],
6301 luma8: [[i32; 64]; 4],
6302 cdc: [[i32; 4]; 2],
6303 cac: [[[i32; 16]; 4]; 2],
6304 nnzs: [u8; 24],
6305}
6306
6307fn edc_on() -> bool {
6314 use std::sync::atomic::{AtomicU8, Ordering};
6315 static ON: AtomicU8 = AtomicU8::new(0);
6316 match ON.load(Ordering::Relaxed) {
6317 0 => {
6318 let v = !std::env::var_os("RS_H264_EDC").is_some_and(|v| v == "0");
6319 ON.store(if v { 1 } else { 2 }, Ordering::Relaxed);
6320 v
6321 }
6322 n => n == 1,
6323 }
6324}
6325
6326fn batch_on() -> bool {
6363 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6364 *V.get_or_init(|| !std::env::var_os("RS_H264_BATCH").is_some_and(|v| v == "0"))
6365}
6366
6367fn nores_on() -> bool {
6368 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6369 *V.get_or_init(|| !std::env::var_os("RS_H264_NORES").is_some_and(|v| v == "0"))
6370}
6371
6372fn double_recon() -> bool {
6373 static V: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6374 *V.get_or_init(|| std::env::var_os("RS_H264_DOUBLE_RECON").is_some())
6375}
6376
6377fn edc_bound() -> usize {
6378 static V: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
6379 *V.get_or_init(|| {
6380 std::env::var("RS_H264_EDC_BOUND")
6381 .ok()
6382 .and_then(|v| v.parse().ok())
6383 .unwrap_or(256)
6384 })
6385}
6386
6387fn edc_dispatch(mb_w: usize, mb_h: usize, bits_per_mb: f64, cabac: bool) -> bool {
6425 const BITS_MIN: f64 = 38.4;
6426 const MAX_MBS: usize = 5000; cabac && bits_per_mb > BITS_MIN && mb_w * mb_h <= MAX_MBS
6432}
6433
6434fn edc_mt() -> Option<bool> {
6435 static V: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
6436 *V.get_or_init(|| match std::env::var("RS_H264_EDC_MT").ok().as_deref() {
6437 Some("0") => Some(false),
6438 Some("1") => Some(true),
6439 _ => None,
6440 })
6441}
6442
6443
6444
6445fn rowdb_on() -> bool {
6448 use std::sync::atomic::{AtomicU8, Ordering};
6449 static ON: AtomicU8 = AtomicU8::new(0);
6450 match ON.load(Ordering::Relaxed) {
6451 0 => {
6452 let v = !std::env::var_os("RS_H264_ROWDB").is_some_and(|v| v == "0");
6453 ON.store(if v { 1 } else { 2 }, Ordering::Relaxed);
6454 v
6455 }
6456 n => n == 1,
6457 }
6458}
6459
6460const CACHE30: [usize; 16] = [7, 8, 13, 14, 9, 10, 15, 16, 19, 20, 25, 26, 21, 22, 27, 28];
6463
6464const G_SCAN4: [usize; 16] = [0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15];
6467
6468fn parse_sub_mb_type_p_cabac(cab: &mut crate::cabac::Cabac) -> u32 {
6470 const S: usize = 21;
6471 if cab.decode_decision(S) != 0 {
6472 return 0;
6473 }
6474 if cab.decode_decision(S + 1) != 0 {
6475 3 - cab.decode_decision(S + 2)
6476 } else {
6477 1
6478 }
6479}
6480
6481fn parse_intra_mb_type_cabac(cab: &mut crate::cabac::Cabac, base: usize) -> u32 {
6484 if cab.decode_decision(base) == 0 {
6485 return 0; }
6487 if cab.decode_terminate() {
6488 return 25; }
6490 let mut t = 1 + 12 * cab.decode_decision(base + 1) as u32; if cab.decode_decision(base + 2) != 0 {
6492 t += 4 + 4 * cab.decode_decision(base + 2) as u32;
6493 }
6494 t += 2 * cab.decode_decision(base + 3) as u32;
6495 t += cab.decode_decision(base + 3) as u32;
6496 t
6497}
6498
6499#[doc(hidden)]
6505pub fn parse_mb_type_b(cab: &mut crate::cabac::Cabac, ctx_inc: usize) -> u32 {
6506 parse_mb_type_b_cabac(cab, ctx_inc)
6507}
6508
6509fn parse_mb_type_b_cabac(cab: &mut crate::cabac::Cabac, ctx_inc: usize) -> u32 {
6510 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
6511 const B: usize = 27;
6512 if cab.decode_decision(B + ctx_inc) == 0 {
6513 return 0; }
6515 if cab.decode_decision(B + 3) == 0 {
6516 return 1 + cab.decode_decision(B + 5) as u32; }
6518 let mut m = (cab.decode_decision(B + 4) as u32) << 3;
6519 m |= (cab.decode_decision(B + 5) as u32) << 2;
6520 m |= (cab.decode_decision(B + 5) as u32) << 1;
6521 m |= cab.decode_decision(B + 5) as u32;
6522 if m < 8 {
6523 return m + 3;
6524 }
6525 if m == 13 {
6526 return parse_intra_mb_type_cabac(cab, 32) + 23;
6527 }
6528 if m == 14 {
6529 return 11; }
6531 if m == 15 {
6532 return 22; }
6534 m = (m << 1) | cab.decode_decision(B + 5) as u32;
6535 m - 4
6536}
6537
6538fn parse_sub_mb_type_b_cabac(cab: &mut crate::cabac::Cabac) -> u32 {
6541 const B: usize = 36;
6542 if cab.decode_decision(B) == 0 {
6543 return 0; }
6545 if cab.decode_decision(B + 1) == 0 {
6546 return 1 + cab.decode_decision(B + 3) as u32; }
6548 let mut st = 3u32;
6549 if cab.decode_decision(B + 2) != 0 {
6550 if cab.decode_decision(B + 3) != 0 {
6551 return 11 + cab.decode_decision(B + 3) as u32; }
6553 st += 4;
6554 }
6555 st += 2 * cab.decode_decision(B + 3) as u32;
6556 st += cab.decode_decision(B + 3) as u32;
6557 st
6558}
6559
6560fn parse_mvd_partition(
6564 cab: &mut crate::cabac::Cabac,
6565 part_idx: usize,
6566 zblocks: &[usize],
6567 mvdc: &mut [[i16; 2]; 30],
6568 refc: &mut [i8; 30],
6569 mmvd: &mut [[i16; 2]; 16],
6570 mref: &mut [i8; 16],
6571 ref_idx: i8,
6572) -> (i32, i32) {
6573 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
6574 let s = CACHE30[part_idx];
6575 let ctx = |comp: usize| -> usize {
6576 let mut a = 0i32;
6577 if refc[s - 6] >= 0 {
6578 a += mvdc[s - 6][comp].unsigned_abs() as i32;
6579 }
6580 if refc[s - 1] >= 0 {
6581 a += mvdc[s - 1][comp].unsigned_abs() as i32;
6582 }
6583 if a >= 3 {
6584 1 + (a > 32) as usize
6585 } else {
6586 0
6587 }
6588 };
6589 let (cx, cy) = (ctx(0), ctx(1));
6590 let mvx = parse_mvd_cabac(cab, 0, cx);
6591 let mvy = parse_mvd_cabac(cab, 1, cy);
6592 for &zb in zblocks {
6593 mvdc[CACHE30[zb]] = [mvx, mvy];
6594 refc[CACHE30[zb]] = ref_idx;
6595 mmvd[G_SCAN4[zb]] = [mvx, mvy];
6596 mref[G_SCAN4[zb]] = ref_idx;
6597 }
6598 (mvx as i32, mvy as i32)
6599}
6600
6601fn parse_ref_idx_cabac(cab: &mut crate::cabac::Cabac, ctx0: usize) -> i8 {
6604 const B: usize = 54;
6605 let mut r = 0i8;
6606 let mut bin_idx = 0u32;
6607 while bin_idx < 32 {
6611 let ctx = match bin_idx {
6612 0 => ctx0,
6613 1 => 4,
6614 _ => 5,
6615 };
6616 if cab.decode_decision(B + ctx) == 0 {
6617 break;
6618 }
6619 r += 1;
6620 bin_idx += 1;
6621 }
6622 r
6623}
6624
6625fn decode_ueg_mv(cab: &mut crate::cabac::Cabac, base: usize) -> u32 {
6628 const P2C: [usize; 8] = [0, 1, 2, 3, 3, 3, 3, 3];
6629 if cab.decode_decision(base) == 0 {
6630 return 0;
6631 }
6632 let mut code = 0u32;
6633 let mut count = 1usize;
6634 let mut tmp;
6635 loop {
6636 tmp = cab.decode_decision(base + P2C[count]);
6637 code += 1;
6638 count += 1;
6639 if tmp == 0 || count == 8 {
6640 break;
6641 }
6642 }
6643 if tmp != 0 {
6644 code += cabac_exp_bypass(cab, 3) + 1;
6645 }
6646 code
6647}
6648
6649fn parse_mvd_cabac(cab: &mut crate::cabac::Cabac, comp: usize, ctx_inc: usize) -> i16 {
6652 let base = 40 + comp * 7; if cab.decode_decision(base + ctx_inc) == 0 {
6654 return 0;
6655 }
6656 let mag = (decode_ueg_mv(cab, base + 3) + 1) as i16;
6657 if cab.decode_bypass() != 0 {
6658 -mag
6659 } else {
6660 mag
6661 }
6662}
6663
6664fn parse_mb_skip_cabac(cab: &mut crate::cabac::Cabac, ctx_inc: usize) -> bool {
6667 cab.decode_decision(ctx_inc) != 0
6668}
6669
6670fn parse_mb_type_p_cabac(cab: &mut crate::cabac::Cabac) -> u32 {
6673 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
6674 const S: usize = 11; if cab.decode_decision(S + 3) == 0 {
6676 return if cab.decode_decision(S + 4) != 0 {
6678 if cab.decode_decision(S + 6) != 0 { 1 } else { 2 }
6679 } else if cab.decode_decision(S + 5) != 0 {
6680 3
6681 } else {
6682 0
6683 };
6684 }
6685 if cab.decode_decision(S + 6) == 0 {
6687 return 5; }
6689 if cab.decode_terminate() {
6690 return 30; }
6692 let mut t = 6 + cab.decode_decision(S + 7) * 12;
6693 if cab.decode_decision(S + 8) != 0 {
6694 t += 4;
6695 if cab.decode_decision(S + 8) != 0 {
6696 t += 4;
6697 }
6698 }
6699 t += cab.decode_decision(S + 9) << 1;
6700 t += cab.decode_decision(S + 9);
6701 t
6702}
6703
6704fn parse_mb_type_i_cabac(cab: &mut crate::cabac::Cabac, ctx_inc: usize) -> u32 {
6709 const O: usize = 3; if cab.decode_decision(O + ctx_inc) == 0 {
6711 return 0; }
6713 if cab.decode_terminate() {
6714 return 25; }
6716 let mut t = 1 + cab.decode_decision(O + 3) * 12; if cab.decode_decision(O + 4) != 0 {
6718 t += 4; if cab.decode_decision(O + 5) != 0 {
6720 t += 4;
6721 }
6722 }
6723 t += cab.decode_decision(O + 6) << 1; t += cab.decode_decision(O + 7);
6725 t
6726}
6727
6728fn parse_intra4x4_pred_mode_cabac(cab: &mut crate::cabac::Cabac) -> i32 {
6732 const IPR: usize = 68;
6733 if cab.decode_decision(IPR) == 1 {
6734 return -1; }
6736 let mut m = cab.decode_decision(IPR + 1) as i32;
6737 m |= (cab.decode_decision(IPR + 1) as i32) << 1;
6738 m |= (cab.decode_decision(IPR + 1) as i32) << 2;
6739 m
6740}
6741
6742fn parse_intra_chroma_pred_mode_cabac(cab: &mut crate::cabac::Cabac, ctx_inc: usize) -> u32 {
6746 const CIPR: usize = 64;
6747 if cab.decode_decision(CIPR + ctx_inc) == 0 {
6748 return 0;
6749 }
6750 if cab.decode_decision(CIPR + 3) == 0 {
6751 return 1;
6752 }
6753 if cab.decode_decision(CIPR + 3) == 0 {
6754 return 2;
6755 }
6756 3
6757}
6758
6759fn parse_cbp_cabac(cab: &mut crate::cabac::Cabac, top: Option<u8>, left: Option<u8>) -> u32 {
6764 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Syntax);
6765 const CBP: usize = 73;
6766 let t = |m: u32| top.map_or(0u32, |c| ((c as u32 & m) == 0) as u32);
6767 let l = |m: u32| left.map_or(0u32, |c| ((c as u32 & m) == 0) as u32);
6768 let nb = |x: u32| (x == 0) as u32; let b0 = cab.decode_decision(CBP + (l(1 << 1) + (t(1 << 2) << 1)) as usize);
6771 let b1 = cab.decode_decision(CBP + (nb(b0) + (t(1 << 3) << 1)) as usize);
6772 let b2 = cab.decode_decision(CBP + (l(1 << 3) + (nb(b0) << 1)) as usize);
6773 let b3 = cab.decode_decision(CBP + (nb(b2) + (nb(b1) << 1)) as usize);
6774 let mut cbp = b0 | (b1 << 1) | (b2 << 2) | (b3 << 3);
6775 let ct = top.map_or(0u32, |c| ((c >> 4) != 0) as u32);
6777 let cl = left.map_or(0u32, |c| ((c >> 4) != 0) as u32);
6778 if cab.decode_decision(CBP + 4 + (cl + (ct << 1)) as usize) != 0 {
6779 let ct2 = top.map_or(0u32, |c| ((c >> 4) == 2) as u32);
6780 let cl2 = left.map_or(0u32, |c| ((c >> 4) == 2) as u32);
6781 let c1 = cab.decode_decision(CBP + 8 + (cl2 + (ct2 << 1)) as usize);
6782 cbp |= 1 << (4 + c1);
6783 }
6784 cbp
6785}
6786
6787fn read_ref_idx(r: &mut BitReader, num_ref_active: usize) -> Result<i32, OutOfData> {
6788 if num_ref_active == 2 {
6789 Ok(if r.read_bit()? { 0 } else { 1 }) } else {
6791 Ok(r.read_ue()? as i32)
6792 }
6793}
6794
6795#[derive(Clone, Copy, PartialEq)]
6797enum BPred {
6798 L0,
6799 L1,
6800 Bi,
6801}
6802impl BPred {
6803 fn uses(self, list: usize) -> bool {
6805 matches!(
6806 (self, list),
6807 (BPred::L0, 0) | (BPred::L1, 1) | (BPred::Bi, 0) | (BPred::Bi, 1)
6808 )
6809 }
6810}
6811
6812const B16X16: &[(usize, usize, usize, usize)] = &[(0, 0, 16, 16)];
6813const B16X8: &[(usize, usize, usize, usize)] = &[(0, 0, 16, 8), (0, 8, 16, 8)];
6814const B8X16: &[(usize, usize, usize, usize)] = &[(0, 0, 8, 16), (8, 0, 8, 16)];
6815
6816type Region = (usize, usize, usize, usize);
6818
6819pub fn b_inter_shape(mb_type: u32) -> (u8, u8, u8) {
6825 let (_, mvmode, preds) = b_inter_layout(mb_type);
6826 let code = |p: BPred| match (p.uses(0), p.uses(1)) {
6827 (true, true) => 3,
6828 (true, false) => 1,
6829 _ => 2,
6830 };
6831 (mvmode, code(preds[0]), code(preds[1]))
6832}
6833
6834fn b_inter_layout(mb_type: u32) -> (&'static [Region], u8, [BPred; 2]) {
6835 use BPred::*;
6836 match mb_type {
6837 1 => (B16X16, 0, [L0, L0]),
6838 2 => (B16X16, 0, [L1, L1]),
6839 3 => (B16X16, 0, [Bi, Bi]),
6840 4 => (B16X8, 1, [L0, L0]),
6841 5 => (B8X16, 2, [L0, L0]),
6842 6 => (B16X8, 1, [L1, L1]),
6843 7 => (B8X16, 2, [L1, L1]),
6844 8 => (B16X8, 1, [L0, L1]),
6845 9 => (B8X16, 2, [L0, L1]),
6846 10 => (B16X8, 1, [L1, L0]),
6847 11 => (B8X16, 2, [L1, L0]),
6848 12 => (B16X8, 1, [L0, Bi]),
6849 13 => (B8X16, 2, [L0, Bi]),
6850 14 => (B16X8, 1, [L1, Bi]),
6851 15 => (B8X16, 2, [L1, Bi]),
6852 16 => (B16X8, 1, [Bi, L0]),
6853 17 => (B8X16, 2, [Bi, L0]),
6854 18 => (B16X8, 1, [Bi, L1]),
6855 19 => (B8X16, 2, [Bi, L1]),
6856 20 => (B16X8, 1, [Bi, Bi]),
6857 _ => (B8X16, 2, [Bi, Bi]), }
6859}
6860
6861fn b_sub_uses(st: u32, list: usize) -> bool {
6863 let pred = match st {
6864 1 | 4 | 5 | 10 => 0, 2 | 6 | 7 | 11 => 1, _ => 2, };
6868 (list == 0 && pred != 1) || (list == 1 && pred != 0)
6869}
6870
6871fn b_sub_parts(st: u32) -> &'static [(usize, usize, usize, usize)] {
6873 match st {
6874 1..=3 => &[(0, 0, 8, 8)],
6875 4 | 6 | 8 => &[(0, 0, 8, 4), (0, 4, 8, 4)],
6876 5 | 7 | 9 => &[(0, 0, 4, 8), (4, 0, 4, 8)],
6877 _ => &[(0, 0, 4, 4), (4, 0, 4, 4), (0, 4, 4, 4), (4, 4, 4, 4)], }
6879}
6880
6881fn sub_mb_partitions(sub_type: u32) -> &'static [(usize, usize, usize, usize)] {
6884 match sub_type {
6885 0 => &[(0, 0, 8, 8)],
6886 1 => &[(0, 0, 8, 4), (0, 4, 8, 4)],
6887 2 => &[(0, 0, 4, 8), (4, 0, 4, 8)],
6888 _ => &[(0, 0, 4, 4), (4, 0, 4, 4), (0, 4, 4, 4), (4, 4, 4, 4)],
6889 }
6890}
6891
6892#[inline]
6902fn restride(dst: &mut [u8], dst_stride: usize, x0: usize, y0: usize, src: &[u8], w: usize, h: usize) {
6903 macro_rules! rows {
6904 ($n:expr) => {{
6905 for dy in 0..h {
6906 dst[(y0 + dy) * dst_stride + x0..][..$n].copy_from_slice(&src[dy * $n..][..$n]);
6907 }
6908 }};
6909 }
6910 match w {
6911 16 => rows!(16),
6912 8 => rows!(8),
6913 4 => rows!(4),
6914 2 => rows!(2),
6915 _ => {
6916 for dy in 0..h {
6917 dst[(y0 + dy) * dst_stride + x0..][..w].copy_from_slice(&src[dy * w..][..w]);
6918 }
6919 }
6920 }
6921}
6922
6923fn store(plane: &mut [u8], stride: usize, x0: usize, y0: usize, s: &[u8; 16]) {
6924 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Scatter);
6925 for dy in 0..4 {
6926 for dx in 0..4 {
6927 plane[(y0 + dy) * stride + (x0 + dx)] = s[dy * 4 + dx];
6928 }
6929 }
6930}
6931
6932fn un_scan_8x8(scan: &[i32; 64]) -> [i32; 64] {
6934 const ZZ8: [usize; 64] = [
6935 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27,
6936 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
6937 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
6938 ];
6939 let mut out = [0i32; 64];
6940 for k in 0..64 {
6941 out[ZZ8[k]] = scan[k];
6942 }
6943 out
6944}
6945
6946#[cfg(test)]
6947mod tests {
6948 use super::*;
6949
6950 fn fd(qp: u8, offset: i32) -> FrameDecoder {
6951 FrameDecoder::new(1, 1, qp, offset, Vec::new(), 1, false, false, true)
6952 }
6953
6954 #[test]
6955 fn mb_qp_delta_accumulates_mod_52() {
6956 let mut d = fd(26, 0);
6957 assert_eq!(d.cur_qp, 26, "QPy starts at the slice QP");
6958 d.step_qp(4);
6959 assert_eq!(d.cur_qp, 30); d.step_qp(-10);
6961 assert_eq!(d.cur_qp, 20); d.step_qp(40);
6964 assert_eq!(d.cur_qp, 8);
6965 d.step_qp(-20);
6967 assert_eq!(d.cur_qp, 40);
6968 }
6969
6970 #[test]
6971 fn chroma_qp_index_offset_applied_and_clamped() {
6972 assert_eq!(fd(0, 0).chroma_qp_for(30), 29);
6974 assert_eq!(fd(0, 2).chroma_qp_for(30), 31);
6976 assert_eq!(fd(0, -12).chroma_qp_for(5), chroma_qp(0));
6978 assert_eq!(fd(0, 99).chroma_qp_for(40), chroma_qp(51));
6979 }
6980}