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 _g = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Total);
164 let mut frame = None;
165 for nal in split_annex_b(annex_b) {
166 if nal.is_empty() {
167 continue;
168 }
169 let nal_type = NalUnitType::from_id(nal[0]);
170 let rbsp = emulation_unprevent(&nal[1..]);
171 match nal_type {
172 NalUnitType::Sps => {
173 let s = Sps::parse(&rbsp)?;
174 self.sps.insert(s.seq_parameter_set_id, s);
175 }
176 NalUnitType::Pps => {
177 let p = Pps::parse(&rbsp)?;
178 self.pps.insert(p.pic_parameter_set_id, p);
179 }
180 NalUnitType::IdrSlice | NalUnitType::NonIdrSlice => {
181 let nal_ref_idc = (nal[0] >> 5) & 3;
182 let is_idr = nal_type == NalUnitType::IdrSlice;
183 if let Some(f) = self.decode_slice(&rbsp, is_idr, nal_ref_idc)? {
184 frame = Some(f);
185 }
186 }
187 _ => {} }
189 }
190 Ok(frame)
191 }
192
193 pub fn decode_stream(&mut self, annex_b: &[u8]) -> Result<Vec<YuvFrame>, DecodeError> {
201 let mut out = Vec::new();
202 let mut gop: Vec<(i32, YuvFrame)> = Vec::new();
203 for au in split_access_units(annex_b) {
204 if au_is_idr(au) {
205 flush_gop(&mut gop, &mut out); }
207 if let Some(frame) = self.decode(au)? {
208 gop.push((self.last_poc, frame));
209 }
210 }
211 flush_gop(&mut gop, &mut out);
212 Ok(out)
213 }
214
215 fn decode_slice(
216 &mut self,
217 rbsp: &[u8],
218 is_idr: bool,
219 nal_ref_idc: u8,
220 ) -> Result<Option<YuvFrame>, DecodeError> {
221 let mut r = BitReader::new(rbsp);
222 let first_mb_in_slice = r.read_ue()? as usize;
224 let slice_type = r.read_ue()?;
225 let is_p = matches!(slice_type, 0 | 5);
226 let is_b = matches!(slice_type, 1 | 6);
227 let is_i = matches!(slice_type, 2 | 7);
228 if !is_p && !is_b && !is_i {
229 return Err(DecodeError::Unsupported("SP/SI slices"));
230 }
231 let pic_parameter_set_id = r.read_ue()?;
233 let pps = self.pps.get(&pic_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
234 let sps = self.sps.get(&pps.seq_parameter_set_id).cloned().ok_or(DecodeError::MissingParameterSet)?;
235 let sps = &sps;
236 let pps = &pps;
237 let cabac = pps.entropy_coding_mode_flag;
241 let frame_num = r.read_bits(sps.log2_max_frame_num)?;
242 if is_idr {
243 let _idr_pic_id = r.read_ue()?;
244 }
245 let mut poc_lsb = 0u32;
248 let mut delta_poc_bottom = 0i32;
249 if sps.pic_order_cnt_type == 0 {
250 poc_lsb = r.read_bits(sps.log2_max_pic_order_cnt_lsb)?;
251 if pps.bottom_field_pic_order_present {
252 delta_poc_bottom = r.read_se()?;
253 }
254 } else if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero {
255 let _delta_pic_order_cnt_0 = r.read_se()?;
256 if pps.bottom_field_pic_order_present {
257 let _delta_pic_order_cnt_1 = r.read_se()?;
258 }
259 }
260 let pic_poc = if first_mb_in_slice == 0 {
263 self.compute_poc(sps, is_idr, nal_ref_idc, frame_num, poc_lsb, delta_poc_bottom)
264 } else {
265 self.cur.as_ref().map_or(0, |p| p.poc)
266 };
267 if pps.redundant_pic_cnt_present_flag {
272 let redundant_pic_cnt = r.read_ue()?;
273 if redundant_pic_cnt != 0 {
274 return Ok(None);
275 }
276 }
277 let direct_spatial = if is_b { r.read_bit()? } else { true };
279 let mut num_ref_idx_l0 = pps.num_ref_idx_l0_default as usize;
280 let mut num_ref_idx_l1 = pps.num_ref_idx_l1_default as usize;
281 let mut reorder_l0: Vec<(u32, u32)> = Vec::new();
282 let mut reorder_l1: Vec<(u32, u32)> = Vec::new();
283 if is_p || is_b {
284 if r.read_bit()? {
286 num_ref_idx_l0 = (r.read_ue()? + 1) as usize;
287 if is_b {
288 num_ref_idx_l1 = (r.read_ue()? + 1) as usize;
289 }
290 }
291 if r.read_bit()? {
293 parse_ref_pic_list_modification(&mut r, &mut reorder_l0)?;
294 }
295 if is_b && r.read_bit()? {
296 parse_ref_pic_list_modification(&mut r, &mut reorder_l1)?;
298 }
299 }
300 let weights = if is_p && pps.weighted_pred {
305 Some(parse_pred_weight_table(&mut r, num_ref_idx_l0, 0, false)?)
306 } else if is_b && pps.weighted_bipred_idc == 1 {
307 return Err(DecodeError::Unsupported("explicit B weighted prediction"));
308 } else {
309 None
310 };
311 let mut idr_long_term = false;
315 let mut mmco_ops: Vec<Mmco> = Vec::new();
316 if nal_ref_idc == 0 {
317 } else if is_idr {
319 let _no_output_of_prior_pics = r.read_bit()?;
320 idr_long_term = r.read_bit()?; } else if r.read_bit()? {
322 loop {
324 let op = r.read_ue()?;
325 match op {
326 0 => break,
327 1 => mmco_ops.push(Mmco::Unref(r.read_ue()?)),
328 2 => mmco_ops.push(Mmco::UnrefLong(r.read_ue()?)),
329 3 => {
330 let diff = r.read_ue()?;
331 let idx = r.read_ue()?;
332 mmco_ops.push(Mmco::AssignLong(diff, idx));
333 }
334 4 => mmco_ops.push(Mmco::MaxLong(r.read_ue()?)),
335 5 => mmco_ops.push(Mmco::Reset),
336 6 => mmco_ops.push(Mmco::CurrentLong(r.read_ue()?)),
337 _ => return Err(DecodeError::Unsupported("invalid MMCO")),
338 }
339 if mmco_ops.len() > 128 {
340 return Err(DecodeError::Truncated);
341 }
342 }
343 }
344 let cabac_init_idc = if cabac && !is_i {
348 let v = r.read_ue()?;
349 if v > 2 {
350 return Err(DecodeError::Unsupported("invalid cabac_init_idc"));
351 }
352 v
353 } else {
354 0
355 };
356 let slice_qp_delta = r.read_se()?;
357 let mut deblock = true;
362 let (mut filter_offset_a, mut filter_offset_b) = (0i32, 0i32);
363 if pps.deblocking_filter_control_present_flag {
364 let disable_deblocking_filter_idc = r.read_ue()?;
365 deblock = disable_deblocking_filter_idc != 1;
368 if disable_deblocking_filter_idc != 1 {
369 filter_offset_a = r.read_se()? * 2;
371 filter_offset_b = r.read_se()? * 2;
372 }
373 }
374 let slice_qp = (pps.pic_init_qp + slice_qp_delta).clamp(0, 51) as u8;
375
376 if first_mb_in_slice == 0 && !is_idr && sps.gaps_in_frame_num_allowed {
379 self.insert_frame_num_gaps(
380 frame_num,
381 1u32 << sps.log2_max_frame_num,
382 sps.max_num_ref_frames.max(1) as usize,
383 sps.pic_width_in_mbs * 16,
384 sps.pic_height_in_mbs * 16,
385 );
386 }
387
388 let max_fn = 1u32 << sps.log2_max_frame_num;
391 let (ref_list0, ref_list1) = if is_b {
392 build_ref_list_b(
393 &self.refs, pic_poc, frame_num, max_fn,
394 num_ref_idx_l0, num_ref_idx_l1, &reorder_l0, &reorder_l1,
395 )?
396 } else if is_p {
397 (build_ref_list_p(&self.refs, frame_num, max_fn, num_ref_idx_l0, &reorder_l0)?, Vec::new())
398 } else {
399 (Vec::new(), Vec::new())
400 };
401 if first_mb_in_slice == 0 {
405 if is_idr {
406 self.refs.clear();
407 }
408 let mut fd = FrameDecoder::new(
409 sps.pic_width_in_mbs,
410 sps.pic_height_in_mbs,
411 slice_qp,
412 pps.chroma_qp_index_offset,
413 ref_list0,
414 num_ref_idx_l0,
415 pps.constrained_intra_pred_flag,
416 pps.transform_8x8_mode_flag,
417 sps.profile_idc != 66, );
419 if is_b {
420 fd.set_b_context(
421 ref_list1,
422 num_ref_idx_l1,
423 direct_spatial,
424 pic_poc,
425 pps.weighted_bipred_idc,
426 sps.direct_8x8_inference,
427 );
428 }
429 if sps.has_scaling || pps.pic_scaling_matrix_present {
430 let (s4, s8) = resolve_scaling(sps, pps);
431 fd.set_scaling(s4, s8);
432 }
433 if let Some(w) = weights {
434 fd.set_weights(w);
435 }
436 self.cur = Some(PendingPic {
437 fd,
438 frame_num,
439 poc: pic_poc,
440 next_mb: 0,
441 total_mb: sps.pic_width_in_mbs * sps.pic_height_in_mbs,
442 slice_count: 0,
443 deblock,
444 filter_offset_a,
445 filter_offset_b,
446 crop_r: sps.frame_crop_right as usize,
447 crop_b: sps.frame_crop_bottom as usize,
448 max_refs: sps.max_num_ref_frames.max(1) as usize,
449 log2_max_frame_num: sps.log2_max_frame_num,
450 is_reference: nal_ref_idc != 0,
451 idr_long_term,
452 mmco_ops,
453 });
454 } else {
455 let Some(pic) = self.cur.as_mut() else {
457 return Err(DecodeError::Unsupported("slice continues a missing picture"));
458 };
459 pic.fd.begin_slice(slice_qp, ref_list0, num_ref_idx_l0);
460 if is_b {
461 pic.fd.set_b_context(
462 ref_list1,
463 num_ref_idx_l1,
464 direct_spatial,
465 pic.poc,
466 pps.weighted_bipred_idc,
467 sps.direct_8x8_inference,
468 );
469 }
470 if sps.has_scaling || pps.pic_scaling_matrix_present {
471 let (s4, s8) = resolve_scaling(sps, pps);
472 pic.fd.set_scaling(s4, s8);
473 }
474 if let Some(w) = weights {
475 pic.fd.set_weights(w);
476 }
477 pic.deblock = deblock;
479 pic.filter_offset_a = filter_offset_a;
480 pic.filter_offset_b = filter_offset_b;
481 pic.idr_long_term |= idr_long_term;
482 pic.mmco_ops.extend(mmco_ops);
483 }
484
485 let pic = self.cur.as_mut().expect("pending picture set above");
486 let first = first_mb_in_slice.min(pic.total_mb);
487 let next = if cabac {
488 r.align_to_byte().map_err(|_| DecodeError::Truncated)?;
490 let (data, start) = (r.data(), r.bit_pos() / 8);
491 pic.fd
492 .decode_slice_data_cabac(data, start, slice_qp, cabac_init_idc, is_i, is_p, first)
493 } else {
494 pic.fd.decode_slice_data(&mut r, is_p, first)
495 }
496 .map_err(|e| match e {
497 mb16::MbError::Truncated => DecodeError::Truncated,
498 mb16::MbError::Unsupported(s) => DecodeError::Unsupported(s),
499 })?;
500 pic.next_mb = next;
501 pic.slice_count += 1;
502
503 if pic.next_mb < pic.total_mb {
504 return Ok(None); }
506
507 let pic = self.cur.take().expect("pending picture");
509 let PendingPic {
510 mut fd,
511 frame_num,
512 poc,
513 deblock,
514 filter_offset_a,
515 filter_offset_b,
516 crop_r,
517 crop_b,
518 max_refs,
519 log2_max_frame_num,
520 is_reference,
521 idr_long_term,
522 mmco_ops,
523 ..
524 } = pic;
525 self.last_poc = poc;
526 if deblock {
527 fd.deblock(filter_offset_a, filter_offset_b);
528 }
529 let reference = if is_reference {
532 let _dg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::DpbClone);
533 Some(fd.as_reference())
534 } else {
535 None
537 };
538 let _fg = rusty_h264_common::prof::scope(rusty_h264_common::prof::Stage::Finalize);
539 if let Some(mut reference) = reference {
540 reference.frame_num = frame_num;
541 reference.poc = poc;
542 if idr_long_term {
543 reference.long_term = true;
544 reference.long_term_idx = 0;
545 }
546 self.prev_ref_frame_num =
548 self.apply_ref_marking(reference, &mmco_ops, frame_num, log2_max_frame_num, max_refs);
549 }
550 Ok(Some(fd.into_frame(crop_r, crop_b)))
551 }
552
553 fn insert_frame_num_gaps(&mut self, frame_num: u32, max_fn: u32, max_refs: usize, w: usize, h: usize) {
559 if max_fn == 0 {
560 return;
561 }
562 let start = (self.prev_ref_frame_num + 1) % max_fn;
563 let gap = (frame_num + max_fn - start) % max_fn;
564 if gap == 0 {
565 return;
566 }
567 let cap = max_refs.max(1);
573 let n = (gap as usize).min(cap);
574 let (cw, ch) = (w, h);
575 let mut expected = (frame_num + max_fn - n as u32) % max_fn;
576 for _ in 0..n {
577 self.refs.insert(
578 0,
579 RefFrame {
580 y: vec![128; cw * ch],
581 u: vec![128; (cw / 2) * (ch / 2)],
582 v: vec![128; (cw / 2) * (ch / 2)],
583 cw,
584 ch,
585 frame_num: expected,
586 poc: 0,
587 mv: Vec::new(),
588 ref_idx: Vec::new(),
589 ref_poc: Vec::new(),
590 w4: 0,
591 long_term: false,
592 long_term_idx: 0,
593 },
594 );
595 self.refs.truncate(cap);
596 expected = (expected + 1) % max_fn;
597 }
598 self.prev_ref_frame_num = (frame_num + max_fn - 1) % max_fn;
599 }
600
601 pub fn last_poc(&self) -> i32 {
605 self.last_poc
606 }
607
608 fn compute_poc(
612 &mut self,
613 sps: &Sps,
614 is_idr: bool,
615 nal_ref_idc: u8,
616 frame_num: u32,
617 poc_lsb: u32,
618 delta_bottom: i32,
619 ) -> i32 {
620 match sps.pic_order_cnt_type {
621 0 => {
622 let max_lsb = 1i32 << sps.log2_max_pic_order_cnt_lsb;
623 let (prev_msb, prev_lsb) =
624 if is_idr { (0, 0) } else { (self.poc.prev_msb, self.poc.prev_lsb) };
625 let lsb = poc_lsb as i32;
626 let msb = if lsb < prev_lsb && prev_lsb - lsb >= max_lsb / 2 {
627 prev_msb + max_lsb
628 } else if lsb > prev_lsb && lsb - prev_lsb > max_lsb / 2 {
629 prev_msb - max_lsb
630 } else {
631 prev_msb
632 };
633 let top = msb + lsb;
634 let poc = top.min(top + delta_bottom);
635 if nal_ref_idc != 0 {
636 self.poc.prev_msb = msb;
637 self.poc.prev_lsb = lsb;
638 }
639 poc
640 }
641 2 => {
642 let max_fn = 1i64 << sps.log2_max_frame_num;
643 let offset = if is_idr {
644 0
645 } else if self.poc.prev_frame_num > frame_num {
646 self.poc.prev_frame_num_offset + max_fn
647 } else {
648 self.poc.prev_frame_num_offset
649 };
650 let poc = if is_idr {
651 0
652 } else {
653 2 * (offset + frame_num as i64) - i64::from(nal_ref_idc == 0)
654 };
655 self.poc.prev_frame_num_offset = offset;
656 self.poc.prev_frame_num = frame_num;
657 poc as i32
658 }
659 _ => {
660 self.poc.prev_frame_num = frame_num;
661 frame_num as i32 * 2
662 }
663 }
664 }
665
666 fn apply_ref_marking(
677 &mut self,
678 mut reference: RefFrame,
679 ops: &[Mmco],
680 frame_num: u32,
681 log2_max_frame_num: u32,
682 max_refs: usize,
683 ) -> u32 {
684 let max = 1i64 << log2_max_frame_num;
685 let curr = frame_num as i64;
686 let pic_num = |rf: &RefFrame| -> i64 {
687 if (rf.frame_num as i64) > curr {
688 rf.frame_num as i64 - max
689 } else {
690 rf.frame_num as i64
691 }
692 };
693
694 if ops.is_empty() {
695 let out_fn = reference.frame_num;
699 self.refs.insert(0, reference);
700 while self.refs.len() > max_refs {
701 match self.refs.iter().rposition(|r| !r.long_term) {
702 Some(pos) => {
703 self.refs.remove(pos);
704 }
705 None => break,
706 }
707 }
708 return out_fn;
709 }
710
711 for &op in ops {
713 match op {
714 Mmco::Unref(diff) => {
715 let target = curr - (diff as i64 + 1);
716 self.refs.retain(|r| r.long_term || pic_num(r) != target);
717 }
718 Mmco::UnrefLong(ltpn) => {
719 self.refs.retain(|r| !(r.long_term && r.long_term_idx == ltpn));
720 }
721 Mmco::AssignLong(diff, idx) => {
722 let target = curr - (diff as i64 + 1);
723 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
724 for r in self.refs.iter_mut() {
725 if !r.long_term && pic_num(r) == target {
726 r.long_term = true;
727 r.long_term_idx = idx;
728 }
729 }
730 }
731 Mmco::MaxLong(max_plus1) => {
732 self.refs.retain(|r| !(r.long_term && r.long_term_idx + 1 > max_plus1));
733 }
734 Mmco::Reset => {
735 self.refs.clear();
736 reference.frame_num = 0;
737 }
738 Mmco::CurrentLong(idx) => {
739 self.refs.retain(|r| !(r.long_term && r.long_term_idx == idx));
740 reference.long_term = true;
741 reference.long_term_idx = idx;
742 }
743 }
744 }
745 let out_fn = reference.frame_num;
746 self.refs.insert(0, reference);
747 let cap = max_refs.max(16);
749 if self.refs.len() > cap {
750 self.refs.truncate(cap);
751 }
752 out_fn
753 }
754}
755
756fn flush_gop(gop: &mut Vec<(i32, YuvFrame)>, out: &mut Vec<YuvFrame>) {
758 gop.sort_by_key(|(poc, _)| *poc);
759 out.extend(gop.drain(..).map(|(_, f)| f));
760}
761
762fn au_is_idr(au: &[u8]) -> bool {
764 split_annex_b(au)
765 .iter()
766 .any(|n| !n.is_empty() && NalUnitType::from_id(n[0]) == NalUnitType::IdrSlice)
767}
768
769fn split_access_units(stream: &[u8]) -> Vec<&[u8]> {
773 let mut codes: Vec<(usize, bool)> = Vec::new();
775 let mut i = 0;
776 while i + 3 <= stream.len() {
777 if stream[i] == 0 && stream[i + 1] == 0 && stream[i + 2] == 1 {
778 let nal_type = NalUnitType::from_id(stream.get(i + 3).copied().unwrap_or(0));
779 let is_vcl = matches!(nal_type, NalUnitType::IdrSlice | NalUnitType::NonIdrSlice);
780 let sc = if i > 0 && stream[i - 1] == 0 { i - 1 } else { i };
782 codes.push((sc, is_vcl));
783 i += 3;
784 } else {
785 i += 1;
786 }
787 }
788 if codes.is_empty() {
789 return vec![stream];
790 }
791 let mut aus = Vec::new();
792 let mut start = codes[0].0;
793 for k in 0..codes.len() {
794 if codes[k].1 {
795 let end = codes.get(k + 1).map_or(stream.len(), |c| c.0);
796 aus.push(&stream[start..end]);
797 start = end;
798 }
799 }
800 aus
801}
802
803fn parse_pred_weight_table(
806 r: &mut BitReader,
807 num_l0: usize,
808 num_l1: usize,
809 is_b: bool,
810) -> Result<WeightTable, DecodeError> {
811 let luma_log2_denom = r.read_ue()? as i32;
812 let chroma_log2_denom = r.read_ue()? as i32;
813 let mut wt = WeightTable {
814 luma_log2_denom,
815 chroma_log2_denom,
816 ..Default::default()
817 };
818 let lists: &[(usize, usize)] = if is_b {
819 &[(0, num_l0), (1, num_l1)]
820 } else {
821 &[(0, num_l0)]
822 };
823 for &(list, n) in lists {
824 let mut luma = Vec::with_capacity(n);
825 let mut chroma = Vec::with_capacity(n);
826 for _ in 0..n {
827 let (mut lw, mut lo) = (1 << luma_log2_denom, 0);
828 if r.read_bit()? {
829 lw = r.read_se()?;
830 lo = r.read_se()?;
831 }
832 luma.push((lw, lo));
833 let mut ch = [(1 << chroma_log2_denom, 0); 2];
834 if r.read_bit()? {
835 for slot in ch.iter_mut() {
836 *slot = (r.read_se()?, r.read_se()?);
837 }
838 }
839 chroma.push(ch);
840 }
841 wt.luma[list] = luma;
842 wt.chroma[list] = chroma;
843 }
844 Ok(wt)
845}
846
847fn resolve_scaling(sps: &Sps, pps: &Pps) -> ([[i32; 16]; 6], [[i32; 64]; 2]) {
852 use crate::params::{
853 DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA,
854 };
855 const ZZ4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
856 const ZZ8: [usize; 64] = [
858 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,
859 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
860 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
861 ];
862 let mut z4 = [[16u8; 16]; 6];
865 for i in 0..6 {
866 z4[i] = if pps.pic_scaling_matrix_present {
867 if pps.scaling_present_4x4[i] {
868 pps.scaling_4x4[i]
869 } else {
870 match i {
871 0 if sps.has_scaling => sps.scaling_4x4[0],
872 0 => DEFAULT_4X4_INTRA,
873 3 if sps.has_scaling => sps.scaling_4x4[3],
874 3 => DEFAULT_4X4_INTER,
875 _ => z4[i - 1],
876 }
877 }
878 } else {
879 sps.scaling_4x4[i]
880 };
881 }
882 let mut z8 = [[16u8; 64]; 2];
883 for (i, list) in z8.iter_mut().enumerate() {
884 *list = if pps.pic_scaling_matrix_present {
885 if pps.scaling_present_8x8[i] {
886 pps.scaling_8x8[i]
887 } else if sps.has_scaling {
888 sps.scaling_8x8[i]
889 } else if i == 0 {
890 DEFAULT_8X8_INTRA
891 } else {
892 DEFAULT_8X8_INTER
893 }
894 } else {
895 sps.scaling_8x8[i]
896 };
897 }
898 let mut out4 = [[16i32; 16]; 6];
899 for (li, list) in out4.iter_mut().enumerate() {
900 for k in 0..16 {
901 list[ZZ4[k]] = z4[li][k] as i32;
902 }
903 }
904 let mut out8 = [[16i32; 64]; 2];
905 for (li, list) in out8.iter_mut().enumerate() {
906 for k in 0..64 {
907 list[ZZ8[k]] = z8[li][k] as i32;
908 }
909 }
910 (out4, out8)
911}
912
913fn parse_ref_pic_list_modification(
916 r: &mut BitReader,
917 out: &mut Vec<(u32, u32)>,
918) -> Result<(), DecodeError> {
919 loop {
920 let idc = r.read_ue()?;
921 if idc == 3 {
922 break;
923 }
924 if idc > 3 {
925 return Err(DecodeError::Unsupported("invalid ref_pic_list_modification"));
926 }
927 let val = r.read_ue()?; out.push((idc, val));
929 if out.len() > 64 {
930 return Err(DecodeError::Truncated); }
932 }
933 Ok(())
934}
935
936fn build_ref_list_p(
940 dpb: &[RefFrame],
941 curr_frame_num: u32,
942 max_frame_num: u32,
943 num_active: usize,
944 mods: &[(u32, u32)],
945) -> Result<Vec<RefFrame>, DecodeError> {
946 let curr = curr_frame_num as i64;
947 let max = max_frame_num as i64;
948 let pic_num = |fnum: u32| -> i64 {
949 let f = fnum as i64;
950 if f > curr { f - max } else { f }
951 };
952 let mut init: Vec<RefFrame> = dpb.iter().filter(|r| !r.long_term).cloned().collect();
953 init.sort_by_key(|rf| core::cmp::Reverse(pic_num(rf.frame_num)));
954 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
955 long.sort_by_key(|rf| rf.long_term_idx);
956 init.extend(long);
957 apply_list_modification(init, curr_frame_num, max_frame_num, num_active, mods)
958}
959
960#[allow(clippy::too_many_arguments)]
965fn build_ref_list_b(
966 dpb: &[RefFrame],
967 curr_poc: i32,
968 curr_frame_num: u32,
969 max_frame_num: u32,
970 num0: usize,
971 num1: usize,
972 mods0: &[(u32, u32)],
973 mods1: &[(u32, u32)],
974) -> Result<(Vec<RefFrame>, Vec<RefFrame>), DecodeError> {
975 let mut less: Vec<RefFrame> =
976 dpb.iter().filter(|r| !r.long_term && r.poc < curr_poc).cloned().collect();
977 let mut greater: Vec<RefFrame> =
978 dpb.iter().filter(|r| !r.long_term && r.poc > curr_poc).cloned().collect();
979 let mut long: Vec<RefFrame> = dpb.iter().filter(|r| r.long_term).cloned().collect();
980 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);
983
984 let mut init0 = less.clone();
985 init0.extend(greater.clone());
986 init0.extend(long.clone());
987 let mut init1 = greater;
988 init1.extend(less);
989 init1.extend(long);
990
991 let eq_len = num0.min(num1).min(init0.len()).min(init1.len());
994 if num1 > 1
995 && init1.len() > 1
996 && (0..eq_len).all(|i| same_picture(&init0[i], &init1[i]))
997 && eq_len == num1.min(init1.len())
998 && eq_len == num0.min(init0.len())
999 {
1000 init1.swap(0, 1);
1001 }
1002
1003 let list0 = apply_list_modification(init0, curr_frame_num, max_frame_num, num0, mods0)?;
1004 let list1 = apply_list_modification(init1, curr_frame_num, max_frame_num, num1, mods1)?;
1005 Ok((list0, list1))
1006}
1007
1008fn same_picture(a: &RefFrame, b: &RefFrame) -> bool {
1010 a.long_term == b.long_term
1011 && if a.long_term { a.long_term_idx == b.long_term_idx } else { a.poc == b.poc }
1012}
1013
1014fn apply_list_modification(
1019 init: Vec<RefFrame>,
1020 curr_frame_num: u32,
1021 max_frame_num: u32,
1022 num_active: usize,
1023 mods: &[(u32, u32)],
1024) -> Result<Vec<RefFrame>, DecodeError> {
1025 if mods.is_empty() {
1026 let mut init = init;
1027 init.truncate(num_active.max(1));
1028 return Ok(init);
1029 }
1030 let curr = curr_frame_num as i64;
1031 let max = max_frame_num as i64;
1032 let mut list = init.clone();
1033 let mut pic_num_pred = curr;
1034 let mut refidx = 0usize;
1035 for &(idc, val) in mods {
1036 let matches: Box<dyn Fn(&RefFrame) -> bool> = if idc == 2 {
1037 Box::new(move |r: &RefFrame| r.long_term && r.long_term_idx == val)
1038 } else {
1039 let abs_diff = (val as i64) + 1;
1040 let no_wrap = if idc == 0 {
1041 let x = pic_num_pred - abs_diff;
1042 if x < 0 { x + max } else { x }
1043 } else {
1044 let x = pic_num_pred + abs_diff;
1045 if x >= max { x - max } else { x }
1046 };
1047 pic_num_pred = no_wrap;
1048 let target = if no_wrap > curr { no_wrap - max } else { no_wrap };
1049 Box::new(move |r: &RefFrame| {
1050 let pn = if r.frame_num as i64 > curr {
1051 r.frame_num as i64 - max
1052 } else {
1053 r.frame_num as i64
1054 };
1055 !r.long_term && pn == target
1056 })
1057 };
1058 let found = init.iter().find(|r| matches(r)).cloned();
1059 let Some(found) = found else {
1060 return Err(DecodeError::Truncated); };
1062 if refidx > list.len() {
1063 break;
1064 }
1065 list.insert(refidx, found);
1066 if let Some(dup) = list.iter().enumerate().skip(refidx + 1).find(|(_, r)| matches(r)).map(|(i, _)| i) {
1067 list.remove(dup);
1068 }
1069 refidx += 1;
1070 if refidx >= num_active {
1071 break;
1072 }
1073 }
1074 list.truncate(num_active.max(1));
1075 Ok(list)
1076}
1077
1078#[cfg(test)]
1079mod tests {
1080 use super::*;
1081
1082 fn ref_at(poc: i32, fnum: u32) -> RefFrame {
1083 RefFrame {
1084 y: vec![],
1085 u: vec![],
1086 v: vec![],
1087 cw: 0,
1088 ch: 0,
1089 frame_num: fnum,
1090 poc,
1091 mv: Vec::new(),
1092 ref_idx: Vec::new(),
1093 ref_poc: Vec::new(),
1094 w4: 0,
1095 long_term: false,
1096 long_term_idx: 0,
1097 }
1098 }
1099
1100 #[test]
1101 fn b_ref_lists_ordered_by_poc() {
1102 let dpb = vec![ref_at(8, 4), ref_at(6, 3), ref_at(2, 1), ref_at(0, 0)];
1104 let (l0, l1) = build_ref_list_b(&dpb, 4, 5, 16, 4, 4, &[], &[]).unwrap();
1105 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 0, 6, 8]);
1107 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![6, 8, 2, 0]);
1109 }
1110
1111 #[test]
1112 fn b_ref_list1_swap_when_equal() {
1113 let dpb = vec![ref_at(4, 2), ref_at(2, 1), ref_at(0, 0)];
1116 let (l0, l1) = build_ref_list_b(&dpb, 6, 3, 16, 3, 3, &[], &[]).unwrap();
1117 assert_eq!(l0.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![4, 2, 0]);
1118 assert_eq!(l1.iter().map(|r| r.poc).collect::<Vec<_>>(), vec![2, 4, 0]);
1119 }
1120
1121 #[test]
1122 fn frame_num_gaps_insert_placeholders() {
1123 let mut d = Decoder::new();
1124 d.prev_ref_frame_num = 2;
1125 d.insert_frame_num_gaps(5, 16, 8, 16, 16);
1127 let fns: Vec<u32> = d.refs.iter().map(|r| r.frame_num).collect();
1128 assert_eq!(fns, vec![4, 3], "most-recent placeholder at the front");
1129 assert_eq!(d.prev_ref_frame_num, 4);
1130 assert!(d.refs.iter().all(|r| r.y.iter().all(|&p| p == 128)), "grey fill");
1131 }
1132
1133 #[test]
1134 fn frame_num_gaps_wrap_and_noop() {
1135 let mut d = Decoder::new();
1137 d.prev_ref_frame_num = 14;
1138 d.insert_frame_num_gaps(1, 16, 8, 16, 16);
1139 assert_eq!(d.refs.iter().map(|r| r.frame_num).collect::<Vec<_>>(), vec![0, 15]);
1140 let mut d = Decoder::new();
1142 d.prev_ref_frame_num = 3;
1143 d.insert_frame_num_gaps(4, 16, 8, 16, 16);
1144 assert!(d.refs.is_empty());
1145 }
1146
1147 #[test]
1148 fn missing_param_sets_errors() {
1149 let mut d = Decoder::new();
1150 let nal = rusty_h264_common::NalUnit::new(3, NalUnitType::IdrSlice, vec![0x88, 0x80]);
1153 let err = d.decode(&nal.to_annex_b()).unwrap_err();
1154 assert_eq!(err, DecodeError::MissingParameterSet);
1155 }
1156}