1mod cabac;
10mod cabac_tables;
11mod mb16;
12mod params;
13
14pub use params::{Pps, Sps};
15
16use mb16::{FrameDecoder, WeightTable};
17use rusty_h264_common::bit_reader::OutOfData;
18use rusty_h264_common::nal::{emulation_unprevent, split_annex_b};
19use rusty_h264_common::{BitReader, NalUnitType, YuvFrame};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum DecodeError {
24 Truncated,
26 MissingParameterSet,
28 Unsupported(&'static str),
30}
31
32impl From<OutOfData> for DecodeError {
33 fn from(_: OutOfData) -> Self {
34 DecodeError::Truncated
35 }
36}
37
38impl core::fmt::Display for DecodeError {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 match self {
41 DecodeError::Truncated => f.write_str("bitstream truncated"),
42 DecodeError::MissingParameterSet => f.write_str("slice before SPS/PPS"),
43 DecodeError::Unsupported(s) => write!(f, "unsupported coding tool: {s}"),
44 }
45 }
46}
47
48impl std::error::Error for DecodeError {}
49
50#[derive(Debug, Clone, Default)]
53#[allow(dead_code)]
54pub(crate) struct RefFrame {
55 pub y: Vec<u8>,
56 pub u: Vec<u8>,
57 pub v: Vec<u8>,
58 pub cw: usize,
59 pub ch: usize,
60 pub frame_num: u32,
62 pub poc: i32,
64 pub mv: Vec<(i32, i32)>,
68 pub ref_idx: Vec<i32>,
69 pub ref_poc: Vec<i32>,
73 pub w4: usize,
74 pub long_term: bool,
78 pub long_term_idx: u32,
79}
80
81#[derive(Clone, Copy)]
83enum Mmco {
84 Unref(u32),
86 UnrefLong(u32),
88 AssignLong(u32, u32),
90 MaxLong(u32),
92 Reset,
94 CurrentLong(u32),
96}
97
98struct PendingPic {
102 fd: mb16::FrameDecoder,
103 frame_num: u32,
104 poc: i32,
105 next_mb: usize,
106 total_mb: usize,
107 slice_count: u16,
108 deblock: bool,
109 filter_offset_a: i32,
110 filter_offset_b: i32,
111 crop_r: usize,
112 crop_b: usize,
113 max_refs: usize,
114 log2_max_frame_num: u32,
115 is_reference: bool,
118 idr_long_term: bool,
119 mmco_ops: Vec<Mmco>,
120}
121
122#[derive(Default)]
125pub struct Decoder {
126 sps: std::collections::HashMap<u32, Sps>,
129 pps: std::collections::HashMap<u32, Pps>,
130 refs: Vec<RefFrame>,
132 cur: Option<PendingPic>,
134 poc: PocState,
138 last_poc: i32,
140 prev_ref_frame_num: u32,
143}
144
145#[derive(Default)]
147struct PocState {
148 prev_msb: i32,
149 prev_lsb: i32,
150 prev_frame_num: u32,
151 prev_frame_num_offset: i64,
152}
153
154impl Decoder {
155 pub fn new() -> Self {
157 Self::default()
158 }
159
160 pub fn decode(&mut self, annex_b: &[u8]) -> Result<Option<YuvFrame>, DecodeError> {
163 let mut frame = None;
164 for nal in split_annex_b(annex_b) {
165 if nal.is_empty() {
166 continue;
167 }
168 let nal_type = NalUnitType::from_id(nal[0]);
169 let rbsp = emulation_unprevent(&nal[1..]);
170 match nal_type {
171 NalUnitType::Sps => {
172 let s = Sps::parse(&rbsp)?;
173 self.sps.insert(s.seq_parameter_set_id, s);
174 }
175 NalUnitType::Pps => {
176 let p = Pps::parse(&rbsp)?;
177 self.pps.insert(p.pic_parameter_set_id, p);
178 }
179 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
180 let nal_ref_idc = (nal[0] >> 5) & 3;
181 let is_idr = nal_type == NalUnitType::IdrSlice;
182 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
183 frame = Some(f);
184 }
185 }
186 _ => {} }
188 }
189 Ok(frame)
190 }
191
192 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
200 let mut out = Vec::new();
201 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
202 for au in split_access_units(annex_b) {
203 if au_is_idr(au) {
204 flush_gop(&mut gop, &mut out); }
206 if let Some(frame) = self.decode(au)? {
207 gop.push((self.last_poc, frame));
208 }
209 }
210 flush_gop(&mut gop, &mut out);
211 Ok(out)
212 }
213
214 fn decode_slice(
215 &mut self,
216 rbsp: &[u8],
217 is_idr: bool,
218 nal_ref_idc: u8,
219 ) -> Result<Option<YuvFrame>, DecodeError> {
220 let mut r = BitReader::new(rbsp);
221 let first_mb_in_slice = r.read_ue()? as usize;
223 let slice_type = r.read_ue()?;
224 let is_p = matches!(slice_type, 0 | 5);
225 let is_b = matches!(slice_type, 1 | 6);
226 if !is_p && !is_b && !matches!(slice_type, 2 | 7) {
227 return Err(DecodeError::Unsupported("SP/SI slices"));
228 }
229 let pic_parameter_set_id = r.read_ue()?;
231 let pps = self.pps.get(&pic_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
232 let sps = self.sps.get(&pps.seq_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
233 let sps = &sps;
234 let pps = &pps;
235 if pps.entropy_coding_mode_flag {
236 return Err(DecodeError::Unsupported("CABAC"));
237 }
238 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
239 if is_idr {
240 let _idr_pic_id = r.read_ue()?;
241 }
242 let mut poc_lsb = 0u32;
245 let mut delta_poc_bottom = 0i32;
246 if sps.pic_order_cnt_type == 0 {
247 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
248 if pps.bottom_field_pic_order_present {
249 delta_poc_bottom = r.read_se()?;
250 }
251 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
252 let _delta_pic_order_cnt_0 = r.read_se()?;
253 if pps.bottom_field_pic_order_present {
254 let _delta_pic_order_cnt_1 = r.read_se()?;
255 }
256 }
257 let pic_poc = if first_mb_in_slice == 0 {
260 self.compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_poc_bottom)
261 } else {
262 self.cur.as_ref().map_or(0, |p| p.poc)
263 };
264 if pps.redundant_pic_cnt_present_flag {
269 let redundant_pic_cnt = r.read_ue()?;
270 if redundant_pic_cnt != 0 {
271 return Ok(None);
272 }
273 }
274 let direct_spatial = if is_b { r.read_bit()? } else { true };
276 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
277 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
278 let mut reorder_l0: Vec<(u32, u32)> = Vec::new();
279 let mut reorder_l1: Vec<(u32, u32)> = Vec::new();
280 if is_p || is_b {
281 if r.read_bit()? {
283 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
284 if is_b {
285 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
286 }
287 }
288 if r.read_bit()? {
290 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
291 }
292 if is_b && r.read_bit()? {
293 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
295 }
296 }
297 let weights = if is_p && pps.weighted_pred {
302 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
303 } else if is_b && pps.weighted_bipred_idc == 1 {
304 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
305 } else {
306 None
307 };
308 let mut idr_long_term = false;
312 let mut mmco_ops: Vec<Mmco> = Vec::new();
313 if nal_ref_idc == 0 {
314 } else if is_idr {
316 let _no_output_of_prior_pics = r.read_bit()?;
317 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
319 loop {
321 let op = r.read_ue()?;
322 match op {
323 0 => break,
324 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
325 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
326 3 => {
327 let diff = r.read_ue()?;
328 let idx = r.read_ue()?;
329 mmco_ops.push(Mmco::AssignLong(diff, idx));
330 }
331 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
332 5 => mmco_ops.push(Mmco::Reset),
333 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
334 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
335 }
336 if mmco_ops.len() > 128 {
337 return Err(DecodeError::Truncated);
338 }
339 }
340 }
341 let slice_qp_delta = r.read_se()?;
342 let mut deblock = true;
347 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
348 if pps.deblocking_filter_control_present_flag {
349 let disable_deblocking_filter_idc = r.read_ue()?;
350 deblock = disable_deblocking_filter_idc != 1;
353 if disable_deblocking_filter_idc != 1 {
354 filter_offset_a = r.read_se()? * 2;
356 filter_offset_b = r.read_se()? * 2;
357 }
358 }
359 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
360
361 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
364 self.insert_frame_num_gaps(
365 frame_num,
366 1u32 << sps.log2_max_frame_num,
367 sps.max_num_ref_frames.max(1) as usize,
368 sps.pic_width_in_mbs * 16,
369 sps.pic_height_in_mbs * 16,
370 );
371 }
372
373 let max_fn = 1u32 << sps.log2_max_frame_num;
376 let (ref_list0, ref_list1) = if is_b {
377 build_ref_list_b(
378 &self.refs, pic_poc, frame_num, max_fn,
379 num_ref_idx_l0, num_ref_idx_l1, &reorder_l0, &reorder_l1,
380 )?
381 } else if is_p {
382 (build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?, Vec::new())
383 } else {
384 (Vec::new(), Vec::new())
385 };
386 if first_mb_in_slice == 0 {
390 if is_idr {
391 self.refs.clear();
392 }
393 let mut fd = FrameDecoder::new(
394 sps.pic_width_in_mbs,
395 sps.pic_height_in_mbs,
396 slice_qp,
397 pps.chroma_qp_index_offset,
398 ref_list0,
399 num_ref_idx_l0,
400 pps.constrained_intra_pred_flag,
401 pps.transform_8x8_mode_flag,
402 );
403 if is_b {
404 fd.set_b_context(
405 ref_list1,
406 num_ref_idx_l1,
407 direct_spatial,
408 pic_poc,
409 pps.weighted_bipred_idc,
410 sps.direct_8x8_inference,
411 );
412 }
413 if sps.has_scaling || pps.pic_scaling_matrix_present {
414 let (s4, s8) = resolve_scaling(sps, pps);
415 fd.set_scaling(s4, s8);
416 }
417 if let Some(w) = weights {
418 fd.set_weights(w);
419 }
420 self.cur = Some(PendingPic {
421 fd,
422 frame_num,
423 poc: pic_poc,
424 next_mb: 0,
425 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
426 slice_count: 0,
427 deblock,
428 filter_offset_a,
429 filter_offset_b,
430 crop_r: sps.frame_crop_right as usize,
431 crop_b: sps.frame_crop_bottom as usize,
432 max_refs: sps.max_num_ref_frames.max(1) as usize,
433 log2_max_frame_num: sps.log2_max_frame_num,
434 is_reference: nal_ref_idc != 0,
435 idr_long_term,
436 mmco_ops,
437 });
438 } else {
439 let Some(pic) = self.cur.as_mut() else {
441 return Err(DecodeError::Unsupported("slice continues a missing picture"));
442 };
443 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
444 if is_b {
445 pic.fd.set_b_context(
446 ref_list1,
447 num_ref_idx_l1,
448 direct_spatial,
449 pic.poc,
450 pps.weighted_bipred_idc,
451 sps.direct_8x8_inference,
452 );
453 }
454 if sps.has_scaling || pps.pic_scaling_matrix_present {
455 let (s4, s8) = resolve_scaling(sps, pps);
456 pic.fd.set_scaling(s4, s8);
457 }
458 if let Some(w) = weights {
459 pic.fd.set_weights(w);
460 }
461 pic.deblock = deblock;
463 pic.filter_offset_a = filter_offset_a;
464 pic.filter_offset_b = filter_offset_b;
465 pic.idr_long_term |= idr_long_term;
466 pic.mmco_ops.extend(mmco_ops);
467 }
468
469 let pic = self.cur.as_mut().expect("pending picture set above");
470 let first = first_mb_in_slice.min(pic.total_mb);
471 let next = pic
472 .fd
473 .decode_slice_data(&mut r, is_p, first)
474 .map_err(|e| match e {
475 mb16::MbError::Truncated => DecodeError::Truncated,
476 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
477 })?;
478 pic.next_mb = next;
479 pic.slice_count += 1;
480
481 if pic.next_mb < pic.total_mb {
482 return Ok(None); }
484
485 let pic = self.cur.take().expect("pending picture");
487 let PendingPic {
488 mut fd,
489 frame_num,
490 poc,
491 deblock,
492 filter_offset_a,
493 filter_offset_b,
494 crop_r,
495 crop_b,
496 max_refs,
497 log2_max_frame_num,
498 is_reference,
499 idr_long_term,
500 mmco_ops,
501 ..
502 } = pic;
503 self.last_poc = poc;
504 if deblock {
505 fd.deblock(filter_offset_a, filter_offset_b);
506 }
507 if is_reference {
509 let mut reference = fd.as_reference();
510 reference.frame_num = frame_num;
511 reference.poc = poc;
512 if idr_long_term {
513 reference.long_term = true;
514 reference.long_term_idx = 0;
515 }
516 self.apply_ref_marking(&mut reference, &mmco_ops, frame_num, log2_max_frame_num, max_refs);
517 self.prev_ref_frame_num = reference.frame_num;
519 }
520 Ok(Some(fd.into_frame(crop_r, crop_b)))
521 }
522
523 fn insert_frame_num_gaps(&mut self, frame_num: u32, max_fn: u32, max_refs: usize, w: usize, h: usize) {
529 let mut expected = (self.prev_ref_frame_num + 1) % max_fn;
530 let mut guard = 0;
531 while expected != frame_num && guard < max_fn {
532 let (cw, ch) = (w, h);
533 self.refs.insert(
534 0,
535 RefFrame {
536 y: vec![128; cw * ch],
537 u: vec![128; (cw / 2) * (ch / 2)],
538 v: vec![128; (cw / 2) * (ch / 2)],
539 cw,
540 ch,
541 frame_num: expected,
542 poc: 0,
543 mv: Vec::new(),
544 ref_idx: Vec::new(),
545 ref_poc: Vec::new(),
546 w4: 0,
547 long_term: false,
548 long_term_idx: 0,
549 },
550 );
551 self.refs.truncate(max_refs.max(1));
552 self.prev_ref_frame_num = expected;
553 expected = (expected + 1) % max_fn;
554 guard += 1;
555 }
556 }
557
558 pub fn last_poc(&self) -> i32 {
562 self.last_poc
563 }
564
565 fn compute_poc(
569 &mut self,
570 sps: &Sps,
571 is_idr: bool,
572 nal_ref_idc: u8,
573 frame_num: u32,
574 poc_lsb: u32,
575 delta_bottom: i32,
576 ) -> i32 {
577 match sps.pic_order_cnt_type {
578 0 => {
579 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
580 let (prev_msb, prev_lsb) =
581 if is_idr { (0, 0) } else { (self.poc.prev_msb, self.poc.prev_lsb) };
582 let lsb = poc_lsb as i32;
583 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
584 prev_msb + max_lsb
585 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
586 prev_msb - max_lsb
587 } else {
588 prev_msb
589 };
590 let top = msb + lsb;
591 let poc = top.min(top + delta_bottom);
592 if nal_ref_idc != 0 {
593 self.poc.prev_msb = msb;
594 self.poc.prev_lsb = lsb;
595 }
596 poc
597 }
598 2 => {
599 let max_fn = 1i64 << sps.log2_max_frame_num;
600 let offset = if is_idr {
601 0
602 } else if self.poc.prev_frame_num > frame_num {
603 self.poc.prev_frame_num_offset + max_fn
604 } else {
605 self.poc.prev_frame_num_offset
606 };
607 let poc = if is_idr {
608 0
609 } else {
610 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
611 };
612 self.poc.prev_frame_num_offset = offset;
613 self.poc.prev_frame_num = frame_num;
614 poc as i32
615 }
616 _ => {
617 self.poc.prev_frame_num = frame_num;
618 frame_num as i32 * 2
619 }
620 }
621 }
622
623 fn apply_ref_marking(
628 &mut self,
629 reference: &mut RefFrame,
630 ops: &[Mmco],
631 frame_num: u32,
632 log2_max_frame_num: u32,
633 max_refs: usize,
634 ) {
635 let max = 1i64 << log2_max_frame_num;
636 let curr = frame_num as i64;
637 let pic_num = |rf: &RefFrame| -> i64 {
638 if (rf.frame_num as i64) > curr {
639 rf.frame_num as i64 - max
640 } else {
641 rf.frame_num as i64
642 }
643 };
644
645 if ops.is_empty() {
646 self.refs.insert(0, reference.clone());
650 while self.refs.len() > max_refs {
651 match self.refs.iter().rposition(|r| !r.long_term) {
652 Some(pos) => {
653 self.refs.remove(pos);
654 }
655 None => break,
656 }
657 }
658 return;
659 }
660
661 for &op in ops {
663 match op {
664 Mmco::Unref(diff) => {
665 let target = curr - (diff as i64 + 1);
666 self.refs.retain(|r| r.long_term || pic_num(r) != target);
667 }
668 Mmco::UnrefLong(ltpn) => {
669 self.refs.retain(|r| !(r.long_term && r.long_term_idx == ltpn));
670 }
671 Mmco::AssignLong(diff, idx) => {
672 let target = curr - (diff as i64 + 1);
673 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
674 for r in self.refs.iter_mut() {
675 if !r.long_term && pic_num(r) == target {
676 r.long_term = true;
677 r.long_term_idx = idx;
678 }
679 }
680 }
681 Mmco::MaxLong(max_plus1) => {
682 self.refs.retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
683 }
684 Mmco::Reset => {
685 self.refs.clear();
686 reference.frame_num = 0;
687 }
688 Mmco::CurrentLong(idx) => {
689 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
690 reference.long_term = true;
691 reference.long_term_idx = idx;
692 }
693 }
694 }
695 self.refs.insert(0, reference.clone());
696 let cap = max_refs.max(16);
698 if self.refs.len() > cap {
699 self.refs.truncate(cap);
700 }
701 }
702}
703
704fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
706 gop.sort_by_key(|(poc, _)| *poc);
707 out.extend(gop.drain(..).map(|(_, f)| f));
708}
709
710fn au_is_idr(au: &[u8]) -> bool {
712 split_annex_b(au)
713 .iter()
714 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
715}
716
717fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
721 let mut codes: Vec<(usize, bool)> = Vec::new();
723 let mut i = 0;
724 while i + 3 <= stream.len() {
725 if stream[i] == 0 && stream[i + 1] == 0 && stream[i + 2] == 1 {
726 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
727 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
728 let sc = if i > 0 && stream[i - 1] == 0 { i - 1 } else { i };
730 codes.push((sc, is_vcl));
731 i += 3;
732 } else {
733 i += 1;
734 }
735 }
736 if codes.is_empty() {
737 return vec![stream];
738 }
739 let mut aus = Vec::new();
740 let mut start = codes[0].0;
741 for k in 0..codes.len() {
742 if codes[k].1 {
743 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
744 aus.push(&stream[start..end]);
745 start = end;
746 }
747 }
748 aus
749}
750
751fn parse_pred_weight_table(
754 r: &mut BitReader,
755 num_l0: usize,
756 num_l1: usize,
757 is_b: bool,
758) -> Result<WeightTable, DecodeError> {
759 let luma_log2_denom = r.read_ue()? as i32;
760 let chroma_log2_denom = r.read_ue()? as i32;
761 let mut wt = WeightTable {
762 luma_log2_denom,
763 chroma_log2_denom,
764 ..Default::default()
765 };
766 let lists: &[(usize, usize)] = if is_b {
767 &[(0, num_l0), (1, num_l1)]
768 } else {
769 &[(0, num_l0)]
770 };
771 for &(list, n) in lists {
772 let mut luma = Vec::with_capacity(n);
773 let mut chroma = Vec::with_capacity(n);
774 for _ in 0..n {
775 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
776 if r.read_bit()? {
777 lw = r.read_se()?;
778 lo = r.read_se()?;
779 }
780 luma.push((lw, lo));
781 let mut ch = [(1 << chroma_log2_denom, 0); 2];
782 if r.read_bit()? {
783 for slot in ch.iter_mut() {
784 *slot = (r.read_se()?, r.read_se()?);
785 }
786 }
787 chroma.push(ch);
788 }
789 wt.luma[list] = luma;
790 wt.chroma[list] = chroma;
791 }
792 Ok(wt)
793}
794
795fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
800 use crate::params::{
801 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
802 };
803 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
804 const ZZ8: [usize; 64] = [
806 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,
807 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
808 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
809 ];
810 let mut z4 = [[16u8; 16]; 6];
813 for i in 0..6 {
814 z4[i] = if pps.pic_scaling_matrix_present {
815 if pps.scaling_present_4x4[i] {
816 pps.scaling_4x4[i]
817 } else {
818 match i {
819 0 if sps.has_scaling => sps.scaling_4x4[0],
820 0 => DEFAULT_4X4_INTRA,
821 3 if sps.has_scaling => sps.scaling_4x4[3],
822 3 => DEFAULT_4X4_INTER,
823 _ => z4[i - 1],
824 }
825 }
826 } else {
827 sps.scaling_4x4[i]
828 };
829 }
830 let mut z8 = [[16u8; 64]; 2];
831 for (i, list) in z8.iter_mut().enumerate() {
832 *list = if pps.pic_scaling_matrix_present {
833 if pps.scaling_present_8x8[i] {
834 pps.scaling_8x8[i]
835 } else if sps.has_scaling {
836 sps.scaling_8x8[i]
837 } else if i == 0 {
838 DEFAULT_8X8_INTRA
839 } else {
840 DEFAULT_8X8_INTER
841 }
842 } else {
843 sps.scaling_8x8[i]
844 };
845 }
846 let mut out4 = [[16i32; 16]; 6];
847 for (li, list) in out4.iter_mut().enumerate() {
848 for k in 0..16 {
849 list[ZZ4[k]] = z4[li][k] as i32;
850 }
851 }
852 let mut out8 = [[16i32; 64]; 2];
853 for (li, list) in out8.iter_mut().enumerate() {
854 for k in 0..64 {
855 list[ZZ8[k]] = z8[li][k] as i32;
856 }
857 }
858 (out4, out8)
859}
860
861fn parse_ref_pic_list_modification(
864 r: &mut BitReader,
865 out: &mut Vec<(u32, u32)>,
866) -> Result<(), DecodeError> {
867 loop {
868 let idc = r.read_ue()?;
869 if idc == 3 {
870 break;
871 }
872 if idc > 3 {
873 return Err(DecodeError::Unsupported("invalid ref_pic_list_modification"));
874 }
875 let val = r.read_ue()?; out.push((idc, val));
877 if out.len() > 64 {
878 return Err(DecodeError::Truncated); }
880 }
881 Ok(())
882}
883
884fn build_ref_list_p(
888 dpb: &[RefFrame],
889 curr_frame_num: u32,
890 max_frame_num: u32,
891 num_active: usize,
892 mods: &[(u32, u32)],
893) -> Result<Vec<RefFrame>, DecodeError> {
894 let curr = curr_frame_num as i64;
895 let max = max_frame_num as i64;
896 let pic_num = |fnum: u32| -> i64 {
897 let f = fnum as i64;
898 if f > curr { f - max } else { f }
899 };
900 let mut init: Vec<RefFrame> = dpb.iter().filter(|r| !r.long_term).cloned().collect();
901 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.frame_num)));
902 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
903 long.sort_by_key(|rf| rf.long_term_idx);
904 init.extend(long);
905 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
906}
907
908#[allow(clippy::too_many_arguments)]
913fn build_ref_list_b(
914 dpb: &[RefFrame],
915 curr_poc: i32,
916 curr_frame_num: u32,
917 max_frame_num: u32,
918 num0: usize,
919 num1: usize,
920 mods0: &[(u32, u32)],
921 mods1: &[(u32, u32)],
922) -> Result<(Vec<RefFrame>, Vec<RefFrame>), DecodeError> {
923 let mut less: Vec<RefFrame> =
924 dpb.iter().filter(|r| !r.long_term && r.poc < curr_poc).cloned().collect();
925 let mut greater: Vec<RefFrame> =
926 dpb.iter().filter(|r| !r.long_term && r.poc > curr_poc).cloned().collect();
927 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
928 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);
931
932 let mut init0 = less.clone();
933 init0.extend(greater.clone());
934 init0.extend(long.clone());
935 let mut init1 = greater;
936 init1.extend(less);
937 init1.extend(long);
938
939 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
942 if num1 > 1
943 && init1.len() > 1
944 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
945 && eq_len == num1.min(init1.len())
946 && eq_len == num0.min(init0.len())
947 {
948 init1.swap(0, 1);
949 }
950
951 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
952 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
953 Ok((list0, list1))
954}
955
956fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
958 a.long_term == b.long_term
959 && if a.long_term { a.long_term_idx == b.long_term_idx } else { a.poc == b.poc }
960}
961
962fn apply_list_modification(
967 init: Vec<RefFrame>,
968 curr_frame_num: u32,
969 max_frame_num: u32,
970 num_active: usize,
971 mods: &[(u32, u32)],
972) -> Result<Vec<RefFrame>, DecodeError> {
973 if mods.is_empty() {
974 let mut init = init;
975 init.truncate(num_active.max(1));
976 return Ok(init);
977 }
978 let curr = curr_frame_num as i64;
979 let max = max_frame_num as i64;
980 let mut list = init.clone();
981 let mut pic_num_pred = curr;
982 let mut refidx = 0usize;
983 for &(idc, val) in mods {
984 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
985 Box::new(move |r: &RefFrame| r.long_term && r.long_term_idx == val)
986 } else {
987 let abs_diff = (val as i64) + 1;
988 let no_wrap = if idc == 0 {
989 let x = pic_num_pred - abs_diff;
990 if x < 0 { x + max } else { x }
991 } else {
992 let x = pic_num_pred + abs_diff;
993 if x >= max { x - max } else { x }
994 };
995 pic_num_pred = no_wrap;
996 let target = if no_wrap > curr { no_wrap - max } else { no_wrap };
997 Box::new(move |r: &RefFrame| {
998 let pn = if r.frame_num as i64 > curr {
999 r.frame_num as i64 - max
1000 } else {
1001 r.frame_num as i64
1002 };
1003 !r.long_term && pn == target
1004 })
1005 };
1006 let found = init.iter().find(|r| matches(r)).cloned();
1007 let Some(found) = found else {
1008 return Err(DecodeError::Truncated); };
1010 if refidx > list.len() {
1011 break;
1012 }
1013 list.insert(refidx, found);
1014 if let Some(dup) = list.iter().enumerate().skip(refidx + 1).find(|(_, r)| matches(r)).map(|(i, _)| i) {
1015 list.remove(dup);
1016 }
1017 refidx += 1;
1018 if refidx >= num_active {
1019 break;
1020 }
1021 }
1022 list.truncate(num_active.max(1));
1023 Ok(list)
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 use super::*;
1029
1030 fn ref_at(poc: i32, fnum: u32) -> RefFrame {
1031 RefFrame {
1032 y: vec![],
1033 u: vec![],
1034 v: vec![],
1035 cw: 0,
1036 ch: 0,
1037 frame_num: fnum,
1038 poc,
1039 mv: Vec::new(),
1040 ref_idx: Vec::new(),
1041 ref_poc: Vec::new(),
1042 w4: 0,
1043 long_term: false,
1044 long_term_idx: 0,
1045 }
1046 }
1047
1048 #[test]
1049 fn b_ref_lists_ordered_by_poc() {
1050 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
1052 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
1053 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 0, 6, 8]);
1055 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![6, 8, 2, 0]);
1057 }
1058
1059 #[test]
1060 fn b_ref_list1_swap_when_equal() {
1061 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
1064 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
1065 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
1066 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
1067 }
1068
1069 #[test]
1070 fn frame_num_gaps_insert_placeholders() {
1071 let mut d = Decoder::new();
1072 d.prev_ref_frame_num = 2;
1073 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
1075 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
1076 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
1077 assert_eq!(d.prev_ref_frame_num, 4);
1078 assert!(d.refs.iter().all(|r| r.y.iter().all(|&p| p == 128)), "grey fill");
1079 }
1080
1081 #[test]
1082 fn frame_num_gaps_wrap_and_noop() {
1083 let mut d = Decoder::new();
1085 d.prev_ref_frame_num = 14;
1086 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
1087 assert_eq!(d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(), vec![0, 15]);
1088 let mut d = Decoder::new();
1090 d.prev_ref_frame_num = 3;
1091 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
1092 assert!(d.refs.is_empty());
1093 }
1094
1095 #[test]
1096 fn missing_param_sets_errors() {
1097 let mut d = Decoder::new();
1098 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
1101 let err = d.decode(&nal.to_annex_b()).unwrap_err();
1102 assert_eq!(err, DecodeError::MissingParameterSet);
1103 }
1104}