1#![cfg_attr(not(feature = "std"), no_std)]
26#![cfg_attr(not(feature = "std"), allow(dead_code))]
30
31extern crate alloc;
32#[cfg(test)]
33extern crate std;
34
35#[cfg(not(feature = "std"))]
44macro_rules! eprintln {
45 ($($t:tt)*) => {{
46 let _ = ::core::format_args!($($t)*);
47 }};
48}
49#[cfg(not(feature = "std"))]
50#[allow(unused_macros)]
51macro_rules! println {
52 ($($t:tt)*) => {{
53 let _ = ::core::format_args!($($t)*);
54 }};
55}
56#[cfg(not(feature = "std"))]
59macro_rules! thread_local {
60 () => {};
61 ($(#[$m:meta])* $vis:vis static $name:ident: $ty:ty = const { $init:expr }; $($rest:tt)*) => {
62 $(#[$m])* #[allow(non_camel_case_types)] $vis struct $name;
63 impl $name {
64 #[allow(dead_code)]
65 pub fn with<R>(&self, f: impl FnOnce(&$ty) -> R) -> R {
66 let v: $ty = $init;
67 f(&v)
68 }
69 }
70 thread_local!($($rest)*);
71 };
72 ($(#[$m:meta])* $vis:vis static $name:ident: $ty:ty = $init:expr; $($rest:tt)*) => {
73 $(#[$m])* #[allow(non_camel_case_types)] $vis struct $name;
74 impl $name {
75 #[allow(dead_code)]
76 pub fn with<R>(&self, f: impl FnOnce(&$ty) -> R) -> R {
77 let v: $ty = $init;
78 f(&v)
79 }
80 }
81 thread_local!($($rest)*);
82 };
83}
84
85pub(crate) mod sync {
93 #[cfg(not(feature = "std"))]
94 pub use core::cell::OnceCell as Once;
95 #[cfg(feature = "std")]
101 pub use std::sync::OnceLock as Once;
102 #[cfg(feature = "std")]
103 pub use std::sync::{mpsc, Arc, Condvar, Mutex, RwLock, RwLockReadGuard};
104 #[cfg(feature = "std")]
105 pub fn yield_now() {
106 std::thread::yield_now();
107 }
108
109 #[cfg(not(feature = "std"))]
110 pub use alloc::sync::Arc;
111 #[cfg(not(feature = "std"))]
112 pub fn yield_now() {
113 core::hint::spin_loop();
114 }
115 #[cfg(not(feature = "std"))]
116 pub use single::*;
117
118 #[cfg(feature = "std")]
137 mod poison_free {
138 use std::sync::{
139 Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
140 };
141
142 pub trait LockPf<T: ?Sized> {
143 fn read_pf(&self) -> RwLockReadGuard<'_, T>;
144 fn write_pf(&self) -> RwLockWriteGuard<'_, T>;
145 }
146 impl<T: ?Sized> LockPf<T> for RwLock<T> {
147 #[inline]
148 fn read_pf(&self) -> RwLockReadGuard<'_, T> {
149 self.read().unwrap_or_else(|e| e.into_inner())
150 }
151 #[inline]
152 fn write_pf(&self) -> RwLockWriteGuard<'_, T> {
153 self.write().unwrap_or_else(|e| e.into_inner())
154 }
155 }
156
157 pub trait MutexPf<T: ?Sized> {
158 fn lock_pf(&self) -> MutexGuard<'_, T>;
159 }
160 impl<T: ?Sized> MutexPf<T> for Mutex<T> {
161 #[inline]
162 fn lock_pf(&self) -> MutexGuard<'_, T> {
163 self.lock().unwrap_or_else(|e| e.into_inner())
164 }
165 }
166
167 pub trait CondvarPf {
168 fn wait_pf<'a, T>(&self, g: MutexGuard<'a, T>) -> MutexGuard<'a, T>;
169 }
170 impl CondvarPf for Condvar {
171 #[inline]
172 fn wait_pf<'a, T>(&self, g: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
173 self.wait(g).unwrap_or_else(|e| e.into_inner())
174 }
175 }
176 }
177
178 #[cfg(not(feature = "std"))]
179 mod poison_free {
180 use super::single::{Condvar, Mutex, RwLock};
181 use core::cell::{Ref, RefMut};
182
183 pub trait LockPf<T> {
184 fn read_pf(&self) -> Ref<'_, T>;
185 fn write_pf(&self) -> RefMut<'_, T>;
186 }
187 impl<T> LockPf<T> for RwLock<T> {
188 #[inline]
189 fn read_pf(&self) -> Ref<'_, T> {
190 self.read().unwrap_or_else(|()| unreachable!())
192 }
193 #[inline]
194 fn write_pf(&self) -> RefMut<'_, T> {
195 self.write().unwrap_or_else(|()| unreachable!())
196 }
197 }
198
199 pub trait MutexPf<T> {
200 fn lock_pf(&self) -> RefMut<'_, T>;
201 }
202 impl<T> MutexPf<T> for Mutex<T> {
203 #[inline]
204 fn lock_pf(&self) -> RefMut<'_, T> {
205 self.lock().unwrap_or_else(|()| unreachable!())
206 }
207 }
208
209 pub trait CondvarPf {
210 fn wait_pf<'a, T>(&self, g: RefMut<'a, T>) -> RefMut<'a, T>;
211 }
212 impl CondvarPf for Condvar {
213 #[inline]
214 fn wait_pf<'a, T>(&self, g: RefMut<'a, T>) -> RefMut<'a, T> {
215 self.wait(g).unwrap_or_else(|()| unreachable!())
216 }
217 }
218 }
219
220 pub use poison_free::{CondvarPf, LockPf, MutexPf};
221
222 #[cfg(not(feature = "std"))]
223 mod single {
224 use core::cell::{Ref, RefCell, RefMut};
225
226 #[derive(Debug, Default)]
227 pub struct RwLock<T>(RefCell<T>);
228 pub type RwLockReadGuard<'a, T> = Ref<'a, T>;
229 impl<T> RwLock<T> {
230 pub const fn new(v: T) -> Self {
231 RwLock(RefCell::new(v))
232 }
233 pub fn read(&self) -> Result<Ref<'_, T>, ()> {
234 Ok(self.0.borrow())
235 }
236 pub fn write(&self) -> Result<RefMut<'_, T>, ()> {
237 Ok(self.0.borrow_mut())
238 }
239 }
240
241 #[derive(Debug, Default)]
242 pub struct Mutex<T>(RefCell<T>);
243 impl<T> Mutex<T> {
244 pub const fn new(v: T) -> Self {
245 Mutex(RefCell::new(v))
246 }
247 pub fn lock(&self) -> Result<RefMut<'_, T>, ()> {
248 Ok(self.0.borrow_mut())
249 }
250 }
251
252 #[derive(Debug, Default)]
253 pub struct Condvar;
254 impl Condvar {
255 pub const fn new() -> Self {
256 Condvar
257 }
258 pub fn wait<'a, T>(&self, g: RefMut<'a, T>) -> Result<RefMut<'a, T>, ()> {
259 Ok(g)
260 }
261 pub fn notify_all(&self) {}
262 pub fn notify_one(&self) {}
263 }
264
265 pub mod mpsc {
269 use core::marker::PhantomData;
270 pub struct SyncSender<T>(PhantomData<T>);
271 pub struct Sender<T>(PhantomData<T>);
272 pub struct Receiver<T>(PhantomData<T>);
273 pub struct SendError<T>(pub T);
274 #[derive(Debug)]
275 pub struct RecvError;
276 impl<T> core::fmt::Debug for SendError<T> {
277 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
278 f.write_str("SendError")
279 }
280 }
281 impl<T> SyncSender<T> {
282 pub fn send(&self, _t: T) -> Result<(), SendError<T>> {
283 unreachable!("no worker thread without std")
284 }
285 }
286 impl<T> Sender<T> {
287 pub fn send(&self, _t: T) -> Result<(), SendError<T>> {
288 unreachable!("no worker thread without std")
289 }
290 }
291 impl<T> Receiver<T> {
292 pub fn recv(&self) -> Result<T, RecvError> {
293 unreachable!("no worker thread without std")
294 }
295 }
296 }
297 }
298}
299
300mod cabac;
301#[cfg(feature = "profile")]
303pub use cabac::bin_census;
304#[cfg(feature = "std")]
305mod frame_mt;
306mod mb16;
307mod params;
308
309pub use mb16::MvField;
310#[cfg(feature = "std")]
311pub use mb16::MV_DUMP;
312pub use params::{Pps, Sps};
313
314#[cfg(feature = "std")]
316pub(crate) fn frame_threads() -> usize {
317 frame_mt::frame_threads()
318}
319#[cfg(not(feature = "std"))]
321pub(crate) fn frame_threads() -> usize {
322 1
323}
324
325#[cfg(feature = "std")]
327pub(crate) fn row_publish_on() -> bool {
328 frame_mt::row_publish_on()
329}
330#[cfg(not(feature = "std"))]
332pub(crate) fn row_publish_on() -> bool {
333 false
334}
335#[cfg(feature = "std")]
337pub(crate) fn row_progress_on() -> bool {
338 frame_mt::row_progress_on()
339}
340#[cfg(not(feature = "std"))]
342pub(crate) fn row_progress_on() -> bool {
343 false
344}
345
346pub fn edc_stats_report() {
348 mb16::edcstat::report();
349 rusty_h264_common::deblock::filtstat::report();
350}
351
352#[doc(hidden)]
355fn abl_deblock() -> bool {
358 #[cfg(not(feature = "knobs"))]
362 {
363 false
364 }
365 #[cfg(feature = "knobs")]
366 {
367 static ON: rusty_h264_common::once::OnceLock<bool> =
368 rusty_h264_common::once::OnceLock::new();
369 *ON.get_or_init(|| rusty_h264_common::knob("RFF_ABL_DEBLOCK").map_or(false, |v| v != "0"))
370 }
371}
372
373pub mod cabac_test {
374 pub use crate::cabac::Cabac;
375 pub use crate::mb16::b_inter_shape;
376 pub use crate::mb16::parse_cbp_cabac;
377 pub use crate::mb16::parse_mb_qp_delta_cabac;
378 pub use crate::mb16::parse_mb_type_b;
379 pub use crate::mb16::parse_ref_idx_cabac;
380}
381
382#[allow(unused_imports)]
383use alloc::borrow::ToOwned;
384use crate::sync::{CondvarPf, LockPf, MutexPf};
385#[allow(unused_imports)]
386use alloc::boxed::Box;
387#[allow(unused_imports)]
388use alloc::format;
389#[allow(unused_imports)]
390use alloc::string::{String, ToString};
391#[allow(unused_imports)]
392use alloc::vec;
393#[allow(unused_imports)]
394use alloc::vec::Vec;
395use mb16::{FrameDecoder, GridPool, WeightTable};
396use rusty_h264_common::bit_reader::OutOfData;
397use rusty_h264_common::nal::{emulation_unprevent, split_annex_b};
398use rusty_h264_common::{BitReader, NalUnitType, YuvFrame};
399
400#[derive(Debug, Clone, PartialEq, Eq)]
402pub enum DecodeError {
403 Truncated,
405 MissingParameterSet,
407 Unsupported(&'static str),
409 Internal(&'static str),
419}
420
421impl From<OutOfData> for DecodeError {
422 fn from(_: OutOfData) -> Self {
423 DecodeError::Truncated
424 }
425}
426
427impl core::fmt::Display for DecodeError {
428 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
429 match self {
430 DecodeError::Truncated => f.write_str("bitstream truncated"),
431 DecodeError::MissingParameterSet => f.write_str("slice before SPS/PPS"),
432 DecodeError::Unsupported(s) => write!(f, "unsupported coding tool: {s}"),
433 DecodeError::Internal(s) => write!(f, "decoder invariant violated: {s}"),
434 }
435 }
436}
437
438impl core::error::Error for DecodeError {}
439
440pub(crate) type Ref = crate::sync::Arc<RefFrame>;
449
450#[derive(Debug, Default)]
451#[allow(dead_code)]
452pub(crate) struct RefFrame {
453 pub py: Vec<u8>,
459 pub pu: Vec<u8>,
460 pub pv: Vec<u8>,
461 pub cw: usize,
462 pub ch: usize,
463 pub ready_rows: core::sync::atomic::AtomicUsize,
467 pub live: Option<crate::sync::Arc<LivePlanes>>,
472 pub frozen: crate::sync::Once<FrozenPlanes>,
475 pub frame_num: u32,
477 pub poc: i32,
479 pub mv: Vec<(i16, i16)>,
484 pub ref_idx: Vec<i8>,
487 pub mv1: Vec<(i16, i16)>,
494 pub ref_idx1: Vec<i8>,
495 pub poc_lut: [i32; 32],
514 pub w4: usize,
515 pub long_term: bool,
519 pub long_term_idx: u32,
520}
521
522impl Clone for RefFrame {
523 fn clone(&self) -> Self {
524 use core::sync::atomic::Ordering::Relaxed;
525 let frozen = crate::sync::Once::new();
526 if let Some(p) = self.frozen.get() {
527 let _ = frozen.set(p.clone());
528 }
529 Self {
530 py: self.py.clone(),
531 pu: self.pu.clone(),
532 pv: self.pv.clone(),
533 cw: self.cw,
534 ch: self.ch,
535 ready_rows: core::sync::atomic::AtomicUsize::new(self.ready_rows.load(Relaxed)),
536 live: self.live.clone(),
537 frozen,
538 frame_num: self.frame_num,
539 poc: self.poc,
540 mv: self.mv.clone(),
541 ref_idx: self.ref_idx.clone(),
542 mv1: self.mv1.clone(),
543 ref_idx1: self.ref_idx1.clone(),
544 poc_lut: self.poc_lut,
545 w4: self.w4,
546 long_term: self.long_term,
547 long_term_idx: self.long_term_idx,
548 }
549 }
550}
551
552pub(crate) const LPAD: usize = 16;
556pub(crate) const CPAD: usize = 8;
557
558thread_local! {
559 static MC_ROW_NEED: core::cell::Cell<usize> = const { core::cell::Cell::new(usize::MAX) };
561}
562
563#[derive(Debug, Clone)]
565pub(crate) struct FrozenPlanes {
566 pub py: Vec<u8>,
567 pub pu: Vec<u8>,
568 pub pv: Vec<u8>,
569}
570
571#[derive(Debug)]
573pub(crate) struct LivePlanes {
574 pub py: crate::sync::RwLock<Vec<u8>>,
575 pub pu: crate::sync::RwLock<Vec<u8>>,
576 pub pv: crate::sync::RwLock<Vec<u8>>,
577 pub meta: crate::sync::RwLock<LiveMeta>,
579 pub wait: crate::sync::Mutex<()>,
581 pub cv: crate::sync::Condvar,
582}
583
584#[derive(Debug, Clone, Default)]
585pub(crate) struct LiveMeta {
586 pub frame_num: u32,
587 pub poc: i32,
588 pub long_term: bool,
589 pub long_term_idx: u32,
590 pub mv: Vec<(i16, i16)>,
592 pub ref_idx: Vec<i8>,
595 pub mv1: Vec<(i16, i16)>,
596 pub ref_idx1: Vec<i8>,
597 pub poc_lut: [i32; 32],
598 pub w4: usize,
599 pub motion_ready: bool,
601}
602
603pub(crate) enum PlaneGuard<'a> {
605 Borrowed(&'a [u8]),
606 Locked(crate::sync::RwLockReadGuard<'a, Vec<u8>>),
607}
608
609impl core::ops::Deref for PlaneGuard<'_> {
610 type Target = [u8];
611 fn deref(&self) -> &[u8] {
612 match self {
613 Self::Borrowed(s) => s,
614 Self::Locked(g) => g.as_slice(),
615 }
616 }
617}
618
619impl RefFrame {
620 #[inline]
622 pub(crate) fn rows_needed_for_mb(mb_y: usize, ch: usize) -> usize {
623 ((mb_y + 1) * 16 + LPAD).min(ch.max(1))
624 }
625
626 #[inline]
630 pub(crate) fn set_mc_row_need(mb_y: usize, ch: usize) {
631 if !crate::row_progress_on() {
634 return;
635 }
636 MC_ROW_NEED.with(|c| c.set(Self::rows_needed_for_mb(mb_y, ch)));
637 }
638
639 #[inline]
640 fn effective_need(&self, need_rows: usize) -> usize {
641 let hint = MC_ROW_NEED.with(|c| c.get());
642 need_rows.min(hint).min(self.ch.max(1))
643 }
644
645 #[inline]
648 pub(crate) fn luma_guard(&self, need_rows: usize) -> PlaneGuard<'_> {
649 if self.live.is_none() {
650 if let Some(f) = self.frozen.get() {
652 return PlaneGuard::Borrowed(&f.py);
653 }
654 return PlaneGuard::Borrowed(&self.py);
655 }
656 let need = self.effective_need(need_rows);
657 self.wait_ready_rows(need);
658 if let Some(f) = self.frozen.get() {
659 return PlaneGuard::Borrowed(&f.py);
660 }
661 if !self.py.is_empty() {
662 return PlaneGuard::Borrowed(&self.py);
663 }
664 if let Some(live) = &self.live {
665 PlaneGuard::Locked(live.py.read_pf())
666 } else {
667 PlaneGuard::Borrowed(&self.py)
668 }
669 }
670
671 #[inline]
672 pub(crate) fn chroma_guard(&self, plane: usize, need_rows: usize) -> PlaneGuard<'_> {
673 if self.live.is_none() {
674 if let Some(f) = self.frozen.get() {
675 return if plane == 0 {
676 PlaneGuard::Borrowed(&f.pu)
677 } else {
678 PlaneGuard::Borrowed(&f.pv)
679 };
680 }
681 return if plane == 0 {
682 PlaneGuard::Borrowed(&self.pu)
683 } else {
684 PlaneGuard::Borrowed(&self.pv)
685 };
686 }
687 let need = self.effective_need(need_rows);
688 self.wait_ready_rows(need);
689 if let Some(f) = self.frozen.get() {
690 return if plane == 0 {
691 PlaneGuard::Borrowed(&f.pu)
692 } else {
693 PlaneGuard::Borrowed(&f.pv)
694 };
695 }
696 if !self.py.is_empty() {
697 return if plane == 0 {
698 PlaneGuard::Borrowed(&self.pu)
699 } else {
700 PlaneGuard::Borrowed(&self.pv)
701 };
702 }
703 if let Some(live) = &self.live {
704 if plane == 0 {
705 PlaneGuard::Locked(live.pu.read_pf())
706 } else {
707 PlaneGuard::Locked(live.pv.read_pf())
708 }
709 } else if plane == 0 {
710 PlaneGuard::Borrowed(&self.pu)
711 } else {
712 PlaneGuard::Borrowed(&self.pv)
713 }
714 }
715 pub(crate) fn new_progress_slot(cw: usize, ch: usize, b_possible: bool, mb_w: usize) -> Ref {
716 let (lpw, lph) = (cw + 2 * LPAD, ch + 2 * LPAD);
717 let (cpw, cph) = (cw / 2 + 2 * CPAD, ch / 2 + 2 * CPAD);
718 let w4 = if b_possible { mb_w * 4 } else { 0 };
719 let n4 = if b_possible {
720 mb_w * 4 * (ch / 16) * 4
721 } else {
722 0
723 };
724 crate::mb16::cpystat::note(
730 &crate::mb16::cpystat::PROGRESS_SLOT,
731 2 * (n4 * core::mem::size_of::<(i32, i32)>() * 2 + n4 * 2),
732 );
733 let (py, pu, pv) = if crate::row_publish_on() {
736 (vec![0; lpw * lph], vec![0; cpw * cph], vec![0; cpw * cph])
737 } else {
738 (Vec::new(), Vec::new(), Vec::new())
739 };
740 crate::sync::Arc::new(RefFrame {
741 py: Vec::new(),
742 pu: Vec::new(),
743 pv: Vec::new(),
744 cw,
745 ch,
746 ready_rows: core::sync::atomic::AtomicUsize::new(0),
747 live: Some(crate::sync::Arc::new(LivePlanes {
748 py: crate::sync::RwLock::new(py),
749 pu: crate::sync::RwLock::new(pu),
750 pv: crate::sync::RwLock::new(pv),
751 meta: crate::sync::RwLock::new(LiveMeta {
752 mv: vec![(0, 0); n4],
753 ref_idx: vec![-1; n4],
754 mv1: vec![(0, 0); n4],
755 ref_idx1: vec![-1; n4],
756 poc_lut: [i32::MIN; 32],
757 w4,
758 ..LiveMeta::default()
759 }),
760 wait: crate::sync::Mutex::new(()),
761 cv: crate::sync::Condvar::new(),
762 })),
763 frozen: crate::sync::Once::new(),
764 frame_num: 0,
765 poc: 0,
766 mv: vec![(0, 0); n4],
767 ref_idx: vec![-1; n4],
768 mv1: vec![(0, 0); n4],
769 ref_idx1: vec![-1; n4],
770 poc_lut: [i32::MIN; 32],
771 w4,
772 long_term: false,
773 long_term_idx: 0,
774 })
775 }
776
777 pub(crate) fn init_progress_identity(slot: &mut Ref, frame_num: u32, poc: i32) {
779 if let Some(s) = crate::sync::Arc::get_mut(slot) {
780 s.frame_num = frame_num;
781 s.poc = poc;
782 if let Some(live) = &s.live {
783 let mut m = live.meta.write_pf();
784 m.frame_num = frame_num;
785 m.poc = poc;
786 }
787 }
788 }
789
790 #[inline]
791 pub(crate) fn fn_num(&self) -> u32 {
792 if let Some(live) = &self.live {
793 live.meta.read_pf().frame_num
794 } else {
795 self.frame_num
796 }
797 }
798
799 #[inline]
800 pub(crate) fn pic_poc(&self) -> i32 {
801 if let Some(live) = &self.live {
802 live.meta.read_pf().poc
803 } else {
804 self.poc
805 }
806 }
807
808 #[inline]
809 pub(crate) fn is_long_term(&self) -> bool {
810 if let Some(live) = &self.live {
811 live.meta.read_pf().long_term
812 } else {
813 self.long_term
814 }
815 }
816
817 #[inline]
818 pub(crate) fn lt_idx(&self) -> u32 {
819 if let Some(live) = &self.live {
820 live.meta.read_pf().long_term_idx
821 } else {
822 self.long_term_idx
823 }
824 }
825
826 pub(crate) fn set_long_term_marks(&self, long_term: bool, idx: u32) {
827 if let Some(live) = &self.live {
828 let mut m = live.meta.write_pf();
829 m.long_term = long_term;
830 m.long_term_idx = idx;
831 }
832 }
833
834 pub(crate) fn set_frame_num_live(&self, frame_num: u32) {
835 if let Some(live) = &self.live {
836 live.meta.write_pf().frame_num = frame_num;
837 }
838 }
839
840 pub(crate) fn wait_motion_ready(&self) {
842 if self.live.is_none() {
843 return;
844 }
845 if let Some(live) = &self.live {
846 if live.meta.read_pf().motion_ready {
847 return;
848 }
849 }
850 if let Some(live) = &self.live {
851 let mut g = live.wait.lock_pf();
852 while !live.meta.read_pf().motion_ready {
853 g = live.cv.wait_pf(g);
854 }
855 }
856 }
857
858 #[inline]
860 pub fn mark_fully_ready(&self) {
861 if let Some(live) = &self.live {
862 let _g = live.wait.lock_pf();
863 self.ready_rows
864 .store(self.ch, core::sync::atomic::Ordering::Release);
865 live.cv.notify_all();
866 } else {
867 self.ready_rows
868 .store(self.ch, core::sync::atomic::Ordering::Release);
869 }
870 }
871
872 #[inline]
874 pub fn publish_ready_rows(&self, rows: usize) {
875 let r = rows.min(self.ch);
876 if let Some(live) = &self.live {
877 let _g = live.wait.lock_pf();
878 let prev = self
879 .ready_rows
880 .fetch_max(r, core::sync::atomic::Ordering::Release);
881 if r > prev {
882 live.cv.notify_all();
883 }
884 } else {
885 let _ = self
886 .ready_rows
887 .fetch_max(r, core::sync::atomic::Ordering::Release);
888 }
889 }
890
891 #[inline]
894 pub fn wait_ready_rows(&self, rows: usize) {
895 use core::sync::atomic::Ordering::Acquire;
896 let need = rows.min(self.ch);
897 if need == 0 || self.ready_rows.load(Acquire) >= need {
898 return;
899 }
900 if self.frozen.get().is_some() {
901 return;
902 }
903 if let Some(live) = &self.live {
904 let mut g = live.wait.lock_pf();
905 while self.ready_rows.load(Acquire) < need {
906 g = live.cv.wait_pf(g);
907 }
908 } else {
909 while self.ready_rows.load(Acquire) < need {
910 crate::sync::yield_now();
911 }
912 }
913 }
914
915 #[inline]
916 pub fn lstride(&self) -> usize {
917 self.cw + 2 * LPAD
918 }
919 #[inline]
920 pub fn cstride(&self) -> usize {
921 self.cw / 2 + 2 * CPAD
922 }
923 #[inline]
930 pub fn lrows(&self) -> usize {
931 self.ch + 2 * LPAD
932 }
933 #[inline]
935 pub fn crows(&self) -> usize {
936 self.ch / 2 + 2 * CPAD
937 }
938}
939
940#[derive(Clone, Copy)]
942enum Mmco {
943 Unref(u32),
945 UnrefLong(u32),
947 AssignLong(u32, u32),
949 MaxLong(u32),
951 Reset,
953 CurrentLong(u32),
955}
956
957#[derive(Clone, Copy, PartialEq, Eq, Debug)]
964pub enum ContentRoute {
965 Light,
966 Mid,
967 DenseInter,
968 EntropyExtreme,
969}
970
971fn route_for(
976 cabac: bool,
977 t8x8: bool,
978 bits_per_mb: f64,
979 skip_frac: f64,
980 coded_frac: f64,
981) -> ContentRoute {
982 let (root_coded, light_skip, extreme_bits) = if !cabac {
986 (0.6116, 0.6433, 406.4)
987 } else if t8x8 {
988 (0.4244, 0.6358, 331.7)
989 } else {
990 (0.3709, 0.6343, 315.2)
991 };
992 if coded_frac <= root_coded {
993 if skip_frac > light_skip {
994 ContentRoute::Light
995 } else {
996 ContentRoute::Mid
997 }
998 } else if bits_per_mb <= extreme_bits {
999 ContentRoute::DenseInter
1000 } else {
1001 ContentRoute::EntropyExtreme
1002 }
1003}
1004
1005struct PendingPic {
1006 fd: mb16::FrameDecoder,
1007 frame_num: u32,
1008 poc: i32,
1009 next_mb: usize,
1010 total_mb: usize,
1011 slice_count: u16,
1012 deblock: bool,
1013 filter_offset_a: i32,
1014 filter_offset_b: i32,
1015 crop_r: usize,
1016 crop_b: usize,
1017 max_refs: usize,
1018 log2_max_frame_num: u32,
1019 is_reference: bool,
1022 idr_long_term: bool,
1023 mmco_ops: Vec<Mmco>,
1024 route_bits: u64,
1026 route_cabac: bool,
1027 route_t8x8: bool,
1028}
1029
1030fn no_pool() -> bool {
1032 #[cfg(not(feature = "knobs"))]
1036 {
1037 false
1038 }
1039 #[cfg(feature = "knobs")]
1040 {
1041 use core::sync::atomic::{AtomicU8, Ordering};
1042 static ON: AtomicU8 = AtomicU8::new(0);
1043 match ON.load(Ordering::Relaxed) {
1044 0 => {
1045 let v = rusty_h264_common::knob("RS_H264_NO_POOL").is_some_and(|v| v == "1");
1046 ON.store(if v { 1 } else { 2 }, Ordering::Relaxed);
1047 v
1048 }
1049 n => n == 1,
1050 }
1051 }
1052}
1053
1054#[derive(Default)]
1058pub struct Decoder {
1059 last_route: Option<ContentRoute>,
1061 route_ema: Option<(f64, f64, f64)>,
1067 pub(crate) sps: alloc::collections::BTreeMap<u32, crate::sync::Arc<Sps>>,
1072 pub(crate) pps: alloc::collections::BTreeMap<u32, crate::sync::Arc<Pps>>,
1073 pub(crate) refs: Vec<Ref>,
1075 cur: Option<PendingPic>,
1077 pub(crate) poc: PocState,
1081 pub(crate) last_poc: i32,
1083 pub(crate) prev_ref_frame_num: u32,
1086 grid_pool: GridPool,
1089 sc_reorder0: Vec<(u32, u32)>,
1091 sc_reorder1: Vec<(u32, u32)>,
1092 sc_mmco: Vec<Mmco>,
1093 plane_pool: Vec<Vec<u8>>,
1096 mv_pool: Vec<Vec<(i16, i16)>>,
1103 ref_pool: Vec<Vec<i8>>,
1104 retired: Vec<Ref>,
1109 pub(crate) detach_dpb: bool,
1112 pub(crate) detached_ref: Option<Ref>,
1114 pub(crate) progress_slot: Option<Ref>,
1116 detached_mmco: Vec<Mmco>,
1117 detached_frame_num: u32,
1118 detached_log2_max_frame_num: u32,
1119 detached_max_refs: usize,
1120 detached_idr_long_term: bool,
1121 pub(crate) frame_mt_row_progress: bool,
1123}
1124
1125#[derive(Clone, Default)]
1127pub(crate) struct PocState {
1128 prev_msb: i32,
1129 prev_lsb: i32,
1130 prev_frame_num: u32,
1131 prev_frame_num_offset: i64,
1132}
1133
1134impl PocState {
1135 pub(crate) fn compute_poc(
1139 &mut self,
1140 sps: &Sps,
1141 is_idr: bool,
1142 nal_ref_idc: u8,
1143 frame_num: u32,
1144 poc_lsb: u32,
1145 delta_bottom: i32,
1146 ) -> i32 {
1147 match sps.pic_order_cnt_type {
1148 0 => {
1149 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
1150 let (prev_msb, prev_lsb) = if is_idr {
1151 (0, 0)
1152 } else {
1153 (self.prev_msb, self.prev_lsb)
1154 };
1155 let lsb = poc_lsb as i32;
1156 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
1157 prev_msb + max_lsb
1158 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
1159 prev_msb - max_lsb
1160 } else {
1161 prev_msb
1162 };
1163 let top = msb + lsb;
1164 let poc = top.min(top + delta_bottom);
1165 if nal_ref_idc != 0 {
1166 self.prev_msb = msb;
1167 self.prev_lsb = lsb;
1168 }
1169 poc
1170 }
1171 2 => {
1172 let max_fn = 1i64 << sps.log2_max_frame_num;
1173 let offset = if is_idr {
1174 0
1175 } else if self.prev_frame_num > frame_num {
1176 self.prev_frame_num_offset + max_fn
1177 } else {
1178 self.prev_frame_num_offset
1179 };
1180 let poc = if is_idr {
1181 0
1182 } else {
1183 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
1184 };
1185 self.prev_frame_num_offset = offset;
1186 self.prev_frame_num = frame_num;
1187 poc as i32
1188 }
1189 _ => {
1190 self.prev_frame_num = frame_num;
1191 frame_num as i32 * 2
1192 }
1193 }
1194 }
1195}
1196
1197impl Decoder {
1198 pub fn new() -> Self {
1200 Self::default()
1201 }
1202
1203 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
1206 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
1207 let mut frame = None;
1208 let nals = {
1212 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecNalSplit);
1213 split_annex_b(annex_b)
1214 };
1215 for nal in nals {
1216 if nal.is_empty() {
1217 continue;
1218 }
1219 let nal_type = NalUnitType::from_id(nal[0]);
1220 let rbsp = {
1221 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecRbsp);
1222 emulation_unprevent(&nal[1..])
1223 };
1224 match nal_type {
1225 NalUnitType::Sps => {
1226 let s = Sps::parse(&rbsp)?;
1227 self.sps
1228 .insert(s.seq_parameter_set_id, crate::sync::Arc::new(s));
1229 }
1230 NalUnitType::Pps => {
1231 let p = Pps::parse(&rbsp)?;
1232 self.pps
1233 .insert(p.pic_parameter_set_id, crate::sync::Arc::new(p));
1234 }
1235 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
1236 let nal_ref_idc = (nal[0] >> 5) & 3;
1237 let is_idr = nal_type == NalUnitType::IdrSlice;
1238 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
1239 frame = Some(f);
1240 }
1241 }
1242 _ => {} }
1244 }
1245 Ok(frame)
1246 }
1247
1248 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
1261 #[cfg(feature = "std")]
1262 {
1263 let n = frame_mt::frame_threads();
1264 if n > 1 {
1265 return frame_mt::decode_stream_threaded(annex_b, n);
1266 }
1267 }
1268 self.decode_stream_serial(annex_b)
1269 }
1270
1271 #[cfg(feature = "std")]
1273 pub fn decode_stream_threaded(
1274 &mut self,
1275 annex_b: &[u8],
1276 threads: usize,
1277 ) -> Result<Vec<YuvFrame>, DecodeError> {
1278 if threads <= 1 {
1279 return self.decode_stream_serial(annex_b);
1280 }
1281 frame_mt::decode_stream_threaded(annex_b, threads)
1282 }
1283
1284 #[cfg(feature = "std")]
1287 pub fn decode_stream_threaded_sink(
1288 &mut self,
1289 annex_b: &[u8],
1290 threads: usize,
1291 sink: impl FnMut(YuvFrame),
1292 ) -> Result<usize, DecodeError> {
1293 if threads <= 1 {
1294 let frames = self.decode_stream_serial(annex_b)?;
1295 let n = frames.len();
1296 let mut sink = sink;
1297 for f in frames {
1298 sink(f);
1299 }
1300 return Ok(n);
1301 }
1302 frame_mt::decode_stream_threaded_sink(annex_b, threads, sink)
1303 }
1304
1305 fn decode_stream_serial(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
1306 let mut out = Vec::new();
1307 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
1308 for au in split_access_units(annex_b) {
1309 if au_is_idr(au) {
1310 flush_gop(&mut gop, &mut out); }
1312 if let Some(frame) = self.decode(au)? {
1313 gop.push((self.last_poc, frame));
1314 }
1315 }
1316 flush_gop(&mut gop, &mut out);
1317 Ok(out)
1318 }
1319
1320 fn decode_slice(
1321 &mut self,
1322 rbsp: &[u8],
1323 is_idr: bool,
1324 nal_ref_idc: u8,
1325 ) -> Result<Option<YuvFrame>, DecodeError> {
1326 let mut r = BitReader::new(rbsp);
1327 let first_mb_in_slice = r.read_ue()? as usize;
1329 let slice_type = r.read_ue()?;
1330 let is_p = matches!(slice_type, 0 | 5);
1331 let is_b = matches!(slice_type, 1 | 6);
1332 let is_i = matches!(slice_type, 2 | 7);
1333 if !is_p && !is_b && !is_i {
1334 return Err(DecodeError::Unsupported("SP/SI slices"));
1335 }
1336 let pic_parameter_set_id = r.read_ue()?;
1338 let pps = self
1339 .pps
1340 .get(&pic_parameter_set_id)
1341 .cloned()
1342 .ok_or(DecodeError::MissingParameterSet)?;
1343 let sps = self
1344 .sps
1345 .get(&pps.seq_parameter_set_id)
1346 .cloned()
1347 .ok_or(DecodeError::MissingParameterSet)?;
1348 let sps = &sps;
1349 let pps = &pps;
1350 let cabac = pps.entropy_coding_mode_flag;
1354 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
1355 if !sps.frame_mbs_only && r.read_bit()? {
1358 return Err(DecodeError::Unsupported(
1359 "interlace / field coding (field picture)",
1360 ));
1361 }
1362 if is_idr {
1363 let _idr_pic_id = r.read_ue()?;
1364 }
1365 let mut poc_lsb = 0u32;
1368 let mut delta_poc_bottom = 0i32;
1369 if sps.pic_order_cnt_type == 0 {
1370 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
1371 if pps.bottom_field_pic_order_present {
1372 delta_poc_bottom = r.read_se()?;
1373 }
1374 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
1375 let _delta_pic_order_cnt_0 = r.read_se()?;
1376 if pps.bottom_field_pic_order_present {
1377 let _delta_pic_order_cnt_1 = r.read_se()?;
1378 }
1379 }
1380 let pic_poc = if first_mb_in_slice == 0 {
1383 self.compute_poc(
1384 sps,
1385 is_idr,
1386 nal_ref_idc,
1387 frame_num,
1388 poc_lsb,
1389 delta_poc_bottom,
1390 )
1391 } else {
1392 self.cur.as_ref().map_or(0, |p| p.poc)
1393 };
1394 if pps.redundant_pic_cnt_present_flag {
1399 let redundant_pic_cnt = r.read_ue()?;
1400 if redundant_pic_cnt != 0 {
1401 return Ok(None);
1402 }
1403 }
1404 if crate::mb16::dump_mb_on() {
1405 eprintln!(
1406 "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}"
1407 );
1408 }
1409 let direct_spatial = if is_b { r.read_bit()? } else { true };
1411 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
1412 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
1413 let mut reorder_l0: Vec<(u32, u32)> = core::mem::take(&mut self.sc_reorder0);
1414 reorder_l0.clear();
1415 let mut reorder_l1: Vec<(u32, u32)> = core::mem::take(&mut self.sc_reorder1);
1416 reorder_l1.clear();
1417 if is_p || is_b {
1418 if r.read_bit()? {
1420 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
1421 if is_b {
1422 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
1423 }
1424 }
1425 if r.read_bit()? {
1427 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
1428 }
1429 if is_b && r.read_bit()? {
1430 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
1432 }
1433 }
1434 let weights = if is_p && pps.weighted_pred {
1439 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
1440 } else if is_b && pps.weighted_bipred_idc == 1 {
1441 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
1442 } else {
1443 None
1444 };
1445 let mut idr_long_term = false;
1449 let mut mmco_ops: Vec<Mmco> = core::mem::take(&mut self.sc_mmco);
1450 mmco_ops.clear();
1451 if nal_ref_idc == 0 {
1452 } else if is_idr {
1454 let _no_output_of_prior_pics = r.read_bit()?;
1455 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
1457 loop {
1459 let op = r.read_ue()?;
1460 match op {
1461 0 => break,
1462 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
1463 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
1464 3 => {
1465 let diff = r.read_ue()?;
1466 let idx = r.read_ue()?;
1467 mmco_ops.push(Mmco::AssignLong(diff, idx));
1468 }
1469 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
1470 5 => mmco_ops.push(Mmco::Reset),
1471 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
1472 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
1473 }
1474 if mmco_ops.len() > 128 {
1475 return Err(DecodeError::Truncated);
1476 }
1477 }
1478 }
1479 let cabac_init_idc = if cabac && !is_i {
1483 let v = r.read_ue()?;
1484 if v > 2 {
1485 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
1486 }
1487 v
1488 } else {
1489 0
1490 };
1491 let slice_qp_delta = r.read_se()?;
1492 let mut deblock = true;
1497 let mut deblock_idc2 = false;
1498 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
1499 if pps.deblocking_filter_control_present_flag {
1500 let disable_deblocking_filter_idc = r.read_ue()?;
1501 deblock = disable_deblocking_filter_idc != 1;
1505 deblock_idc2 = disable_deblocking_filter_idc == 2;
1506 if disable_deblocking_filter_idc != 1 {
1507 filter_offset_a = r.read_se()? * 2;
1509 filter_offset_b = r.read_se()? * 2;
1510 }
1511 }
1512 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
1513
1514 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
1517 self.insert_frame_num_gaps(
1518 frame_num,
1519 1u32 << sps.log2_max_frame_num,
1520 sps.max_num_ref_frames.max(1) as usize,
1521 sps.pic_width_in_mbs * 16,
1522 sps.pic_height_in_mbs * 16,
1523 );
1524 }
1525
1526 let max_fn = 1u32 << sps.log2_max_frame_num;
1529 let (ref_list0, ref_list1) = if is_b {
1530 build_ref_list_b(
1531 &self.refs,
1532 pic_poc,
1533 frame_num,
1534 max_fn,
1535 num_ref_idx_l0,
1536 num_ref_idx_l1,
1537 &reorder_l0,
1538 &reorder_l1,
1539 )?
1540 } else if is_p {
1541 (
1542 build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?,
1543 Vec::new(),
1544 )
1545 } else {
1546 (Vec::new(), Vec::new())
1547 };
1548 self.sc_reorder0 = reorder_l0;
1550 self.sc_reorder1 = reorder_l1;
1551 if first_mb_in_slice == 0 {
1555 if is_idr {
1556 self.retired.append(&mut self.refs);
1560 }
1561 let _g_setup = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecSetup);
1572 let mut fd = FrameDecoder::with_pool(
1573 sps.pic_width_in_mbs,
1574 sps.pic_height_in_mbs,
1575 slice_qp,
1576 pps.chroma_qp_index_offset,
1577 ref_list0,
1578 num_ref_idx_l0,
1579 pps.constrained_intra_pred_flag,
1580 pps.transform_8x8_mode_flag,
1581 sps.profile_idc != 66, if no_pool() {
1586 GridPool::default()
1587 } else {
1588 core::mem::take(&mut self.grid_pool)
1589 },
1590 );
1591 if is_b {
1592 fd.set_b_context(
1593 ref_list1,
1594 num_ref_idx_l1,
1595 direct_spatial,
1596 pic_poc,
1597 pps.weighted_bipred_idc,
1598 sps.direct_8x8_inference,
1599 );
1600 }
1601 if sps.has_scaling || pps.pic_scaling_matrix_present {
1602 let (s4, s8) = resolve_scaling(sps, pps);
1603 fd.set_scaling(s4, s8);
1604 }
1605 fd.set_transform_bypass(sps.transform_bypass);
1606 if let Some(w) = weights {
1607 fd.set_weights(w);
1608 }
1609 if let Some(slot) = self.progress_slot.clone() {
1610 fd.set_progress_slot(slot);
1611 }
1612 if let Some(prev) = self.cur.take() {
1620 if prev.next_mb < prev.total_mb {
1621 return Err(DecodeError::Truncated);
1622 }
1623 }
1624 self.cur = Some(PendingPic {
1625 fd,
1626 frame_num,
1627 poc: pic_poc,
1628 next_mb: 0,
1629 route_bits: 0,
1630 route_cabac: pps.entropy_coding_mode_flag,
1631 route_t8x8: pps.transform_8x8_mode_flag,
1632 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
1633 slice_count: 0,
1634 deblock,
1635 filter_offset_a,
1636 filter_offset_b,
1637 crop_r: sps.frame_crop_right as usize,
1638 crop_b: sps.frame_crop_bottom as usize * sps.crop_unit_y() / 2,
1641 max_refs: sps.max_num_ref_frames.max(1) as usize,
1642 log2_max_frame_num: sps.log2_max_frame_num,
1643 is_reference: nal_ref_idc != 0,
1644 idr_long_term,
1645 mmco_ops,
1646 });
1647 } else {
1648 let Some(pic) = self.cur.as_mut() else {
1650 return Err(DecodeError::Unsupported(
1651 "slice continues a missing picture",
1652 ));
1653 };
1654 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
1655 if is_b {
1656 pic.fd.set_b_context(
1657 ref_list1,
1658 num_ref_idx_l1,
1659 direct_spatial,
1660 pic.poc,
1661 pps.weighted_bipred_idc,
1662 sps.direct_8x8_inference,
1663 );
1664 }
1665 if sps.has_scaling || pps.pic_scaling_matrix_present {
1666 let (s4, s8) = resolve_scaling(sps, pps);
1667 pic.fd.set_scaling(s4, s8);
1668 }
1669 pic.fd.set_transform_bypass(sps.transform_bypass);
1670 if let Some(w) = weights {
1671 pic.fd.set_weights(w);
1672 }
1673 pic.deblock = deblock;
1675 pic.filter_offset_a = filter_offset_a;
1676 pic.filter_offset_b = filter_offset_b;
1677 pic.idr_long_term |= idr_long_term;
1678 pic.mmco_ops.extend(mmco_ops);
1679 }
1680
1681 let pic = self
1682 .cur
1683 .as_mut()
1684 .ok_or(DecodeError::Internal("no pending picture at slice decode"))?;
1685 pic.fd.set_deblock_params(
1689 deblock && !abl_deblock(),
1690 filter_offset_a,
1691 filter_offset_b,
1692 deblock_idc2,
1693 );
1694 let first = first_mb_in_slice.min(pic.total_mb);
1695 pic.route_bits += r.data().len() as u64;
1696 let next = if cabac {
1697 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
1699 let (data, start) = (r.data(), r.bit_pos() / 8);
1700 pic.fd
1701 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
1702 } else {
1703 pic.fd.decode_slice_data(&mut r, is_p, first)
1704 }
1705 .map_err(|e| match e {
1706 mb16::MbError::Truncated => DecodeError::Truncated,
1707 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
1708 })?;
1709 pic.next_mb = next;
1710 pic.slice_count += 1;
1711 if crate::mb16::dump_mb_on() {
1712 eprintln!(
1713 " slice decoded {}/{} MBs{}",
1714 next,
1715 pic.total_mb,
1716 if next < pic.total_mb {
1717 " <-- INCOMPLETE"
1718 } else {
1719 ""
1720 }
1721 );
1722 }
1723
1724 if pic.next_mb < pic.total_mb {
1725 return Ok(None); }
1727
1728 let pic = self
1730 .cur
1731 .take()
1732 .ok_or(DecodeError::Internal("no pending picture at finalize"))?;
1733 if let Some(what) = pic.fd.fault() {
1739 return Err(DecodeError::Internal(what));
1740 }
1741 {
1742 let (skips, coded) = pic.fd.route_counters();
1743 let mbs = pic.total_mb.max(1) as f64;
1744 let bits_per_mb = pic.route_bits as f64 * 8.0 / mbs;
1745 let (skip_frac, coded_frac) = (skips as f64 / mbs, coded as f64 / mbs);
1746 let (eb, es, ec) = match self.route_ema {
1747 None => (bits_per_mb, skip_frac, coded_frac),
1748 Some((pb, ps, pc)) => (
1749 pb + (bits_per_mb - pb) / 8.0,
1750 ps + (skip_frac - ps) / 8.0,
1751 pc + (coded_frac - pc) / 8.0,
1752 ),
1753 };
1754 self.route_ema = Some((eb, es, ec));
1755 let route = route_for(pic.route_cabac, pic.route_t8x8, eb, es, ec);
1756 self.last_route = Some(route);
1757 if crate::mb16::route_dump_on() {
1761 eprintln!(
1762 "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:?}",
1763 pic.route_cabac, pic.route_t8x8
1764 );
1765 }
1766 }
1767 let PendingPic {
1768 mut fd,
1769 frame_num,
1770 poc,
1771 deblock,
1772 filter_offset_a,
1773 filter_offset_b,
1774 crop_r,
1775 crop_b,
1776 max_refs,
1777 log2_max_frame_num,
1778 is_reference,
1779 idr_long_term,
1780 mut mmco_ops,
1781 ..
1782 } = pic;
1783 self.last_poc = poc;
1784 if deblock && !abl_deblock() {
1792 fd.deblock(filter_offset_a, filter_offset_b);
1793 } else {
1794 fd.flush_deferred();
1795 }
1796 let reference = if is_reference {
1799 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
1800 Some(fd.as_reference_pooled(
1801 &mut self.plane_pool,
1802 &mut self.mv_pool,
1803 &mut self.ref_pool,
1804 ))
1805 } else {
1806 None
1807 };
1808 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
1809 if let Some(mut reference) = reference {
1810 reference.frame_num = frame_num;
1811 reference.poc = poc;
1812 if crate::mb16::dump_mb_on() {
1813 eprintln!("DPB-ADD fn={frame_num} poc={poc}");
1814 }
1815 if idr_long_term {
1816 reference.long_term = true;
1817 reference.long_term_idx = 0;
1818 }
1819 let reference = reference; if self.detach_dpb {
1821 self.detached_mmco = core::mem::take(&mut mmco_ops);
1822 self.detached_frame_num = frame_num;
1823 self.detached_log2_max_frame_num = log2_max_frame_num;
1824 self.detached_max_refs = max_refs;
1825 self.detached_idr_long_term = idr_long_term;
1826 if let Some(slot) = self.progress_slot.take() {
1827 Self::fill_progress_slot(&slot, reference);
1829 slot.mark_fully_ready();
1830 self.detached_ref = Some(slot);
1831 } else {
1832 let arc = crate::sync::Arc::new(reference);
1833 arc.mark_fully_ready();
1834 self.detached_ref = Some(arc);
1835 }
1836 } else {
1837 reference.mark_fully_ready();
1838 self.prev_ref_frame_num = self.apply_ref_marking(
1839 reference,
1840 &mmco_ops,
1841 frame_num,
1842 log2_max_frame_num,
1843 max_refs,
1844 );
1845 }
1846 }
1847 self.sc_mmco = mmco_ops; let (frame, pool) = fd.into_frame_recycle(crop_r, crop_b);
1849 self.grid_pool = pool;
1850 self.reclaim_retired();
1851 Ok(Some(frame))
1852 }
1853
1854 pub(crate) fn commit_detached_ref_arc(&mut self, reference: Ref) -> Result<u32, DecodeError> {
1858 reference.mark_fully_ready();
1859 let mmco = core::mem::take(&mut self.detached_mmco);
1860 let frame_num = self.detached_frame_num;
1861 let log2 = self.detached_log2_max_frame_num;
1862 let max_refs = self.detached_max_refs;
1863 self.prev_ref_frame_num =
1864 self.apply_ref_marking_arc(reference, &mmco, frame_num, log2, max_refs);
1865 Ok(self.prev_ref_frame_num)
1866 }
1867
1868 fn fill_progress_slot(slot: &Ref, mut finished: crate::RefFrame) {
1871 let planes = FrozenPlanes {
1872 py: core::mem::take(&mut finished.py),
1873 pu: core::mem::take(&mut finished.pu),
1874 pv: core::mem::take(&mut finished.pv),
1875 };
1876 if let Some(live) = &slot.live {
1877 let _w = live.wait.lock_pf();
1878 {
1879 let mut m = live.meta.write_pf();
1880 m.frame_num = finished.frame_num;
1881 m.poc = finished.poc;
1882 m.long_term = finished.long_term;
1883 m.long_term_idx = finished.long_term_idx;
1884 m.mv = core::mem::take(&mut finished.mv);
1885 m.ref_idx = core::mem::take(&mut finished.ref_idx);
1886 m.mv1 = core::mem::take(&mut finished.mv1);
1887 m.ref_idx1 = core::mem::take(&mut finished.ref_idx1);
1888 m.poc_lut = finished.poc_lut;
1889 m.w4 = finished.w4;
1890 m.motion_ready = true;
1891 }
1892 let _ = slot.frozen.set(planes);
1893 slot.ready_rows
1894 .store(slot.ch, core::sync::atomic::Ordering::Release);
1895 live.cv.notify_all();
1896 } else {
1897 let _ = slot.frozen.set(planes);
1898 slot.mark_fully_ready();
1899 }
1900 }
1901
1902 fn retire_retain(&mut self, keep: impl Fn(&Ref) -> bool) {
1919 let mut i = 0;
1920 while i < self.refs.len() {
1921 if keep(&self.refs[i]) {
1922 i += 1;
1923 } else {
1924 let dropped = self.refs.remove(i);
1925 self.retired.push(dropped);
1926 }
1927 }
1928 }
1929
1930 fn reclaim_retired(&mut self) {
1935 for arc in self.retired.drain(..) {
1936 if let Ok(mut rf) = crate::sync::Arc::try_unwrap(arc) {
1937 if let Some(f) = rf.frozen.take() {
1938 if !f.py.is_empty() {
1939 self.plane_pool.push(f.py);
1940 self.plane_pool.push(f.pu);
1941 self.plane_pool.push(f.pv);
1942 }
1943 } else if !rf.py.is_empty() {
1944 self.plane_pool.push(rf.py);
1945 self.plane_pool.push(rf.pu);
1946 self.plane_pool.push(rf.pv);
1947 }
1948 for v in [core::mem::take(&mut rf.mv), core::mem::take(&mut rf.mv1)] {
1952 if !v.is_empty() {
1953 self.mv_pool.push(v);
1954 }
1955 }
1956 for v in [
1957 core::mem::take(&mut rf.ref_idx),
1958 core::mem::take(&mut rf.ref_idx1),
1959 ] {
1960 if !v.is_empty() {
1961 self.ref_pool.push(v);
1962 }
1963 }
1964 }
1965 }
1966 self.mv_pool.truncate(12);
1969 self.ref_pool.truncate(12);
1970 self.plane_pool.truncate(18);
1971 }
1972
1973 fn insert_frame_num_gaps(
1979 &mut self,
1980 frame_num: u32,
1981 max_fn: u32,
1982 max_refs: usize,
1983 w: usize,
1984 h: usize,
1985 ) {
1986 if max_fn == 0 {
1987 return;
1988 }
1989 let start = (self.prev_ref_frame_num + 1) % max_fn;
1990 let gap = (frame_num + max_fn - start) % max_fn;
1991 if gap == 0 {
1992 return;
1993 }
1994 let cap = max_refs.max(1);
2000 let n = (gap as usize).min(cap);
2001 let (cw, ch) = (w, h);
2002 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
2003 for _ in 0..n {
2004 self.refs.insert(
2005 0,
2006 crate::sync::Arc::new(RefFrame {
2007 py: vec![128; (cw + 2 * LPAD) * (ch + 2 * LPAD)],
2009 pu: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
2010 pv: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
2011 cw,
2012 ch,
2013 ready_rows: core::sync::atomic::AtomicUsize::new(ch),
2014 live: None,
2015 frozen: crate::sync::Once::new(),
2016 frame_num: expected,
2017 poc: 0,
2018 mv: Vec::new(),
2019 ref_idx: Vec::new(),
2020 mv1: Vec::new(),
2021 ref_idx1: Vec::new(),
2022 poc_lut: [i32::MIN; 32],
2023 w4: 0,
2024 long_term: false,
2025 long_term_idx: 0,
2026 }),
2027 );
2028 if self.refs.len() > cap {
2029 self.retired.extend(self.refs.drain(cap..));
2034 }
2035 expected = (expected + 1) % max_fn;
2036 }
2037 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
2038 }
2039
2040 pub fn content_route(&self) -> Option<ContentRoute> {
2047 self.last_route
2048 }
2049
2050 pub fn last_poc(&self) -> i32 {
2051 self.last_poc
2052 }
2053
2054 fn compute_poc(
2055 &mut self,
2056 sps: &Sps,
2057 is_idr: bool,
2058 nal_ref_idc: u8,
2059 frame_num: u32,
2060 poc_lsb: u32,
2061 delta_bottom: i32,
2062 ) -> i32 {
2063 self.poc
2064 .compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_bottom)
2065 }
2066
2067 fn apply_ref_marking(
2078 &mut self,
2079 mut reference: RefFrame,
2080 ops: &[Mmco],
2081 frame_num: u32,
2082 log2_max_frame_num: u32,
2083 max_refs: usize,
2084 ) -> u32 {
2085 let max = 1i64 << log2_max_frame_num;
2086 let curr = frame_num as i64;
2087 let pic_num = |rf: &RefFrame| -> i64 {
2088 if (rf.frame_num as i64) > curr {
2089 rf.frame_num as i64 - max
2090 } else {
2091 rf.frame_num as i64
2092 }
2093 };
2094
2095 if ops.is_empty() {
2096 let out_fn = reference.frame_num;
2100 self.refs.insert(0, crate::sync::Arc::new(reference));
2101 while self.refs.len() > max_refs {
2102 match self.refs.iter().rposition(|r| !r.long_term) {
2103 Some(pos) => {
2104 let evicted = self.refs.remove(pos);
2107 self.retired.push(evicted);
2108 }
2109 None => break,
2110 }
2111 }
2112 return out_fn;
2113 }
2114
2115 for &op in ops {
2117 match op {
2118 Mmco::Unref(diff) => {
2119 let target = curr - (diff as i64 + 1);
2120 self.retire_retain(|r| r.long_term || pic_num(r) != target);
2121 }
2122 Mmco::UnrefLong(ltpn) => {
2123 self.retire_retain(|r| !(r.long_term && r.long_term_idx == ltpn));
2124 }
2125 Mmco::AssignLong(diff, idx) => {
2126 let target = curr - (diff as i64 + 1);
2127 self.retire_retain(|r| !(r.long_term && r.long_term_idx == idx));
2128 for r in self.refs.iter_mut() {
2129 if !r.long_term && pic_num(r) == target {
2130 let r = crate::sync::Arc::make_mut(r);
2132 r.long_term = true;
2133 r.long_term_idx = idx;
2134 }
2135 }
2136 }
2137 Mmco::MaxLong(max_plus1) => {
2138 self.retire_retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
2139 }
2140 Mmco::Reset => {
2141 self.retired.append(&mut self.refs);
2142 reference.frame_num = 0;
2143 }
2144 Mmco::CurrentLong(idx) => {
2145 self.retire_retain(|r| !(r.long_term && r.long_term_idx == idx));
2146 reference.long_term = true;
2147 reference.long_term_idx = idx;
2148 }
2149 }
2150 }
2151 let out_fn = reference.frame_num;
2152 self.refs.insert(0, crate::sync::Arc::new(reference));
2153 let cap = max_refs.max(16);
2155 if self.refs.len() > cap {
2156 self.retired.extend(self.refs.drain(cap..));
2157 }
2158 out_fn
2159 }
2160
2161 fn apply_ref_marking_arc(
2164 &mut self,
2165 mut reference: Ref,
2166 ops: &[Mmco],
2167 frame_num: u32,
2168 log2_max_frame_num: u32,
2169 max_refs: usize,
2170 ) -> u32 {
2171 let max = 1i64 << log2_max_frame_num;
2172 let curr = frame_num as i64;
2173 let pic_num = |rf: &RefFrame| -> i64 {
2174 let f = rf.fn_num() as i64;
2175 if f > curr {
2176 f - max
2177 } else {
2178 f
2179 }
2180 };
2181
2182 if ops.is_empty() {
2183 let out_fn = reference.fn_num();
2184 self.refs.insert(0, reference);
2185 while self.refs.len() > max_refs {
2186 match self.refs.iter().rposition(|r| !r.is_long_term()) {
2187 Some(pos) => {
2188 let evicted = self.refs.remove(pos);
2189 self.retired.push(evicted);
2190 }
2191 None => break,
2192 }
2193 }
2194 return out_fn;
2195 }
2196
2197 for &op in ops {
2198 match op {
2199 Mmco::Unref(diff) => {
2200 let target = curr - (diff as i64 + 1);
2201 self.refs
2202 .retain(|r| r.is_long_term() || pic_num(r) != target);
2203 }
2204 Mmco::UnrefLong(ltpn) => {
2205 self.retire_retain(|r| !(r.is_long_term() && r.lt_idx() == ltpn));
2206 }
2207 Mmco::AssignLong(diff, idx) => {
2208 let target = curr - (diff as i64 + 1);
2209 self.retire_retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
2210 for r in self.refs.iter_mut() {
2211 if !r.is_long_term() && pic_num(r) == target {
2212 if r.live.is_some() {
2213 r.set_long_term_marks(true, idx);
2214 } else {
2215 let r = crate::sync::Arc::make_mut(r);
2216 r.long_term = true;
2217 r.long_term_idx = idx;
2218 }
2219 }
2220 }
2221 }
2222 Mmco::MaxLong(max_plus1) => {
2223 self.retire_retain(|r| !(r.is_long_term() && r.lt_idx() + 1 > max_plus1));
2224 }
2225 Mmco::Reset => {
2226 self.retired.append(&mut self.refs);
2227 reference.set_frame_num_live(0);
2228 if let Some(r) = crate::sync::Arc::get_mut(&mut reference) {
2229 r.frame_num = 0;
2230 }
2231 }
2232 Mmco::CurrentLong(idx) => {
2233 self.retire_retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
2234 reference.set_long_term_marks(true, idx);
2235 if let Some(r) = crate::sync::Arc::get_mut(&mut reference) {
2236 r.long_term = true;
2237 r.long_term_idx = idx;
2238 }
2239 }
2240 }
2241 }
2242 let out_fn = reference.fn_num();
2243 self.refs.insert(0, reference);
2244 let cap = max_refs.max(16);
2245 if self.refs.len() > cap {
2246 self.retired.extend(self.refs.drain(cap..));
2247 }
2248 out_fn
2249 }
2250}
2251
2252pub(crate) fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
2254 gop.sort_by_key(|(poc, _)| *poc);
2255 out.extend(gop.drain(..).map(|(_, f)| f));
2256}
2257
2258pub fn au_is_idr(au: &[u8]) -> bool {
2263 split_annex_b(au)
2264 .iter()
2265 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
2266}
2267
2268pub fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
2276 let mut codes: Vec<(usize, bool)> = Vec::new();
2278 let mut i = 0;
2279 while let Some(w) = stream.get(i..i + 3) {
2283 if w[0] == 0 && w[1] == 0 && w[2] == 1 {
2284 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
2285 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
2286 let sc = if i > 0 && stream.get(i - 1) == Some(&0) {
2288 i - 1
2289 } else {
2290 i
2291 };
2292 codes.push((sc, is_vcl));
2293 i += 3;
2294 } else {
2295 i += 1;
2296 }
2297 }
2298 if codes.is_empty() {
2299 return vec![stream];
2300 }
2301 let mut aus = Vec::new();
2302 let mut start = codes[0].0;
2303 for k in 0..codes.len() {
2304 if codes[k].1 {
2305 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
2306 aus.push(&stream[start..end]);
2307 start = end;
2308 }
2309 }
2310 aus
2311}
2312
2313fn parse_pred_weight_table(
2316 r: &mut BitReader,
2317 num_l0: usize,
2318 num_l1: usize,
2319 is_b: bool,
2320) -> Result<WeightTable, DecodeError> {
2321 let luma_log2_denom = r.read_ue()? as i32;
2322 let chroma_log2_denom = r.read_ue()? as i32;
2323 if !(0..=7).contains(&luma_log2_denom) || !(0..=7).contains(&chroma_log2_denom) {
2327 return Err(DecodeError::Unsupported("invalid weight denom"));
2328 }
2329 let mut wt = WeightTable {
2330 luma_log2_denom,
2331 chroma_log2_denom,
2332 ..Default::default()
2333 };
2334 let lists: &[(usize, usize)] = if is_b {
2335 &[(0, num_l0), (1, num_l1)]
2336 } else {
2337 &[(0, num_l0)]
2338 };
2339 for &(list, n) in lists {
2340 let mut luma = Vec::with_capacity(n);
2341 let mut chroma = Vec::with_capacity(n);
2342 for _ in 0..n {
2343 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
2344 if r.read_bit()? {
2345 lw = r.read_se()?;
2346 lo = r.read_se()?;
2347 }
2348 luma.push((lw, lo));
2349 let mut ch = [(1 << chroma_log2_denom, 0); 2];
2350 if r.read_bit()? {
2351 for slot in ch.iter_mut() {
2352 *slot = (r.read_se()?, r.read_se()?);
2353 }
2354 }
2355 chroma.push(ch);
2356 }
2357 wt.luma[list & 1] = luma;
2358 wt.chroma[list & 1] = chroma;
2359 }
2360 Ok(wt)
2361}
2362
2363fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
2368 use crate::params::{
2369 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
2370 };
2371 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
2372 const ZZ8: [usize; 64] = [
2374 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,
2375 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
2376 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
2377 ];
2378 let mut z4 = [[16u8; 16]; 6];
2381 for i in 0..6 {
2382 z4[i] = if pps.pic_scaling_matrix_present {
2383 if pps.scaling_present_4x4[i] {
2384 pps.scaling_4x4[i]
2385 } else {
2386 match i {
2387 0 if sps.has_scaling => sps.scaling_4x4[0],
2388 0 => DEFAULT_4X4_INTRA,
2389 3 if sps.has_scaling => sps.scaling_4x4[3],
2390 3 => DEFAULT_4X4_INTER,
2391 _ => z4[i - 1],
2392 }
2393 }
2394 } else {
2395 sps.scaling_4x4[i]
2396 };
2397 }
2398 let mut z8 = [[16u8; 64]; 2];
2399 for (i, list) in z8.iter_mut().enumerate() {
2400 *list = if pps.pic_scaling_matrix_present {
2401 if pps.scaling_present_8x8[i] {
2402 pps.scaling_8x8[i]
2403 } else if sps.has_scaling {
2404 sps.scaling_8x8[i]
2405 } else if i == 0 {
2406 DEFAULT_8X8_INTRA
2407 } else {
2408 DEFAULT_8X8_INTER
2409 }
2410 } else {
2411 sps.scaling_8x8[i]
2412 };
2413 }
2414 let mut out4 = [[16i32; 16]; 6];
2415 for (li, list) in out4.iter_mut().enumerate() {
2416 for k in 0..16 {
2417 list[ZZ4[k]] = z4[li][k] as i32;
2418 }
2419 }
2420 let mut out8 = [[16i32; 64]; 2];
2421 for (li, list) in out8.iter_mut().enumerate() {
2422 for k in 0..64 {
2423 list[ZZ8[k]] = z8[li][k] as i32;
2424 }
2425 }
2426 (out4, out8)
2427}
2428
2429fn parse_ref_pic_list_modification(
2432 r: &mut BitReader,
2433 out: &mut Vec<(u32, u32)>,
2434) -> Result<(), DecodeError> {
2435 loop {
2436 let idc = r.read_ue()?;
2437 if idc == 3 {
2438 break;
2439 }
2440 if idc > 3 {
2441 return Err(DecodeError::Unsupported(
2442 "invalid ref_pic_list_modification",
2443 ));
2444 }
2445 let val = r.read_ue()?; out.push((idc, val));
2447 if out.len() > 64 {
2448 return Err(DecodeError::Truncated); }
2450 }
2451 Ok(())
2452}
2453
2454fn build_ref_list_p(
2458 dpb: &[Ref],
2459 curr_frame_num: u32,
2460 max_frame_num: u32,
2461 num_active: usize,
2462 mods: &[(u32, u32)],
2463) -> Result<Vec<Ref>, DecodeError> {
2464 let curr = curr_frame_num as i64;
2465 let max = max_frame_num as i64;
2466 let pic_num = |fnum: u32| -> i64 {
2467 let f = fnum as i64;
2468 if f > curr {
2469 f - max
2470 } else {
2471 f
2472 }
2473 };
2474 let mut init: Vec<Ref> = dpb.iter().filter(|r| !r.is_long_term()).cloned().collect();
2475 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.fn_num())));
2476 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
2477 long.sort_by_key(|rf| rf.lt_idx());
2478 init.extend(long);
2479 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
2480}
2481
2482fn build_ref_list_b(
2487 dpb: &[Ref],
2488 curr_poc: i32,
2489 curr_frame_num: u32,
2490 max_frame_num: u32,
2491 num0: usize,
2492 num1: usize,
2493 mods0: &[(u32, u32)],
2494 mods1: &[(u32, u32)],
2495) -> Result<(Vec<Ref>, Vec<Ref>), DecodeError> {
2496 let mut less: Vec<Ref> = dpb
2497 .iter()
2498 .filter(|r| !r.is_long_term() && r.pic_poc() < curr_poc)
2499 .cloned()
2500 .collect();
2501 let mut greater: Vec<Ref> = dpb
2502 .iter()
2503 .filter(|r| !r.is_long_term() && r.pic_poc() > curr_poc)
2504 .cloned()
2505 .collect();
2506 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
2507 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());
2510
2511 let mut init0 = less.clone();
2512 init0.extend(greater.clone());
2513 init0.extend(long.clone());
2514 let mut init1 = greater;
2515 init1.extend(less);
2516 init1.extend(long);
2517
2518 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
2521 if num1 > 1
2522 && init1.len() > 1
2523 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
2524 && eq_len == num1.min(init1.len())
2525 && eq_len == num0.min(init0.len())
2526 {
2527 if let [a, b, ..] = &mut init1[..] {
2530 core::mem::swap(a, b);
2531 }
2532 }
2533
2534 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
2535 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
2536 Ok((list0, list1))
2537}
2538
2539fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
2541 a.is_long_term() == b.is_long_term()
2542 && if a.is_long_term() {
2543 a.lt_idx() == b.lt_idx()
2544 } else {
2545 a.pic_poc() == b.pic_poc()
2546 }
2547}
2548
2549fn apply_list_modification(
2554 init: Vec<Ref>,
2555 curr_frame_num: u32,
2556 max_frame_num: u32,
2557 num_active: usize,
2558 mods: &[(u32, u32)],
2559) -> Result<Vec<Ref>, DecodeError> {
2560 if mods.is_empty() {
2561 let mut init = init;
2562 init.truncate(num_active.max(1));
2563 return Ok(init);
2564 }
2565 let curr = curr_frame_num as i64;
2566 let max = max_frame_num as i64;
2567 let mut list = init.clone();
2568 let mut pic_num_pred = curr;
2569 let mut refidx = 0usize;
2570 for &(idc, val) in mods {
2571 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
2572 Box::new(move |r: &RefFrame| r.is_long_term() && r.lt_idx() == val)
2573 } else {
2574 let abs_diff = (val as i64) + 1;
2575 let no_wrap = if idc == 0 {
2576 let x = pic_num_pred - abs_diff;
2577 if x < 0 {
2578 x + max
2579 } else {
2580 x
2581 }
2582 } else {
2583 let x = pic_num_pred + abs_diff;
2584 if x >= max {
2585 x - max
2586 } else {
2587 x
2588 }
2589 };
2590 pic_num_pred = no_wrap;
2591 let target = if no_wrap > curr {
2592 no_wrap - max
2593 } else {
2594 no_wrap
2595 };
2596 Box::new(move |r: &RefFrame| {
2597 let f = r.fn_num() as i64;
2598 let pn = if f > curr { f - max } else { f };
2599 !r.is_long_term() && pn == target
2600 })
2601 };
2602 let found = init.iter().find(|r| matches(r)).cloned();
2603 let Some(found) = found else {
2604 if crate::mb16::dump_mb_on() {
2605 let cand: Vec<String> = init
2606 .iter()
2607 .map(|r| {
2608 let f = r.fn_num() as i64;
2609 let pn = if f > curr { f - max } else { f };
2610 format!(
2611 "(fn={} poc={} lt={} picnum={})",
2612 r.fn_num(),
2613 r.pic_poc(),
2614 r.is_long_term(),
2615 pn
2616 )
2617 })
2618 .collect();
2619 eprintln!(
2620 "MODFAIL idc={idc} val={val} curr_frame_num={curr} max={max} init={}",
2621 cand.join(" ")
2622 );
2623 }
2624 return Err(DecodeError::Truncated); };
2626 if refidx > list.len() {
2627 break;
2628 }
2629 list.insert(refidx, found);
2630 if let Some(dup) = list
2631 .iter()
2632 .enumerate()
2633 .skip(refidx + 1)
2634 .find(|(_, r)| matches(r))
2635 .map(|(i, _)| i)
2636 {
2637 list.remove(dup);
2638 }
2639 refidx += 1;
2640 if refidx >= num_active {
2641 break;
2642 }
2643 }
2644 list.truncate(num_active.max(1));
2645 Ok(list)
2646}
2647
2648#[cfg(test)]
2649mod tests {
2650 use super::*;
2651
2652 fn ref_at(poc: i32, fnum: u32) -> Ref {
2653 crate::sync::Arc::new(RefFrame {
2654 py: vec![],
2655 pu: vec![],
2656 pv: vec![],
2657 cw: 0,
2658 ch: 0,
2659 ready_rows: core::sync::atomic::AtomicUsize::new(0),
2660 live: None,
2661 frozen: crate::sync::Once::new(),
2662 frame_num: fnum,
2663 poc,
2664 mv: Vec::new(),
2665 ref_idx: Vec::new(),
2666 mv1: Vec::new(),
2667 ref_idx1: Vec::new(),
2668 poc_lut: [i32::MIN; 32],
2669 w4: 0,
2670 long_term: false,
2671 long_term_idx: 0,
2672 })
2673 }
2674
2675 #[test]
2676 fn b_ref_lists_ordered_by_poc() {
2677 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
2679 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
2680 assert_eq!(
2682 l0.iter().map(|r| r.poc).collect::<Vec<_>>(),
2683 vec![2, 0, 6, 8]
2684 );
2685 assert_eq!(
2687 l1.iter().map(|r| r.poc).collect::<Vec<_>>(),
2688 vec![6, 8, 2, 0]
2689 );
2690 }
2691
2692 #[test]
2693 fn b_ref_list1_swap_when_equal() {
2694 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
2697 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
2698 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
2699 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
2700 }
2701
2702 #[test]
2703 fn frame_num_gaps_insert_placeholders() {
2704 let mut d = Decoder::new();
2705 d.prev_ref_frame_num = 2;
2706 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
2708 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
2709 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
2710 assert_eq!(d.prev_ref_frame_num, 4);
2711 assert!(
2712 d.refs.iter().all(|r| r.py.iter().all(|&p| p == 128)),
2713 "grey fill"
2714 );
2715 }
2716
2717 #[test]
2718 fn frame_num_gaps_wrap_and_noop() {
2719 let mut d = Decoder::new();
2721 d.prev_ref_frame_num = 14;
2722 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
2723 assert_eq!(
2724 d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(),
2725 vec![0, 15]
2726 );
2727 let mut d = Decoder::new();
2729 d.prev_ref_frame_num = 3;
2730 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
2731 assert!(d.refs.is_empty());
2732 }
2733
2734 #[test]
2735 fn missing_param_sets_errors() {
2736 let mut d = Decoder::new();
2737 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
2740 let err = d.decode(&nal.to_annex_b()).unwrap_err();
2741 assert_eq!(err, DecodeError::MissingParameterSet);
2742 }
2743}