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(not(feature = "std"))]
119 mod single {
120 use core::cell::{Ref, RefCell, RefMut};
121
122 #[derive(Debug, Default)]
123 pub struct RwLock<T>(RefCell<T>);
124 pub type RwLockReadGuard<'a, T> = Ref<'a, T>;
125 impl<T> RwLock<T> {
126 pub const fn new(v: T) -> Self {
127 RwLock(RefCell::new(v))
128 }
129 pub fn read(&self) -> Result<Ref<'_, T>, ()> {
130 Ok(self.0.borrow())
131 }
132 pub fn write(&self) -> Result<RefMut<'_, T>, ()> {
133 Ok(self.0.borrow_mut())
134 }
135 }
136
137 #[derive(Debug, Default)]
138 pub struct Mutex<T>(RefCell<T>);
139 impl<T> Mutex<T> {
140 pub const fn new(v: T) -> Self {
141 Mutex(RefCell::new(v))
142 }
143 pub fn lock(&self) -> Result<RefMut<'_, T>, ()> {
144 Ok(self.0.borrow_mut())
145 }
146 }
147
148 #[derive(Debug, Default)]
149 pub struct Condvar;
150 impl Condvar {
151 pub const fn new() -> Self {
152 Condvar
153 }
154 pub fn wait<'a, T>(&self, g: RefMut<'a, T>) -> Result<RefMut<'a, T>, ()> {
155 Ok(g)
156 }
157 pub fn notify_all(&self) {}
158 pub fn notify_one(&self) {}
159 }
160
161 pub mod mpsc {
165 use core::marker::PhantomData;
166 pub struct SyncSender<T>(PhantomData<T>);
167 pub struct Sender<T>(PhantomData<T>);
168 pub struct Receiver<T>(PhantomData<T>);
169 pub struct SendError<T>(pub T);
170 #[derive(Debug)]
171 pub struct RecvError;
172 impl<T> core::fmt::Debug for SendError<T> {
173 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 f.write_str("SendError")
175 }
176 }
177 impl<T> SyncSender<T> {
178 pub fn send(&self, _t: T) -> Result<(), SendError<T>> {
179 unreachable!("no worker thread without std")
180 }
181 }
182 impl<T> Sender<T> {
183 pub fn send(&self, _t: T) -> Result<(), SendError<T>> {
184 unreachable!("no worker thread without std")
185 }
186 }
187 impl<T> Receiver<T> {
188 pub fn recv(&self) -> Result<T, RecvError> {
189 unreachable!("no worker thread without std")
190 }
191 }
192 }
193 }
194}
195
196mod cabac;
197#[cfg(feature = "profile")]
199pub use cabac::bin_census;
200#[cfg(feature = "std")]
201mod frame_mt;
202mod mb16;
203mod params;
204
205pub use mb16::MvField;
206#[cfg(feature = "std")]
207pub use mb16::MV_DUMP;
208pub use params::{Pps, Sps};
209
210#[cfg(feature = "std")]
212pub(crate) fn frame_threads() -> usize {
213 frame_mt::frame_threads()
214}
215#[cfg(not(feature = "std"))]
217pub(crate) fn frame_threads() -> usize {
218 1
219}
220
221#[cfg(feature = "std")]
223pub(crate) fn row_publish_on() -> bool {
224 frame_mt::row_publish_on()
225}
226#[cfg(not(feature = "std"))]
228pub(crate) fn row_publish_on() -> bool {
229 false
230}
231#[cfg(feature = "std")]
233pub(crate) fn row_progress_on() -> bool {
234 frame_mt::row_progress_on()
235}
236#[cfg(not(feature = "std"))]
238pub(crate) fn row_progress_on() -> bool {
239 false
240}
241
242pub fn edc_stats_report() {
244 mb16::edcstat::report();
245 rusty_h264_common::deblock::filtstat::report();
246}
247
248#[doc(hidden)]
251fn abl_deblock() -> bool {
254 #[cfg(not(feature = "knobs"))]
258 {
259 return false;
260 }
261 #[cfg(feature = "knobs")]
262 {
263 static ON: rusty_h264_common::once::OnceLock<bool> =
264 rusty_h264_common::once::OnceLock::new();
265 *ON.get_or_init(|| rusty_h264_common::knob("RFF_ABL_DEBLOCK").map_or(false, |v| v != "0"))
266 }
267}
268
269pub mod cabac_test {
270 pub use crate::cabac::Cabac;
271 pub use crate::mb16::b_inter_shape;
272 pub use crate::mb16::parse_cbp_cabac;
273 pub use crate::mb16::parse_mb_qp_delta_cabac;
274 pub use crate::mb16::parse_mb_type_b;
275 pub use crate::mb16::parse_ref_idx_cabac;
276}
277
278#[allow(unused_imports)]
279use alloc::borrow::ToOwned;
280#[allow(unused_imports)]
281use alloc::boxed::Box;
282#[allow(unused_imports)]
283use alloc::format;
284#[allow(unused_imports)]
285use alloc::string::{String, ToString};
286#[allow(unused_imports)]
287use alloc::vec;
288#[allow(unused_imports)]
289use alloc::vec::Vec;
290use mb16::{FrameDecoder, GridPool, WeightTable};
291use rusty_h264_common::bit_reader::OutOfData;
292use rusty_h264_common::nal::{emulation_unprevent, split_annex_b};
293use rusty_h264_common::{BitReader, NalUnitType, YuvFrame};
294
295#[derive(Debug, Clone, PartialEq, Eq)]
297pub enum DecodeError {
298 Truncated,
300 MissingParameterSet,
302 Unsupported(&'static str),
304}
305
306impl From<OutOfData> for DecodeError {
307 fn from(_: OutOfData) -> Self {
308 DecodeError::Truncated
309 }
310}
311
312impl core::fmt::Display for DecodeError {
313 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
314 match self {
315 DecodeError::Truncated => f.write_str("bitstream truncated"),
316 DecodeError::MissingParameterSet => f.write_str("slice before SPS/PPS"),
317 DecodeError::Unsupported(s) => write!(f, "unsupported coding tool: {s}"),
318 }
319 }
320}
321
322impl core::error::Error for DecodeError {}
323
324pub(crate) type Ref = crate::sync::Arc<RefFrame>;
333
334#[derive(Debug, Default)]
335#[allow(dead_code)]
336pub(crate) struct RefFrame {
337 pub py: Vec<u8>,
343 pub pu: Vec<u8>,
344 pub pv: Vec<u8>,
345 pub cw: usize,
346 pub ch: usize,
347 pub ready_rows: core::sync::atomic::AtomicUsize,
351 pub live: Option<crate::sync::Arc<LivePlanes>>,
356 pub frozen: crate::sync::Once<FrozenPlanes>,
359 pub frame_num: u32,
361 pub poc: i32,
363 pub mv: Vec<(i32, i32)>,
367 pub ref_idx: Vec<i32>,
368 pub mv1: Vec<(i32, i32)>,
375 pub ref_idx1: Vec<i32>,
376 pub ref_poc: Vec<i32>,
380 pub w4: usize,
381 pub long_term: bool,
385 pub long_term_idx: u32,
386}
387
388impl Clone for RefFrame {
389 fn clone(&self) -> Self {
390 use core::sync::atomic::Ordering::Relaxed;
391 let frozen = crate::sync::Once::new();
392 if let Some(p) = self.frozen.get() {
393 let _ = frozen.set(p.clone());
394 }
395 Self {
396 py: self.py.clone(),
397 pu: self.pu.clone(),
398 pv: self.pv.clone(),
399 cw: self.cw,
400 ch: self.ch,
401 ready_rows: core::sync::atomic::AtomicUsize::new(self.ready_rows.load(Relaxed)),
402 live: self.live.clone(),
403 frozen,
404 frame_num: self.frame_num,
405 poc: self.poc,
406 mv: self.mv.clone(),
407 ref_idx: self.ref_idx.clone(),
408 mv1: self.mv1.clone(),
409 ref_idx1: self.ref_idx1.clone(),
410 ref_poc: self.ref_poc.clone(),
411 w4: self.w4,
412 long_term: self.long_term,
413 long_term_idx: self.long_term_idx,
414 }
415 }
416}
417
418pub(crate) const LPAD: usize = 16;
422pub(crate) const CPAD: usize = 8;
423
424thread_local! {
425 static MC_ROW_NEED: core::cell::Cell<usize> = const { core::cell::Cell::new(usize::MAX) };
427}
428
429#[derive(Debug, Clone)]
431pub(crate) struct FrozenPlanes {
432 pub py: Vec<u8>,
433 pub pu: Vec<u8>,
434 pub pv: Vec<u8>,
435}
436
437#[derive(Debug)]
439pub(crate) struct LivePlanes {
440 pub py: crate::sync::RwLock<Vec<u8>>,
441 pub pu: crate::sync::RwLock<Vec<u8>>,
442 pub pv: crate::sync::RwLock<Vec<u8>>,
443 pub meta: crate::sync::RwLock<LiveMeta>,
445 pub wait: crate::sync::Mutex<()>,
447 pub cv: crate::sync::Condvar,
448}
449
450#[derive(Debug, Clone, Default)]
451pub(crate) struct LiveMeta {
452 pub frame_num: u32,
453 pub poc: i32,
454 pub long_term: bool,
455 pub long_term_idx: u32,
456 pub mv: Vec<(i32, i32)>,
457 pub ref_idx: Vec<i32>,
458 pub mv1: Vec<(i32, i32)>,
459 pub ref_idx1: Vec<i32>,
460 pub ref_poc: Vec<i32>,
461 pub w4: usize,
462 pub motion_ready: bool,
464}
465
466pub(crate) enum PlaneGuard<'a> {
468 Borrowed(&'a [u8]),
469 Locked(crate::sync::RwLockReadGuard<'a, Vec<u8>>),
470}
471
472impl core::ops::Deref for PlaneGuard<'_> {
473 type Target = [u8];
474 fn deref(&self) -> &[u8] {
475 match self {
476 Self::Borrowed(s) => s,
477 Self::Locked(g) => g.as_slice(),
478 }
479 }
480}
481
482impl RefFrame {
483 #[inline]
485 pub(crate) fn rows_needed_for_mb(mb_y: usize, ch: usize) -> usize {
486 ((mb_y + 1) * 16 + LPAD).min(ch.max(1))
487 }
488
489 #[inline]
493 pub(crate) fn set_mc_row_need(mb_y: usize, ch: usize) {
494 if !crate::row_progress_on() {
497 return;
498 }
499 MC_ROW_NEED.with(|c| c.set(Self::rows_needed_for_mb(mb_y, ch)));
500 }
501
502 #[inline]
503 fn effective_need(&self, need_rows: usize) -> usize {
504 let hint = MC_ROW_NEED.with(|c| c.get());
505 need_rows.min(hint).min(self.ch.max(1))
506 }
507
508 #[inline]
511 pub(crate) fn luma_guard(&self, need_rows: usize) -> PlaneGuard<'_> {
512 if self.live.is_none() {
513 if let Some(f) = self.frozen.get() {
515 return PlaneGuard::Borrowed(&f.py);
516 }
517 return PlaneGuard::Borrowed(&self.py);
518 }
519 let need = self.effective_need(need_rows);
520 self.wait_ready_rows(need);
521 if let Some(f) = self.frozen.get() {
522 return PlaneGuard::Borrowed(&f.py);
523 }
524 if !self.py.is_empty() {
525 return PlaneGuard::Borrowed(&self.py);
526 }
527 if let Some(live) = &self.live {
528 PlaneGuard::Locked(live.py.read().unwrap())
529 } else {
530 PlaneGuard::Borrowed(&self.py)
531 }
532 }
533
534 #[inline]
535 pub(crate) fn chroma_guard(&self, plane: usize, need_rows: usize) -> PlaneGuard<'_> {
536 if self.live.is_none() {
537 if let Some(f) = self.frozen.get() {
538 return if plane == 0 {
539 PlaneGuard::Borrowed(&f.pu)
540 } else {
541 PlaneGuard::Borrowed(&f.pv)
542 };
543 }
544 return if plane == 0 {
545 PlaneGuard::Borrowed(&self.pu)
546 } else {
547 PlaneGuard::Borrowed(&self.pv)
548 };
549 }
550 let need = self.effective_need(need_rows);
551 self.wait_ready_rows(need);
552 if let Some(f) = self.frozen.get() {
553 return if plane == 0 {
554 PlaneGuard::Borrowed(&f.pu)
555 } else {
556 PlaneGuard::Borrowed(&f.pv)
557 };
558 }
559 if !self.py.is_empty() {
560 return if plane == 0 {
561 PlaneGuard::Borrowed(&self.pu)
562 } else {
563 PlaneGuard::Borrowed(&self.pv)
564 };
565 }
566 if let Some(live) = &self.live {
567 if plane == 0 {
568 PlaneGuard::Locked(live.pu.read().unwrap())
569 } else {
570 PlaneGuard::Locked(live.pv.read().unwrap())
571 }
572 } else if plane == 0 {
573 PlaneGuard::Borrowed(&self.pu)
574 } else {
575 PlaneGuard::Borrowed(&self.pv)
576 }
577 }
578 pub(crate) fn new_progress_slot(cw: usize, ch: usize, b_possible: bool, mb_w: usize) -> Ref {
579 let (lpw, lph) = (cw + 2 * LPAD, ch + 2 * LPAD);
580 let (cpw, cph) = (cw / 2 + 2 * CPAD, ch / 2 + 2 * CPAD);
581 let w4 = if b_possible { mb_w * 4 } else { 0 };
582 let n4 = if b_possible {
583 mb_w * 4 * (ch / 16) * 4
584 } else {
585 0
586 };
587 let (py, pu, pv) = if crate::row_publish_on() {
590 (vec![0; lpw * lph], vec![0; cpw * cph], vec![0; cpw * cph])
591 } else {
592 (Vec::new(), Vec::new(), Vec::new())
593 };
594 crate::sync::Arc::new(RefFrame {
595 py: Vec::new(),
596 pu: Vec::new(),
597 pv: Vec::new(),
598 cw,
599 ch,
600 ready_rows: core::sync::atomic::AtomicUsize::new(0),
601 live: Some(crate::sync::Arc::new(LivePlanes {
602 py: crate::sync::RwLock::new(py),
603 pu: crate::sync::RwLock::new(pu),
604 pv: crate::sync::RwLock::new(pv),
605 meta: crate::sync::RwLock::new(LiveMeta {
606 mv: vec![(0, 0); n4],
607 ref_idx: vec![-1; n4],
608 mv1: vec![(0, 0); n4],
609 ref_idx1: vec![-1; n4],
610 ref_poc: vec![i32::MIN; n4],
611 w4,
612 ..LiveMeta::default()
613 }),
614 wait: crate::sync::Mutex::new(()),
615 cv: crate::sync::Condvar::new(),
616 })),
617 frozen: crate::sync::Once::new(),
618 frame_num: 0,
619 poc: 0,
620 mv: vec![(0, 0); n4],
621 ref_idx: vec![-1; n4],
622 mv1: vec![(0, 0); n4],
623 ref_idx1: vec![-1; n4],
624 ref_poc: vec![i32::MIN; n4],
625 w4,
626 long_term: false,
627 long_term_idx: 0,
628 })
629 }
630
631 pub(crate) fn init_progress_identity(slot: &mut Ref, frame_num: u32, poc: i32) {
633 if let Some(s) = crate::sync::Arc::get_mut(slot) {
634 s.frame_num = frame_num;
635 s.poc = poc;
636 if let Some(live) = &s.live {
637 let mut m = live.meta.write().unwrap();
638 m.frame_num = frame_num;
639 m.poc = poc;
640 }
641 }
642 }
643
644 #[inline]
645 pub(crate) fn fn_num(&self) -> u32 {
646 if let Some(live) = &self.live {
647 live.meta.read().unwrap().frame_num
648 } else {
649 self.frame_num
650 }
651 }
652
653 #[inline]
654 pub(crate) fn pic_poc(&self) -> i32 {
655 if let Some(live) = &self.live {
656 live.meta.read().unwrap().poc
657 } else {
658 self.poc
659 }
660 }
661
662 #[inline]
663 pub(crate) fn is_long_term(&self) -> bool {
664 if let Some(live) = &self.live {
665 live.meta.read().unwrap().long_term
666 } else {
667 self.long_term
668 }
669 }
670
671 #[inline]
672 pub(crate) fn lt_idx(&self) -> u32 {
673 if let Some(live) = &self.live {
674 live.meta.read().unwrap().long_term_idx
675 } else {
676 self.long_term_idx
677 }
678 }
679
680 pub(crate) fn set_long_term_marks(&self, long_term: bool, idx: u32) {
681 if let Some(live) = &self.live {
682 let mut m = live.meta.write().unwrap();
683 m.long_term = long_term;
684 m.long_term_idx = idx;
685 }
686 }
687
688 pub(crate) fn set_frame_num_live(&self, frame_num: u32) {
689 if let Some(live) = &self.live {
690 live.meta.write().unwrap().frame_num = frame_num;
691 }
692 }
693
694 pub(crate) fn wait_motion_ready(&self) {
696 if self.live.is_none() {
697 return;
698 }
699 if let Some(live) = &self.live {
700 if live.meta.read().unwrap().motion_ready {
701 return;
702 }
703 }
704 if let Some(live) = &self.live {
705 let mut g = live.wait.lock().unwrap();
706 while !live.meta.read().unwrap().motion_ready {
707 g = live.cv.wait(g).unwrap();
708 }
709 }
710 }
711
712 #[inline]
714 pub fn mark_fully_ready(&self) {
715 if let Some(live) = &self.live {
716 let _g = live.wait.lock().unwrap();
717 self.ready_rows
718 .store(self.ch, core::sync::atomic::Ordering::Release);
719 live.cv.notify_all();
720 } else {
721 self.ready_rows
722 .store(self.ch, core::sync::atomic::Ordering::Release);
723 }
724 }
725
726 #[inline]
728 pub fn publish_ready_rows(&self, rows: usize) {
729 let r = rows.min(self.ch);
730 if let Some(live) = &self.live {
731 let _g = live.wait.lock().unwrap();
732 let prev = self
733 .ready_rows
734 .fetch_max(r, core::sync::atomic::Ordering::Release);
735 if r > prev {
736 live.cv.notify_all();
737 }
738 } else {
739 let _ = self
740 .ready_rows
741 .fetch_max(r, core::sync::atomic::Ordering::Release);
742 }
743 }
744
745 #[inline]
748 pub fn wait_ready_rows(&self, rows: usize) {
749 use core::sync::atomic::Ordering::Acquire;
750 let need = rows.min(self.ch);
751 if need == 0 || self.ready_rows.load(Acquire) >= need {
752 return;
753 }
754 if self.frozen.get().is_some() {
755 return;
756 }
757 if let Some(live) = &self.live {
758 let mut g = live.wait.lock().unwrap();
759 while self.ready_rows.load(Acquire) < need {
760 g = live.cv.wait(g).unwrap();
761 }
762 } else {
763 while self.ready_rows.load(Acquire) < need {
764 crate::sync::yield_now();
765 }
766 }
767 }
768
769 #[inline]
770 pub fn lstride(&self) -> usize {
771 self.cw + 2 * LPAD
772 }
773 #[inline]
774 pub fn cstride(&self) -> usize {
775 self.cw / 2 + 2 * CPAD
776 }
777 #[inline]
784 pub fn lrows(&self) -> usize {
785 self.ch + 2 * LPAD
786 }
787 #[inline]
789 pub fn crows(&self) -> usize {
790 self.ch / 2 + 2 * CPAD
791 }
792}
793
794#[derive(Clone, Copy)]
796enum Mmco {
797 Unref(u32),
799 UnrefLong(u32),
801 AssignLong(u32, u32),
803 MaxLong(u32),
805 Reset,
807 CurrentLong(u32),
809}
810
811#[derive(Clone, Copy, PartialEq, Eq, Debug)]
818pub enum ContentRoute {
819 Light,
820 Mid,
821 DenseInter,
822 EntropyExtreme,
823}
824
825fn route_for(
830 cabac: bool,
831 t8x8: bool,
832 bits_per_mb: f64,
833 skip_frac: f64,
834 coded_frac: f64,
835) -> ContentRoute {
836 let (root_coded, light_skip, extreme_bits) = if !cabac {
840 (0.6116, 0.6433, 406.4)
841 } else if t8x8 {
842 (0.4244, 0.6358, 331.7)
843 } else {
844 (0.3709, 0.6343, 315.2)
845 };
846 if coded_frac <= root_coded {
847 if skip_frac > light_skip {
848 ContentRoute::Light
849 } else {
850 ContentRoute::Mid
851 }
852 } else if bits_per_mb <= extreme_bits {
853 ContentRoute::DenseInter
854 } else {
855 ContentRoute::EntropyExtreme
856 }
857}
858
859struct PendingPic {
860 fd: mb16::FrameDecoder,
861 frame_num: u32,
862 poc: i32,
863 next_mb: usize,
864 total_mb: usize,
865 slice_count: u16,
866 deblock: bool,
867 filter_offset_a: i32,
868 filter_offset_b: i32,
869 crop_r: usize,
870 crop_b: usize,
871 max_refs: usize,
872 log2_max_frame_num: u32,
873 is_reference: bool,
876 idr_long_term: bool,
877 mmco_ops: Vec<Mmco>,
878 route_bits: u64,
880 route_cabac: bool,
881 route_t8x8: bool,
882}
883
884fn no_pool() -> bool {
886 #[cfg(not(feature = "knobs"))]
890 {
891 return false;
892 }
893 #[cfg(feature = "knobs")]
894 {
895 use core::sync::atomic::{AtomicU8, Ordering};
896 static ON: AtomicU8 = AtomicU8::new(0);
897 match ON.load(Ordering::Relaxed) {
898 0 => {
899 let v = rusty_h264_common::knob("RS_H264_NO_POOL").is_some_and(|v| v == "1");
900 ON.store(if v { 1 } else { 2 }, Ordering::Relaxed);
901 v
902 }
903 n => n == 1,
904 }
905 }
906}
907
908#[derive(Default)]
911pub struct Decoder {
912 last_route: Option<ContentRoute>,
914 route_ema: Option<(f64, f64, f64)>,
920 pub(crate) sps: alloc::collections::BTreeMap<u32, crate::sync::Arc<Sps>>,
925 pub(crate) pps: alloc::collections::BTreeMap<u32, crate::sync::Arc<Pps>>,
926 pub(crate) refs: Vec<Ref>,
928 cur: Option<PendingPic>,
930 pub(crate) poc: PocState,
934 pub(crate) last_poc: i32,
936 pub(crate) prev_ref_frame_num: u32,
939 grid_pool: GridPool,
942 sc_reorder0: Vec<(u32, u32)>,
944 sc_reorder1: Vec<(u32, u32)>,
945 sc_mmco: Vec<Mmco>,
946 plane_pool: Vec<Vec<u8>>,
949 retired: Vec<Ref>,
954 pub(crate) detach_dpb: bool,
957 pub(crate) detached_ref: Option<Ref>,
959 pub(crate) progress_slot: Option<Ref>,
961 detached_mmco: Vec<Mmco>,
962 detached_frame_num: u32,
963 detached_log2_max_frame_num: u32,
964 detached_max_refs: usize,
965 detached_idr_long_term: bool,
966 pub(crate) frame_mt_row_progress: bool,
968}
969
970#[derive(Clone, Default)]
972pub(crate) struct PocState {
973 prev_msb: i32,
974 prev_lsb: i32,
975 prev_frame_num: u32,
976 prev_frame_num_offset: i64,
977}
978
979impl PocState {
980 pub(crate) fn compute_poc(
984 &mut self,
985 sps: &Sps,
986 is_idr: bool,
987 nal_ref_idc: u8,
988 frame_num: u32,
989 poc_lsb: u32,
990 delta_bottom: i32,
991 ) -> i32 {
992 match sps.pic_order_cnt_type {
993 0 => {
994 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
995 let (prev_msb, prev_lsb) = if is_idr {
996 (0, 0)
997 } else {
998 (self.prev_msb, self.prev_lsb)
999 };
1000 let lsb = poc_lsb as i32;
1001 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
1002 prev_msb + max_lsb
1003 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
1004 prev_msb - max_lsb
1005 } else {
1006 prev_msb
1007 };
1008 let top = msb + lsb;
1009 let poc = top.min(top + delta_bottom);
1010 if nal_ref_idc != 0 {
1011 self.prev_msb = msb;
1012 self.prev_lsb = lsb;
1013 }
1014 poc
1015 }
1016 2 => {
1017 let max_fn = 1i64 << sps.log2_max_frame_num;
1018 let offset = if is_idr {
1019 0
1020 } else if self.prev_frame_num > frame_num {
1021 self.prev_frame_num_offset + max_fn
1022 } else {
1023 self.prev_frame_num_offset
1024 };
1025 let poc = if is_idr {
1026 0
1027 } else {
1028 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
1029 };
1030 self.prev_frame_num_offset = offset;
1031 self.prev_frame_num = frame_num;
1032 poc as i32
1033 }
1034 _ => {
1035 self.prev_frame_num = frame_num;
1036 frame_num as i32 * 2
1037 }
1038 }
1039 }
1040}
1041
1042impl Decoder {
1043 pub fn new() -> Self {
1045 Self::default()
1046 }
1047
1048 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
1051 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
1052 let mut frame = None;
1053 let nals = {
1057 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecNalSplit);
1058 split_annex_b(annex_b)
1059 };
1060 for nal in nals {
1061 if nal.is_empty() {
1062 continue;
1063 }
1064 let nal_type = NalUnitType::from_id(nal[0]);
1065 let rbsp = {
1066 let _s = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecRbsp);
1067 emulation_unprevent(&nal[1..])
1068 };
1069 match nal_type {
1070 NalUnitType::Sps => {
1071 let s = Sps::parse(&rbsp)?;
1072 self.sps
1073 .insert(s.seq_parameter_set_id, crate::sync::Arc::new(s));
1074 }
1075 NalUnitType::Pps => {
1076 let p = Pps::parse(&rbsp)?;
1077 self.pps
1078 .insert(p.pic_parameter_set_id, crate::sync::Arc::new(p));
1079 }
1080 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
1081 let nal_ref_idc = (nal[0] >> 5) & 3;
1082 let is_idr = nal_type == NalUnitType::IdrSlice;
1083 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
1084 frame = Some(f);
1085 }
1086 }
1087 _ => {} }
1089 }
1090 Ok(frame)
1091 }
1092
1093 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
1106 #[cfg(feature = "std")]
1107 {
1108 let n = frame_mt::frame_threads();
1109 if n > 1 {
1110 return frame_mt::decode_stream_threaded(annex_b, n);
1111 }
1112 }
1113 self.decode_stream_serial(annex_b)
1114 }
1115
1116 #[cfg(feature = "std")]
1118 pub fn decode_stream_threaded(
1119 &mut self,
1120 annex_b: &[u8],
1121 threads: usize,
1122 ) -> Result<Vec<YuvFrame>, DecodeError> {
1123 if threads <= 1 {
1124 return self.decode_stream_serial(annex_b);
1125 }
1126 frame_mt::decode_stream_threaded(annex_b, threads)
1127 }
1128
1129 #[cfg(feature = "std")]
1132 pub fn decode_stream_threaded_sink(
1133 &mut self,
1134 annex_b: &[u8],
1135 threads: usize,
1136 sink: impl FnMut(YuvFrame),
1137 ) -> Result<usize, DecodeError> {
1138 if threads <= 1 {
1139 let frames = self.decode_stream_serial(annex_b)?;
1140 let n = frames.len();
1141 let mut sink = sink;
1142 for f in frames {
1143 sink(f);
1144 }
1145 return Ok(n);
1146 }
1147 frame_mt::decode_stream_threaded_sink(annex_b, threads, sink)
1148 }
1149
1150 fn decode_stream_serial(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
1151 let mut out = Vec::new();
1152 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
1153 for au in split_access_units(annex_b) {
1154 if au_is_idr(au) {
1155 flush_gop(&mut gop, &mut out); }
1157 if let Some(frame) = self.decode(au)? {
1158 gop.push((self.last_poc, frame));
1159 }
1160 }
1161 flush_gop(&mut gop, &mut out);
1162 Ok(out)
1163 }
1164
1165 fn decode_slice(
1166 &mut self,
1167 rbsp: &[u8],
1168 is_idr: bool,
1169 nal_ref_idc: u8,
1170 ) -> Result<Option<YuvFrame>, DecodeError> {
1171 let mut r = BitReader::new(rbsp);
1172 let first_mb_in_slice = r.read_ue()? as usize;
1174 let slice_type = r.read_ue()?;
1175 let is_p = matches!(slice_type, 0 | 5);
1176 let is_b = matches!(slice_type, 1 | 6);
1177 let is_i = matches!(slice_type, 2 | 7);
1178 if !is_p && !is_b && !is_i {
1179 return Err(DecodeError::Unsupported("SP/SI slices"));
1180 }
1181 let pic_parameter_set_id = r.read_ue()?;
1183 let pps = self
1184 .pps
1185 .get(&pic_parameter_set_id)
1186 .cloned()
1187 .ok_or(DecodeError::MissingParameterSet)?;
1188 let sps = self
1189 .sps
1190 .get(&pps.seq_parameter_set_id)
1191 .cloned()
1192 .ok_or(DecodeError::MissingParameterSet)?;
1193 let sps = &sps;
1194 let pps = &pps;
1195 let cabac = pps.entropy_coding_mode_flag;
1199 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
1200 if is_idr {
1201 let _idr_pic_id = r.read_ue()?;
1202 }
1203 let mut poc_lsb = 0u32;
1206 let mut delta_poc_bottom = 0i32;
1207 if sps.pic_order_cnt_type == 0 {
1208 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
1209 if pps.bottom_field_pic_order_present {
1210 delta_poc_bottom = r.read_se()?;
1211 }
1212 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
1213 let _delta_pic_order_cnt_0 = r.read_se()?;
1214 if pps.bottom_field_pic_order_present {
1215 let _delta_pic_order_cnt_1 = r.read_se()?;
1216 }
1217 }
1218 let pic_poc = if first_mb_in_slice == 0 {
1221 self.compute_poc(
1222 sps,
1223 is_idr,
1224 nal_ref_idc,
1225 frame_num,
1226 poc_lsb,
1227 delta_poc_bottom,
1228 )
1229 } else {
1230 self.cur.as_ref().map_or(0, |p| p.poc)
1231 };
1232 if pps.redundant_pic_cnt_present_flag {
1237 let redundant_pic_cnt = r.read_ue()?;
1238 if redundant_pic_cnt != 0 {
1239 return Ok(None);
1240 }
1241 }
1242 if crate::mb16::dump_mb_on() {
1243 eprintln!(
1244 "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}"
1245 );
1246 }
1247 let direct_spatial = if is_b { r.read_bit()? } else { true };
1249 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
1250 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
1251 let mut reorder_l0: Vec<(u32, u32)> = core::mem::take(&mut self.sc_reorder0);
1252 reorder_l0.clear();
1253 let mut reorder_l1: Vec<(u32, u32)> = core::mem::take(&mut self.sc_reorder1);
1254 reorder_l1.clear();
1255 if is_p || is_b {
1256 if r.read_bit()? {
1258 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
1259 if is_b {
1260 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
1261 }
1262 }
1263 if r.read_bit()? {
1265 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
1266 }
1267 if is_b && r.read_bit()? {
1268 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
1270 }
1271 }
1272 let weights = if is_p && pps.weighted_pred {
1277 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
1278 } else if is_b && pps.weighted_bipred_idc == 1 {
1279 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
1280 } else {
1281 None
1282 };
1283 let mut idr_long_term = false;
1287 let mut mmco_ops: Vec<Mmco> = core::mem::take(&mut self.sc_mmco);
1288 mmco_ops.clear();
1289 if nal_ref_idc == 0 {
1290 } else if is_idr {
1292 let _no_output_of_prior_pics = r.read_bit()?;
1293 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
1295 loop {
1297 let op = r.read_ue()?;
1298 match op {
1299 0 => break,
1300 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
1301 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
1302 3 => {
1303 let diff = r.read_ue()?;
1304 let idx = r.read_ue()?;
1305 mmco_ops.push(Mmco::AssignLong(diff, idx));
1306 }
1307 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
1308 5 => mmco_ops.push(Mmco::Reset),
1309 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
1310 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
1311 }
1312 if mmco_ops.len() > 128 {
1313 return Err(DecodeError::Truncated);
1314 }
1315 }
1316 }
1317 let cabac_init_idc = if cabac && !is_i {
1321 let v = r.read_ue()?;
1322 if v > 2 {
1323 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
1324 }
1325 v
1326 } else {
1327 0
1328 };
1329 let slice_qp_delta = r.read_se()?;
1330 let mut deblock = true;
1335 let mut deblock_idc2 = false;
1336 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
1337 if pps.deblocking_filter_control_present_flag {
1338 let disable_deblocking_filter_idc = r.read_ue()?;
1339 deblock = disable_deblocking_filter_idc != 1;
1343 deblock_idc2 = disable_deblocking_filter_idc == 2;
1344 if disable_deblocking_filter_idc != 1 {
1345 filter_offset_a = r.read_se()? * 2;
1347 filter_offset_b = r.read_se()? * 2;
1348 }
1349 }
1350 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
1351
1352 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
1355 self.insert_frame_num_gaps(
1356 frame_num,
1357 1u32 << sps.log2_max_frame_num,
1358 sps.max_num_ref_frames.max(1) as usize,
1359 sps.pic_width_in_mbs * 16,
1360 sps.pic_height_in_mbs * 16,
1361 );
1362 }
1363
1364 let max_fn = 1u32 << sps.log2_max_frame_num;
1367 let (ref_list0, ref_list1) = if is_b {
1368 build_ref_list_b(
1369 &self.refs,
1370 pic_poc,
1371 frame_num,
1372 max_fn,
1373 num_ref_idx_l0,
1374 num_ref_idx_l1,
1375 &reorder_l0,
1376 &reorder_l1,
1377 )?
1378 } else if is_p {
1379 (
1380 build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?,
1381 Vec::new(),
1382 )
1383 } else {
1384 (Vec::new(), Vec::new())
1385 };
1386 self.sc_reorder0 = reorder_l0;
1388 self.sc_reorder1 = reorder_l1;
1389 if first_mb_in_slice == 0 {
1393 if is_idr {
1394 self.refs.clear();
1395 }
1396 let _g_setup = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DecSetup);
1407 let mut fd = FrameDecoder::with_pool(
1408 sps.pic_width_in_mbs,
1409 sps.pic_height_in_mbs,
1410 slice_qp,
1411 pps.chroma_qp_index_offset,
1412 ref_list0,
1413 num_ref_idx_l0,
1414 pps.constrained_intra_pred_flag,
1415 pps.transform_8x8_mode_flag,
1416 sps.profile_idc != 66, if no_pool() {
1421 GridPool::default()
1422 } else {
1423 core::mem::take(&mut self.grid_pool)
1424 },
1425 );
1426 if is_b {
1427 fd.set_b_context(
1428 ref_list1,
1429 num_ref_idx_l1,
1430 direct_spatial,
1431 pic_poc,
1432 pps.weighted_bipred_idc,
1433 sps.direct_8x8_inference,
1434 );
1435 }
1436 if sps.has_scaling || pps.pic_scaling_matrix_present {
1437 let (s4, s8) = resolve_scaling(sps, pps);
1438 fd.set_scaling(s4, s8);
1439 }
1440 fd.set_transform_bypass(sps.transform_bypass);
1441 if let Some(w) = weights {
1442 fd.set_weights(w);
1443 }
1444 if let Some(slot) = self.progress_slot.clone() {
1445 fd.set_progress_slot(slot);
1446 }
1447 if let Some(prev) = self.cur.take() {
1455 if prev.next_mb < prev.total_mb {
1456 return Err(DecodeError::Truncated);
1457 }
1458 }
1459 self.cur = Some(PendingPic {
1460 fd,
1461 frame_num,
1462 poc: pic_poc,
1463 next_mb: 0,
1464 route_bits: 0,
1465 route_cabac: pps.entropy_coding_mode_flag,
1466 route_t8x8: pps.transform_8x8_mode_flag,
1467 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
1468 slice_count: 0,
1469 deblock,
1470 filter_offset_a,
1471 filter_offset_b,
1472 crop_r: sps.frame_crop_right as usize,
1473 crop_b: sps.frame_crop_bottom as usize,
1474 max_refs: sps.max_num_ref_frames.max(1) as usize,
1475 log2_max_frame_num: sps.log2_max_frame_num,
1476 is_reference: nal_ref_idc != 0,
1477 idr_long_term,
1478 mmco_ops,
1479 });
1480 } else {
1481 let Some(pic) = self.cur.as_mut() else {
1483 return Err(DecodeError::Unsupported(
1484 "slice continues a missing picture",
1485 ));
1486 };
1487 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
1488 if is_b {
1489 pic.fd.set_b_context(
1490 ref_list1,
1491 num_ref_idx_l1,
1492 direct_spatial,
1493 pic.poc,
1494 pps.weighted_bipred_idc,
1495 sps.direct_8x8_inference,
1496 );
1497 }
1498 if sps.has_scaling || pps.pic_scaling_matrix_present {
1499 let (s4, s8) = resolve_scaling(sps, pps);
1500 pic.fd.set_scaling(s4, s8);
1501 }
1502 pic.fd.set_transform_bypass(sps.transform_bypass);
1503 if let Some(w) = weights {
1504 pic.fd.set_weights(w);
1505 }
1506 pic.deblock = deblock;
1508 pic.filter_offset_a = filter_offset_a;
1509 pic.filter_offset_b = filter_offset_b;
1510 pic.idr_long_term |= idr_long_term;
1511 pic.mmco_ops.extend(mmco_ops);
1512 }
1513
1514 let pic = self.cur.as_mut().expect("pending picture set above");
1515 pic.fd.set_deblock_params(
1519 deblock && !abl_deblock(),
1520 filter_offset_a,
1521 filter_offset_b,
1522 deblock_idc2,
1523 );
1524 let first = first_mb_in_slice.min(pic.total_mb);
1525 pic.route_bits += r.data().len() as u64;
1526 let next = if cabac {
1527 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
1529 let (data, start) = (r.data(), r.bit_pos() / 8);
1530 pic.fd
1531 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
1532 } else {
1533 pic.fd.decode_slice_data(&mut r, is_p, first)
1534 }
1535 .map_err(|e| match e {
1536 mb16::MbError::Truncated => DecodeError::Truncated,
1537 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
1538 })?;
1539 pic.next_mb = next;
1540 pic.slice_count += 1;
1541 if crate::mb16::dump_mb_on() {
1542 eprintln!(
1543 " slice decoded {}/{} MBs{}",
1544 next,
1545 pic.total_mb,
1546 if next < pic.total_mb {
1547 " <-- INCOMPLETE"
1548 } else {
1549 ""
1550 }
1551 );
1552 }
1553
1554 if pic.next_mb < pic.total_mb {
1555 return Ok(None); }
1557
1558 let pic = self.cur.take().expect("pending picture");
1560 {
1561 let (skips, coded) = pic.fd.route_counters();
1562 let mbs = pic.total_mb.max(1) as f64;
1563 let bits_per_mb = pic.route_bits as f64 * 8.0 / mbs;
1564 let (skip_frac, coded_frac) = (skips as f64 / mbs, coded as f64 / mbs);
1565 let (eb, es, ec) = match self.route_ema {
1566 None => (bits_per_mb, skip_frac, coded_frac),
1567 Some((pb, ps, pc)) => (
1568 pb + (bits_per_mb - pb) / 8.0,
1569 ps + (skip_frac - ps) / 8.0,
1570 pc + (coded_frac - pc) / 8.0,
1571 ),
1572 };
1573 self.route_ema = Some((eb, es, ec));
1574 let route = route_for(pic.route_cabac, pic.route_t8x8, eb, es, ec);
1575 self.last_route = Some(route);
1576 if crate::mb16::route_dump_on() {
1580 eprintln!(
1581 "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:?}",
1582 pic.route_cabac, pic.route_t8x8
1583 );
1584 }
1585 }
1586 let PendingPic {
1587 mut fd,
1588 frame_num,
1589 poc,
1590 deblock,
1591 filter_offset_a,
1592 filter_offset_b,
1593 crop_r,
1594 crop_b,
1595 max_refs,
1596 log2_max_frame_num,
1597 is_reference,
1598 idr_long_term,
1599 mut mmco_ops,
1600 ..
1601 } = pic;
1602 self.last_poc = poc;
1603 if deblock && !abl_deblock() {
1611 fd.deblock(filter_offset_a, filter_offset_b);
1612 }
1613 let reference = if is_reference {
1616 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
1617 Some(fd.as_reference_pooled(&mut self.plane_pool))
1618 } else {
1619 None
1620 };
1621 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
1622 if let Some(mut reference) = reference {
1623 reference.frame_num = frame_num;
1624 reference.poc = poc;
1625 if crate::mb16::dump_mb_on() {
1626 eprintln!("DPB-ADD fn={frame_num} poc={poc}");
1627 }
1628 if idr_long_term {
1629 reference.long_term = true;
1630 reference.long_term_idx = 0;
1631 }
1632 let reference = reference; if self.detach_dpb {
1634 self.detached_mmco = core::mem::take(&mut mmco_ops);
1635 self.detached_frame_num = frame_num;
1636 self.detached_log2_max_frame_num = log2_max_frame_num;
1637 self.detached_max_refs = max_refs;
1638 self.detached_idr_long_term = idr_long_term;
1639 if let Some(slot) = self.progress_slot.take() {
1640 Self::fill_progress_slot(&slot, reference);
1642 slot.mark_fully_ready();
1643 self.detached_ref = Some(slot);
1644 } else {
1645 let arc = crate::sync::Arc::new(reference);
1646 arc.mark_fully_ready();
1647 self.detached_ref = Some(arc);
1648 }
1649 } else {
1650 reference.mark_fully_ready();
1651 self.prev_ref_frame_num = self.apply_ref_marking(
1652 reference,
1653 &mmco_ops,
1654 frame_num,
1655 log2_max_frame_num,
1656 max_refs,
1657 );
1658 }
1659 }
1660 self.sc_mmco = mmco_ops; let (frame, pool) = fd.into_frame_recycle(crop_r, crop_b);
1662 self.grid_pool = pool;
1663 self.reclaim_retired();
1664 Ok(Some(frame))
1665 }
1666
1667 pub(crate) fn commit_detached_ref_arc(&mut self, reference: Ref) -> Result<u32, DecodeError> {
1671 reference.mark_fully_ready();
1672 let mmco = core::mem::take(&mut self.detached_mmco);
1673 let frame_num = self.detached_frame_num;
1674 let log2 = self.detached_log2_max_frame_num;
1675 let max_refs = self.detached_max_refs;
1676 self.prev_ref_frame_num =
1677 self.apply_ref_marking_arc(reference, &mmco, frame_num, log2, max_refs);
1678 Ok(self.prev_ref_frame_num)
1679 }
1680
1681 fn fill_progress_slot(slot: &Ref, mut finished: crate::RefFrame) {
1684 let planes = FrozenPlanes {
1685 py: core::mem::take(&mut finished.py),
1686 pu: core::mem::take(&mut finished.pu),
1687 pv: core::mem::take(&mut finished.pv),
1688 };
1689 if let Some(live) = &slot.live {
1690 let _w = live.wait.lock().unwrap();
1691 {
1692 let mut m = live.meta.write().unwrap();
1693 m.frame_num = finished.frame_num;
1694 m.poc = finished.poc;
1695 m.long_term = finished.long_term;
1696 m.long_term_idx = finished.long_term_idx;
1697 m.mv = core::mem::take(&mut finished.mv);
1698 m.ref_idx = core::mem::take(&mut finished.ref_idx);
1699 m.mv1 = core::mem::take(&mut finished.mv1);
1700 m.ref_idx1 = core::mem::take(&mut finished.ref_idx1);
1701 m.ref_poc = core::mem::take(&mut finished.ref_poc);
1702 m.w4 = finished.w4;
1703 m.motion_ready = true;
1704 }
1705 let _ = slot.frozen.set(planes);
1706 slot.ready_rows
1707 .store(slot.ch, core::sync::atomic::Ordering::Release);
1708 live.cv.notify_all();
1709 } else {
1710 let _ = slot.frozen.set(planes);
1711 slot.mark_fully_ready();
1712 }
1713 }
1714
1715 fn reclaim_retired(&mut self) {
1720 for arc in self.retired.drain(..) {
1721 if let Ok(mut rf) = crate::sync::Arc::try_unwrap(arc) {
1722 if let Some(f) = rf.frozen.take() {
1723 if !f.py.is_empty() {
1724 self.plane_pool.push(f.py);
1725 self.plane_pool.push(f.pu);
1726 self.plane_pool.push(f.pv);
1727 }
1728 } else if !rf.py.is_empty() {
1729 self.plane_pool.push(rf.py);
1730 self.plane_pool.push(rf.pu);
1731 self.plane_pool.push(rf.pv);
1732 }
1733 }
1734 }
1735 self.plane_pool.truncate(18);
1738 }
1739
1740 fn insert_frame_num_gaps(
1746 &mut self,
1747 frame_num: u32,
1748 max_fn: u32,
1749 max_refs: usize,
1750 w: usize,
1751 h: usize,
1752 ) {
1753 if max_fn == 0 {
1754 return;
1755 }
1756 let start = (self.prev_ref_frame_num + 1) % max_fn;
1757 let gap = (frame_num + max_fn - start) % max_fn;
1758 if gap == 0 {
1759 return;
1760 }
1761 let cap = max_refs.max(1);
1767 let n = (gap as usize).min(cap);
1768 let (cw, ch) = (w, h);
1769 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
1770 for _ in 0..n {
1771 self.refs.insert(
1772 0,
1773 crate::sync::Arc::new(RefFrame {
1774 py: vec![128; (cw + 2 * LPAD) * (ch + 2 * LPAD)],
1776 pu: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
1777 pv: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
1778 cw,
1779 ch,
1780 ready_rows: core::sync::atomic::AtomicUsize::new(ch),
1781 live: None,
1782 frozen: crate::sync::Once::new(),
1783 frame_num: expected,
1784 poc: 0,
1785 mv: Vec::new(),
1786 ref_idx: Vec::new(),
1787 mv1: Vec::new(),
1788 ref_idx1: Vec::new(),
1789 ref_poc: Vec::new(),
1790 w4: 0,
1791 long_term: false,
1792 long_term_idx: 0,
1793 }),
1794 );
1795 self.refs.truncate(cap);
1796 expected = (expected + 1) % max_fn;
1797 }
1798 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
1799 }
1800
1801 pub fn content_route(&self) -> Option<ContentRoute> {
1808 self.last_route
1809 }
1810
1811 pub fn last_poc(&self) -> i32 {
1812 self.last_poc
1813 }
1814
1815 fn compute_poc(
1816 &mut self,
1817 sps: &Sps,
1818 is_idr: bool,
1819 nal_ref_idc: u8,
1820 frame_num: u32,
1821 poc_lsb: u32,
1822 delta_bottom: i32,
1823 ) -> i32 {
1824 self.poc
1825 .compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_bottom)
1826 }
1827
1828 fn apply_ref_marking(
1839 &mut self,
1840 mut reference: RefFrame,
1841 ops: &[Mmco],
1842 frame_num: u32,
1843 log2_max_frame_num: u32,
1844 max_refs: usize,
1845 ) -> u32 {
1846 let max = 1i64 << log2_max_frame_num;
1847 let curr = frame_num as i64;
1848 let pic_num = |rf: &RefFrame| -> i64 {
1849 if (rf.frame_num as i64) > curr {
1850 rf.frame_num as i64 - max
1851 } else {
1852 rf.frame_num as i64
1853 }
1854 };
1855
1856 if ops.is_empty() {
1857 let out_fn = reference.frame_num;
1861 self.refs.insert(0, crate::sync::Arc::new(reference));
1862 while self.refs.len() > max_refs {
1863 match self.refs.iter().rposition(|r| !r.long_term) {
1864 Some(pos) => {
1865 let evicted = self.refs.remove(pos);
1868 self.retired.push(evicted);
1869 }
1870 None => break,
1871 }
1872 }
1873 return out_fn;
1874 }
1875
1876 for &op in ops {
1878 match op {
1879 Mmco::Unref(diff) => {
1880 let target = curr - (diff as i64 + 1);
1881 self.refs.retain(|r| r.long_term || pic_num(r) != target);
1882 }
1883 Mmco::UnrefLong(ltpn) => {
1884 self.refs
1885 .retain(|r| !(r.long_term && r.long_term_idx == ltpn));
1886 }
1887 Mmco::AssignLong(diff, idx) => {
1888 let target = curr - (diff as i64 + 1);
1889 self.refs
1890 .retain(|r| !(r.long_term && r.long_term_idx == idx));
1891 for r in self.refs.iter_mut() {
1892 if !r.long_term && pic_num(r) == target {
1893 let r = crate::sync::Arc::make_mut(r);
1895 r.long_term = true;
1896 r.long_term_idx = idx;
1897 }
1898 }
1899 }
1900 Mmco::MaxLong(max_plus1) => {
1901 self.refs
1902 .retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
1903 }
1904 Mmco::Reset => {
1905 self.refs.clear();
1906 reference.frame_num = 0;
1907 }
1908 Mmco::CurrentLong(idx) => {
1909 self.refs
1910 .retain(|r| !(r.long_term && r.long_term_idx == idx));
1911 reference.long_term = true;
1912 reference.long_term_idx = idx;
1913 }
1914 }
1915 }
1916 let out_fn = reference.frame_num;
1917 self.refs.insert(0, crate::sync::Arc::new(reference));
1918 let cap = max_refs.max(16);
1920 if self.refs.len() > cap {
1921 self.refs.truncate(cap);
1922 }
1923 out_fn
1924 }
1925
1926 fn apply_ref_marking_arc(
1929 &mut self,
1930 mut reference: Ref,
1931 ops: &[Mmco],
1932 frame_num: u32,
1933 log2_max_frame_num: u32,
1934 max_refs: usize,
1935 ) -> u32 {
1936 let max = 1i64 << log2_max_frame_num;
1937 let curr = frame_num as i64;
1938 let pic_num = |rf: &RefFrame| -> i64 {
1939 let f = rf.fn_num() as i64;
1940 if f > curr {
1941 f - max
1942 } else {
1943 f
1944 }
1945 };
1946
1947 if ops.is_empty() {
1948 let out_fn = reference.fn_num();
1949 self.refs.insert(0, reference);
1950 while self.refs.len() > max_refs {
1951 match self.refs.iter().rposition(|r| !r.is_long_term()) {
1952 Some(pos) => {
1953 let evicted = self.refs.remove(pos);
1954 self.retired.push(evicted);
1955 }
1956 None => break,
1957 }
1958 }
1959 return out_fn;
1960 }
1961
1962 for &op in ops {
1963 match op {
1964 Mmco::Unref(diff) => {
1965 let target = curr - (diff as i64 + 1);
1966 self.refs
1967 .retain(|r| r.is_long_term() || pic_num(r) != target);
1968 }
1969 Mmco::UnrefLong(ltpn) => {
1970 self.refs
1971 .retain(|r| !(r.is_long_term() && r.lt_idx() == ltpn));
1972 }
1973 Mmco::AssignLong(diff, idx) => {
1974 let target = curr - (diff as i64 + 1);
1975 self.refs
1976 .retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
1977 for r in self.refs.iter_mut() {
1978 if !r.is_long_term() && pic_num(r) == target {
1979 if r.live.is_some() {
1980 r.set_long_term_marks(true, idx);
1981 } else {
1982 let r = crate::sync::Arc::make_mut(r);
1983 r.long_term = true;
1984 r.long_term_idx = idx;
1985 }
1986 }
1987 }
1988 }
1989 Mmco::MaxLong(max_plus1) => {
1990 self.refs
1991 .retain(|r| !(r.is_long_term() && r.lt_idx() + 1 > max_plus1));
1992 }
1993 Mmco::Reset => {
1994 self.refs.clear();
1995 reference.set_frame_num_live(0);
1996 if let Some(r) = crate::sync::Arc::get_mut(&mut reference) {
1997 r.frame_num = 0;
1998 }
1999 }
2000 Mmco::CurrentLong(idx) => {
2001 self.refs
2002 .retain(|r| !(r.is_long_term() && r.lt_idx() == idx));
2003 reference.set_long_term_marks(true, idx);
2004 if let Some(r) = crate::sync::Arc::get_mut(&mut reference) {
2005 r.long_term = true;
2006 r.long_term_idx = idx;
2007 }
2008 }
2009 }
2010 }
2011 let out_fn = reference.fn_num();
2012 self.refs.insert(0, reference);
2013 let cap = max_refs.max(16);
2014 if self.refs.len() > cap {
2015 self.refs.truncate(cap);
2016 }
2017 out_fn
2018 }
2019}
2020
2021pub(crate) fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
2023 gop.sort_by_key(|(poc, _)| *poc);
2024 out.extend(gop.drain(..).map(|(_, f)| f));
2025}
2026
2027pub fn au_is_idr(au: &[u8]) -> bool {
2032 split_annex_b(au)
2033 .iter()
2034 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
2035}
2036
2037pub fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
2045 let mut codes: Vec<(usize, bool)> = Vec::new();
2047 let mut i = 0;
2048 while let Some(w) = stream.get(i..i + 3) {
2052 if w[0] == 0 && w[1] == 0 && w[2] == 1 {
2053 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
2054 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
2055 let sc = if i > 0 && stream.get(i - 1) == Some(&0) {
2057 i - 1
2058 } else {
2059 i
2060 };
2061 codes.push((sc, is_vcl));
2062 i += 3;
2063 } else {
2064 i += 1;
2065 }
2066 }
2067 if codes.is_empty() {
2068 return vec![stream];
2069 }
2070 let mut aus = Vec::new();
2071 let mut start = codes[0].0;
2072 for k in 0..codes.len() {
2073 if codes[k].1 {
2074 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
2075 aus.push(&stream[start..end]);
2076 start = end;
2077 }
2078 }
2079 aus
2080}
2081
2082fn parse_pred_weight_table(
2085 r: &mut BitReader,
2086 num_l0: usize,
2087 num_l1: usize,
2088 is_b: bool,
2089) -> Result<WeightTable, DecodeError> {
2090 let luma_log2_denom = r.read_ue()? as i32;
2091 let chroma_log2_denom = r.read_ue()? as i32;
2092 if !(0..=7).contains(&luma_log2_denom) || !(0..=7).contains(&chroma_log2_denom) {
2096 return Err(DecodeError::Unsupported("invalid weight denom"));
2097 }
2098 let mut wt = WeightTable {
2099 luma_log2_denom,
2100 chroma_log2_denom,
2101 ..Default::default()
2102 };
2103 let lists: &[(usize, usize)] = if is_b {
2104 &[(0, num_l0), (1, num_l1)]
2105 } else {
2106 &[(0, num_l0)]
2107 };
2108 for &(list, n) in lists {
2109 let mut luma = Vec::with_capacity(n);
2110 let mut chroma = Vec::with_capacity(n);
2111 for _ in 0..n {
2112 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
2113 if r.read_bit()? {
2114 lw = r.read_se()?;
2115 lo = r.read_se()?;
2116 }
2117 luma.push((lw, lo));
2118 let mut ch = [(1 << chroma_log2_denom, 0); 2];
2119 if r.read_bit()? {
2120 for slot in ch.iter_mut() {
2121 *slot = (r.read_se()?, r.read_se()?);
2122 }
2123 }
2124 chroma.push(ch);
2125 }
2126 wt.luma[list & 1] = luma;
2127 wt.chroma[list & 1] = chroma;
2128 }
2129 Ok(wt)
2130}
2131
2132fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
2137 use crate::params::{
2138 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
2139 };
2140 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
2141 const ZZ8: [usize; 64] = [
2143 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,
2144 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
2145 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
2146 ];
2147 let mut z4 = [[16u8; 16]; 6];
2150 for i in 0..6 {
2151 z4[i] = if pps.pic_scaling_matrix_present {
2152 if pps.scaling_present_4x4[i] {
2153 pps.scaling_4x4[i]
2154 } else {
2155 match i {
2156 0 if sps.has_scaling => sps.scaling_4x4[0],
2157 0 => DEFAULT_4X4_INTRA,
2158 3 if sps.has_scaling => sps.scaling_4x4[3],
2159 3 => DEFAULT_4X4_INTER,
2160 _ => z4[i - 1],
2161 }
2162 }
2163 } else {
2164 sps.scaling_4x4[i]
2165 };
2166 }
2167 let mut z8 = [[16u8; 64]; 2];
2168 for (i, list) in z8.iter_mut().enumerate() {
2169 *list = if pps.pic_scaling_matrix_present {
2170 if pps.scaling_present_8x8[i] {
2171 pps.scaling_8x8[i]
2172 } else if sps.has_scaling {
2173 sps.scaling_8x8[i]
2174 } else if i == 0 {
2175 DEFAULT_8X8_INTRA
2176 } else {
2177 DEFAULT_8X8_INTER
2178 }
2179 } else {
2180 sps.scaling_8x8[i]
2181 };
2182 }
2183 let mut out4 = [[16i32; 16]; 6];
2184 for (li, list) in out4.iter_mut().enumerate() {
2185 for k in 0..16 {
2186 list[ZZ4[k]] = z4[li][k] as i32;
2187 }
2188 }
2189 let mut out8 = [[16i32; 64]; 2];
2190 for (li, list) in out8.iter_mut().enumerate() {
2191 for k in 0..64 {
2192 list[ZZ8[k]] = z8[li][k] as i32;
2193 }
2194 }
2195 (out4, out8)
2196}
2197
2198fn parse_ref_pic_list_modification(
2201 r: &mut BitReader,
2202 out: &mut Vec<(u32, u32)>,
2203) -> Result<(), DecodeError> {
2204 loop {
2205 let idc = r.read_ue()?;
2206 if idc == 3 {
2207 break;
2208 }
2209 if idc > 3 {
2210 return Err(DecodeError::Unsupported(
2211 "invalid ref_pic_list_modification",
2212 ));
2213 }
2214 let val = r.read_ue()?; out.push((idc, val));
2216 if out.len() > 64 {
2217 return Err(DecodeError::Truncated); }
2219 }
2220 Ok(())
2221}
2222
2223fn build_ref_list_p(
2227 dpb: &[Ref],
2228 curr_frame_num: u32,
2229 max_frame_num: u32,
2230 num_active: usize,
2231 mods: &[(u32, u32)],
2232) -> Result<Vec<Ref>, DecodeError> {
2233 let curr = curr_frame_num as i64;
2234 let max = max_frame_num as i64;
2235 let pic_num = |fnum: u32| -> i64 {
2236 let f = fnum as i64;
2237 if f > curr {
2238 f - max
2239 } else {
2240 f
2241 }
2242 };
2243 let mut init: Vec<Ref> = dpb.iter().filter(|r| !r.is_long_term()).cloned().collect();
2244 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.fn_num())));
2245 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
2246 long.sort_by_key(|rf| rf.lt_idx());
2247 init.extend(long);
2248 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
2249}
2250
2251#[allow(clippy::too_many_arguments)]
2256fn build_ref_list_b(
2257 dpb: &[Ref],
2258 curr_poc: i32,
2259 curr_frame_num: u32,
2260 max_frame_num: u32,
2261 num0: usize,
2262 num1: usize,
2263 mods0: &[(u32, u32)],
2264 mods1: &[(u32, u32)],
2265) -> Result<(Vec<Ref>, Vec<Ref>), DecodeError> {
2266 let mut less: Vec<Ref> = dpb
2267 .iter()
2268 .filter(|r| !r.is_long_term() && r.pic_poc() < curr_poc)
2269 .cloned()
2270 .collect();
2271 let mut greater: Vec<Ref> = dpb
2272 .iter()
2273 .filter(|r| !r.is_long_term() && r.pic_poc() > curr_poc)
2274 .cloned()
2275 .collect();
2276 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.is_long_term()).cloned().collect();
2277 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());
2280
2281 let mut init0 = less.clone();
2282 init0.extend(greater.clone());
2283 init0.extend(long.clone());
2284 let mut init1 = greater;
2285 init1.extend(less);
2286 init1.extend(long);
2287
2288 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
2291 if num1 > 1
2292 && init1.len() > 1
2293 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
2294 && eq_len == num1.min(init1.len())
2295 && eq_len == num0.min(init0.len())
2296 {
2297 if let [a, b, ..] = &mut init1[..] {
2300 core::mem::swap(a, b);
2301 }
2302 }
2303
2304 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
2305 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
2306 Ok((list0, list1))
2307}
2308
2309fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
2311 a.is_long_term() == b.is_long_term()
2312 && if a.is_long_term() {
2313 a.lt_idx() == b.lt_idx()
2314 } else {
2315 a.pic_poc() == b.pic_poc()
2316 }
2317}
2318
2319fn apply_list_modification(
2324 init: Vec<Ref>,
2325 curr_frame_num: u32,
2326 max_frame_num: u32,
2327 num_active: usize,
2328 mods: &[(u32, u32)],
2329) -> Result<Vec<Ref>, DecodeError> {
2330 if mods.is_empty() {
2331 let mut init = init;
2332 init.truncate(num_active.max(1));
2333 return Ok(init);
2334 }
2335 let curr = curr_frame_num as i64;
2336 let max = max_frame_num as i64;
2337 let mut list = init.clone();
2338 let mut pic_num_pred = curr;
2339 let mut refidx = 0usize;
2340 for &(idc, val) in mods {
2341 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
2342 Box::new(move |r: &RefFrame| r.is_long_term() && r.lt_idx() == val)
2343 } else {
2344 let abs_diff = (val as i64) + 1;
2345 let no_wrap = if idc == 0 {
2346 let x = pic_num_pred - abs_diff;
2347 if x < 0 {
2348 x + max
2349 } else {
2350 x
2351 }
2352 } else {
2353 let x = pic_num_pred + abs_diff;
2354 if x >= max {
2355 x - max
2356 } else {
2357 x
2358 }
2359 };
2360 pic_num_pred = no_wrap;
2361 let target = if no_wrap > curr {
2362 no_wrap - max
2363 } else {
2364 no_wrap
2365 };
2366 Box::new(move |r: &RefFrame| {
2367 let f = r.fn_num() as i64;
2368 let pn = if f > curr { f - max } else { f };
2369 !r.is_long_term() && pn == target
2370 })
2371 };
2372 let found = init.iter().find(|r| matches(r)).cloned();
2373 let Some(found) = found else {
2374 if crate::mb16::dump_mb_on() {
2375 let cand: Vec<String> = init
2376 .iter()
2377 .map(|r| {
2378 let f = r.fn_num() as i64;
2379 let pn = if f > curr { f - max } else { f };
2380 format!(
2381 "(fn={} poc={} lt={} picnum={})",
2382 r.fn_num(),
2383 r.pic_poc(),
2384 r.is_long_term(),
2385 pn
2386 )
2387 })
2388 .collect();
2389 eprintln!(
2390 "MODFAIL idc={idc} val={val} curr_frame_num={curr} max={max} init={}",
2391 cand.join(" ")
2392 );
2393 }
2394 return Err(DecodeError::Truncated); };
2396 if refidx > list.len() {
2397 break;
2398 }
2399 list.insert(refidx, found);
2400 if let Some(dup) = list
2401 .iter()
2402 .enumerate()
2403 .skip(refidx + 1)
2404 .find(|(_, r)| matches(r))
2405 .map(|(i, _)| i)
2406 {
2407 list.remove(dup);
2408 }
2409 refidx += 1;
2410 if refidx >= num_active {
2411 break;
2412 }
2413 }
2414 list.truncate(num_active.max(1));
2415 Ok(list)
2416}
2417
2418#[cfg(test)]
2419mod tests {
2420 use super::*;
2421
2422 fn ref_at(poc: i32, fnum: u32) -> Ref {
2423 crate::sync::Arc::new(RefFrame {
2424 py: vec![],
2425 pu: vec![],
2426 pv: vec![],
2427 cw: 0,
2428 ch: 0,
2429 ready_rows: core::sync::atomic::AtomicUsize::new(0),
2430 live: None,
2431 frozen: crate::sync::Once::new(),
2432 frame_num: fnum,
2433 poc,
2434 mv: Vec::new(),
2435 ref_idx: Vec::new(),
2436 mv1: Vec::new(),
2437 ref_idx1: Vec::new(),
2438 ref_poc: Vec::new(),
2439 w4: 0,
2440 long_term: false,
2441 long_term_idx: 0,
2442 })
2443 }
2444
2445 #[test]
2446 fn b_ref_lists_ordered_by_poc() {
2447 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
2449 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
2450 assert_eq!(
2452 l0.iter().map(|r| r.poc).collect::<Vec<_>>(),
2453 vec![2, 0, 6, 8]
2454 );
2455 assert_eq!(
2457 l1.iter().map(|r| r.poc).collect::<Vec<_>>(),
2458 vec![6, 8, 2, 0]
2459 );
2460 }
2461
2462 #[test]
2463 fn b_ref_list1_swap_when_equal() {
2464 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
2467 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
2468 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
2469 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
2470 }
2471
2472 #[test]
2473 fn frame_num_gaps_insert_placeholders() {
2474 let mut d = Decoder::new();
2475 d.prev_ref_frame_num = 2;
2476 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
2478 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
2479 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
2480 assert_eq!(d.prev_ref_frame_num, 4);
2481 assert!(
2482 d.refs.iter().all(|r| r.py.iter().all(|&p| p == 128)),
2483 "grey fill"
2484 );
2485 }
2486
2487 #[test]
2488 fn frame_num_gaps_wrap_and_noop() {
2489 let mut d = Decoder::new();
2491 d.prev_ref_frame_num = 14;
2492 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
2493 assert_eq!(
2494 d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(),
2495 vec![0, 15]
2496 );
2497 let mut d = Decoder::new();
2499 d.prev_ref_frame_num = 3;
2500 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
2501 assert!(d.refs.is_empty());
2502 }
2503
2504 #[test]
2505 fn missing_param_sets_errors() {
2506 let mut d = Decoder::new();
2507 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
2510 let err = d.decode(&nal.to_annex_b()).unwrap_err();
2511 assert_eq!(err, DecodeError::MissingParameterSet);
2512 }
2513}