1mod cabac;
26mod mb16;
27mod params;
28
29pub use params::{Pps, Sps};
30pub use mb16::{MvField, MV_DUMP};
31
32#[doc(hidden)]
35pub mod cabac_test {
36 pub use crate::cabac::Cabac;
37}
38
39use mb16::{FrameDecoder, WeightTable};
40use rusty_h264_common::bit_reader::OutOfData;
41use rusty_h264_common::nal::{emulation_unprevent, split_annex_b};
42use rusty_h264_common::{BitReader, NalUnitType, YuvFrame};
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum DecodeError {
47 Truncated,
49 MissingParameterSet,
51 Unsupported(&'static str),
53}
54
55impl From<OutOfData> for DecodeError {
56 fn from(_: OutOfData) -> Self {
57 DecodeError::Truncated
58 }
59}
60
61impl core::fmt::Display for DecodeError {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 match self {
64 DecodeError::Truncated => f.write_str("bitstream truncated"),
65 DecodeError::MissingParameterSet => f.write_str("slice before SPS/PPS"),
66 DecodeError::Unsupported(s) => write!(f, "unsupported coding tool: {s}"),
67 }
68 }
69}
70
71impl std::error::Error for DecodeError {}
72
73pub(crate) type Ref = std::sync::Arc<RefFrame>;
82
83#[derive(Debug, Clone, Default)]
84#[allow(dead_code)]
85pub(crate) struct RefFrame {
86 pub py: Vec<u8>,
92 pub pu: Vec<u8>,
93 pub pv: Vec<u8>,
94 pub cw: usize,
95 pub ch: usize,
96 pub frame_num: u32,
98 pub poc: i32,
100 pub mv: Vec<(i32, i32)>,
104 pub ref_idx: Vec<i32>,
105 pub ref_poc: Vec<i32>,
109 pub w4: usize,
110 pub long_term: bool,
114 pub long_term_idx: u32,
115}
116
117pub(crate) const LPAD: usize = 16;
121pub(crate) const CPAD: usize = 8;
122
123impl RefFrame {
124 #[inline]
125 pub fn lstride(&self) -> usize {
126 self.cw + 2 * LPAD
127 }
128 #[inline]
129 pub fn cstride(&self) -> usize {
130 self.cw / 2 + 2 * CPAD
131 }
132}
133
134#[derive(Clone, Copy)]
136enum Mmco {
137 Unref(u32),
139 UnrefLong(u32),
141 AssignLong(u32, u32),
143 MaxLong(u32),
145 Reset,
147 CurrentLong(u32),
149}
150
151struct PendingPic {
155 fd: mb16::FrameDecoder,
156 frame_num: u32,
157 poc: i32,
158 next_mb: usize,
159 total_mb: usize,
160 slice_count: u16,
161 deblock: bool,
162 filter_offset_a: i32,
163 filter_offset_b: i32,
164 crop_r: usize,
165 crop_b: usize,
166 max_refs: usize,
167 log2_max_frame_num: u32,
168 is_reference: bool,
171 idr_long_term: bool,
172 mmco_ops: Vec<Mmco>,
173}
174
175#[derive(Default)]
178pub struct Decoder {
179 sps: std::collections::HashMap<u32, Sps>,
182 pps: std::collections::HashMap<u32, Pps>,
183 refs: Vec<Ref>,
185 cur: Option<PendingPic>,
187 poc: PocState,
191 last_poc: i32,
193 prev_ref_frame_num: u32,
196}
197
198#[derive(Default)]
200struct PocState {
201 prev_msb: i32,
202 prev_lsb: i32,
203 prev_frame_num: u32,
204 prev_frame_num_offset: i64,
205}
206
207impl Decoder {
208 pub fn new() -> Self {
210 Self::default()
211 }
212
213 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
216 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
217 let mut frame = None;
218 for nal in split_annex_b(annex_b) {
219 if nal.is_empty() {
220 continue;
221 }
222 let nal_type = NalUnitType::from_id(nal[0]);
223 let rbsp = emulation_unprevent(&nal[1..]);
224 match nal_type {
225 NalUnitType::Sps => {
226 let s = Sps::parse(&rbsp)?;
227 self.sps.insert(s.seq_parameter_set_id, s);
228 }
229 NalUnitType::Pps => {
230 let p = Pps::parse(&rbsp)?;
231 self.pps.insert(p.pic_parameter_set_id, p);
232 }
233 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
234 let nal_ref_idc = (nal[0] >> 5) & 3;
235 let is_idr = nal_type == NalUnitType::IdrSlice;
236 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
237 frame = Some(f);
238 }
239 }
240 _ => {} }
242 }
243 Ok(frame)
244 }
245
246 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
254 let mut out = Vec::new();
255 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
256 for au in split_access_units(annex_b) {
257 if au_is_idr(au) {
258 flush_gop(&mut gop, &mut out); }
260 if let Some(frame) = self.decode(au)? {
261 gop.push((self.last_poc, frame));
262 }
263 }
264 flush_gop(&mut gop, &mut out);
265 Ok(out)
266 }
267
268 fn decode_slice(
269 &mut self,
270 rbsp: &[u8],
271 is_idr: bool,
272 nal_ref_idc: u8,
273 ) -> Result<Option<YuvFrame>, DecodeError> {
274 let mut r = BitReader::new(rbsp);
275 let first_mb_in_slice = r.read_ue()? as usize;
277 let slice_type = r.read_ue()?;
278 let is_p = matches!(slice_type, 0 | 5);
279 let is_b = matches!(slice_type, 1 | 6);
280 let is_i = matches!(slice_type, 2 | 7);
281 if !is_p && !is_b && !is_i {
282 return Err(DecodeError::Unsupported("SP/SI slices"));
283 }
284 let pic_parameter_set_id = r.read_ue()?;
286 let pps = self.pps.get(&pic_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
287 let sps = self.sps.get(&pps.seq_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
288 let sps = &sps;
289 let pps = &pps;
290 let cabac = pps.entropy_coding_mode_flag;
294 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
295 if is_idr {
296 let _idr_pic_id = r.read_ue()?;
297 }
298 let mut poc_lsb = 0u32;
301 let mut delta_poc_bottom = 0i32;
302 if sps.pic_order_cnt_type == 0 {
303 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
304 if pps.bottom_field_pic_order_present {
305 delta_poc_bottom = r.read_se()?;
306 }
307 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
308 let _delta_pic_order_cnt_0 = r.read_se()?;
309 if pps.bottom_field_pic_order_present {
310 let _delta_pic_order_cnt_1 = r.read_se()?;
311 }
312 }
313 let pic_poc = if first_mb_in_slice == 0 {
316 self.compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_poc_bottom)
317 } else {
318 self.cur.as_ref().map_or(0, |p| p.poc)
319 };
320 if pps.redundant_pic_cnt_present_flag {
325 let redundant_pic_cnt = r.read_ue()?;
326 if redundant_pic_cnt != 0 {
327 return Ok(None);
328 }
329 }
330 let direct_spatial = if is_b { r.read_bit()? } else { true };
332 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
333 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
334 let mut reorder_l0: Vec<(u32, u32)> = Vec::new();
335 let mut reorder_l1: Vec<(u32, u32)> = Vec::new();
336 if is_p || is_b {
337 if r.read_bit()? {
339 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
340 if is_b {
341 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
342 }
343 }
344 if r.read_bit()? {
346 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
347 }
348 if is_b && r.read_bit()? {
349 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
351 }
352 }
353 let weights = if is_p && pps.weighted_pred {
358 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
359 } else if is_b && pps.weighted_bipred_idc == 1 {
360 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
361 } else {
362 None
363 };
364 let mut idr_long_term = false;
368 let mut mmco_ops: Vec<Mmco> = Vec::new();
369 if nal_ref_idc == 0 {
370 } else if is_idr {
372 let _no_output_of_prior_pics = r.read_bit()?;
373 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
375 loop {
377 let op = r.read_ue()?;
378 match op {
379 0 => break,
380 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
381 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
382 3 => {
383 let diff = r.read_ue()?;
384 let idx = r.read_ue()?;
385 mmco_ops.push(Mmco::AssignLong(diff, idx));
386 }
387 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
388 5 => mmco_ops.push(Mmco::Reset),
389 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
390 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
391 }
392 if mmco_ops.len() > 128 {
393 return Err(DecodeError::Truncated);
394 }
395 }
396 }
397 let cabac_init_idc = if cabac && !is_i {
401 let v = r.read_ue()?;
402 if v > 2 {
403 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
404 }
405 v
406 } else {
407 0
408 };
409 let slice_qp_delta = r.read_se()?;
410 let mut deblock = true;
415 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
416 if pps.deblocking_filter_control_present_flag {
417 let disable_deblocking_filter_idc = r.read_ue()?;
418 deblock = disable_deblocking_filter_idc != 1;
421 if disable_deblocking_filter_idc != 1 {
422 filter_offset_a = r.read_se()? * 2;
424 filter_offset_b = r.read_se()? * 2;
425 }
426 }
427 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
428
429 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
432 self.insert_frame_num_gaps(
433 frame_num,
434 1u32 << sps.log2_max_frame_num,
435 sps.max_num_ref_frames.max(1) as usize,
436 sps.pic_width_in_mbs * 16,
437 sps.pic_height_in_mbs * 16,
438 );
439 }
440
441 let max_fn = 1u32 << sps.log2_max_frame_num;
444 let (ref_list0, ref_list1) = if is_b {
445 build_ref_list_b(
446 &self.refs, pic_poc, frame_num, max_fn,
447 num_ref_idx_l0, num_ref_idx_l1, &reorder_l0, &reorder_l1,
448 )?
449 } else if is_p {
450 (build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?, Vec::new())
451 } else {
452 (Vec::new(), Vec::new())
453 };
454 if first_mb_in_slice == 0 {
458 if is_idr {
459 self.refs.clear();
460 }
461 let mut fd = FrameDecoder::new(
462 sps.pic_width_in_mbs,
463 sps.pic_height_in_mbs,
464 slice_qp,
465 pps.chroma_qp_index_offset,
466 ref_list0,
467 num_ref_idx_l0,
468 pps.constrained_intra_pred_flag,
469 pps.transform_8x8_mode_flag,
470 sps.profile_idc != 66, );
472 if is_b {
473 fd.set_b_context(
474 ref_list1,
475 num_ref_idx_l1,
476 direct_spatial,
477 pic_poc,
478 pps.weighted_bipred_idc,
479 sps.direct_8x8_inference,
480 );
481 }
482 if sps.has_scaling || pps.pic_scaling_matrix_present {
483 let (s4, s8) = resolve_scaling(sps, pps);
484 fd.set_scaling(s4, s8);
485 }
486 if let Some(w) = weights {
487 fd.set_weights(w);
488 }
489 self.cur = Some(PendingPic {
490 fd,
491 frame_num,
492 poc: pic_poc,
493 next_mb: 0,
494 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
495 slice_count: 0,
496 deblock,
497 filter_offset_a,
498 filter_offset_b,
499 crop_r: sps.frame_crop_right as usize,
500 crop_b: sps.frame_crop_bottom as usize,
501 max_refs: sps.max_num_ref_frames.max(1) as usize,
502 log2_max_frame_num: sps.log2_max_frame_num,
503 is_reference: nal_ref_idc != 0,
504 idr_long_term,
505 mmco_ops,
506 });
507 } else {
508 let Some(pic) = self.cur.as_mut() else {
510 return Err(DecodeError::Unsupported("slice continues a missing picture"));
511 };
512 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
513 if is_b {
514 pic.fd.set_b_context(
515 ref_list1,
516 num_ref_idx_l1,
517 direct_spatial,
518 pic.poc,
519 pps.weighted_bipred_idc,
520 sps.direct_8x8_inference,
521 );
522 }
523 if sps.has_scaling || pps.pic_scaling_matrix_present {
524 let (s4, s8) = resolve_scaling(sps, pps);
525 pic.fd.set_scaling(s4, s8);
526 }
527 if let Some(w) = weights {
528 pic.fd.set_weights(w);
529 }
530 pic.deblock = deblock;
532 pic.filter_offset_a = filter_offset_a;
533 pic.filter_offset_b = filter_offset_b;
534 pic.idr_long_term |= idr_long_term;
535 pic.mmco_ops.extend(mmco_ops);
536 }
537
538 let pic = self.cur.as_mut().expect("pending picture set above");
539 let first = first_mb_in_slice.min(pic.total_mb);
540 let next = if cabac {
541 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
543 let (data, start) = (r.data(), r.bit_pos() / 8);
544 pic.fd
545 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
546 } else {
547 pic.fd.decode_slice_data(&mut r, is_p, first)
548 }
549 .map_err(|e| match e {
550 mb16::MbError::Truncated => DecodeError::Truncated,
551 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
552 })?;
553 pic.next_mb = next;
554 pic.slice_count += 1;
555
556 if pic.next_mb < pic.total_mb {
557 return Ok(None); }
559
560 let pic = self.cur.take().expect("pending picture");
562 let PendingPic {
563 mut fd,
564 frame_num,
565 poc,
566 deblock,
567 filter_offset_a,
568 filter_offset_b,
569 crop_r,
570 crop_b,
571 max_refs,
572 log2_max_frame_num,
573 is_reference,
574 idr_long_term,
575 mmco_ops,
576 ..
577 } = pic;
578 self.last_poc = poc;
579 if deblock {
580 fd.deblock(filter_offset_a, filter_offset_b);
581 }
582 let reference = if is_reference {
585 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
586 Some(fd.as_reference())
587 } else {
588 None
590 };
591 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
592 if let Some(mut reference) = reference {
593 reference.frame_num = frame_num;
594 reference.poc = poc;
595 if idr_long_term {
596 reference.long_term = true;
597 reference.long_term_idx = 0;
598 }
599 self.prev_ref_frame_num =
601 self.apply_ref_marking(reference, &mmco_ops, frame_num, log2_max_frame_num, max_refs);
602 }
603 Ok(Some(fd.into_frame(crop_r, crop_b)))
604 }
605
606 fn insert_frame_num_gaps(&mut self, frame_num: u32, max_fn: u32, max_refs: usize, w: usize, h: usize) {
612 if max_fn == 0 {
613 return;
614 }
615 let start = (self.prev_ref_frame_num + 1) % max_fn;
616 let gap = (frame_num + max_fn - start) % max_fn;
617 if gap == 0 {
618 return;
619 }
620 let cap = max_refs.max(1);
626 let n = (gap as usize).min(cap);
627 let (cw, ch) = (w, h);
628 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
629 for _ in 0..n {
630 self.refs.insert(
631 0,
632 std::sync::Arc::new(RefFrame {
633 py: vec![128; (cw + 2 * LPAD) * (ch + 2 * LPAD)],
635 pu: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
636 pv: vec![128; (cw / 2 + 2 * CPAD) * (ch / 2 + 2 * CPAD)],
637 cw,
638 ch,
639 frame_num: expected,
640 poc: 0,
641 mv: Vec::new(),
642 ref_idx: Vec::new(),
643 ref_poc: Vec::new(),
644 w4: 0,
645 long_term: false,
646 long_term_idx: 0,
647 }),
648 );
649 self.refs.truncate(cap);
650 expected = (expected + 1) % max_fn;
651 }
652 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
653 }
654
655 pub fn last_poc(&self) -> i32 {
659 self.last_poc
660 }
661
662 fn compute_poc(
666 &mut self,
667 sps: &Sps,
668 is_idr: bool,
669 nal_ref_idc: u8,
670 frame_num: u32,
671 poc_lsb: u32,
672 delta_bottom: i32,
673 ) -> i32 {
674 match sps.pic_order_cnt_type {
675 0 => {
676 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
677 let (prev_msb, prev_lsb) =
678 if is_idr { (0, 0) } else { (self.poc.prev_msb, self.poc.prev_lsb) };
679 let lsb = poc_lsb as i32;
680 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
681 prev_msb + max_lsb
682 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
683 prev_msb - max_lsb
684 } else {
685 prev_msb
686 };
687 let top = msb + lsb;
688 let poc = top.min(top + delta_bottom);
689 if nal_ref_idc != 0 {
690 self.poc.prev_msb = msb;
691 self.poc.prev_lsb = lsb;
692 }
693 poc
694 }
695 2 => {
696 let max_fn = 1i64 << sps.log2_max_frame_num;
697 let offset = if is_idr {
698 0
699 } else if self.poc.prev_frame_num > frame_num {
700 self.poc.prev_frame_num_offset + max_fn
701 } else {
702 self.poc.prev_frame_num_offset
703 };
704 let poc = if is_idr {
705 0
706 } else {
707 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
708 };
709 self.poc.prev_frame_num_offset = offset;
710 self.poc.prev_frame_num = frame_num;
711 poc as i32
712 }
713 _ => {
714 self.poc.prev_frame_num = frame_num;
715 frame_num as i32 * 2
716 }
717 }
718 }
719
720 fn apply_ref_marking(
731 &mut self,
732 mut reference: RefFrame,
733 ops: &[Mmco],
734 frame_num: u32,
735 log2_max_frame_num: u32,
736 max_refs: usize,
737 ) -> u32 {
738 let max = 1i64 << log2_max_frame_num;
739 let curr = frame_num as i64;
740 let pic_num = |rf: &RefFrame| -> i64 {
741 if (rf.frame_num as i64) > curr {
742 rf.frame_num as i64 - max
743 } else {
744 rf.frame_num as i64
745 }
746 };
747
748 if ops.is_empty() {
749 let out_fn = reference.frame_num;
753 self.refs.insert(0, std::sync::Arc::new(reference));
754 while self.refs.len() > max_refs {
755 match self.refs.iter().rposition(|r| !r.long_term) {
756 Some(pos) => {
757 self.refs.remove(pos);
758 }
759 None => break,
760 }
761 }
762 return out_fn;
763 }
764
765 for &op in ops {
767 match op {
768 Mmco::Unref(diff) => {
769 let target = curr - (diff as i64 + 1);
770 self.refs.retain(|r| r.long_term || pic_num(r) != target);
771 }
772 Mmco::UnrefLong(ltpn) => {
773 self.refs.retain(|r| !(r.long_term && r.long_term_idx == ltpn));
774 }
775 Mmco::AssignLong(diff, idx) => {
776 let target = curr - (diff as i64 + 1);
777 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
778 for r in self.refs.iter_mut() {
779 if !r.long_term && pic_num(r) == target {
780 let r = std::sync::Arc::make_mut(r);
782 r.long_term = true;
783 r.long_term_idx = idx;
784 }
785 }
786 }
787 Mmco::MaxLong(max_plus1) => {
788 self.refs.retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
789 }
790 Mmco::Reset => {
791 self.refs.clear();
792 reference.frame_num = 0;
793 }
794 Mmco::CurrentLong(idx) => {
795 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
796 reference.long_term = true;
797 reference.long_term_idx = idx;
798 }
799 }
800 }
801 let out_fn = reference.frame_num;
802 self.refs.insert(0, std::sync::Arc::new(reference));
803 let cap = max_refs.max(16);
805 if self.refs.len() > cap {
806 self.refs.truncate(cap);
807 }
808 out_fn
809 }
810}
811
812fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
814 gop.sort_by_key(|(poc, _)| *poc);
815 out.extend(gop.drain(..).map(|(_, f)| f));
816}
817
818fn au_is_idr(au: &[u8]) -> bool {
820 split_annex_b(au)
821 .iter()
822 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
823}
824
825fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
829 let mut codes: Vec<(usize, bool)> = Vec::new();
831 let mut i = 0;
832 while i + 3 <= stream.len() {
833 if stream[i] == 0 && stream[i + 1] == 0 && stream[i + 2] == 1 {
834 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
835 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
836 let sc = if i > 0 && stream[i - 1] == 0 { i - 1 } else { i };
838 codes.push((sc, is_vcl));
839 i += 3;
840 } else {
841 i += 1;
842 }
843 }
844 if codes.is_empty() {
845 return vec![stream];
846 }
847 let mut aus = Vec::new();
848 let mut start = codes[0].0;
849 for k in 0..codes.len() {
850 if codes[k].1 {
851 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
852 aus.push(&stream[start..end]);
853 start = end;
854 }
855 }
856 aus
857}
858
859fn parse_pred_weight_table(
862 r: &mut BitReader,
863 num_l0: usize,
864 num_l1: usize,
865 is_b: bool,
866) -> Result<WeightTable, DecodeError> {
867 let luma_log2_denom = r.read_ue()? as i32;
868 let chroma_log2_denom = r.read_ue()? as i32;
869 if !(0..=7).contains(&luma_log2_denom) || !(0..=7).contains(&chroma_log2_denom) {
873 return Err(DecodeError::Unsupported("invalid weight denom"));
874 }
875 let mut wt = WeightTable {
876 luma_log2_denom,
877 chroma_log2_denom,
878 ..Default::default()
879 };
880 let lists: &[(usize, usize)] = if is_b {
881 &[(0, num_l0), (1, num_l1)]
882 } else {
883 &[(0, num_l0)]
884 };
885 for &(list, n) in lists {
886 let mut luma = Vec::with_capacity(n);
887 let mut chroma = Vec::with_capacity(n);
888 for _ in 0..n {
889 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
890 if r.read_bit()? {
891 lw = r.read_se()?;
892 lo = r.read_se()?;
893 }
894 luma.push((lw, lo));
895 let mut ch = [(1 << chroma_log2_denom, 0); 2];
896 if r.read_bit()? {
897 for slot in ch.iter_mut() {
898 *slot = (r.read_se()?, r.read_se()?);
899 }
900 }
901 chroma.push(ch);
902 }
903 wt.luma[list] = luma;
904 wt.chroma[list] = chroma;
905 }
906 Ok(wt)
907}
908
909fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
914 use crate::params::{
915 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
916 };
917 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
918 const ZZ8: [usize; 64] = [
920 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,
921 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
922 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
923 ];
924 let mut z4 = [[16u8; 16]; 6];
927 for i in 0..6 {
928 z4[i] = if pps.pic_scaling_matrix_present {
929 if pps.scaling_present_4x4[i] {
930 pps.scaling_4x4[i]
931 } else {
932 match i {
933 0 if sps.has_scaling => sps.scaling_4x4[0],
934 0 => DEFAULT_4X4_INTRA,
935 3 if sps.has_scaling => sps.scaling_4x4[3],
936 3 => DEFAULT_4X4_INTER,
937 _ => z4[i - 1],
938 }
939 }
940 } else {
941 sps.scaling_4x4[i]
942 };
943 }
944 let mut z8 = [[16u8; 64]; 2];
945 for (i, list) in z8.iter_mut().enumerate() {
946 *list = if pps.pic_scaling_matrix_present {
947 if pps.scaling_present_8x8[i] {
948 pps.scaling_8x8[i]
949 } else if sps.has_scaling {
950 sps.scaling_8x8[i]
951 } else if i == 0 {
952 DEFAULT_8X8_INTRA
953 } else {
954 DEFAULT_8X8_INTER
955 }
956 } else {
957 sps.scaling_8x8[i]
958 };
959 }
960 let mut out4 = [[16i32; 16]; 6];
961 for (li, list) in out4.iter_mut().enumerate() {
962 for k in 0..16 {
963 list[ZZ4[k]] = z4[li][k] as i32;
964 }
965 }
966 let mut out8 = [[16i32; 64]; 2];
967 for (li, list) in out8.iter_mut().enumerate() {
968 for k in 0..64 {
969 list[ZZ8[k]] = z8[li][k] as i32;
970 }
971 }
972 (out4, out8)
973}
974
975fn parse_ref_pic_list_modification(
978 r: &mut BitReader,
979 out: &mut Vec<(u32, u32)>,
980) -> Result<(), DecodeError> {
981 loop {
982 let idc = r.read_ue()?;
983 if idc == 3 {
984 break;
985 }
986 if idc > 3 {
987 return Err(DecodeError::Unsupported("invalid ref_pic_list_modification"));
988 }
989 let val = r.read_ue()?; out.push((idc, val));
991 if out.len() > 64 {
992 return Err(DecodeError::Truncated); }
994 }
995 Ok(())
996}
997
998fn build_ref_list_p(
1002 dpb: &[Ref],
1003 curr_frame_num: u32,
1004 max_frame_num: u32,
1005 num_active: usize,
1006 mods: &[(u32, u32)],
1007) -> Result<Vec<Ref>, DecodeError> {
1008 let curr = curr_frame_num as i64;
1009 let max = max_frame_num as i64;
1010 let pic_num = |fnum: u32| -> i64 {
1011 let f = fnum as i64;
1012 if f > curr { f - max } else { f }
1013 };
1014 let mut init: Vec<Ref> = dpb.iter().filter(|r| !r.long_term).cloned().collect();
1015 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.frame_num)));
1016 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.long_term).cloned().collect();
1017 long.sort_by_key(|rf| rf.long_term_idx);
1018 init.extend(long);
1019 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
1020}
1021
1022#[allow(clippy::too_many_arguments)]
1027fn build_ref_list_b(
1028 dpb: &[Ref],
1029 curr_poc: i32,
1030 curr_frame_num: u32,
1031 max_frame_num: u32,
1032 num0: usize,
1033 num1: usize,
1034 mods0: &[(u32, u32)],
1035 mods1: &[(u32, u32)],
1036) -> Result<(Vec<Ref>, Vec<Ref>), DecodeError> {
1037 let mut less: Vec<Ref> =
1038 dpb.iter().filter(|r| !r.long_term && r.poc < curr_poc).cloned().collect();
1039 let mut greater: Vec<Ref> =
1040 dpb.iter().filter(|r| !r.long_term && r.poc > curr_poc).cloned().collect();
1041 let mut long: Vec<Ref> = dpb.iter().filter(|r| r.long_term).cloned().collect();
1042 less.sort_by_key(|r| core::cmp::Reverse(r.poc)); greater.sort_by_key(|r| r.poc); long.sort_by_key(|r| r.long_term_idx);
1045
1046 let mut init0 = less.clone();
1047 init0.extend(greater.clone());
1048 init0.extend(long.clone());
1049 let mut init1 = greater;
1050 init1.extend(less);
1051 init1.extend(long);
1052
1053 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
1056 if num1 > 1
1057 && init1.len() > 1
1058 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
1059 && eq_len == num1.min(init1.len())
1060 && eq_len == num0.min(init0.len())
1061 {
1062 init1.swap(0, 1);
1063 }
1064
1065 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
1066 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
1067 Ok((list0, list1))
1068}
1069
1070fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
1072 a.long_term == b.long_term
1073 && if a.long_term { a.long_term_idx == b.long_term_idx } else { a.poc == b.poc }
1074}
1075
1076fn apply_list_modification(
1081 init: Vec<Ref>,
1082 curr_frame_num: u32,
1083 max_frame_num: u32,
1084 num_active: usize,
1085 mods: &[(u32, u32)],
1086) -> Result<Vec<Ref>, DecodeError> {
1087 if mods.is_empty() {
1088 let mut init = init;
1089 init.truncate(num_active.max(1));
1090 return Ok(init);
1091 }
1092 let curr = curr_frame_num as i64;
1093 let max = max_frame_num as i64;
1094 let mut list = init.clone();
1095 let mut pic_num_pred = curr;
1096 let mut refidx = 0usize;
1097 for &(idc, val) in mods {
1098 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
1099 Box::new(move |r: &RefFrame| r.long_term && r.long_term_idx == val)
1100 } else {
1101 let abs_diff = (val as i64) + 1;
1102 let no_wrap = if idc == 0 {
1103 let x = pic_num_pred - abs_diff;
1104 if x < 0 { x + max } else { x }
1105 } else {
1106 let x = pic_num_pred + abs_diff;
1107 if x >= max { x - max } else { x }
1108 };
1109 pic_num_pred = no_wrap;
1110 let target = if no_wrap > curr { no_wrap - max } else { no_wrap };
1111 Box::new(move |r: &RefFrame| {
1112 let pn = if r.frame_num as i64 > curr {
1113 r.frame_num as i64 - max
1114 } else {
1115 r.frame_num as i64
1116 };
1117 !r.long_term && pn == target
1118 })
1119 };
1120 let found = init.iter().find(|r| matches(r)).cloned();
1121 let Some(found) = found else {
1122 return Err(DecodeError::Truncated); };
1124 if refidx > list.len() {
1125 break;
1126 }
1127 list.insert(refidx, found);
1128 if let Some(dup) = list.iter().enumerate().skip(refidx + 1).find(|(_, r)| matches(r)).map(|(i, _)| i) {
1129 list.remove(dup);
1130 }
1131 refidx += 1;
1132 if refidx >= num_active {
1133 break;
1134 }
1135 }
1136 list.truncate(num_active.max(1));
1137 Ok(list)
1138}
1139
1140#[cfg(test)]
1141mod tests {
1142 use super::*;
1143
1144 fn ref_at(poc: i32, fnum: u32) -> Ref {
1145 std::sync::Arc::new(RefFrame {
1146 py: vec![],
1147 pu: vec![],
1148 pv: vec![],
1149 cw: 0,
1150 ch: 0,
1151 frame_num: fnum,
1152 poc,
1153 mv: Vec::new(),
1154 ref_idx: Vec::new(),
1155 ref_poc: Vec::new(),
1156 w4: 0,
1157 long_term: false,
1158 long_term_idx: 0,
1159 })
1160 }
1161
1162 #[test]
1163 fn b_ref_lists_ordered_by_poc() {
1164 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
1166 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
1167 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 0, 6, 8]);
1169 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![6, 8, 2, 0]);
1171 }
1172
1173 #[test]
1174 fn b_ref_list1_swap_when_equal() {
1175 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
1178 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
1179 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
1180 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
1181 }
1182
1183 #[test]
1184 fn frame_num_gaps_insert_placeholders() {
1185 let mut d = Decoder::new();
1186 d.prev_ref_frame_num = 2;
1187 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
1189 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
1190 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
1191 assert_eq!(d.prev_ref_frame_num, 4);
1192 assert!(d.refs.iter().all(|r| r.py.iter().all(|&p| p == 128)), "grey fill");
1193 }
1194
1195 #[test]
1196 fn frame_num_gaps_wrap_and_noop() {
1197 let mut d = Decoder::new();
1199 d.prev_ref_frame_num = 14;
1200 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
1201 assert_eq!(d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(), vec![0, 15]);
1202 let mut d = Decoder::new();
1204 d.prev_ref_frame_num = 3;
1205 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
1206 assert!(d.refs.is_empty());
1207 }
1208
1209 #[test]
1210 fn missing_param_sets_errors() {
1211 let mut d = Decoder::new();
1212 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
1215 let err = d.decode(&nal.to_annex_b()).unwrap_err();
1216 assert_eq!(err, DecodeError::MissingParameterSet);
1217 }
1218}