1mod cabac;
26#[cfg(feature = "profile")]
28pub use cabac::bin_census;
29mod frame_mt;
30mod mb16;
31mod params;
32
33pub use params::{Pps, Sps};
34pub use mb16::{MvField, MV_DUMP};
35
36pub fn edc_stats_report() {
38 mb16::edcstat::report();
39 rusty_h264_common::deblock::filtstat::report();
40}
41
42#[doc(hidden)]
45fn abl_deblock() -> bool {
48 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
49 *ON.get_or_init(|| std::env::var("RFF_ABL_DEBLOCK").map_or(false, |v| v != "0"))
50}
51
52pub mod cabac_test {
53 pub use crate::cabac::Cabac;
54 pub use crate::mb16::b_inter_shape;
55 pub use crate::mb16::parse_cbp_cabac;
56 pub use crate::mb16::parse_mb_qp_delta_cabac;
57 pub use crate::mb16::parse_mb_type_b;
58 pub use crate::mb16::parse_ref_idx_cabac;
59}
60
61use mb16::{FrameDecoder, GridPool, WeightTable};
62use rusty_h264_common::bit_reader::OutOfData;
63use rusty_h264_common::nal::{emulation_unprevent, split_annex_b};
64use rusty_h264_common::{BitReader, NalUnitType, YuvFrame};
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68pub enum DecodeError {
69 Truncated,
71 MissingParameterSet,
73 Unsupported(&'static str),
75}
76
77impl From<OutOfData> for DecodeError {
78 fn from(_: OutOfData) -> Self {
79 DecodeError::Truncated
80 }
81}
82
83impl core::fmt::Display for DecodeError {
84 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 match self {
86 DecodeError::Truncated => f.write_str("bitstream truncated"),
87 DecodeError::MissingParameterSet => f.write_str("slice before SPS/PPS"),
88 DecodeError::Unsupported(s) => write!(f, "unsupported coding tool: {s}"),
89 }
90 }
91}
92
93impl std::error::Error for DecodeError {}
94
95pub(crate) type Ref = std::sync::Arc<RefFrame>;
104
105#[derive(Debug, Default)]
106#[allow(dead_code)]
107pub(crate) struct RefFrame {
108 pub py: Vec<u8>,
114 pub pu: Vec<u8>,
115 pub pv: Vec<u8>,
116 pub cw: usize,
117 pub ch: usize,
118 pub ready_rows: std::sync::atomic::AtomicUsize,
122 pub live: Option<std::sync::Arc<LivePlanes>>,
127 pub frozen: std::sync::OnceLock<FrozenPlanes>,
130 pub frame_num: u32,
132 pub poc: i32,
134 pub mv: Vec<(i32, i32)>,
138 pub ref_idx: Vec<i32>,
139 pub mv1: Vec<(i32, i32)>,
146 pub ref_idx1: Vec<i32>,
147 pub ref_poc: Vec<i32>,
151 pub w4: usize,
152 pub long_term: bool,
156 pub long_term_idx: u32,
157}
158
159impl Clone for RefFrame {
160 fn clone(&self) -> Self {
161 use std::sync::atomic::Ordering::Relaxed;
162 let frozen = std::sync::OnceLock::new();
163 if let Some(p) = self.frozen.get() {
164 let _ = frozen.set(p.clone());
165 }
166 Self {
167 py: self.py.clone(),
168 pu: self.pu.clone(),
169 pv: self.pv.clone(),
170 cw: self.cw,
171 ch: self.ch,
172 ready_rows: std::sync::atomic::AtomicUsize::new(self.ready_rows.load(Relaxed)),
173 live: self.live.clone(),
174 frozen,
175 frame_num: self.frame_num,
176 poc: self.poc,
177 mv: self.mv.clone(),
178 ref_idx: self.ref_idx.clone(),
179 mv1: self.mv1.clone(),
180 ref_idx1: self.ref_idx1.clone(),
181 ref_poc: self.ref_poc.clone(),
182 w4: self.w4,
183 long_term: self.long_term,
184 long_term_idx: self.long_term_idx,
185 }
186 }
187}
188
189pub(crate) const LPAD: usize = 16;
193pub(crate) const CPAD: usize = 8;
194
195thread_local! {
196 static MC_ROW_NEED: std::cell::Cell<usize> = const { std::cell::Cell::new(usize::MAX) };
198}
199
200#[derive(Debug, Clone)]
202pub(crate) struct FrozenPlanes {
203 pub py: Vec<u8>,
204 pub pu: Vec<u8>,
205 pub pv: Vec<u8>,
206}
207
208#[derive(Debug)]
210pub(crate) struct LivePlanes {
211 pub py: std::sync::RwLock<Vec<u8>>,
212 pub pu: std::sync::RwLock<Vec<u8>>,
213 pub pv: std::sync::RwLock<Vec<u8>>,
214 pub meta: std::sync::RwLock<LiveMeta>,
216 pub wait: std::sync::Mutex<()>,
218 pub cv: std::sync::Condvar,
219}
220
221#[derive(Debug, Clone, Default)]
222pub(crate) struct LiveMeta {
223 pub frame_num: u32,
224 pub poc: i32,
225 pub long_term: bool,
226 pub long_term_idx: u32,
227 pub mv: Vec<(i32, i32)>,
228 pub ref_idx: Vec<i32>,
229 pub mv1: Vec<(i32, i32)>,
230 pub ref_idx1: Vec<i32>,
231 pub ref_poc: Vec<i32>,
232 pub w4: usize,
233 pub motion_ready: bool,
235}
236
237pub(crate) enum PlaneGuard<'a> {
239 Borrowed(&'a [u8]),
240 Locked(std::sync::RwLockReadGuard<'a, Vec<u8>>),
241}
242
243impl std::ops::Deref for PlaneGuard<'_> {
244 type Target = [u8];
245 fn deref(&self) -> &[u8] {
246 match self {
247 Self::Borrowed(s) => s,
248 Self::Locked(g) => g.as_slice(),
249 }
250 }
251}
252
253impl RefFrame {
254 #[inline]
256 pub(crate) fn rows_needed_for_mb(mb_y: usize, ch: usize) -> usize {
257 ((mb_y + 1) * 16 + LPAD).min(ch.max(1))
258 }
259
260 #[inline]
264 pub(crate) fn set_mc_row_need(mb_y: usize, ch: usize) {
265 if !crate::frame_mt::row_progress_on() {
268 return;
269 }
270 MC_ROW_NEED.with(|c| c.set(Self::rows_needed_for_mb(mb_y, ch)));
271 }
272
273 #[inline]
274 fn effective_need(&self, need_rows: usize) -> usize {
275 let hint = MC_ROW_NEED.with(|c| c.get());
276 need_rows.min(hint).min(self.ch.max(1))
277 }
278
279 #[inline]
282 pub(crate) fn luma_guard(&self, need_rows: usize) -> PlaneGuard<'_> {
283 if self.live.is_none() {
284 if let Some(f) = self.frozen.get() {
286 return PlaneGuard::Borrowed(&f.py);
287 }
288 return PlaneGuard::Borrowed(&self.py);
289 }
290 let need = self.effective_need(need_rows);
291 self.wait_ready_rows(need);
292 if let Some(f) = self.frozen.get() {
293 return PlaneGuard::Borrowed(&f.py);
294 }
295 if !self.py.is_empty() {
296 return PlaneGuard::Borrowed(&self.py);
297 }
298 if let Some(live) = &self.live {
299 PlaneGuard::Locked(live.py.read().unwrap())
300 } else {
301 PlaneGuard::Borrowed(&self.py)
302 }
303 }
304
305 #[inline]
306 pub(crate) fn chroma_guard(&self, plane: usize, need_rows: usize) -> PlaneGuard<'_> {
307 if self.live.is_none() {
308 if let Some(f) = self.frozen.get() {
309 return if plane == 0 {
310 PlaneGuard::Borrowed(&f.pu)
311 } else {
312 PlaneGuard::Borrowed(&f.pv)
313 };
314 }
315 return if plane == 0 {
316 PlaneGuard::Borrowed(&self.pu)
317 } else {
318 PlaneGuard::Borrowed(&self.pv)
319 };
320 }
321 let need = self.effective_need(need_rows);
322 self.wait_ready_rows(need);
323 if let Some(f) = self.frozen.get() {
324 return if plane == 0 {
325 PlaneGuard::Borrowed(&f.pu)
326 } else {
327 PlaneGuard::Borrowed(&f.pv)
328 };
329 }
330 if !self.py.is_empty() {
331 return if plane == 0 {
332 PlaneGuard::Borrowed(&self.pu)
333 } else {
334 PlaneGuard::Borrowed(&self.pv)
335 };
336 }
337 if let Some(live) = &self.live {
338 if plane == 0 {
339 PlaneGuard::Locked(live.pu.read().unwrap())
340 } else {
341 PlaneGuard::Locked(live.pv.read().unwrap())
342 }
343 } else if plane == 0 {
344 PlaneGuard::Borrowed(&self.pu)
345 } else {
346 PlaneGuard::Borrowed(&self.pv)
347 }
348 }
349 pub(crate) fn new_progress_slot(cw: usize, ch: usize, b_possible: bool, mb_w: usize) -> Ref {
350 let (lpw, lph) = (cw + 2 * LPAD, ch + 2 * LPAD);
351 let (cpw, cph) = (cw / 2 + 2 * CPAD, ch / 2 + 2 * CPAD);
352 let w4 = if b_possible { mb_w * 4 } else { 0 };
353 let n4 = if b_possible {
354 mb_w * 4 * (ch / 16) * 4
355 } else {
356 0
357 };
358 let (py, pu, pv) = if crate::frame_mt::row_publish_on() {
361 (
362 vec![0; lpw * lph],
363 vec![0; cpw * cph],
364 vec![0; cpw * cph],
365 )
366 } else {
367 (Vec::new(), Vec::new(), Vec::new())
368 };
369 std::sync::Arc::new(RefFrame {
370 py: Vec::new(),
371 pu: Vec::new(),
372 pv: Vec::new(),
373 cw,
374 ch,
375 ready_rows: std::sync::atomic::AtomicUsize::new(0),
376 live: Some(std::sync::Arc::new(LivePlanes {
377 py: std::sync::RwLock::new(py),
378 pu: std::sync::RwLock::new(pu),
379 pv: std::sync::RwLock::new(pv),
380 meta: std::sync::RwLock::new(LiveMeta {
381 mv: vec![(0, 0); n4],
382 ref_idx: vec![-1; n4],
383 mv1: vec![(0, 0); n4],
384 ref_idx1: vec![-1; n4],
385 ref_poc: vec![i32::MIN; n4],
386 w4,
387 ..LiveMeta::default()
388 }),
389 wait: std::sync::Mutex::new(()),
390 cv: std::sync::Condvar::new(),
391 })),
392 frozen: std::sync::OnceLock::new(),
393 frame_num: 0,
394 poc: 0,
395 mv: vec![(0, 0); n4],
396 ref_idx: vec![-1; n4],
397 mv1: vec![(0, 0); n4],
398 ref_idx1: vec![-1; n4],
399 ref_poc: vec![i32::MIN; n4],
400 w4,
401 long_term: false,
402 long_term_idx: 0,
403 })
404 }
405
406 pub(crate) fn init_progress_identity(slot: &mut Ref, frame_num: u32, poc: i32) {
408 if let Some(s) = std::sync::Arc::get_mut(slot) {
409 s.frame_num = frame_num;
410 s.poc = poc;
411 if let Some(live) = &s.live {
412 let mut m = live.meta.write().unwrap();
413 m.frame_num = frame_num;
414 m.poc = poc;
415 }
416 }
417 }
418
419 #[inline]
420 pub(crate) fn fn_num(&self) -> u32 {
421 if let Some(live) = &self.live {
422 live.meta.read().unwrap().frame_num
423 } else {
424 self.frame_num
425 }
426 }
427
428 #[inline]
429 pub(crate) fn pic_poc(&self) -> i32 {
430 if let Some(live) = &self.live {
431 live.meta.read().unwrap().poc
432 } else {
433 self.poc
434 }
435 }
436
437 #[inline]
438 pub(crate) fn is_long_term(&self) -> bool {
439 if let Some(live) = &self.live {
440 live.meta.read().unwrap().long_term
441 } else {
442 self.long_term
443 }
444 }
445
446 #[inline]
447 pub(crate) fn lt_idx(&self) -> u32 {
448 if let Some(live) = &self.live {
449 live.meta.read().unwrap().long_term_idx
450 } else {
451 self.long_term_idx
452 }
453 }
454
455 pub(crate) fn set_long_term_marks(&self, long_term: bool, idx: u32) {
456 if let Some(live) = &self.live {
457 let mut m = live.meta.write().unwrap();
458 m.long_term = long_term;
459 m.long_term_idx = idx;
460 }
461 }
462
463 pub(crate) fn set_frame_num_live(&self, frame_num: u32) {
464 if let Some(live) = &self.live {
465 live.meta.write().unwrap().frame_num = frame_num;
466 }
467 }
468
469 pub(crate) fn wait_motion_ready(&self) {
471 if self.live.is_none() {
472 return;
473 }
474 if let Some(live) = &self.live {
475 if live.meta.read().unwrap().motion_ready {
476 return;
477 }
478 }
479 if let Some(live) = &self.live {
480 let mut g = live.wait.lock().unwrap();
481 while !live.meta.read().unwrap().motion_ready {
482 g = live.cv.wait(g).unwrap();
483 }
484 }
485 }
486
487 #[inline]
489 pub fn mark_fully_ready(&self) {
490 if let Some(live) = &self.live {
491 let _g = live.wait.lock().unwrap();
492 self.ready_rows
493 .store(self.ch, std::sync::atomic::Ordering::Release);
494 live.cv.notify_all();
495 } else {
496 self.ready_rows
497 .store(self.ch, std::sync::atomic::Ordering::Release);
498 }
499 }
500
501 #[inline]
503 pub fn publish_ready_rows(&self, rows: usize) {
504 let r = rows.min(self.ch);
505 if let Some(live) = &self.live {
506 let _g = live.wait.lock().unwrap();
507 let prev = self
508 .ready_rows
509 .fetch_max(r, std::sync::atomic::Ordering::Release);
510 if r > prev {
511 live.cv.notify_all();
512 }
513 } else {
514 let _ = self
515 .ready_rows
516 .fetch_max(r, std::sync::atomic::Ordering::Release);
517 }
518 }
519
520 #[inline]
523 pub fn wait_ready_rows(&self, rows: usize) {
524 use std::sync::atomic::Ordering::Acquire;
525 let need = rows.min(self.ch);
526 if need == 0 || self.ready_rows.load(Acquire) >= need {
527 return;
528 }
529 if self.frozen.get().is_some() {
530 return;
531 }
532 if let Some(live) = &self.live {
533 let mut g = live.wait.lock().unwrap();
534 while self.ready_rows.load(Acquire) < need {
535 g = live.cv.wait(g).unwrap();
536 }
537 } else {
538 while self.ready_rows.load(Acquire) < need {
539 std::thread::yield_now();
540 }
541 }
542 }
543
544 #[inline]
545 pub fn lstride(&self) -> usize {
546 self.cw + 2 * LPAD
547 }
548 #[inline]
549 pub fn cstride(&self) -> usize {
550 self.cw / 2 + 2 * CPAD
551 }
552 #[inline]
559 pub fn lrows(&self) -> usize {
560 self.ch + 2 * LPAD
561 }
562 #[inline]
564 pub fn crows(&self) -> usize {
565 self.ch / 2 + 2 * CPAD
566 }
567}
568
569#[derive(Clone, Copy)]
571enum Mmco {
572 Unref(u32),
574 UnrefLong(u32),
576 AssignLong(u32, u32),
578 MaxLong(u32),
580 Reset,
582 CurrentLong(u32),
584}
585
586#[derive(Clone, Copy, PartialEq, Eq, Debug)]
593pub enum ContentRoute {
594 Light,
595 Mid,
596 DenseInter,
597 EntropyExtreme,
598}
599
600fn route_for(cabac: bool, t8x8: bool, bits_per_mb: f64, skip_frac: f64, coded_frac: f64) -> ContentRoute {
605 let (root_coded, light_skip, extreme_bits) = if !cabac {
609 (0.6116, 0.6433, 406.4)
610 } else if t8x8 {
611 (0.4244, 0.6358, 331.7)
612 } else {
613 (0.3709, 0.6343, 315.2)
614 };
615 if coded_frac <= root_coded {
616 if skip_frac > light_skip {
617 ContentRoute::Light
618 } else {
619 ContentRoute::Mid
620 }
621 } else if bits_per_mb <= extreme_bits {
622 ContentRoute::DenseInter
623 } else {
624 ContentRoute::EntropyExtreme
625 }
626}
627
628struct PendingPic {
629 fd: mb16::FrameDecoder,
630 frame_num: u32,
631 poc: i32,
632 next_mb: usize,
633 total_mb: usize,
634 slice_count: u16,
635 deblock: bool,
636 filter_offset_a: i32,
637 filter_offset_b: i32,
638 crop_r: usize,
639 crop_b: usize,
640 max_refs: usize,
641 log2_max_frame_num: u32,
642 is_reference: bool,
645 idr_long_term: bool,
646 mmco_ops: Vec<Mmco>,
647 route_bits: u64,
649 route_cabac: bool,
650 route_t8x8: bool,
651}
652
653fn no_pool() -> bool {
655 use std::sync::atomic::{AtomicU8, Ordering};
656 static ON: AtomicU8 = AtomicU8::new(0);
657 match ON.load(Ordering::Relaxed) {
658 0 => {
659 let v = std::env::var_os("RS_H264_NO_POOL").is_some_and(|v| v == "1");
660 ON.store(if v { 1 } else { 2 }, Ordering::Relaxed);
661 v
662 }
663 n => n == 1,
664 }
665}
666
667#[derive(Default)]
670pub struct Decoder {
671 last_route: Option<ContentRoute>,
673 route_ema: Option<(f64, f64, f64)>,
679 pub(crate) sps: std::collections::HashMap<u32, std::sync::Arc<Sps>>,
684 pub(crate) pps: std::collections::HashMap<u32, std::sync::Arc<Pps>>,
685 pub(crate) refs: Vec<Ref>,
687 cur: Option<PendingPic>,
689 pub(crate) poc: PocState,
693 pub(crate) last_poc: i32,
695 pub(crate) prev_ref_frame_num: u32,
698 grid_pool: GridPool,
701 sc_reorder0: Vec<(u32, u32)>,
703 sc_reorder1: Vec<(u32, u32)>,
704 sc_mmco: Vec<Mmco>,
705 plane_pool: Vec<Vec<u8>>,
708 retired: Vec<Ref>,
713 pub(crate) detach_dpb: bool,
716 pub(crate) detached_ref: Option<Ref>,
718 pub(crate) progress_slot: Option<Ref>,
720 detached_mmco: Vec<Mmco>,
721 detached_frame_num: u32,
722 detached_log2_max_frame_num: u32,
723 detached_max_refs: usize,
724 detached_idr_long_term: bool,
725 pub(crate) frame_mt_row_progress: bool,
727}
728
729#[derive(Clone, Default)]
731pub(crate) struct PocState {
732 prev_msb: i32,
733 prev_lsb: i32,
734 prev_frame_num: u32,
735 prev_frame_num_offset: i64,
736}
737
738impl PocState {
739 pub(crate) fn compute_poc(
743 &mut self,
744 sps: &Sps,
745 is_idr: bool,
746 nal_ref_idc: u8,
747 frame_num: u32,
748 poc_lsb: u32,
749 delta_bottom: i32,
750 ) -> i32 {
751 match sps.pic_order_cnt_type {
752 0 => {
753 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
754 let (prev_msb, prev_lsb) =
755 if is_idr { (0, 0) } else { (self.prev_msb, self.prev_lsb) };
756 let lsb = poc_lsb as i32;
757 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
758 prev_msb + max_lsb
759 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
760 prev_msb - max_lsb
761 } else {
762 prev_msb
763 };
764 let top = msb + lsb;
765 let poc = top.min(top + delta_bottom);
766 if nal_ref_idc != 0 {
767 self.prev_msb = msb;
768 self.prev_lsb = lsb;
769 }
770 poc
771 }
772 2 => {
773 let max_fn = 1i64 << sps.log2_max_frame_num;
774 let offset = if is_idr {
775 0
776 } else if self.prev_frame_num > frame_num {
777 self.prev_frame_num_offset + max_fn
778 } else {
779 self.prev_frame_num_offset
780 };
781 let poc = if is_idr {
782 0
783 } else {
784 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
785 };
786 self.prev_frame_num_offset = offset;
787 self.prev_frame_num = frame_num;
788 poc as i32
789 }
790 _ => {
791 self.prev_frame_num = frame_num;
792 frame_num as i32 * 2
793 }
794 }
795 }
796}
797
798impl Decoder {
799 pub fn new() -> Self {
801 Self::default()
802 }
803
804 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
807 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
808 let mut frame = None;
809 let nals = {
813 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecNalSplit);
814 split_annex_b(annex_b)
815 };
816 for nal in nals {
817 if nal.is_empty() {
818 continue;
819 }
820 let nal_type = NalUnitType::from_id(nal[0]);
821 let rbsp = {
822 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecRbsp);
823 emulation_unprevent(&nal[1..])
824 };
825 match nal_type {
826 NalUnitType::Sps => {
827 let s = Sps::parse(&rbsp)?;
828 self.sps.insert(s.seq_parameter_set_id, std::sync::Arc::new(s));
829 }
830 NalUnitType::Pps => {
831 let p = Pps::parse(&rbsp)?;
832 self.pps.insert(p.pic_parameter_set_id, std::sync::Arc::new(p));
833 }
834 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
835 let nal_ref_idc = (nal[0] >> 5) & 3;
836 let is_idr = nal_type == NalUnitType::IdrSlice;
837 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
838 frame = Some(f);
839 }
840 }
841 _ => {} }
843 }
844 Ok(frame)
845 }
846
847 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
860 let n = frame_mt::frame_threads();
861 if n > 1 {
862 return frame_mt::decode_stream_threaded(annex_b, n);
863 }
864 self.decode_stream_serial(annex_b)
865 }
866
867 pub fn decode_stream_threaded(
869 &mut self,
870 annex_b: &[u8],
871 threads: usize,
872 ) -> Result<Vec<YuvFrame>, DecodeError> {
873 if threads <= 1 {
874 return self.decode_stream_serial(annex_b);
875 }
876 frame_mt::decode_stream_threaded(annex_b, threads)
877 }
878
879 pub fn decode_stream_threaded_sink(
882 &mut self,
883 annex_b: &[u8],
884 threads: usize,
885 sink: impl FnMut(YuvFrame),
886 ) -> Result<usize, DecodeError> {
887 if threads <= 1 {
888 let frames = self.decode_stream_serial(annex_b)?;
889 let n = frames.len();
890 let mut sink = sink;
891 for f in frames {
892 sink(f);
893 }
894 return Ok(n);
895 }
896 frame_mt::decode_stream_threaded_sink(annex_b, threads, sink)
897 }
898
899 fn decode_stream_serial(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
900 let mut out = Vec::new();
901 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
902 for au in split_access_units(annex_b) {
903 if au_is_idr(au) {
904 flush_gop(&mut gop, &mut out); }
906 if let Some(frame) = self.decode(au)? {
907 gop.push((self.last_poc, frame));
908 }
909 }
910 flush_gop(&mut gop, &mut out);
911 Ok(out)
912 }
913
914 fn decode_slice(
915 &mut self,
916 rbsp: &[u8],
917 is_idr: bool,
918 nal_ref_idc: u8,
919 ) -> Result<Option<YuvFrame>, DecodeError> {
920 let mut r = BitReader::new(rbsp);
921 let first_mb_in_slice = r.read_ue()? as usize;
923 let slice_type = r.read_ue()?;
924 let is_p = matches!(slice_type, 0 | 5);
925 let is_b = matches!(slice_type, 1 | 6);
926 let is_i = matches!(slice_type, 2 | 7);
927 if !is_p && !is_b && !is_i {
928 return Err(DecodeError::Unsupported("SP/SI slices"));
929 }
930 let pic_parameter_set_id = r.read_ue()?;
932 let pps = self.pps.get(&pic_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
933 let sps = self.sps.get(&pps.seq_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
934 let sps = &sps;
935 let pps = &pps;
936 let cabac = pps.entropy_coding_mode_flag;
940 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
941 if is_idr {
942 let _idr_pic_id = r.read_ue()?;
943 }
944 let mut poc_lsb = 0u32;
947 let mut delta_poc_bottom = 0i32;
948 if sps.pic_order_cnt_type == 0 {
949 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
950 if pps.bottom_field_pic_order_present {
951 delta_poc_bottom = r.read_se()?;
952 }
953 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
954 let _delta_pic_order_cnt_0 = r.read_se()?;
955 if pps.bottom_field_pic_order_present {
956 let _delta_pic_order_cnt_1 = r.read_se()?;
957 }
958 }
959 let pic_poc = if first_mb_in_slice == 0 {
962 self.compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_poc_bottom)
963 } else {
964 self.cur.as_ref().map_or(0, |p| p.poc)
965 };
966 if pps.redundant_pic_cnt_present_flag {
971 let redundant_pic_cnt = r.read_ue()?;
972 if redundant_pic_cnt != 0 {
973 return Ok(None);
974 }
975 }
976 if std::env::var_os("RH264_DUMP_MB").is_some() {
977 eprintln!(
978 "SLICE fn={frame_num} poc={pic_poc} nal_ref_idc={nal_ref_idc} is_p={is_p} is_b={is_b} first_mb={first_mb_in_slice}"
979 );
980 }
981 let direct_spatial = if is_b { r.read_bit()? } else { true };
983 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
984 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
985 let mut reorder_l0: Vec<(u32, u32)> = std::mem::take(&mut self.sc_reorder0);
986 reorder_l0.clear();
987 let mut reorder_l1: Vec<(u32, u32)> = std::mem::take(&mut self.sc_reorder1);
988 reorder_l1.clear();
989 if is_p || is_b {
990 if r.read_bit()? {
992 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
993 if is_b {
994 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
995 }
996 }
997 if r.read_bit()? {
999 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
1000 }
1001 if is_b && r.read_bit()? {
1002 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
1004 }
1005 }
1006 let weights = if is_p && pps.weighted_pred {
1011 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
1012 } else if is_b && pps.weighted_bipred_idc == 1 {
1013 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
1014 } else {
1015 None
1016 };
1017 let mut idr_long_term = false;
1021 let mut mmco_ops: Vec<Mmco> = std::mem::take(&mut self.sc_mmco);
1022 mmco_ops.clear();
1023 if nal_ref_idc == 0 {
1024 } else if is_idr {
1026 let _no_output_of_prior_pics = r.read_bit()?;
1027 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
1029 loop {
1031 let op = r.read_ue()?;
1032 match op {
1033 0 => break,
1034 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
1035 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
1036 3 => {
1037 let diff = r.read_ue()?;
1038 let idx = r.read_ue()?;
1039 mmco_ops.push(Mmco::AssignLong(diff, idx));
1040 }
1041 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
1042 5 => mmco_ops.push(Mmco::Reset),
1043 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
1044 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
1045 }
1046 if mmco_ops.len() > 128 {
1047 return Err(DecodeError::Truncated);
1048 }
1049 }
1050 }
1051 let cabac_init_idc = if cabac && !is_i {
1055 let v = r.read_ue()?;
1056 if v > 2 {
1057 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
1058 }
1059 v
1060 } else {
1061 0
1062 };
1063 let slice_qp_delta = r.read_se()?;
1064 let mut deblock = true;
1069 let mut deblock_idc2 = false;
1070 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
1071 if pps.deblocking_filter_control_present_flag {
1072 let disable_deblocking_filter_idc = r.read_ue()?;
1073 deblock = disable_deblocking_filter_idc != 1;
1077 deblock_idc2 = disable_deblocking_filter_idc == 2;
1078 if disable_deblocking_filter_idc != 1 {
1079 filter_offset_a = r.read_se()? * 2;
1081 filter_offset_b = r.read_se()? * 2;
1082 }
1083 }
1084 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
1085
1086 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
1089 self.insert_frame_num_gaps(
1090 frame_num,
1091 1u32 << sps.log2_max_frame_num,
1092 sps.max_num_ref_frames.max(1) as usize,
1093 sps.pic_width_in_mbs * 16,
1094 sps.pic_height_in_mbs * 16,
1095 );
1096 }
1097
1098 let max_fn = 1u32 << sps.log2_max_frame_num;
1101 let (ref_list0, ref_list1) = if is_b {
1102 build_ref_list_b(
1103 &self.refs, pic_poc, frame_num, max_fn,
1104 num_ref_idx_l0, num_ref_idx_l1, &reorder_l0, &reorder_l1,
1105 )?
1106 } else if is_p {
1107 (build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?, Vec::new())
1108 } else {
1109 (Vec::new(), Vec::new())
1110 };
1111 self.sc_reorder0 = reorder_l0;
1113 self.sc_reorder1 = reorder_l1;
1114 if first_mb_in_slice == 0 {
1118 if is_idr {
1119 self.refs.clear();
1120 }
1121 let _g_setup = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecSetup);
1132 let mut fd = FrameDecoder::with_pool(
1133 sps.pic_width_in_mbs,
1134 sps.pic_height_in_mbs,
1135 slice_qp,
1136 pps.chroma_qp_index_offset,
1137 ref_list0,
1138 num_ref_idx_l0,
1139 pps.constrained_intra_pred_flag,
1140 pps.transform_8x8_mode_flag,
1141 sps.profile_idc != 66, if no_pool() { GridPool::default() } else { std::mem::take(&mut self.grid_pool) },
1146 );
1147 if is_b {
1148 fd.set_b_context(
1149 ref_list1,
1150 num_ref_idx_l1,
1151 direct_spatial,
1152 pic_poc,
1153 pps.weighted_bipred_idc,
1154 sps.direct_8x8_inference,
1155 );
1156 }
1157 if sps.has_scaling || pps.pic_scaling_matrix_present {
1158 let (s4, s8) = resolve_scaling(sps, pps);
1159 fd.set_scaling(s4, s8);
1160 }
1161 fd.set_transform_bypass(sps.transform_bypass);
1162 if let Some(w) = weights {
1163 fd.set_weights(w);
1164 }
1165 if let Some(slot) = self.progress_slot.clone() {
1166 fd.set_progress_slot(slot);
1167 }
1168 if let Some(prev) = self.cur.take() {
1176 if prev.next_mb < prev.total_mb {
1177 return Err(DecodeError::Truncated);
1178 }
1179 }
1180 self.cur = Some(PendingPic {
1181 fd,
1182 frame_num,
1183 poc: pic_poc,
1184 next_mb: 0,
1185 route_bits: 0,
1186 route_cabac: pps.entropy_coding_mode_flag,
1187 route_t8x8: pps.transform_8x8_mode_flag,
1188 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
1189 slice_count: 0,
1190 deblock,
1191 filter_offset_a,
1192 filter_offset_b,
1193 crop_r: sps.frame_crop_right as usize,
1194 crop_b: sps.frame_crop_bottom as usize,
1195 max_refs: sps.max_num_ref_frames.max(1) as usize,
1196 log2_max_frame_num: sps.log2_max_frame_num,
1197 is_reference: nal_ref_idc != 0,
1198 idr_long_term,
1199 mmco_ops,
1200 });
1201 } else {
1202 let Some(pic) = self.cur.as_mut() else {
1204 return Err(DecodeError::Unsupported("slice continues a missing picture"));
1205 };
1206 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
1207 if is_b {
1208 pic.fd.set_b_context(
1209 ref_list1,
1210 num_ref_idx_l1,
1211 direct_spatial,
1212 pic.poc,
1213 pps.weighted_bipred_idc,
1214 sps.direct_8x8_inference,
1215 );
1216 }
1217 if sps.has_scaling || pps.pic_scaling_matrix_present {
1218 let (s4, s8) = resolve_scaling(sps, pps);
1219 pic.fd.set_scaling(s4, s8);
1220 }
1221 pic.fd.set_transform_bypass(sps.transform_bypass);
1222 if let Some(w) = weights {
1223 pic.fd.set_weights(w);
1224 }
1225 pic.deblock = deblock;
1227 pic.filter_offset_a = filter_offset_a;
1228 pic.filter_offset_b = filter_offset_b;
1229 pic.idr_long_term |= idr_long_term;
1230 pic.mmco_ops.extend(mmco_ops);
1231 }
1232
1233 let pic = self.cur.as_mut().expect("pending picture set above");
1234 pic.fd.set_deblock_params(deblock && !abl_deblock(), filter_offset_a, filter_offset_b, deblock_idc2);
1238 let first = first_mb_in_slice.min(pic.total_mb);
1239 pic.route_bits += r.data().len() as u64;
1240 let next = if cabac {
1241 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
1243 let (data, start) = (r.data(), r.bit_pos() / 8);
1244 pic.fd
1245 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
1246 } else {
1247 pic.fd.decode_slice_data(&mut r, is_p, first)
1248 }
1249 .map_err(|e| match e {
1250 mb16::MbError::Truncated => DecodeError::Truncated,
1251 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
1252 })?;
1253 pic.next_mb = next;
1254 pic.slice_count += 1;
1255 if std::env::var_os("RH264_DUMP_MB").is_some() {
1256 eprintln!(
1257 " slice decoded {}/{} MBs{}",
1258 next,
1259 pic.total_mb,
1260 if next < pic.total_mb { " <-- INCOMPLETE" } else { "" }
1261 );
1262 }
1263
1264 if pic.next_mb < pic.total_mb {
1265 return Ok(None); }
1267
1268 let pic = self.cur.take().expect("pending picture");
1270 {
1271 let (skips, coded) = pic.fd.route_counters();
1272 let mbs = pic.total_mb.max(1) as f64;
1273 let bits_per_mb = pic.route_bits as f64 * 8.0 / mbs;
1274 let (skip_frac, coded_frac) = (skips as f64 / mbs, coded as f64 / mbs);
1275 let (eb, es, ec) = match self.route_ema {
1276 None => (bits_per_mb, skip_frac, coded_frac),
1277 Some((pb, ps, pc)) => (
1278 pb + (bits_per_mb - pb) / 8.0,
1279 ps + (skip_frac - ps) / 8.0,
1280 pc + (coded_frac - pc) / 8.0,
1281 ),
1282 };
1283 self.route_ema = Some((eb, es, ec));
1284 let route = route_for(pic.route_cabac, pic.route_t8x8, eb, es, ec);
1285 self.last_route = Some(route);
1286 if std::env::var_os("RS_H264_ROUTE_DUMP").is_some() {
1287 eprintln!(
1288 "ROUTE cabac={} t8x8={} bits_per_mb={bits_per_mb:.2} skip_frac={skip_frac:.4} coded_frac={coded_frac:.4} ema=({eb:.2},{es:.4},{ec:.4}) -> {route:?}",
1289 pic.route_cabac, pic.route_t8x8
1290 );
1291 }
1292 }
1293 let PendingPic {
1294 mut fd,
1295 frame_num,
1296 poc,
1297 deblock,
1298 filter_offset_a,
1299 filter_offset_b,
1300 crop_r,
1301 crop_b,
1302 max_refs,
1303 log2_max_frame_num,
1304 is_reference,
1305 idr_long_term,
1306 mut mmco_ops,
1307 ..
1308 } = pic;
1309 self.last_poc = poc;
1310 if deblock && !abl_deblock() {
1318 fd.deblock(filter_offset_a, filter_offset_b);
1319 }
1320 let reference = if is_reference {
1323 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
1324 Some(fd.as_reference_pooled(&mut self.plane_pool))
1325 } else {
1326 None
1327 };
1328 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
1329 if let Some(mut reference) = reference {
1330 reference.frame_num = frame_num;
1331 reference.poc = poc;
1332 if std::env::var_os("RH264_DUMP_MB").is_some() {
1333 eprintln!("DPB-ADD fn={frame_num} poc={poc}");
1334 }
1335 if idr_long_term {
1336 reference.long_term = true;
1337 reference.long_term_idx = 0;
1338 }
1339 let reference = reference; if self.detach_dpb {
1341 self.detached_mmco = std::mem::take(&mut mmco_ops);
1342 self.detached_frame_num = frame_num;
1343 self.detached_log2_max_frame_num = log2_max_frame_num;
1344 self.detached_max_refs = max_refs;
1345 self.detached_idr_long_term = idr_long_term;
1346 if let Some(slot) = self.progress_slot.take() {
1347 Self::fill_progress_slot(&slot, reference);
1349 slot.mark_fully_ready();
1350 self.detached_ref = Some(slot);
1351 } else {
1352 let arc = std::sync::Arc::new(reference);
1353 arc.mark_fully_ready();
1354 self.detached_ref = Some(arc);
1355 }
1356 } else {
1357 reference.mark_fully_ready();
1358 self.prev_ref_frame_num = self.apply_ref_marking(
1359 reference,
1360 &mmco_ops,
1361 frame_num,
1362 log2_max_frame_num,
1363 max_refs,
1364 );
1365 }
1366 }
1367 self.sc_mmco = mmco_ops; let (frame, pool) = fd.into_frame_recycle(crop_r, crop_b);
1369 self.grid_pool = pool;
1370 self.reclaim_retired();
1371 Ok(Some(frame))
1372 }
1373
1374 pub(crate) fn commit_detached_ref_arc(
1378 &mut self,
1379 reference: Ref,
1380 ) -> Result<u32, DecodeError> {
1381 reference.mark_fully_ready();
1382 let mmco = std::mem::take(&mut self.detached_mmco);
1383 let frame_num = self.detached_frame_num;
1384 let log2 = self.detached_log2_max_frame_num;
1385 let max_refs = self.detached_max_refs;
1386 self.prev_ref_frame_num =
1387 self.apply_ref_marking_arc(reference, &mmco, frame_num, log2, max_refs);
1388 Ok(self.prev_ref_frame_num)
1389 }
1390
1391 fn fill_progress_slot(slot: &Ref, mut finished: crate::RefFrame) {
1394 let planes = FrozenPlanes {
1395 py: std::mem::take(&mut finished.py),
1396 pu: std::mem::take(&mut finished.pu),
1397 pv: std::mem::take(&mut finished.pv),
1398 };
1399 if let Some(live) = &slot.live {
1400 let _w = live.wait.lock().unwrap();
1401 {
1402 let mut m = live.meta.write().unwrap();
1403 m.frame_num = finished.frame_num;
1404 m.poc = finished.poc;
1405 m.long_term = finished.long_term;
1406 m.long_term_idx = finished.long_term_idx;
1407 m.mv = std::mem::take(&mut finished.mv);
1408 m.ref_idx = std::mem::take(&mut finished.ref_idx);
1409 m.mv1 = std::mem::take(&mut finished.mv1);
1410 m.ref_idx1 = std::mem::take(&mut finished.ref_idx1);
1411 m.ref_poc = std::mem::take(&mut finished.ref_poc);
1412 m.w4 = finished.w4;
1413 m.motion_ready = true;
1414 }
1415 let _ = slot.frozen.set(planes);
1416 slot.ready_rows
1417 .store(slot.ch, std::sync::atomic::Ordering::Release);
1418 live.cv.notify_all();
1419 } else {
1420 let _ = slot.frozen.set(planes);
1421 slot.mark_fully_ready();
1422 }
1423 }
1424
1425 fn reclaim_retired(&mut self) {
1430 for arc in self.retired.drain(..) {
1431 if let Ok(mut rf) = std::sync::Arc::try_unwrap(arc) {
1432 if let Some(f) = rf.frozen.take() {
1433 if !f.py.is_empty() {
1434 self.plane_pool.push(f.py);
1435 self.plane_pool.push(f.pu);
1436 self.plane_pool.push(f.pv);
1437 }
1438 } else if !rf.py.is_empty() {
1439 self.plane_pool.push(rf.py);
1440 self.plane_pool.push(rf.pu);
1441 self.plane_pool.push(rf.pv);
1442 }
1443 }
1444 }
1445 self.plane_pool.truncate(18);
1448 }
1449
1450 fn insert_frame_num_gaps(&mut self, frame_num: u32, max_fn: u32, max_refs: usize, w: usize, h: usize) {
1456 if max_fn == 0 {
1457 return;
1458 }
1459 let start = (self.prev_ref_frame_num + 1) % max_fn;
1460 let gap = (frame_num + max_fn - start) % max_fn;
1461 if gap == 0 {
1462 return;
1463 }
1464 let cap = max_refs.max(1);
1470 let n = (gap as usize).min(cap);
1471 let (cw, ch) = (w, h);
1472 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
1473 for _ in 0..n {
1474 self.refs.insert(
1475 0,
1476 std::sync::Arc::new(RefFrame {
1477 py: vec![128; (cw + 2 * LPAD) * (ch + 2 * LPAD)],
1479 pu: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
1480 pv: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
1481 cw,
1482 ch,
1483 ready_rows: std::sync::atomic::AtomicUsize::new(ch),
1484 live: None,
1485 frozen: std::sync::OnceLock::new(),
1486 frame_num: expected,
1487 poc: 0,
1488 mv: Vec::new(),
1489 ref_idx: Vec::new(),
1490 mv1: Vec::new(),
1491 ref_idx1: Vec::new(),
1492 ref_poc: Vec::new(),
1493 w4: 0,
1494 long_term: false,
1495 long_term_idx: 0,
1496 }),
1497 );
1498 self.refs.truncate(cap);
1499 expected = (expected + 1) % max_fn;
1500 }
1501 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
1502 }
1503
1504 pub fn content_route(&self) -> Option<ContentRoute> {
1511 self.last_route
1512 }
1513
1514 pub fn last_poc(&self) -> i32 {
1515 self.last_poc
1516 }
1517
1518 fn compute_poc(
1519 &mut self,
1520 sps: &Sps,
1521 is_idr: bool,
1522 nal_ref_idc: u8,
1523 frame_num: u32,
1524 poc_lsb: u32,
1525 delta_bottom: i32,
1526 ) -> i32 {
1527 self.poc
1528 .compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_bottom)
1529 }
1530
1531 fn apply_ref_marking(
1542 &mut self,
1543 mut reference: RefFrame,
1544 ops: &[Mmco],
1545 frame_num: u32,
1546 log2_max_frame_num: u32,
1547 max_refs: usize,
1548 ) -> u32 {
1549 let max = 1i64 << log2_max_frame_num;
1550 let curr = frame_num as i64;
1551 let pic_num = |rf: &RefFrame| -> i64 {
1552 if (rf.frame_num as i64) > curr {
1553 rf.frame_num as i64 - max
1554 } else {
1555 rf.frame_num as i64
1556 }
1557 };
1558
1559 if ops.is_empty() {
1560 let out_fn = reference.frame_num;
1564 self.refs.insert(0, std::sync::Arc::new(reference));
1565 while self.refs.len() > max_refs {
1566 match self.refs.iter().rposition(|r| !r.long_term) {
1567 Some(pos) => {
1568 let evicted = self.refs.remove(pos);
1571 self.retired.push(evicted);
1572 }
1573 None => break,
1574 }
1575 }
1576 return out_fn;
1577 }
1578
1579 for &op in ops {
1581 match op {
1582 Mmco::Unref(diff) => {
1583 let target = curr - (diff as i64 + 1);
1584 self.refs.retain(|r| r.long_term || pic_num(r) != target);
1585 }
1586 Mmco::UnrefLong(ltpn) => {
1587 self.refs.retain(|r| !(r.long_term && r.long_term_idx == ltpn));
1588 }
1589 Mmco::AssignLong(diff, idx) => {
1590 let target = curr - (diff as i64 + 1);
1591 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
1592 for r in self.refs.iter_mut() {
1593 if !r.long_term && pic_num(r) == target {
1594 let r = std::sync::Arc::make_mut(r);
1596 r.long_term = true;
1597 r.long_term_idx = idx;
1598 }
1599 }
1600 }
1601 Mmco::MaxLong(max_plus1) => {
1602 self.refs.retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
1603 }
1604 Mmco::Reset => {
1605 self.refs.clear();
1606 reference.frame_num = 0;
1607 }
1608 Mmco::CurrentLong(idx) => {
1609 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
1610 reference.long_term = true;
1611 reference.long_term_idx = idx;
1612 }
1613 }
1614 }
1615 let out_fn = reference.frame_num;
1616 self.refs.insert(0, std::sync::Arc::new(reference));
1617 let cap = max_refs.max(16);
1619 if self.refs.len() > cap {
1620 self.refs.truncate(cap);
1621 }
1622 out_fn
1623 }
1624
1625 fn apply_ref_marking_arc(
1628 &mut self,
1629 mut reference: Ref,
1630 ops: &[Mmco],
1631 frame_num: u32,
1632 log2_max_frame_num: u32,
1633 max_refs: usize,
1634 ) -> u32 {
1635 let max = 1i64 << log2_max_frame_num;
1636 let curr = frame_num as i64;
1637 let pic_num = |rf: &RefFrame| -> i64 {
1638 let f = rf.fn_num() as i64;
1639 if f > curr {
1640 f - max
1641 } else {
1642 f
1643 }
1644 };
1645
1646 if ops.is_empty() {
1647 let out_fn = reference.fn_num();
1648 self.refs.insert(0, reference);
1649 while self.refs.len() > max_refs {
1650 match self.refs.iter().rposition(|r| !r.is_long_term()) {
1651 Some(pos) => {
1652 let evicted = self.refs.remove(pos);
1653 self.retired.push(evicted);
1654 }
1655 None => break,
1656 }
1657 }
1658 return out_fn;
1659 }
1660
1661 for &op in ops {
1662 match op {
1663 Mmco::Unref(diff) => {
1664 let target = curr - (diff as i64 + 1);
1665 self.refs.retain(|r| r.is_long_term() || pic_num(r) != target);
1666 }
1667 Mmco::UnrefLong(ltpn) => {
1668 self.refs
1669 .retain(|r| !(r.is_long_term() && r.lt_idx() == ltpn));
1670 }
1671 Mmco::AssignLong(diff, idx) => {
1672 let target = curr - (diff as i64 + 1);
1673 self.refs
1674 .retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
1675 for r in self.refs.iter_mut() {
1676 if !r.is_long_term() && pic_num(r) == target {
1677 if r.live.is_some() {
1678 r.set_long_term_marks(true, idx);
1679 } else {
1680 let r = std::sync::Arc::make_mut(r);
1681 r.long_term = true;
1682 r.long_term_idx = idx;
1683 }
1684 }
1685 }
1686 }
1687 Mmco::MaxLong(max_plus1) => {
1688 self.refs
1689 .retain(|r| !(r.is_long_term() && r.lt_idx() + 1 > max_plus1));
1690 }
1691 Mmco::Reset => {
1692 self.refs.clear();
1693 reference.set_frame_num_live(0);
1694 if let Some(r) = std::sync::Arc::get_mut(&mut reference) {
1695 r.frame_num = 0;
1696 }
1697 }
1698 Mmco::CurrentLong(idx) => {
1699 self.refs
1700 .retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
1701 reference.set_long_term_marks(true, idx);
1702 if let Some(r) = std::sync::Arc::get_mut(&mut reference) {
1703 r.long_term = true;
1704 r.long_term_idx = idx;
1705 }
1706 }
1707 }
1708 }
1709 let out_fn = reference.fn_num();
1710 self.refs.insert(0, reference);
1711 let cap = max_refs.max(16);
1712 if self.refs.len() > cap {
1713 self.refs.truncate(cap);
1714 }
1715 out_fn
1716 }
1717}
1718
1719pub(crate) fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
1721 gop.sort_by_key(|(poc, _)| *poc);
1722 out.extend(gop.drain(..).map(|(_, f)| f));
1723}
1724
1725pub fn au_is_idr(au: &[u8]) -> bool {
1730 split_annex_b(au)
1731 .iter()
1732 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
1733}
1734
1735pub fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
1743 let mut codes: Vec<(usize, bool)> = Vec::new();
1745 let mut i = 0;
1746 while let Some(w) = stream.get(i..i + 3) {
1750 if w[0] == 0 && w[1] == 0 && w[2] == 1 {
1751 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
1752 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
1753 let sc = if i > 0 && stream.get(i - 1) == Some(&0) { i - 1 } else { i };
1755 codes.push((sc, is_vcl));
1756 i += 3;
1757 } else {
1758 i += 1;
1759 }
1760 }
1761 if codes.is_empty() {
1762 return vec![stream];
1763 }
1764 let mut aus = Vec::new();
1765 let mut start = codes[0].0;
1766 for k in 0..codes.len() {
1767 if codes[k].1 {
1768 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
1769 aus.push(&stream[start..end]);
1770 start = end;
1771 }
1772 }
1773 aus
1774}
1775
1776fn parse_pred_weight_table(
1779 r: &mut BitReader,
1780 num_l0: usize,
1781 num_l1: usize,
1782 is_b: bool,
1783) -> Result<WeightTable, DecodeError> {
1784 let luma_log2_denom = r.read_ue()? as i32;
1785 let chroma_log2_denom = r.read_ue()? as i32;
1786 if !(0..=7).contains(&luma_log2_denom) || !(0..=7).contains(&chroma_log2_denom) {
1790 return Err(DecodeError::Unsupported("invalid weight denom"));
1791 }
1792 let mut wt = WeightTable {
1793 luma_log2_denom,
1794 chroma_log2_denom,
1795 ..Default::default()
1796 };
1797 let lists: &[(usize, usize)] = if is_b {
1798 &[(0, num_l0), (1, num_l1)]
1799 } else {
1800 &[(0, num_l0)]
1801 };
1802 for &(list, n) in lists {
1803 let mut luma = Vec::with_capacity(n);
1804 let mut chroma = Vec::with_capacity(n);
1805 for _ in 0..n {
1806 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
1807 if r.read_bit()? {
1808 lw = r.read_se()?;
1809 lo = r.read_se()?;
1810 }
1811 luma.push((lw, lo));
1812 let mut ch = [(1 << chroma_log2_denom, 0); 2];
1813 if r.read_bit()? {
1814 for slot in ch.iter_mut() {
1815 *slot = (r.read_se()?, r.read_se()?);
1816 }
1817 }
1818 chroma.push(ch);
1819 }
1820 wt.luma[list & 1] = luma;
1821 wt.chroma[list & 1] = chroma;
1822 }
1823 Ok(wt)
1824}
1825
1826fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
1831 use crate::params::{
1832 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
1833 };
1834 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
1835 const ZZ8: [usize; 64] = [
1837 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,
1838 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
1839 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
1840 ];
1841 let mut z4 = [[16u8; 16]; 6];
1844 for i in 0..6 {
1845 z4[i] = if pps.pic_scaling_matrix_present {
1846 if pps.scaling_present_4x4[i] {
1847 pps.scaling_4x4[i]
1848 } else {
1849 match i {
1850 0 if sps.has_scaling => sps.scaling_4x4[0],
1851 0 => DEFAULT_4X4_INTRA,
1852 3 if sps.has_scaling => sps.scaling_4x4[3],
1853 3 => DEFAULT_4X4_INTER,
1854 _ => z4[i - 1],
1855 }
1856 }
1857 } else {
1858 sps.scaling_4x4[i]
1859 };
1860 }
1861 let mut z8 = [[16u8; 64]; 2];
1862 for (i, list) in z8.iter_mut().enumerate() {
1863 *list = if pps.pic_scaling_matrix_present {
1864 if pps.scaling_present_8x8[i] {
1865 pps.scaling_8x8[i]
1866 } else if sps.has_scaling {
1867 sps.scaling_8x8[i]
1868 } else if i == 0 {
1869 DEFAULT_8X8_INTRA
1870 } else {
1871 DEFAULT_8X8_INTER
1872 }
1873 } else {
1874 sps.scaling_8x8[i]
1875 };
1876 }
1877 let mut out4 = [[16i32; 16]; 6];
1878 for (li, list) in out4.iter_mut().enumerate() {
1879 for k in 0..16 {
1880 list[ZZ4[k]] = z4[li][k] as i32;
1881 }
1882 }
1883 let mut out8 = [[16i32; 64]; 2];
1884 for (li, list) in out8.iter_mut().enumerate() {
1885 for k in 0..64 {
1886 list[ZZ8[k]] = z8[li][k] as i32;
1887 }
1888 }
1889 (out4, out8)
1890}
1891
1892fn parse_ref_pic_list_modification(
1895 r: &mut BitReader,
1896 out: &mut Vec<(u32, u32)>,
1897) -> Result<(), DecodeError> {
1898 loop {
1899 let idc = r.read_ue()?;
1900 if idc == 3 {
1901 break;
1902 }
1903 if idc > 3 {
1904 return Err(DecodeError::Unsupported("invalid ref_pic_list_modification"));
1905 }
1906 let val = r.read_ue()?; out.push((idc, val));
1908 if out.len() > 64 {
1909 return Err(DecodeError::Truncated); }
1911 }
1912 Ok(())
1913}
1914
1915fn build_ref_list_p(
1919 dpb: &[Ref],
1920 curr_frame_num: u32,
1921 max_frame_num: u32,
1922 num_active: usize,
1923 mods: &[(u32, u32)],
1924) -> Result<Vec<Ref>, DecodeError> {
1925 let curr = curr_frame_num as i64;
1926 let max = max_frame_num as i64;
1927 let pic_num = |fnum: u32| -> i64 {
1928 let f = fnum as i64;
1929 if f > curr { f - max } else { f }
1930 };
1931 let mut init: Vec<Ref> = dpb.iter().filter(|r| !r.is_long_term()).cloned().collect();
1932 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.fn_num())));
1933 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
1934 long.sort_by_key(|rf| rf.lt_idx());
1935 init.extend(long);
1936 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
1937}
1938
1939#[allow(clippy::too_many_arguments)]
1944fn build_ref_list_b(
1945 dpb: &[Ref],
1946 curr_poc: i32,
1947 curr_frame_num: u32,
1948 max_frame_num: u32,
1949 num0: usize,
1950 num1: usize,
1951 mods0: &[(u32, u32)],
1952 mods1: &[(u32, u32)],
1953) -> Result<(Vec<Ref>, Vec<Ref>), DecodeError> {
1954 let mut less: Vec<Ref> = dpb
1955 .iter()
1956 .filter(|r| !r.is_long_term() && r.pic_poc() < curr_poc)
1957 .cloned()
1958 .collect();
1959 let mut greater: Vec<Ref> = dpb
1960 .iter()
1961 .filter(|r| !r.is_long_term() && r.pic_poc() > curr_poc)
1962 .cloned()
1963 .collect();
1964 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
1965 less.sort_by_key(|r| core::cmp::Reverse(r.pic_poc())); greater.sort_by_key(|r| r.pic_poc()); long.sort_by_key(|r| r.lt_idx());
1968
1969 let mut init0 = less.clone();
1970 init0.extend(greater.clone());
1971 init0.extend(long.clone());
1972 let mut init1 = greater;
1973 init1.extend(less);
1974 init1.extend(long);
1975
1976 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
1979 if num1 > 1
1980 && init1.len() > 1
1981 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
1982 && eq_len == num1.min(init1.len())
1983 && eq_len == num0.min(init0.len())
1984 {
1985 if let [a, b, ..] = &mut init1[..] {
1988 std::mem::swap(a, b);
1989 }
1990 }
1991
1992 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
1993 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
1994 Ok((list0, list1))
1995}
1996
1997fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
1999 a.is_long_term() == b.is_long_term()
2000 && if a.is_long_term() {
2001 a.lt_idx() == b.lt_idx()
2002 } else {
2003 a.pic_poc() == b.pic_poc()
2004 }
2005}
2006
2007fn apply_list_modification(
2012 init: Vec<Ref>,
2013 curr_frame_num: u32,
2014 max_frame_num: u32,
2015 num_active: usize,
2016 mods: &[(u32, u32)],
2017) -> Result<Vec<Ref>, DecodeError> {
2018 if mods.is_empty() {
2019 let mut init = init;
2020 init.truncate(num_active.max(1));
2021 return Ok(init);
2022 }
2023 let curr = curr_frame_num as i64;
2024 let max = max_frame_num as i64;
2025 let mut list = init.clone();
2026 let mut pic_num_pred = curr;
2027 let mut refidx = 0usize;
2028 for &(idc, val) in mods {
2029 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
2030 Box::new(move |r: &RefFrame| r.is_long_term() && r.lt_idx() == val)
2031 } else {
2032 let abs_diff = (val as i64) + 1;
2033 let no_wrap = if idc == 0 {
2034 let x = pic_num_pred - abs_diff;
2035 if x < 0 { x + max } else { x }
2036 } else {
2037 let x = pic_num_pred + abs_diff;
2038 if x >= max { x - max } else { x }
2039 };
2040 pic_num_pred = no_wrap;
2041 let target = if no_wrap > curr { no_wrap - max } else { no_wrap };
2042 Box::new(move |r: &RefFrame| {
2043 let f = r.fn_num() as i64;
2044 let pn = if f > curr { f - max } else { f };
2045 !r.is_long_term() && pn == target
2046 })
2047 };
2048 let found = init.iter().find(|r| matches(r)).cloned();
2049 let Some(found) = found else {
2050 if std::env::var_os("RH264_DUMP_MB").is_some() {
2051 let cand: Vec<String> = init
2052 .iter()
2053 .map(|r| {
2054 let f = r.fn_num() as i64;
2055 let pn = if f > curr { f - max } else { f };
2056 format!(
2057 "(fn={} poc={} lt={} picnum={})",
2058 r.fn_num(),
2059 r.pic_poc(),
2060 r.is_long_term(),
2061 pn
2062 )
2063 })
2064 .collect();
2065 eprintln!(
2066 "MODFAIL idc={idc} val={val} curr_frame_num={curr} max={max} init={}",
2067 cand.join(" ")
2068 );
2069 }
2070 return Err(DecodeError::Truncated); };
2072 if refidx > list.len() {
2073 break;
2074 }
2075 list.insert(refidx, found);
2076 if let Some(dup) = list.iter().enumerate().skip(refidx + 1).find(|(_, r)| matches(r)).map(|(i, _)| i) {
2077 list.remove(dup);
2078 }
2079 refidx += 1;
2080 if refidx >= num_active {
2081 break;
2082 }
2083 }
2084 list.truncate(num_active.max(1));
2085 Ok(list)
2086}
2087
2088#[cfg(test)]
2089mod tests {
2090 use super::*;
2091
2092 fn ref_at(poc: i32, fnum: u32) -> Ref {
2093 std::sync::Arc::new(RefFrame {
2094 py: vec![],
2095 pu: vec![],
2096 pv: vec![],
2097 cw: 0,
2098 ch: 0,
2099 ready_rows: std::sync::atomic::AtomicUsize::new(0),
2100 live: None,
2101 frozen: std::sync::OnceLock::new(),
2102 frame_num: fnum,
2103 poc,
2104 mv: Vec::new(),
2105 ref_idx: Vec::new(),
2106 mv1: Vec::new(),
2107 ref_idx1: Vec::new(),
2108 ref_poc: Vec::new(),
2109 w4: 0,
2110 long_term: false,
2111 long_term_idx: 0,
2112 })
2113 }
2114
2115 #[test]
2116 fn b_ref_lists_ordered_by_poc() {
2117 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
2119 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
2120 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 0, 6, 8]);
2122 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![6, 8, 2, 0]);
2124 }
2125
2126 #[test]
2127 fn b_ref_list1_swap_when_equal() {
2128 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
2131 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
2132 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
2133 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
2134 }
2135
2136 #[test]
2137 fn frame_num_gaps_insert_placeholders() {
2138 let mut d = Decoder::new();
2139 d.prev_ref_frame_num = 2;
2140 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
2142 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
2143 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
2144 assert_eq!(d.prev_ref_frame_num, 4);
2145 assert!(d.refs.iter().all(|r| r.py.iter().all(|&p| p == 128)), "grey fill");
2146 }
2147
2148 #[test]
2149 fn frame_num_gaps_wrap_and_noop() {
2150 let mut d = Decoder::new();
2152 d.prev_ref_frame_num = 14;
2153 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
2154 assert_eq!(d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(), vec![0, 15]);
2155 let mut d = Decoder::new();
2157 d.prev_ref_frame_num = 3;
2158 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
2159 assert!(d.refs.is_empty());
2160 }
2161
2162 #[test]
2163 fn missing_param_sets_errors() {
2164 let mut d = Decoder::new();
2165 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
2168 let err = d.decode(&nal.to_annex_b()).unwrap_err();
2169 assert_eq!(err, DecodeError::MissingParameterSet);
2170 }
2171}