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
73#[derive(Debug, Clone, Default)]
76#[allow(dead_code)]
77pub(crate) struct RefFrame {
78 pub y: Vec<u8>,
79 pub u: Vec<u8>,
80 pub v: Vec<u8>,
81 pub cw: usize,
82 pub ch: usize,
83 pub frame_num: u32,
85 pub poc: i32,
87 pub mv: Vec<(i32, i32)>,
91 pub ref_idx: Vec<i32>,
92 pub ref_poc: Vec<i32>,
96 pub w4: usize,
97 pub long_term: bool,
101 pub long_term_idx: u32,
102}
103
104#[derive(Clone, Copy)]
106enum Mmco {
107 Unref(u32),
109 UnrefLong(u32),
111 AssignLong(u32, u32),
113 MaxLong(u32),
115 Reset,
117 CurrentLong(u32),
119}
120
121struct PendingPic {
125 fd: mb16::FrameDecoder,
126 frame_num: u32,
127 poc: i32,
128 next_mb: usize,
129 total_mb: usize,
130 slice_count: u16,
131 deblock: bool,
132 filter_offset_a: i32,
133 filter_offset_b: i32,
134 crop_r: usize,
135 crop_b: usize,
136 max_refs: usize,
137 log2_max_frame_num: u32,
138 is_reference: bool,
141 idr_long_term: bool,
142 mmco_ops: Vec<Mmco>,
143}
144
145#[derive(Default)]
148pub struct Decoder {
149 sps: std::collections::HashMap<u32, Sps>,
152 pps: std::collections::HashMap<u32, Pps>,
153 refs: Vec<RefFrame>,
155 cur: Option<PendingPic>,
157 poc: PocState,
161 last_poc: i32,
163 prev_ref_frame_num: u32,
166}
167
168#[derive(Default)]
170struct PocState {
171 prev_msb: i32,
172 prev_lsb: i32,
173 prev_frame_num: u32,
174 prev_frame_num_offset: i64,
175}
176
177impl Decoder {
178 pub fn new() -> Self {
180 Self::default()
181 }
182
183 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
186 let _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
187 let mut frame = None;
188 for nal in split_annex_b(annex_b) {
189 if nal.is_empty() {
190 continue;
191 }
192 let nal_type = NalUnitType::from_id(nal[0]);
193 let rbsp = emulation_unprevent(&nal[1..]);
194 match nal_type {
195 NalUnitType::Sps => {
196 let s = Sps::parse(&rbsp)?;
197 self.sps.insert(s.seq_parameter_set_id, s);
198 }
199 NalUnitType::Pps => {
200 let p = Pps::parse(&rbsp)?;
201 self.pps.insert(p.pic_parameter_set_id, p);
202 }
203 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
204 let nal_ref_idc = (nal[0] >> 5) & 3;
205 let is_idr = nal_type == NalUnitType::IdrSlice;
206 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
207 frame = Some(f);
208 }
209 }
210 _ => {} }
212 }
213 Ok(frame)
214 }
215
216 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
224 let mut out = Vec::new();
225 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
226 for au in split_access_units(annex_b) {
227 if au_is_idr(au) {
228 flush_gop(&mut gop, &mut out); }
230 if let Some(frame) = self.decode(au)? {
231 gop.push((self.last_poc, frame));
232 }
233 }
234 flush_gop(&mut gop, &mut out);
235 Ok(out)
236 }
237
238 fn decode_slice(
239 &mut self,
240 rbsp: &[u8],
241 is_idr: bool,
242 nal_ref_idc: u8,
243 ) -> Result<Option<YuvFrame>, DecodeError> {
244 let mut r = BitReader::new(rbsp);
245 let first_mb_in_slice = r.read_ue()? as usize;
247 let slice_type = r.read_ue()?;
248 let is_p = matches!(slice_type, 0 | 5);
249 let is_b = matches!(slice_type, 1 | 6);
250 let is_i = matches!(slice_type, 2 | 7);
251 if !is_p && !is_b && !is_i {
252 return Err(DecodeError::Unsupported("SP/SI slices"));
253 }
254 let pic_parameter_set_id = r.read_ue()?;
256 let pps = self.pps.get(&pic_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
257 let sps = self.sps.get(&pps.seq_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
258 let sps = &sps;
259 let pps = &pps;
260 let cabac = pps.entropy_coding_mode_flag;
264 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
265 if is_idr {
266 let _idr_pic_id = r.read_ue()?;
267 }
268 let mut poc_lsb = 0u32;
271 let mut delta_poc_bottom = 0i32;
272 if sps.pic_order_cnt_type == 0 {
273 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
274 if pps.bottom_field_pic_order_present {
275 delta_poc_bottom = r.read_se()?;
276 }
277 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
278 let _delta_pic_order_cnt_0 = r.read_se()?;
279 if pps.bottom_field_pic_order_present {
280 let _delta_pic_order_cnt_1 = r.read_se()?;
281 }
282 }
283 let pic_poc = if first_mb_in_slice == 0 {
286 self.compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_poc_bottom)
287 } else {
288 self.cur.as_ref().map_or(0, |p| p.poc)
289 };
290 if pps.redundant_pic_cnt_present_flag {
295 let redundant_pic_cnt = r.read_ue()?;
296 if redundant_pic_cnt != 0 {
297 return Ok(None);
298 }
299 }
300 let direct_spatial = if is_b { r.read_bit()? } else { true };
302 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
303 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
304 let mut reorder_l0: Vec<(u32, u32)> = Vec::new();
305 let mut reorder_l1: Vec<(u32, u32)> = Vec::new();
306 if is_p || is_b {
307 if r.read_bit()? {
309 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
310 if is_b {
311 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
312 }
313 }
314 if r.read_bit()? {
316 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
317 }
318 if is_b && r.read_bit()? {
319 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
321 }
322 }
323 let weights = if is_p && pps.weighted_pred {
328 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
329 } else if is_b && pps.weighted_bipred_idc == 1 {
330 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
331 } else {
332 None
333 };
334 let mut idr_long_term = false;
338 let mut mmco_ops: Vec<Mmco> = Vec::new();
339 if nal_ref_idc == 0 {
340 } else if is_idr {
342 let _no_output_of_prior_pics = r.read_bit()?;
343 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
345 loop {
347 let op = r.read_ue()?;
348 match op {
349 0 => break,
350 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
351 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
352 3 => {
353 let diff = r.read_ue()?;
354 let idx = r.read_ue()?;
355 mmco_ops.push(Mmco::AssignLong(diff, idx));
356 }
357 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
358 5 => mmco_ops.push(Mmco::Reset),
359 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
360 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
361 }
362 if mmco_ops.len() > 128 {
363 return Err(DecodeError::Truncated);
364 }
365 }
366 }
367 let cabac_init_idc = if cabac && !is_i {
371 let v = r.read_ue()?;
372 if v > 2 {
373 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
374 }
375 v
376 } else {
377 0
378 };
379 let slice_qp_delta = r.read_se()?;
380 let mut deblock = true;
385 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
386 if pps.deblocking_filter_control_present_flag {
387 let disable_deblocking_filter_idc = r.read_ue()?;
388 deblock = disable_deblocking_filter_idc != 1;
391 if disable_deblocking_filter_idc != 1 {
392 filter_offset_a = r.read_se()? * 2;
394 filter_offset_b = r.read_se()? * 2;
395 }
396 }
397 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
398
399 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
402 self.insert_frame_num_gaps(
403 frame_num,
404 1u32 << sps.log2_max_frame_num,
405 sps.max_num_ref_frames.max(1) as usize,
406 sps.pic_width_in_mbs * 16,
407 sps.pic_height_in_mbs * 16,
408 );
409 }
410
411 let max_fn = 1u32 << sps.log2_max_frame_num;
414 let (ref_list0, ref_list1) = if is_b {
415 build_ref_list_b(
416 &self.refs, pic_poc, frame_num, max_fn,
417 num_ref_idx_l0, num_ref_idx_l1, &reorder_l0, &reorder_l1,
418 )?
419 } else if is_p {
420 (build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?, Vec::new())
421 } else {
422 (Vec::new(), Vec::new())
423 };
424 if first_mb_in_slice == 0 {
428 if is_idr {
429 self.refs.clear();
430 }
431 let mut fd = FrameDecoder::new(
432 sps.pic_width_in_mbs,
433 sps.pic_height_in_mbs,
434 slice_qp,
435 pps.chroma_qp_index_offset,
436 ref_list0,
437 num_ref_idx_l0,
438 pps.constrained_intra_pred_flag,
439 pps.transform_8x8_mode_flag,
440 sps.profile_idc != 66, );
442 if is_b {
443 fd.set_b_context(
444 ref_list1,
445 num_ref_idx_l1,
446 direct_spatial,
447 pic_poc,
448 pps.weighted_bipred_idc,
449 sps.direct_8x8_inference,
450 );
451 }
452 if sps.has_scaling || pps.pic_scaling_matrix_present {
453 let (s4, s8) = resolve_scaling(sps, pps);
454 fd.set_scaling(s4, s8);
455 }
456 if let Some(w) = weights {
457 fd.set_weights(w);
458 }
459 self.cur = Some(PendingPic {
460 fd,
461 frame_num,
462 poc: pic_poc,
463 next_mb: 0,
464 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
465 slice_count: 0,
466 deblock,
467 filter_offset_a,
468 filter_offset_b,
469 crop_r: sps.frame_crop_right as usize,
470 crop_b: sps.frame_crop_bottom as usize,
471 max_refs: sps.max_num_ref_frames.max(1) as usize,
472 log2_max_frame_num: sps.log2_max_frame_num,
473 is_reference: nal_ref_idc != 0,
474 idr_long_term,
475 mmco_ops,
476 });
477 } else {
478 let Some(pic) = self.cur.as_mut() else {
480 return Err(DecodeError::Unsupported("slice continues a missing picture"));
481 };
482 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
483 if is_b {
484 pic.fd.set_b_context(
485 ref_list1,
486 num_ref_idx_l1,
487 direct_spatial,
488 pic.poc,
489 pps.weighted_bipred_idc,
490 sps.direct_8x8_inference,
491 );
492 }
493 if sps.has_scaling || pps.pic_scaling_matrix_present {
494 let (s4, s8) = resolve_scaling(sps, pps);
495 pic.fd.set_scaling(s4, s8);
496 }
497 if let Some(w) = weights {
498 pic.fd.set_weights(w);
499 }
500 pic.deblock = deblock;
502 pic.filter_offset_a = filter_offset_a;
503 pic.filter_offset_b = filter_offset_b;
504 pic.idr_long_term |= idr_long_term;
505 pic.mmco_ops.extend(mmco_ops);
506 }
507
508 let pic = self.cur.as_mut().expect("pending picture set above");
509 let first = first_mb_in_slice.min(pic.total_mb);
510 let next = if cabac {
511 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
513 let (data, start) = (r.data(), r.bit_pos() / 8);
514 pic.fd
515 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
516 } else {
517 pic.fd.decode_slice_data(&mut r, is_p, first)
518 }
519 .map_err(|e| match e {
520 mb16::MbError::Truncated => DecodeError::Truncated,
521 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
522 })?;
523 pic.next_mb = next;
524 pic.slice_count += 1;
525
526 if pic.next_mb < pic.total_mb {
527 return Ok(None); }
529
530 let pic = self.cur.take().expect("pending picture");
532 let PendingPic {
533 mut fd,
534 frame_num,
535 poc,
536 deblock,
537 filter_offset_a,
538 filter_offset_b,
539 crop_r,
540 crop_b,
541 max_refs,
542 log2_max_frame_num,
543 is_reference,
544 idr_long_term,
545 mmco_ops,
546 ..
547 } = pic;
548 self.last_poc = poc;
549 if deblock {
550 fd.deblock(filter_offset_a, filter_offset_b);
551 }
552 let reference = if is_reference {
555 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
556 Some(fd.as_reference())
557 } else {
558 None
560 };
561 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
562 if let Some(mut reference) = reference {
563 reference.frame_num = frame_num;
564 reference.poc = poc;
565 if idr_long_term {
566 reference.long_term = true;
567 reference.long_term_idx = 0;
568 }
569 self.prev_ref_frame_num =
571 self.apply_ref_marking(reference, &mmco_ops, frame_num, log2_max_frame_num, max_refs);
572 }
573 Ok(Some(fd.into_frame(crop_r, crop_b)))
574 }
575
576 fn insert_frame_num_gaps(&mut self, frame_num: u32, max_fn: u32, max_refs: usize, w: usize, h: usize) {
582 if max_fn == 0 {
583 return;
584 }
585 let start = (self.prev_ref_frame_num + 1) % max_fn;
586 let gap = (frame_num + max_fn - start) % max_fn;
587 if gap == 0 {
588 return;
589 }
590 let cap = max_refs.max(1);
596 let n = (gap as usize).min(cap);
597 let (cw, ch) = (w, h);
598 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
599 for _ in 0..n {
600 self.refs.insert(
601 0,
602 RefFrame {
603 y: vec![128; cw * ch],
604 u: vec![128; (cw / 2) * (ch / 2)],
605 v: vec![128; (cw / 2) * (ch / 2)],
606 cw,
607 ch,
608 frame_num: expected,
609 poc: 0,
610 mv: Vec::new(),
611 ref_idx: Vec::new(),
612 ref_poc: Vec::new(),
613 w4: 0,
614 long_term: false,
615 long_term_idx: 0,
616 },
617 );
618 self.refs.truncate(cap);
619 expected = (expected + 1) % max_fn;
620 }
621 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
622 }
623
624 pub fn last_poc(&self) -> i32 {
628 self.last_poc
629 }
630
631 fn compute_poc(
635 &mut self,
636 sps: &Sps,
637 is_idr: bool,
638 nal_ref_idc: u8,
639 frame_num: u32,
640 poc_lsb: u32,
641 delta_bottom: i32,
642 ) -> i32 {
643 match sps.pic_order_cnt_type {
644 0 => {
645 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
646 let (prev_msb, prev_lsb) =
647 if is_idr { (0, 0) } else { (self.poc.prev_msb, self.poc.prev_lsb) };
648 let lsb = poc_lsb as i32;
649 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
650 prev_msb + max_lsb
651 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
652 prev_msb - max_lsb
653 } else {
654 prev_msb
655 };
656 let top = msb + lsb;
657 let poc = top.min(top + delta_bottom);
658 if nal_ref_idc != 0 {
659 self.poc.prev_msb = msb;
660 self.poc.prev_lsb = lsb;
661 }
662 poc
663 }
664 2 => {
665 let max_fn = 1i64 << sps.log2_max_frame_num;
666 let offset = if is_idr {
667 0
668 } else if self.poc.prev_frame_num > frame_num {
669 self.poc.prev_frame_num_offset + max_fn
670 } else {
671 self.poc.prev_frame_num_offset
672 };
673 let poc = if is_idr {
674 0
675 } else {
676 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
677 };
678 self.poc.prev_frame_num_offset = offset;
679 self.poc.prev_frame_num = frame_num;
680 poc as i32
681 }
682 _ => {
683 self.poc.prev_frame_num = frame_num;
684 frame_num as i32 * 2
685 }
686 }
687 }
688
689 fn apply_ref_marking(
700 &mut self,
701 mut reference: RefFrame,
702 ops: &[Mmco],
703 frame_num: u32,
704 log2_max_frame_num: u32,
705 max_refs: usize,
706 ) -> u32 {
707 let max = 1i64 << log2_max_frame_num;
708 let curr = frame_num as i64;
709 let pic_num = |rf: &RefFrame| -> i64 {
710 if (rf.frame_num as i64) > curr {
711 rf.frame_num as i64 - max
712 } else {
713 rf.frame_num as i64
714 }
715 };
716
717 if ops.is_empty() {
718 let out_fn = reference.frame_num;
722 self.refs.insert(0, reference);
723 while self.refs.len() > max_refs {
724 match self.refs.iter().rposition(|r| !r.long_term) {
725 Some(pos) => {
726 self.refs.remove(pos);
727 }
728 None => break,
729 }
730 }
731 return out_fn;
732 }
733
734 for &op in ops {
736 match op {
737 Mmco::Unref(diff) => {
738 let target = curr - (diff as i64 + 1);
739 self.refs.retain(|r| r.long_term || pic_num(r) != target);
740 }
741 Mmco::UnrefLong(ltpn) => {
742 self.refs.retain(|r| !(r.long_term && r.long_term_idx == ltpn));
743 }
744 Mmco::AssignLong(diff, idx) => {
745 let target = curr - (diff as i64 + 1);
746 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
747 for r in self.refs.iter_mut() {
748 if !r.long_term && pic_num(r) == target {
749 r.long_term = true;
750 r.long_term_idx = idx;
751 }
752 }
753 }
754 Mmco::MaxLong(max_plus1) => {
755 self.refs.retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
756 }
757 Mmco::Reset => {
758 self.refs.clear();
759 reference.frame_num = 0;
760 }
761 Mmco::CurrentLong(idx) => {
762 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
763 reference.long_term = true;
764 reference.long_term_idx = idx;
765 }
766 }
767 }
768 let out_fn = reference.frame_num;
769 self.refs.insert(0, reference);
770 let cap = max_refs.max(16);
772 if self.refs.len() > cap {
773 self.refs.truncate(cap);
774 }
775 out_fn
776 }
777}
778
779fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
781 gop.sort_by_key(|(poc, _)| *poc);
782 out.extend(gop.drain(..).map(|(_, f)| f));
783}
784
785fn au_is_idr(au: &[u8]) -> bool {
787 split_annex_b(au)
788 .iter()
789 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
790}
791
792fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
796 let mut codes: Vec<(usize, bool)> = Vec::new();
798 let mut i = 0;
799 while i + 3 <= stream.len() {
800 if stream[i] == 0 && stream[i + 1] == 0 && stream[i + 2] == 1 {
801 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
802 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
803 let sc = if i > 0 && stream[i - 1] == 0 { i - 1 } else { i };
805 codes.push((sc, is_vcl));
806 i += 3;
807 } else {
808 i += 1;
809 }
810 }
811 if codes.is_empty() {
812 return vec![stream];
813 }
814 let mut aus = Vec::new();
815 let mut start = codes[0].0;
816 for k in 0..codes.len() {
817 if codes[k].1 {
818 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
819 aus.push(&stream[start..end]);
820 start = end;
821 }
822 }
823 aus
824}
825
826fn parse_pred_weight_table(
829 r: &mut BitReader,
830 num_l0: usize,
831 num_l1: usize,
832 is_b: bool,
833) -> Result<WeightTable, DecodeError> {
834 let luma_log2_denom = r.read_ue()? as i32;
835 let chroma_log2_denom = r.read_ue()? as i32;
836 if !(0..=7).contains(&luma_log2_denom) || !(0..=7).contains(&chroma_log2_denom) {
840 return Err(DecodeError::Unsupported("invalid weight denom"));
841 }
842 let mut wt = WeightTable {
843 luma_log2_denom,
844 chroma_log2_denom,
845 ..Default::default()
846 };
847 let lists: &[(usize, usize)] = if is_b {
848 &[(0, num_l0), (1, num_l1)]
849 } else {
850 &[(0, num_l0)]
851 };
852 for &(list, n) in lists {
853 let mut luma = Vec::with_capacity(n);
854 let mut chroma = Vec::with_capacity(n);
855 for _ in 0..n {
856 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
857 if r.read_bit()? {
858 lw = r.read_se()?;
859 lo = r.read_se()?;
860 }
861 luma.push((lw, lo));
862 let mut ch = [(1 << chroma_log2_denom, 0); 2];
863 if r.read_bit()? {
864 for slot in ch.iter_mut() {
865 *slot = (r.read_se()?, r.read_se()?);
866 }
867 }
868 chroma.push(ch);
869 }
870 wt.luma[list] = luma;
871 wt.chroma[list] = chroma;
872 }
873 Ok(wt)
874}
875
876fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
881 use crate::params::{
882 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
883 };
884 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
885 const ZZ8: [usize; 64] = [
887 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,
888 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
889 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
890 ];
891 let mut z4 = [[16u8; 16]; 6];
894 for i in 0..6 {
895 z4[i] = if pps.pic_scaling_matrix_present {
896 if pps.scaling_present_4x4[i] {
897 pps.scaling_4x4[i]
898 } else {
899 match i {
900 0 if sps.has_scaling => sps.scaling_4x4[0],
901 0 => DEFAULT_4X4_INTRA,
902 3 if sps.has_scaling => sps.scaling_4x4[3],
903 3 => DEFAULT_4X4_INTER,
904 _ => z4[i - 1],
905 }
906 }
907 } else {
908 sps.scaling_4x4[i]
909 };
910 }
911 let mut z8 = [[16u8; 64]; 2];
912 for (i, list) in z8.iter_mut().enumerate() {
913 *list = if pps.pic_scaling_matrix_present {
914 if pps.scaling_present_8x8[i] {
915 pps.scaling_8x8[i]
916 } else if sps.has_scaling {
917 sps.scaling_8x8[i]
918 } else if i == 0 {
919 DEFAULT_8X8_INTRA
920 } else {
921 DEFAULT_8X8_INTER
922 }
923 } else {
924 sps.scaling_8x8[i]
925 };
926 }
927 let mut out4 = [[16i32; 16]; 6];
928 for (li, list) in out4.iter_mut().enumerate() {
929 for k in 0..16 {
930 list[ZZ4[k]] = z4[li][k] as i32;
931 }
932 }
933 let mut out8 = [[16i32; 64]; 2];
934 for (li, list) in out8.iter_mut().enumerate() {
935 for k in 0..64 {
936 list[ZZ8[k]] = z8[li][k] as i32;
937 }
938 }
939 (out4, out8)
940}
941
942fn parse_ref_pic_list_modification(
945 r: &mut BitReader,
946 out: &mut Vec<(u32, u32)>,
947) -> Result<(), DecodeError> {
948 loop {
949 let idc = r.read_ue()?;
950 if idc == 3 {
951 break;
952 }
953 if idc > 3 {
954 return Err(DecodeError::Unsupported("invalid ref_pic_list_modification"));
955 }
956 let val = r.read_ue()?; out.push((idc, val));
958 if out.len() > 64 {
959 return Err(DecodeError::Truncated); }
961 }
962 Ok(())
963}
964
965fn build_ref_list_p(
969 dpb: &[RefFrame],
970 curr_frame_num: u32,
971 max_frame_num: u32,
972 num_active: usize,
973 mods: &[(u32, u32)],
974) -> Result<Vec<RefFrame>, DecodeError> {
975 let curr = curr_frame_num as i64;
976 let max = max_frame_num as i64;
977 let pic_num = |fnum: u32| -> i64 {
978 let f = fnum as i64;
979 if f > curr { f - max } else { f }
980 };
981 let mut init: Vec<RefFrame> = dpb.iter().filter(|r| !r.long_term).cloned().collect();
982 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.frame_num)));
983 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
984 long.sort_by_key(|rf| rf.long_term_idx);
985 init.extend(long);
986 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
987}
988
989#[allow(clippy::too_many_arguments)]
994fn build_ref_list_b(
995 dpb: &[RefFrame],
996 curr_poc: i32,
997 curr_frame_num: u32,
998 max_frame_num: u32,
999 num0: usize,
1000 num1: usize,
1001 mods0: &[(u32, u32)],
1002 mods1: &[(u32, u32)],
1003) -> Result<(Vec<RefFrame>, Vec<RefFrame>), DecodeError> {
1004 let mut less: Vec<RefFrame> =
1005 dpb.iter().filter(|r| !r.long_term && r.poc < curr_poc).cloned().collect();
1006 let mut greater: Vec<RefFrame> =
1007 dpb.iter().filter(|r| !r.long_term && r.poc > curr_poc).cloned().collect();
1008 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
1009 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);
1012
1013 let mut init0 = less.clone();
1014 init0.extend(greater.clone());
1015 init0.extend(long.clone());
1016 let mut init1 = greater;
1017 init1.extend(less);
1018 init1.extend(long);
1019
1020 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
1023 if num1 > 1
1024 && init1.len() > 1
1025 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
1026 && eq_len == num1.min(init1.len())
1027 && eq_len == num0.min(init0.len())
1028 {
1029 init1.swap(0, 1);
1030 }
1031
1032 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
1033 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
1034 Ok((list0, list1))
1035}
1036
1037fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
1039 a.long_term == b.long_term
1040 && if a.long_term { a.long_term_idx == b.long_term_idx } else { a.poc == b.poc }
1041}
1042
1043fn apply_list_modification(
1048 init: Vec<RefFrame>,
1049 curr_frame_num: u32,
1050 max_frame_num: u32,
1051 num_active: usize,
1052 mods: &[(u32, u32)],
1053) -> Result<Vec<RefFrame>, DecodeError> {
1054 if mods.is_empty() {
1055 let mut init = init;
1056 init.truncate(num_active.max(1));
1057 return Ok(init);
1058 }
1059 let curr = curr_frame_num as i64;
1060 let max = max_frame_num as i64;
1061 let mut list = init.clone();
1062 let mut pic_num_pred = curr;
1063 let mut refidx = 0usize;
1064 for &(idc, val) in mods {
1065 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
1066 Box::new(move |r: &RefFrame| r.long_term && r.long_term_idx == val)
1067 } else {
1068 let abs_diff = (val as i64) + 1;
1069 let no_wrap = if idc == 0 {
1070 let x = pic_num_pred - abs_diff;
1071 if x < 0 { x + max } else { x }
1072 } else {
1073 let x = pic_num_pred + abs_diff;
1074 if x >= max { x - max } else { x }
1075 };
1076 pic_num_pred = no_wrap;
1077 let target = if no_wrap > curr { no_wrap - max } else { no_wrap };
1078 Box::new(move |r: &RefFrame| {
1079 let pn = if r.frame_num as i64 > curr {
1080 r.frame_num as i64 - max
1081 } else {
1082 r.frame_num as i64
1083 };
1084 !r.long_term && pn == target
1085 })
1086 };
1087 let found = init.iter().find(|r| matches(r)).cloned();
1088 let Some(found) = found else {
1089 return Err(DecodeError::Truncated); };
1091 if refidx > list.len() {
1092 break;
1093 }
1094 list.insert(refidx, found);
1095 if let Some(dup) = list.iter().enumerate().skip(refidx + 1).find(|(_, r)| matches(r)).map(|(i, _)| i) {
1096 list.remove(dup);
1097 }
1098 refidx += 1;
1099 if refidx >= num_active {
1100 break;
1101 }
1102 }
1103 list.truncate(num_active.max(1));
1104 Ok(list)
1105}
1106
1107#[cfg(test)]
1108mod tests {
1109 use super::*;
1110
1111 fn ref_at(poc: i32, fnum: u32) -> RefFrame {
1112 RefFrame {
1113 y: vec![],
1114 u: vec![],
1115 v: vec![],
1116 cw: 0,
1117 ch: 0,
1118 frame_num: fnum,
1119 poc,
1120 mv: Vec::new(),
1121 ref_idx: Vec::new(),
1122 ref_poc: Vec::new(),
1123 w4: 0,
1124 long_term: false,
1125 long_term_idx: 0,
1126 }
1127 }
1128
1129 #[test]
1130 fn b_ref_lists_ordered_by_poc() {
1131 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
1133 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
1134 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 0, 6, 8]);
1136 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![6, 8, 2, 0]);
1138 }
1139
1140 #[test]
1141 fn b_ref_list1_swap_when_equal() {
1142 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
1145 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
1146 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
1147 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
1148 }
1149
1150 #[test]
1151 fn frame_num_gaps_insert_placeholders() {
1152 let mut d = Decoder::new();
1153 d.prev_ref_frame_num = 2;
1154 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
1156 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
1157 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
1158 assert_eq!(d.prev_ref_frame_num, 4);
1159 assert!(d.refs.iter().all(|r| r.y.iter().all(|&p| p == 128)), "grey fill");
1160 }
1161
1162 #[test]
1163 fn frame_num_gaps_wrap_and_noop() {
1164 let mut d = Decoder::new();
1166 d.prev_ref_frame_num = 14;
1167 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
1168 assert_eq!(d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(), vec![0, 15]);
1169 let mut d = Decoder::new();
1171 d.prev_ref_frame_num = 3;
1172 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
1173 assert!(d.refs.is_empty());
1174 }
1175
1176 #[test]
1177 fn missing_param_sets_errors() {
1178 let mut d = Decoder::new();
1179 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
1182 let err = d.decode(&nal.to_annex_b()).unwrap_err();
1183 assert_eq!(err, DecodeError::MissingParameterSet);
1184 }
1185}