Skip to main content

vk_video/parser/
reference_manager.rs

1use std::sync::Arc;
2
3use h264_reader::nal::{
4    pps::PicParameterSet,
5    slice::{
6        DecRefPicMarking, MemoryManagementControlOperation, ModificationOfPicNums, NumRefIdxActive,
7        RefPicListModifications, SliceHeader,
8    },
9    sps::SeqParameterSet,
10};
11
12use crate::{parameters::MissedFrameHandling, parser::decoder_instructions::DecoderInstruction};
13
14use super::nalu_parser::{Slice, SpsExt};
15
16#[derive(Debug, thiserror::Error)]
17pub enum ReferenceManagementError {
18    #[error("SI frames are not supported")]
19    SIFramesNotSupported,
20
21    #[error("SP frames are not supported")]
22    SPFramesNotSupported,
23
24    #[error("PicOrderCntType {0} is not supperted")]
25    PicOrderCntTypeNotSupported(u8),
26
27    #[error("The H.264 bytestream is not spec compliant: {0}.")]
28    IncorrectData(String),
29
30    #[error("Missing frame. Decoder is in a corrupted state. Waiting for IDR frame")]
31    MissingFrame,
32}
33
34#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
35pub(crate) struct ReferenceId(usize);
36
37#[derive(Debug, Clone, Copy)]
38enum BFrameReferenceListKind {
39    L0,
40    L1,
41}
42
43#[derive(Debug, Default)]
44#[allow(non_snake_case)]
45pub(crate) struct ReferenceContext {
46    pictures: ReferencePictures,
47    next_reference_id: ReferenceId,
48    prevFrameNum: u16,
49    PrevRefFrameNum: u16,
50    prev_pic_order_cnt_msb: i32,
51    prev_pic_order_cnt_lsb: i32,
52    MaxLongTermFrameIdx: MaxLongTermFrameIdx,
53    prevFrameNumOffset: i64,
54    previous_picture_included_mmco_equal_5: bool,
55    detected_missed_frames: bool,
56    missed_frame_handling: MissedFrameHandling,
57}
58
59#[derive(Debug, Default)]
60enum MaxLongTermFrameIdx {
61    #[default]
62    NoLongTermFrameIndices,
63    Idx(u64),
64}
65
66impl ReferenceContext {
67    pub fn new(missed_frame_handling: MissedFrameHandling) -> Self {
68        Self {
69            missed_frame_handling,
70            ..Default::default()
71        }
72    }
73
74    fn next_reference_id(&mut self) -> ReferenceId {
75        let result = self.next_reference_id;
76        self.next_reference_id = ReferenceId(result.0 + 1);
77        result
78    }
79
80    fn reset_state(&mut self) {
81        *self = Self {
82            pictures: ReferencePictures::default(),
83            next_reference_id: ReferenceId::default(),
84            prevFrameNum: 0,
85            PrevRefFrameNum: 0,
86            prev_pic_order_cnt_msb: 0,
87            prev_pic_order_cnt_lsb: 0,
88            MaxLongTermFrameIdx: MaxLongTermFrameIdx::NoLongTermFrameIndices,
89            prevFrameNumOffset: 0,
90            previous_picture_included_mmco_equal_5: false,
91            detected_missed_frames: false,
92            missed_frame_handling: self.missed_frame_handling,
93        };
94    }
95
96    #[allow(non_snake_case)]
97    fn add_long_term_reference(
98        &mut self,
99        header: Arc<SliceHeader>,
100        LongTermFrameIdx: u64,
101        pic_order_cnt: [i32; 2],
102    ) -> ReferenceId {
103        let id = self.next_reference_id();
104        self.pictures.long_term.push(LongTermReferencePicture {
105            header,
106            id,
107            LongTermFrameIdx,
108            pic_order_cnt,
109        });
110
111        id
112    }
113
114    fn add_short_term_reference(
115        &mut self,
116        header: Arc<SliceHeader>,
117        pic_order_cnt: [i32; 2],
118    ) -> ReferenceId {
119        let id = self.next_reference_id();
120        self.pictures.short_term.push(ShortTermReferencePicture {
121            header,
122            id,
123            pic_order_cnt,
124        });
125        id
126    }
127
128    pub(crate) fn mark_missed_frames(&mut self) {
129        self.detected_missed_frames = true;
130    }
131
132    pub(crate) fn put_picture(
133        &mut self,
134        mut slices: Vec<(Slice, Option<u64>)>,
135    ) -> Result<Vec<DecoderInstruction>, ReferenceManagementError> {
136        let header = slices.last().unwrap().0.header.clone();
137        let sps = slices.last().unwrap().0.sps.clone();
138        let pps = slices.last().unwrap().0.pps.clone();
139        let pts = slices.last().unwrap().1;
140
141        let is_ref_frame = header.dec_ref_pic_marking.is_some();
142        let is_idr = matches!(
143            &header.dec_ref_pic_marking,
144            Some(DecRefPicMarking::Idr { .. })
145        );
146        if is_ref_frame && !is_idr && self.missed_frame_handling == MissedFrameHandling::Strict {
147            self.verify_frame_num(&sps, &header)?;
148        }
149
150        // maybe this should be done in a different place, but if you think about it, there's not
151        // really that many places to put this code in
152        let mut rbsp_bytes = Vec::new();
153        let mut slice_indices = Vec::new();
154        for (slice, _) in &mut slices {
155            if slice.rbsp_bytes.is_empty() {
156                continue;
157            }
158            slice_indices.push(rbsp_bytes.len());
159            rbsp_bytes.append(&mut slice.rbsp_bytes);
160        }
161
162        let decode_info = self.decode_information_for_frame(
163            header.clone(),
164            slice_indices,
165            rbsp_bytes,
166            &sps,
167            &pps,
168            pts,
169        )?;
170
171        let decoder_instructions = match &header.clone().dec_ref_pic_marking {
172            Some(DecRefPicMarking::Idr {
173                long_term_reference_flag,
174                ..
175            }) => self.reference_picture_marking_process_idr(
176                header.clone(),
177                decode_info,
178                *long_term_reference_flag,
179            )?,
180
181            Some(DecRefPicMarking::SlidingWindow) => self
182                .reference_picture_marking_process_sliding_window(
183                    &sps,
184                    header.clone(),
185                    decode_info,
186                )?,
187            Some(DecRefPicMarking::Adaptive(memory_management_control_operations)) => self
188                .reference_picture_marking_process_adaptive(
189                    &sps,
190                    header.clone(),
191                    decode_info,
192                    memory_management_control_operations,
193                )?,
194
195            // this picture is not a reference
196            None => {
197                let reference_id = self.next_reference_id();
198                vec![
199                    DecoderInstruction::Decode {
200                        decode_info,
201                        reference_id,
202                    },
203                    DecoderInstruction::Drop {
204                        reference_ids: vec![reference_id],
205                    },
206                ]
207            }
208        };
209
210        self.previous_picture_included_mmco_equal_5 = header.includes_mmco_equal_5();
211        self.prevFrameNum = header.frame_num;
212        if is_ref_frame {
213            self.PrevRefFrameNum = header.frame_num;
214        }
215
216        Ok(decoder_instructions)
217    }
218
219    fn remove_long_term_ref(
220        &mut self,
221        long_term_frame_idx: u64,
222    ) -> Result<LongTermReferencePicture, ReferenceManagementError> {
223        for (i, frame) in self.pictures.long_term.iter().enumerate() {
224            if frame.LongTermFrameIdx == long_term_frame_idx {
225                return Ok(self.pictures.long_term.remove(i));
226            }
227        }
228
229        Err(ReferenceManagementError::IncorrectData(format!(
230            "cannot remove long term reference with id {long_term_frame_idx}, because it does not exist"
231        )))
232    }
233
234    #[allow(non_snake_case)]
235    fn remove_short_term_ref(
236        &mut self,
237        current_frame_num: i64,
238        sps: &SeqParameterSet,
239        pic_num_to_remove: i64,
240    ) -> Result<ShortTermReferencePicture, ReferenceManagementError> {
241        for (i, picture) in self.pictures.short_term.iter().enumerate() {
242            let PicNum = decode_picture_numbers_for_short_term_ref(
243                picture.header.frame_num.into(),
244                current_frame_num,
245                sps,
246            )
247            .PicNum;
248
249            if PicNum == pic_num_to_remove {
250                return Ok(self.pictures.short_term.remove(i));
251            }
252        }
253
254        Err(ReferenceManagementError::IncorrectData(format!(
255            "cannot remove short term reference with pic num {pic_num_to_remove}, because it does not exist"
256        )))
257    }
258
259    fn reference_picture_marking_process_adaptive(
260        &mut self,
261        sps: &SeqParameterSet,
262        header: Arc<SliceHeader>,
263        decode_info: DecodeInformation,
264        memory_management_control_operations: &[MemoryManagementControlOperation],
265    ) -> Result<Vec<DecoderInstruction>, ReferenceManagementError> {
266        let mut decoder_instructions = Vec::new();
267
268        let mut new_long_term_frame_idx = None;
269
270        for memory_management_control_operation in memory_management_control_operations {
271            match memory_management_control_operation {
272                MemoryManagementControlOperation::ShortTermUnusedForRef {
273                    difference_of_pic_nums_minus1,
274                } => {
275                    let pic_num_to_remove =
276                        header.frame_num as i64 - (*difference_of_pic_nums_minus1 as i64 + 1);
277
278                    let removed = self.remove_short_term_ref(
279                        header.frame_num.into(),
280                        sps,
281                        pic_num_to_remove,
282                    )?;
283
284                    decoder_instructions.push(DecoderInstruction::Drop {
285                        reference_ids: vec![removed.id],
286                    });
287                }
288
289                MemoryManagementControlOperation::LongTermUnusedForRef { long_term_pic_num } => {
290                    let removed = self.remove_long_term_ref(*long_term_pic_num as u64)?;
291
292                    decoder_instructions.push(DecoderInstruction::Drop {
293                        reference_ids: vec![removed.id],
294                    });
295                }
296
297                MemoryManagementControlOperation::ShortTermUsedForLongTerm {
298                    difference_of_pic_nums_minus1,
299                    long_term_frame_idx,
300                } => {
301                    if let Ok(removed) = self.remove_long_term_ref(*long_term_frame_idx as u64) {
302                        decoder_instructions.push(DecoderInstruction::Drop {
303                            reference_ids: vec![removed.id],
304                        });
305                    }
306
307                    let pic_num_to_remove =
308                        header.frame_num as i64 - (*difference_of_pic_nums_minus1 as i64 + 1);
309
310                    let picture = self.remove_short_term_ref(
311                        header.frame_num.into(),
312                        sps,
313                        pic_num_to_remove,
314                    )?;
315
316                    self.pictures.long_term.push(LongTermReferencePicture {
317                        header: picture.header,
318                        LongTermFrameIdx: *long_term_frame_idx as u64,
319                        pic_order_cnt: picture.pic_order_cnt,
320                        id: picture.id,
321                    });
322                }
323
324                MemoryManagementControlOperation::MaxUsedLongTermFrameRef {
325                    max_long_term_frame_idx_plus1,
326                } => {
327                    if *max_long_term_frame_idx_plus1 != 0 {
328                        self.MaxLongTermFrameIdx =
329                            MaxLongTermFrameIdx::Idx(*max_long_term_frame_idx_plus1 as u64 - 1);
330                    } else {
331                        self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices;
332                    }
333
334                    let max_idx = *max_long_term_frame_idx_plus1 as i128 - 1;
335
336                    let reference_ids_to_remove = self
337                        .pictures
338                        .long_term
339                        .iter()
340                        .filter(|p| p.LongTermFrameIdx as i128 > max_idx)
341                        .map(|p| p.id)
342                        .collect();
343
344                    self.pictures.long_term = self
345                        .pictures
346                        .long_term
347                        .iter()
348                        .filter(|p| p.LongTermFrameIdx as i128 <= max_idx)
349                        .cloned()
350                        .collect();
351
352                    decoder_instructions.push(DecoderInstruction::Drop {
353                        reference_ids: reference_ids_to_remove,
354                    })
355                }
356
357                MemoryManagementControlOperation::AllRefPicturesUnused => {
358                    let reference_ids = self
359                        .pictures
360                        .short_term
361                        .drain(..)
362                        .map(|p| p.id)
363                        .chain(self.pictures.long_term.drain(..).map(|p| p.id))
364                        .collect();
365
366                    self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices;
367
368                    decoder_instructions.push(DecoderInstruction::Drop { reference_ids })
369                }
370                MemoryManagementControlOperation::CurrentUsedForLongTerm {
371                    long_term_frame_idx,
372                } => {
373                    if let Ok(picture) = self.remove_long_term_ref(*long_term_frame_idx as u64) {
374                        decoder_instructions.push(DecoderInstruction::Drop {
375                            reference_ids: vec![picture.id],
376                        });
377                    }
378
379                    new_long_term_frame_idx = Some(*long_term_frame_idx as u64);
380                }
381            }
382        }
383
384        let reference_id = match new_long_term_frame_idx {
385            Some(long_term_frame_idx) => self.add_long_term_reference(
386                header,
387                long_term_frame_idx,
388                decode_info.picture_info.PicOrderCnt_as_reference_pic,
389            ),
390            None => self.add_short_term_reference(
391                header,
392                decode_info.picture_info.PicOrderCnt_as_reference_pic,
393            ),
394        };
395
396        decoder_instructions.insert(
397            0,
398            DecoderInstruction::Decode {
399                decode_info,
400                reference_id,
401            },
402        );
403
404        if let MaxLongTermFrameIdx::Idx(max) = self.MaxLongTermFrameIdx {
405            if self.pictures.long_term.len() > max as usize + 1 {
406                return Err(ReferenceManagementError::IncorrectData(format!(
407                    "there are {} long-term references, but there shouldn't be more than {max}",
408                    self.pictures.long_term.len()
409                )));
410            }
411        }
412
413        Ok(decoder_instructions)
414    }
415
416    fn reference_picture_marking_process_sliding_window(
417        &mut self,
418        sps: &SeqParameterSet,
419        header: Arc<SliceHeader>,
420        decode_info: DecodeInformation,
421    ) -> Result<Vec<DecoderInstruction>, ReferenceManagementError> {
422        let num_short_term = self.pictures.short_term.len();
423        let num_long_term = self.pictures.long_term.len();
424
425        let reference_id = self.add_short_term_reference(
426            header.clone(),
427            decode_info.picture_info.PicOrderCnt_as_reference_pic,
428        );
429
430        let mut decoder_instructions = vec![DecoderInstruction::Decode {
431            decode_info,
432            reference_id,
433        }];
434
435        if num_short_term + num_long_term == sps.max_num_ref_frames.max(1) as usize
436            && !self.pictures.short_term.is_empty()
437        {
438            let (idx, _) = self
439                .pictures
440                .short_term
441                .iter()
442                .enumerate()
443                .min_by_key(|(_, reference)| {
444                    decode_picture_numbers_for_short_term_ref(
445                        reference.header.frame_num.into(),
446                        header.frame_num.into(),
447                        sps,
448                    )
449                    .FrameNumWrap
450                })
451                .unwrap();
452
453            decoder_instructions.push(DecoderInstruction::Drop {
454                reference_ids: vec![self.pictures.short_term.remove(idx).id],
455            })
456        }
457
458        Ok(decoder_instructions)
459    }
460
461    fn reference_picture_marking_process_idr(
462        &mut self,
463        header: Arc<SliceHeader>,
464        decode_info: DecodeInformation,
465        long_term_reference_flag: bool,
466    ) -> Result<Vec<DecoderInstruction>, ReferenceManagementError> {
467        self.reset_state();
468
469        let reference_id = if long_term_reference_flag {
470            self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::Idx(0);
471            self.add_long_term_reference(
472                header,
473                0,
474                decode_info.picture_info.PicOrderCnt_as_reference_pic,
475            )
476        } else {
477            self.MaxLongTermFrameIdx = MaxLongTermFrameIdx::NoLongTermFrameIndices;
478            self.add_short_term_reference(
479                header,
480                decode_info.picture_info.PicOrderCnt_as_reference_pic,
481            )
482        };
483
484        Ok(vec![DecoderInstruction::Idr {
485            decode_info,
486            reference_id,
487        }])
488    }
489
490    #[allow(non_snake_case)]
491    fn decode_information_for_frame(
492        &mut self,
493        header: Arc<SliceHeader>,
494        slice_indices: Vec<usize>,
495        rbsp_bytes: Vec<u8>,
496        sps: &SeqParameterSet,
497        pps: &PicParameterSet,
498        pts: Option<u64>,
499    ) -> Result<DecodeInformation, ReferenceManagementError> {
500        let PicOrderCnt_for_decoding = self.decode_pic_order_cnt(&header, sps)?;
501        let PicOrderCnt_as_reference_pic = if header.includes_mmco_equal_5() {
502            [0, 0]
503        } else {
504            PicOrderCnt_for_decoding
505        };
506
507        let (reference_list_l0, reference_list_l1) = match header.slice_type.family {
508            h264_reader::nal::slice::SliceFamily::P => {
509                let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps);
510
511                let mut reference_list_l0 =
512                    self.initialize_reference_picture_list_for_p_frame(&header, sps)?;
513
514                match &header.ref_pic_list_modification {
515                    Some(RefPicListModifications::P {
516                        ref_pic_list_modification_l0,
517                    }) => {
518                        self.modify_reference_picture_list(
519                            sps,
520                            &header,
521                            &mut reference_list_l0,
522                            ref_pic_list_modification_l0,
523                        )?;
524                    }
525
526                    None
527                    | Some(RefPicListModifications::I)
528                    | Some(RefPicListModifications::B { .. }) => return Err(ReferenceManagementError::IncorrectData(
529                        "a slice marked 'P' slice family contains a reference picture list for a different family".into()
530                    ))?,
531                }
532
533                reference_list_l0.truncate(num_ref_idx_l0_active as usize);
534
535                (Some(reference_list_l0), None)
536            }
537            h264_reader::nal::slice::SliceFamily::I => (None, None),
538            h264_reader::nal::slice::SliceFamily::B => {
539                let num_ref_idx_l0_active = header.num_ref_idx_l0_active(pps);
540                let num_ref_idx_l1_active = header.num_ref_idx_l1_active(pps)?;
541
542                let mut reference_list_l0 = self.initialize_reference_picture_list_for_b_frame(
543                    PicOrderCnt_for_decoding,
544                    BFrameReferenceListKind::L0,
545                )?;
546                let mut reference_list_l1 = self.initialize_reference_picture_list_for_b_frame(
547                    PicOrderCnt_for_decoding,
548                    BFrameReferenceListKind::L1,
549                )?;
550
551                match &header.ref_pic_list_modification {
552                    Some(RefPicListModifications::B {
553                        ref_pic_list_modification_l0,
554                        ref_pic_list_modification_l1,
555                    }) => {
556                        self.modify_reference_picture_list(
557                            sps,
558                            &header,
559                            &mut reference_list_l0,
560                            ref_pic_list_modification_l0,
561                        )?;
562
563                        self.modify_reference_picture_list(
564                            sps,
565                            &header,
566                            &mut reference_list_l1,
567                            ref_pic_list_modification_l1
568                        )?;
569                    }
570
571                    None
572                    | Some(RefPicListModifications::I)
573                    | Some(RefPicListModifications::P { .. }) => return Err(ReferenceManagementError::IncorrectData(
574                        "a slice marked 'B' slice family contains a reference picture list for a different family".into()
575                    ))?,
576                }
577
578                reference_list_l0.truncate(num_ref_idx_l0_active as usize);
579                reference_list_l1.truncate(num_ref_idx_l1_active as usize);
580
581                (Some(reference_list_l0), Some(reference_list_l1))
582            }
583            h264_reader::nal::slice::SliceFamily::SP => {
584                return Err(ReferenceManagementError::SPFramesNotSupported);
585            }
586            h264_reader::nal::slice::SliceFamily::SI => {
587                return Err(ReferenceManagementError::SIFramesNotSupported);
588            }
589        };
590
591        Ok(DecodeInformation {
592            reference_list_l0,
593            reference_list_l1,
594            header: header.clone(),
595            slice_indices,
596            rbsp_bytes,
597            sps_id: sps.id().id(),
598            pps_id: pps.pic_parameter_set_id.id(),
599            picture_info: PictureInfo {
600                non_existing: false,
601                used_for_long_term_reference: false,
602                PicOrderCnt_for_decoding,
603                PicOrderCnt_as_reference_pic,
604                FrameNum: header.frame_num,
605            },
606            pts,
607        })
608    }
609
610    fn decode_pic_order_cnt(
611        &mut self,
612        header: &SliceHeader,
613        sps: &SeqParameterSet,
614    ) -> Result<[i32; 2], ReferenceManagementError> {
615        match sps.pic_order_cnt {
616            h264_reader::nal::sps::PicOrderCntType::TypeZero {
617                log2_max_pic_order_cnt_lsb_minus4,
618            } => self.decode_pic_order_cnt_type_zero(header, log2_max_pic_order_cnt_lsb_minus4),
619
620            h264_reader::nal::sps::PicOrderCntType::TypeOne { .. } => {
621                Err(ReferenceManagementError::PicOrderCntTypeNotSupported(1))
622            }
623
624            h264_reader::nal::sps::PicOrderCntType::TypeTwo => {
625                self.decode_pic_order_cnt_type_two(header, sps)
626            }
627        }
628    }
629
630    #[allow(non_snake_case)]
631    fn decode_pic_order_cnt_type_two(
632        &mut self,
633        header: &SliceHeader,
634        sps: &SeqParameterSet,
635    ) -> Result<[i32; 2], ReferenceManagementError> {
636        let FrameNumOffset = if header.idr_pic_id.is_some() {
637            0
638        } else {
639            let prevFrameNumOffset = if self.previous_picture_included_mmco_equal_5 {
640                0
641            } else {
642                self.prevFrameNumOffset
643            };
644
645            if self.prevFrameNum > header.frame_num {
646                prevFrameNumOffset + sps.max_frame_num()
647            } else {
648                prevFrameNumOffset
649            }
650        };
651
652        let tempPicOrderCnt = if header.idr_pic_id.is_some() {
653            0
654        } else if header.dec_ref_pic_marking.is_none() {
655            2 * (FrameNumOffset as i32 + header.frame_num as i32) - 1
656        } else {
657            2 * (FrameNumOffset as i32 + header.frame_num as i32)
658        };
659
660        self.prevFrameNumOffset = FrameNumOffset;
661
662        Ok([tempPicOrderCnt; 2])
663    }
664
665    fn decode_pic_order_cnt_type_zero(
666        &mut self,
667        header: &SliceHeader,
668        log2_max_pic_order_cnt_lsb_minus4: u8,
669    ) -> Result<[i32; 2], ReferenceManagementError> {
670        // this section is very hard to read, but all of this code is just copied from the
671        // h.264 spec, where it looks almost exactly like this
672
673        let max_pic_order_cnt_lsb = 2_i32.pow(log2_max_pic_order_cnt_lsb_minus4 as u32 + 4);
674
675        let (prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb) = if header.idr_pic_id.is_some() {
676            (0, 0)
677        } else {
678            (self.prev_pic_order_cnt_msb, self.prev_pic_order_cnt_lsb)
679        };
680
681        let (pic_order_cnt_lsb, delta_pic_order_cnt_bottom) = match header
682                    .pic_order_cnt_lsb
683                    .as_ref()
684                    .ok_or(ReferenceManagementError::IncorrectData("pic_order_cnt_lsb is not present in a slice header, but is required for decoding".into()))?
685                {
686                    h264_reader::nal::slice::PicOrderCountLsb::Frame(pic_order_cnt_lsb) => {
687                        (*pic_order_cnt_lsb, 0)
688                    }
689                    h264_reader::nal::slice::PicOrderCountLsb::FieldsAbsolute {
690                        pic_order_cnt_lsb,
691                        delta_pic_order_cnt_bottom,
692                    } => (*pic_order_cnt_lsb, *delta_pic_order_cnt_bottom),
693                    h264_reader::nal::slice::PicOrderCountLsb::FieldsDelta(_) => {
694                        Err(ReferenceManagementError::IncorrectData("pic_order_cnt_lsb is not present in a slice header, but is required for decoding".into()))?
695                    }
696                };
697
698        let pic_order_cnt_lsb = pic_order_cnt_lsb as i32;
699
700        let pic_order_cnt_msb = if pic_order_cnt_lsb < prev_pic_order_cnt_lsb
701            && prev_pic_order_cnt_lsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2
702        {
703            prev_pic_order_cnt_msb + max_pic_order_cnt_lsb
704        } else if pic_order_cnt_lsb > prev_pic_order_cnt_lsb
705            && pic_order_cnt_lsb - prev_pic_order_cnt_lsb > max_pic_order_cnt_lsb / 2
706        {
707            prev_pic_order_cnt_msb - max_pic_order_cnt_lsb
708        } else {
709            prev_pic_order_cnt_msb
710        };
711
712        let pic_order_cnt = if header.field_pic == h264_reader::nal::slice::FieldPic::Frame {
713            let top_field_order_cnt = pic_order_cnt_msb + pic_order_cnt_lsb;
714
715            let bottom_field_order_cnt = top_field_order_cnt + delta_pic_order_cnt_bottom;
716
717            top_field_order_cnt.min(bottom_field_order_cnt)
718        } else {
719            pic_order_cnt_msb + pic_order_cnt_lsb
720        };
721
722        self.prev_pic_order_cnt_msb = pic_order_cnt_msb;
723        self.prev_pic_order_cnt_lsb = pic_order_cnt_lsb;
724
725        Ok([pic_order_cnt; 2])
726    }
727
728    fn initialize_short_term_reference_picture_list_for_p_frame(
729        &self,
730        header: &SliceHeader,
731        sps: &SeqParameterSet,
732    ) -> Vec<ReferencePictureInfo> {
733        let mut short_term_reference_list = self
734            .pictures
735            .short_term
736            .iter()
737            .map(|reference| {
738                (
739                    reference,
740                    decode_picture_numbers_for_short_term_ref(
741                        reference.header.frame_num.into(),
742                        header.frame_num.into(),
743                        sps,
744                    ),
745                )
746            })
747            .collect::<Vec<_>>();
748
749        short_term_reference_list.sort_by_key(|(_, numbers)| -numbers.PicNum);
750
751        short_term_reference_list
752            .into_iter()
753            .map(|(reference, numbers)| ReferencePictureInfo {
754                id: reference.id,
755                LongTermPicNum: None,
756                FrameNum: numbers.FrameNum as u16,
757                non_existing: false,
758                PicOrderCnt: reference.pic_order_cnt,
759            })
760            .collect()
761    }
762
763    fn initialize_long_term_reference_picture_list_for_frame(&self) -> Vec<ReferencePictureInfo> {
764        let mut long_term_reference_list = self.pictures.long_term.clone();
765
766        long_term_reference_list.sort_by_key(|pic| pic.LongTermFrameIdx);
767
768        long_term_reference_list
769            .into_iter()
770            .map(|pic| ReferencePictureInfo {
771                id: pic.id,
772                LongTermPicNum: Some(pic.LongTermFrameIdx),
773                PicOrderCnt: pic.pic_order_cnt,
774                non_existing: false,
775                FrameNum: pic.header.frame_num,
776            })
777            .collect()
778    }
779
780    fn initialize_reference_picture_list_for_p_frame(
781        &self,
782        header: &SliceHeader,
783        sps: &SeqParameterSet,
784    ) -> Result<Vec<ReferencePictureInfo>, ReferenceManagementError> {
785        let short_term_reference_list =
786            self.initialize_short_term_reference_picture_list_for_p_frame(header, sps);
787
788        let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame();
789
790        let reference_list = short_term_reference_list
791            .into_iter()
792            .chain(long_term_reference_list)
793            .collect::<Vec<_>>();
794
795        Ok(reference_list)
796    }
797
798    #[allow(non_snake_case)]
799    fn initialize_reference_picture_list_for_b_frame(
800        &self,
801        CurrPicOrderCnt: [i32; 2],
802        list_kind: BFrameReferenceListKind,
803    ) -> Result<Vec<ReferencePictureInfo>, ReferenceManagementError> {
804        let short_term_reference_list = self
805            .initialize_short_term_reference_picture_list_for_b_frame(CurrPicOrderCnt, list_kind)?;
806
807        let long_term_reference_list = self.initialize_long_term_reference_picture_list_for_frame();
808
809        let reference_list = short_term_reference_list
810            .into_iter()
811            .chain(long_term_reference_list)
812            .collect();
813
814        Ok(reference_list)
815    }
816
817    fn verify_frame_num(
818        &mut self,
819        sps: &SeqParameterSet,
820        header: &SliceHeader,
821    ) -> Result<(), ReferenceManagementError> {
822        let is_expected_frame_num = !sps.gaps_in_frame_num_value_allowed_flag
823            && header.frame_num != self.PrevRefFrameNum
824            && header.frame_num != ((self.PrevRefFrameNum as i64 + 1) % sps.max_frame_num()) as u16;
825        if is_expected_frame_num || self.detected_missed_frames {
826            self.detected_missed_frames = true;
827            return Err(ReferenceManagementError::MissingFrame);
828        }
829
830        Ok(())
831    }
832
833    #[allow(non_snake_case)]
834    fn initialize_short_term_reference_picture_list_for_b_frame(
835        &self,
836        CurrPicOrderCnt: [i32; 2],
837        list_kind: BFrameReferenceListKind,
838    ) -> Result<Vec<ReferencePictureInfo>, ReferenceManagementError> {
839        let mut reference_list = self
840            .pictures
841            .short_term
842            .iter()
843            .filter(|pic| match list_kind {
844                BFrameReferenceListKind::L0 => pic.pic_order_cnt < CurrPicOrderCnt,
845                BFrameReferenceListKind::L1 => pic.pic_order_cnt > CurrPicOrderCnt,
846            })
847            .collect::<Vec<_>>();
848
849        reference_list.sort_by_key(|pic| match list_kind {
850            BFrameReferenceListKind::L0 => -pic.pic_order_cnt[0],
851            BFrameReferenceListKind::L1 => pic.pic_order_cnt[0],
852        });
853
854        let reference_list = reference_list
855            .into_iter()
856            .map(|pic| ReferencePictureInfo {
857                LongTermPicNum: None,
858                FrameNum: pic.header.frame_num,
859                non_existing: false,
860                PicOrderCnt: pic.pic_order_cnt,
861                id: pic.id,
862            })
863            .collect();
864
865        Ok(reference_list)
866    }
867
868    #[allow(non_snake_case)]
869    fn modify_reference_picture_list(
870        &self,
871        sps: &SeqParameterSet,
872        header: &SliceHeader,
873        reference_list: &mut Vec<ReferencePictureInfo>,
874        ref_pic_list_modifications: &[ModificationOfPicNums],
875    ) -> Result<(), ReferenceManagementError> {
876        // 0 is Subtract, 1 is Add, 2 is LongTermRef
877        let mut refIdxLX = 0;
878        let mut picNumLXPred = header.frame_num as i64;
879
880        for ref_pic_list_modification in ref_pic_list_modifications {
881            match ref_pic_list_modification {
882                ModificationOfPicNums::Subtract(_) | ModificationOfPicNums::Add(_) => {
883                    self.modify_short_term_reference_picture_list(
884                        sps,
885                        header,
886                        reference_list,
887                        ref_pic_list_modification,
888                        &mut refIdxLX,
889                        &mut picNumLXPred,
890                    )?;
891                }
892
893                ModificationOfPicNums::LongTermRef(long_term_pic_num) => {
894                    self.modify_long_term_reference_picture_list(
895                        reference_list,
896                        *long_term_pic_num,
897                        &mut refIdxLX,
898                    )?;
899                }
900            }
901        }
902
903        Ok(())
904    }
905
906    #[allow(non_snake_case)]
907    fn modify_long_term_reference_picture_list(
908        &self,
909        reference_list: &mut Vec<ReferencePictureInfo>,
910        picture_to_shift: u32,
911        refIdxLX: &mut usize,
912    ) -> Result<(), ReferenceManagementError> {
913        let shifted_picture_idx = reference_list
914            .iter()
915            .enumerate()
916            .find(|(_, pic)| match pic.LongTermPicNum {
917                Some(num) => num == picture_to_shift as u64,
918                None => false,
919            })
920            .map(|(i, _)| i)
921            .ok_or(ReferenceManagementError::IncorrectData(
922                format!("picture with LongTermPicNum = {picture_to_shift} is not present in the reference list during modification")
923            ))?;
924
925        if reference_list[shifted_picture_idx].non_existing {
926            return Err(ReferenceManagementError::IncorrectData(
927                "a reference picture marked for shifting in the long-term reference list modification process is marked as non-existing".into()
928            ));
929        }
930
931        let shifted_picture = reference_list.remove(shifted_picture_idx);
932        reference_list.insert(*refIdxLX, shifted_picture);
933        *refIdxLX += 1;
934
935        Ok(())
936    }
937
938    #[allow(non_snake_case)]
939    fn modify_short_term_reference_picture_list(
940        &self,
941        sps: &SeqParameterSet,
942        header: &SliceHeader,
943        reference_list: &mut Vec<ReferencePictureInfo>,
944        ref_pic_list_modification: &ModificationOfPicNums,
945        refIdxLX: &mut usize,
946        picNumLXPred: &mut i64,
947    ) -> Result<(), ReferenceManagementError> {
948        let picNumLXNoWrap = match *ref_pic_list_modification {
949            ModificationOfPicNums::Subtract(abs_diff_pic_num_minus_1) => {
950                let abs_diff_pic_num = abs_diff_pic_num_minus_1 as i64 + 1;
951                if *picNumLXPred - abs_diff_pic_num < 0 {
952                    *picNumLXPred - abs_diff_pic_num + sps.max_frame_num()
953                } else {
954                    *picNumLXPred - abs_diff_pic_num
955                }
956            }
957            ModificationOfPicNums::Add(abs_diff_pic_num_minus_1) => {
958                let abs_diff_pic_num = abs_diff_pic_num_minus_1 as i64 + 1;
959                if *picNumLXPred + abs_diff_pic_num >= sps.max_frame_num() {
960                    *picNumLXPred + abs_diff_pic_num - sps.max_frame_num()
961                } else {
962                    *picNumLXPred + abs_diff_pic_num
963                }
964            }
965            ModificationOfPicNums::LongTermRef(_) => return Ok(()),
966        };
967
968        *picNumLXPred = picNumLXNoWrap;
969
970        let picNumLX = if picNumLXNoWrap > header.frame_num as i64 {
971            picNumLXNoWrap - sps.max_frame_num()
972        } else {
973            picNumLXNoWrap
974        };
975
976        let mut shifted_picture_idx = reference_list
977            .iter()
978            .enumerate()
979            .find(|(_, picture_info)| decode_picture_numbers_for_short_term_ref(picture_info.FrameNum.into(), header.frame_num.into(), sps).PicNum == picNumLX)
980            .map(|(i, _)| i)
981            .ok_or(ReferenceManagementError::IncorrectData(
982                format!("picture with picNumLX = {picNumLX} is not present in the reference list during modification")
983            ))?;
984
985        if reference_list[shifted_picture_idx].non_existing {
986            return Err(ReferenceManagementError::IncorrectData(
987                "a short-term reference picture marked for shifting in the reference list modification process is marked as non-existing".into()
988            ));
989        }
990
991        if reference_list[shifted_picture_idx].is_long_term() {
992            return Err(ReferenceManagementError::IncorrectData(
993                "a long-term reference picture marked for shifting in the short-term reference list modification process".into()
994            ));
995        }
996
997        let shifted_picture_info = reference_list[shifted_picture_idx];
998        if *refIdxLX <= reference_list.len() {
999            reference_list.insert(*refIdxLX, shifted_picture_info);
1000            shifted_picture_idx = if *refIdxLX <= shifted_picture_idx {
1001                shifted_picture_idx + 1
1002            } else {
1003                shifted_picture_idx
1004            };
1005        }
1006        *refIdxLX += 1;
1007        reference_list.remove(shifted_picture_idx);
1008
1009        Ok(())
1010    }
1011}
1012
1013#[derive(Debug)]
1014struct ShortTermReferencePicture {
1015    header: Arc<SliceHeader>,
1016    id: ReferenceId,
1017    pic_order_cnt: [i32; 2],
1018}
1019
1020#[allow(non_snake_case)]
1021fn decode_picture_numbers_for_short_term_ref(
1022    frame_num: i64,
1023    current_frame_num: i64,
1024    sps: &SeqParameterSet,
1025) -> ShortTermReferencePictureNumbers {
1026    let MaxFrameNum = sps.max_frame_num();
1027
1028    let FrameNum = frame_num;
1029
1030    let FrameNumWrap = if FrameNum > current_frame_num {
1031        FrameNum - MaxFrameNum
1032    } else {
1033        FrameNum
1034    };
1035
1036    // this assumes we're dealing with a short-term reference frame
1037    let PicNum = FrameNumWrap;
1038
1039    ShortTermReferencePictureNumbers {
1040        FrameNum,
1041        FrameNumWrap,
1042        PicNum,
1043    }
1044}
1045
1046#[derive(Debug, Clone)]
1047#[allow(non_snake_case)]
1048struct LongTermReferencePicture {
1049    header: Arc<SliceHeader>,
1050    LongTermFrameIdx: u64,
1051    id: ReferenceId,
1052    pic_order_cnt: [i32; 2],
1053}
1054
1055#[allow(non_snake_case)]
1056struct ShortTermReferencePictureNumbers {
1057    FrameNum: i64,
1058
1059    FrameNumWrap: i64,
1060
1061    PicNum: i64,
1062}
1063
1064#[derive(Debug, Default)]
1065struct ReferencePictures {
1066    long_term: Vec<LongTermReferencePicture>,
1067    short_term: Vec<ShortTermReferencePicture>,
1068}
1069
1070trait SliceHeaderExt {
1071    fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32;
1072    fn num_ref_idx_l1_active(&self, pps: &PicParameterSet)
1073    -> Result<u32, ReferenceManagementError>;
1074    fn includes_mmco_equal_5(&self) -> bool;
1075}
1076
1077impl SliceHeaderExt for SliceHeader {
1078    fn num_ref_idx_l0_active(&self, pps: &PicParameterSet) -> u32 {
1079        self.num_ref_idx_active
1080            .as_ref()
1081            .map(|num| match num {
1082                NumRefIdxActive::P {
1083                    num_ref_idx_l0_active_minus1,
1084                } => *num_ref_idx_l0_active_minus1,
1085                NumRefIdxActive::B {
1086                    num_ref_idx_l0_active_minus1,
1087                    ..
1088                } => *num_ref_idx_l0_active_minus1,
1089            })
1090            .unwrap_or(pps.num_ref_idx_l0_default_active_minus1)
1091            + 1
1092    }
1093
1094    fn num_ref_idx_l1_active(
1095        &self,
1096        pps: &PicParameterSet,
1097    ) -> Result<u32, ReferenceManagementError> {
1098        Ok(
1099            self
1100                .num_ref_idx_active
1101                .as_ref()
1102                .map(|num| match num {
1103                    NumRefIdxActive::P { .. } => Err(ReferenceManagementError::IncorrectData(
1104                        "requested num_ref_idx_l1_active, but the header contains the information for a P-frame, which does not include it".into()
1105                    )),
1106                    NumRefIdxActive::B { num_ref_idx_l1_active_minus1, .. } => Ok(*num_ref_idx_l1_active_minus1)
1107                })
1108                .unwrap_or(Ok(pps.num_ref_idx_l1_default_active_minus1))? + 1
1109        )
1110    }
1111
1112    fn includes_mmco_equal_5(&self) -> bool {
1113        let Some(DecRefPicMarking::Adaptive(ref mmcos)) = self.dec_ref_pic_marking else {
1114            return false;
1115        };
1116
1117        mmcos
1118            .iter()
1119            .any(|mmco| matches!(mmco, MemoryManagementControlOperation::AllRefPicturesUnused))
1120    }
1121}
1122
1123#[derive(Clone, derivative::Derivative)]
1124#[derivative(Debug)]
1125pub struct DecodeInformation {
1126    pub(crate) reference_list_l0: Option<Vec<ReferencePictureInfo>>,
1127    pub(crate) reference_list_l1: Option<Vec<ReferencePictureInfo>>,
1128    #[derivative(Debug = "ignore")]
1129    pub(crate) rbsp_bytes: Vec<u8>,
1130    pub(crate) slice_indices: Vec<usize>,
1131    #[derivative(Debug = "ignore")]
1132    pub(crate) header: Arc<SliceHeader>,
1133    pub(crate) sps_id: u8,
1134    pub(crate) pps_id: u8,
1135    pub(crate) picture_info: PictureInfo,
1136    pub(crate) pts: Option<u64>,
1137}
1138
1139#[derive(Debug, Clone, Copy)]
1140#[allow(non_snake_case)]
1141pub(crate) struct ReferencePictureInfo {
1142    pub(crate) id: ReferenceId,
1143    pub(crate) LongTermPicNum: Option<u64>,
1144    pub(crate) non_existing: bool,
1145    pub(crate) FrameNum: u16,
1146    pub(crate) PicOrderCnt: [i32; 2],
1147}
1148
1149impl ReferencePictureInfo {
1150    pub fn is_long_term(&self) -> bool {
1151        self.LongTermPicNum.is_some()
1152    }
1153}
1154
1155#[derive(Debug, Clone, Copy)]
1156#[allow(non_snake_case)]
1157pub(crate) struct PictureInfo {
1158    pub(crate) used_for_long_term_reference: bool,
1159    pub(crate) non_existing: bool,
1160    pub(crate) FrameNum: u16,
1161    pub(crate) PicOrderCnt_for_decoding: [i32; 2],
1162    pub(crate) PicOrderCnt_as_reference_pic: [i32; 2],
1163}