h264_reader/nal/slice/
mod.rs

1use crate::nal::pps;
2use crate::nal::pps::{PicParamSetId, PicParameterSet};
3use crate::nal::sps;
4use crate::nal::sps::SeqParameterSet;
5use crate::nal::NalHeader;
6use crate::rbsp::BitRead;
7use crate::rbsp::BitReaderError;
8use crate::Context;
9
10#[derive(Debug, PartialEq)]
11pub enum SliceFamily {
12    P,
13    B,
14    I,
15    SP,
16    SI,
17}
18#[derive(Debug, PartialEq)]
19pub enum SliceExclusive {
20    /// All slices in the picture have the same type
21    Exclusive,
22    /// Other slices in the picture may have a different type than the current slice
23    NonExclusive,
24}
25#[derive(Debug, PartialEq)]
26pub struct SliceType {
27    pub family: SliceFamily,
28    pub exclusive: SliceExclusive,
29}
30impl SliceType {
31    fn from_id(id: u32) -> Result<SliceType, SliceHeaderError> {
32        match id {
33            0 => Ok(SliceType {
34                family: SliceFamily::P,
35                exclusive: SliceExclusive::NonExclusive,
36            }),
37            1 => Ok(SliceType {
38                family: SliceFamily::B,
39                exclusive: SliceExclusive::NonExclusive,
40            }),
41            2 => Ok(SliceType {
42                family: SliceFamily::I,
43                exclusive: SliceExclusive::NonExclusive,
44            }),
45            3 => Ok(SliceType {
46                family: SliceFamily::SP,
47                exclusive: SliceExclusive::NonExclusive,
48            }),
49            4 => Ok(SliceType {
50                family: SliceFamily::SI,
51                exclusive: SliceExclusive::NonExclusive,
52            }),
53            5 => Ok(SliceType {
54                family: SliceFamily::P,
55                exclusive: SliceExclusive::Exclusive,
56            }),
57            6 => Ok(SliceType {
58                family: SliceFamily::B,
59                exclusive: SliceExclusive::Exclusive,
60            }),
61            7 => Ok(SliceType {
62                family: SliceFamily::I,
63                exclusive: SliceExclusive::Exclusive,
64            }),
65            8 => Ok(SliceType {
66                family: SliceFamily::SP,
67                exclusive: SliceExclusive::Exclusive,
68            }),
69            9 => Ok(SliceType {
70                family: SliceFamily::SI,
71                exclusive: SliceExclusive::Exclusive,
72            }),
73            _ => Err(SliceHeaderError::InvalidSliceType(id)),
74        }
75    }
76}
77
78#[derive(Debug)]
79pub enum SliceHeaderError {
80    RbspError(BitReaderError),
81    InvalidSliceType(u32),
82    InvalidSeqParamSetId(pps::PicParamSetIdError),
83    UndefinedPicParamSetId(pps::PicParamSetId),
84    UndefinedSeqParamSetId(sps::SeqParamSetId),
85    ColourPlaneError(ColourPlaneError),
86    InvalidModificationOfPicNumIdc(u32),
87    InvalidMemoryManagementControlOperation(u32),
88    InvalidSliceQpDelta(i32),
89    InvalidSliceQsDelta(i32),
90    InvalidDisableDeblockingFilterIdc(u32),
91    /// `slice_alpha_c0_offset_div2` was outside the expected range of `-6` to `+6`
92    InvalidSliceAlphaC0OffsetDiv2(i32),
93    /// `num_ref_idx_l0_default_active_minus1` or num_ref_idx_l1_default_active_minus1` is
94    /// greater than allowed 32.
95    InvalidNumRefIdx(&'static str, u32),
96    /// The header contained syntax elements that the parser isn't able to handle yet
97    UnsupportedSyntax(&'static str),
98}
99impl From<BitReaderError> for SliceHeaderError {
100    fn from(e: BitReaderError) -> Self {
101        SliceHeaderError::RbspError(e)
102    }
103}
104impl From<pps::PicParamSetIdError> for SliceHeaderError {
105    fn from(e: pps::PicParamSetIdError) -> Self {
106        SliceHeaderError::InvalidSeqParamSetId(e)
107    }
108}
109impl From<ColourPlaneError> for SliceHeaderError {
110    fn from(e: ColourPlaneError) -> Self {
111        SliceHeaderError::ColourPlaneError(e)
112    }
113}
114
115#[derive(Debug)]
116pub enum ColourPlane {
117    /// Indicates the _chroma_ colour plane
118    Y,
119    /// Indicates the _blue-difference_ colour plane
120    Cb,
121    /// Indicates the _red-difference_ colour plane
122    Cr,
123}
124#[derive(Debug)]
125pub enum ColourPlaneError {
126    InvalidId(u8),
127}
128impl ColourPlane {
129    fn from_id(id: u8) -> Result<ColourPlane, ColourPlaneError> {
130        match id {
131            0 => Ok(ColourPlane::Y),
132            1 => Ok(ColourPlane::Cb),
133            2 => Ok(ColourPlane::Cr),
134            _ => Err(ColourPlaneError::InvalidId(id)),
135        }
136    }
137}
138
139#[derive(Debug, PartialEq)]
140pub enum Field {
141    Top,
142    Bottom,
143}
144
145#[derive(Debug, PartialEq)]
146pub enum FieldPic {
147    Frame,
148    Field(Field),
149}
150
151#[derive(Debug, PartialEq)]
152pub enum PicOrderCountLsb {
153    Frame(u32),
154    FieldsAbsolute {
155        pic_order_cnt_lsb: u32,
156        delta_pic_order_cnt_bottom: i32,
157    },
158    FieldsDelta([i32; 2]),
159}
160
161#[derive(Debug)]
162pub enum NumRefIdxActive {
163    P {
164        num_ref_idx_l0_active_minus1: u32,
165    },
166    B {
167        num_ref_idx_l0_active_minus1: u32,
168        num_ref_idx_l1_active_minus1: u32,
169    },
170}
171impl NumRefIdxActive {
172    fn num_ref_idx_l0_active_minus1(&self) -> u32 {
173        match *self {
174            NumRefIdxActive::P {
175                num_ref_idx_l0_active_minus1,
176            } => num_ref_idx_l0_active_minus1,
177            NumRefIdxActive::B {
178                num_ref_idx_l0_active_minus1,
179                ..
180            } => num_ref_idx_l0_active_minus1,
181        }
182    }
183}
184
185#[derive(Debug)]
186pub enum ModificationOfPicNums {
187    Subtract(u32),
188    Add(u32),
189    LongTermRef(u32),
190}
191#[derive(Debug)]
192pub enum RefPicListModifications {
193    I,
194    P {
195        ref_pic_list_modification_l0: Vec<ModificationOfPicNums>,
196    },
197    B {
198        ref_pic_list_modification_l0: Vec<ModificationOfPicNums>,
199        ref_pic_list_modification_l1: Vec<ModificationOfPicNums>,
200    },
201}
202impl RefPicListModifications {
203    fn read<R: BitRead>(
204        slice_family: &SliceFamily,
205        r: &mut R,
206    ) -> Result<RefPicListModifications, SliceHeaderError> {
207        Ok(match slice_family {
208            SliceFamily::I | SliceFamily::SI => RefPicListModifications::I,
209            SliceFamily::B => RefPicListModifications::B {
210                ref_pic_list_modification_l0: Self::read_list(r)?,
211                ref_pic_list_modification_l1: Self::read_list(r)?,
212            },
213            SliceFamily::P | SliceFamily::SP => RefPicListModifications::P {
214                ref_pic_list_modification_l0: Self::read_list(r)?,
215            },
216        })
217    }
218
219    fn read_list<R: BitRead>(r: &mut R) -> Result<Vec<ModificationOfPicNums>, SliceHeaderError> {
220        let mut result = vec![];
221        // either ref_pic_list_modification_flag_l0 or ref_pic_list_modification_flag_l1 depending
222        // on call-site,
223        if !r.read_bool("ref_pic_list_modification_flag")? {
224            return Ok(result);
225        }
226        loop {
227            match r.read_ue("modification_of_pic_nums_idc")? {
228                0 => result.push(ModificationOfPicNums::Subtract(
229                    r.read_ue("abs_diff_pic_num_minus1")?,
230                )),
231                1 => result.push(ModificationOfPicNums::Add(
232                    r.read_ue("abs_diff_pic_num_minus1")?,
233                )),
234                2 => result.push(ModificationOfPicNums::LongTermRef(
235                    r.read_ue("long_term_pic_num")?,
236                )),
237                3 => break,
238                v => return Err(SliceHeaderError::InvalidModificationOfPicNumIdc(v)),
239            }
240        }
241        Ok(result)
242    }
243}
244
245#[derive(Debug)]
246pub struct PredWeight {
247    pub weight: i32,
248    pub offset: i32,
249}
250#[derive(Debug)]
251pub struct PredWeightTable {
252    pub luma_log2_weight_denom: u32,
253    pub chroma_log2_weight_denom: Option<u32>,
254    pub luma_weights: Vec<Option<PredWeight>>,
255    pub chroma_weights: Vec<Vec<PredWeight>>,
256}
257impl PredWeightTable {
258    fn read<R: BitRead>(
259        r: &mut R,
260        slice_type: &SliceType,
261        pps: &pps::PicParameterSet,
262        sps: &sps::SeqParameterSet,
263        num_ref_active: &Option<NumRefIdxActive>,
264    ) -> Result<PredWeightTable, SliceHeaderError> {
265        let chroma_array_type = if sps.chroma_info.separate_colour_plane_flag {
266            // TODO: "Otherwise (separate_colour_plane_flag is equal to 1), ChromaArrayType is
267            //       set equal to 0."  ...does this mean ChromaFormat::Monochrome then?
268            sps::ChromaFormat::Monochrome
269        } else {
270            sps.chroma_info.chroma_format
271        };
272        let luma_log2_weight_denom = r.read_ue("luma_log2_weight_denom")?;
273        let chroma_log2_weight_denom = if chroma_array_type != sps::ChromaFormat::Monochrome {
274            Some(r.read_ue("chroma_log2_weight_denom")?)
275        } else {
276            None
277        };
278        let num_ref_idx_l0_active_minus1 = num_ref_active
279            .as_ref()
280            .map(|n| n.num_ref_idx_l0_active_minus1())
281            .unwrap_or_else(|| pps.num_ref_idx_l0_default_active_minus1);
282        let mut luma_weights = Vec::with_capacity((num_ref_idx_l0_active_minus1 + 1) as usize);
283        let mut chroma_weights = Vec::with_capacity((num_ref_idx_l0_active_minus1 + 1) as usize);
284        for _ in 0..=num_ref_idx_l0_active_minus1 {
285            if r.read_bool("luma_weight_l0_flag")? {
286                luma_weights.push(Some(PredWeight {
287                    weight: r.read_se("luma_weight_l0")?,
288                    offset: r.read_se("luma_offset_l0")?,
289                }));
290            } else {
291                luma_weights.push(None);
292            }
293            if chroma_array_type != sps::ChromaFormat::Monochrome {
294                let mut weights = Vec::with_capacity(2); // TODO: just an array?
295                if r.read_bool("chroma_weight_l0_flag")? {
296                    for _j in 0..2 {
297                        weights.push(PredWeight {
298                            weight: r.read_se("chroma_weight_l0")?,
299                            offset: r.read_se("chroma_offset_l0")?,
300                        });
301                    }
302                }
303                chroma_weights.push(weights);
304            }
305        }
306        if slice_type.family == SliceFamily::B {
307            return Err(SliceHeaderError::UnsupportedSyntax("B frame"));
308        }
309        Ok(PredWeightTable {
310            luma_log2_weight_denom,
311            chroma_log2_weight_denom,
312            luma_weights,
313            chroma_weights,
314        })
315    }
316}
317
318#[derive(Debug)]
319pub enum MemoryManagementControlOperation {
320    /// `memory_management_control_operation` value of `1`
321    ShortTermUnusedForRef { difference_of_pic_nums_minus1: u32 },
322    /// `memory_management_control_operation` value of `2`
323    LongTermUnusedForRef { long_term_pic_num: u32 },
324    /// `memory_management_control_operation` value of `3`
325    ShortTermUsedForLongTerm {
326        difference_of_pic_nums_minus1: u32,
327        long_term_frame_idx: u32,
328    },
329    /// `memory_management_control_operation` value of `4`
330    MaxUsedLongTermFrameRef { max_long_term_frame_idx_plus1: u32 },
331    /// `memory_management_control_operation` value of `5`
332    AllRefPicturesUnused,
333    /// `memory_management_control_operation` value of `6`
334    CurrentUsedForLongTerm { long_term_frame_idx: u32 },
335}
336
337/// Decoded reference picture marking
338#[derive(Debug)]
339pub enum DecRefPicMarking {
340    Idr {
341        no_output_of_prior_pics_flag: bool,
342        long_term_reference_flag: bool,
343    },
344    /// `adaptive_ref_pic_marking_mode_flag` equal to `0`
345    SlidingWindow,
346    /// `adaptive_ref_pic_marking_mode_flag` equal to `1`
347    Adaptive(Vec<MemoryManagementControlOperation>),
348}
349impl DecRefPicMarking {
350    fn read<R: BitRead>(
351        r: &mut R,
352        header: NalHeader,
353    ) -> Result<DecRefPicMarking, SliceHeaderError> {
354        Ok(
355            if header.nal_unit_type() == crate::nal::UnitType::SliceLayerWithoutPartitioningIdr {
356                DecRefPicMarking::Idr {
357                    no_output_of_prior_pics_flag: r.read_bool("no_output_of_prior_pics_flag")?,
358                    long_term_reference_flag: r.read_bool("long_term_reference_flag")?,
359                }
360            } else if r.read_bool("adaptive_ref_pic_marking_mode_flag")? {
361                let mut ctl = vec![];
362                loop {
363                    let op = match r.read_ue("memory_management_control_operation")? {
364                        0 => break,
365                        1 => {
366                            let difference_of_pic_nums_minus1 =
367                                r.read_ue("difference_of_pic_nums_minus1")?;
368                            MemoryManagementControlOperation::ShortTermUnusedForRef {
369                                difference_of_pic_nums_minus1,
370                            }
371                        }
372                        2 => {
373                            let long_term_pic_num = r.read_ue("long_term_pic_num")?;
374                            MemoryManagementControlOperation::LongTermUnusedForRef {
375                                long_term_pic_num,
376                            }
377                        }
378                        3 => {
379                            let difference_of_pic_nums_minus1 =
380                                r.read_ue("difference_of_pic_nums_minus1")?;
381                            let long_term_frame_idx = r.read_ue("long_term_frame_idx")?;
382                            MemoryManagementControlOperation::ShortTermUsedForLongTerm {
383                                difference_of_pic_nums_minus1,
384                                long_term_frame_idx,
385                            }
386                        }
387                        4 => {
388                            let max_long_term_frame_idx_plus1 =
389                                r.read_ue("max_long_term_frame_idx_plus1")?;
390                            MemoryManagementControlOperation::MaxUsedLongTermFrameRef {
391                                max_long_term_frame_idx_plus1,
392                            }
393                        }
394                        5 => MemoryManagementControlOperation::AllRefPicturesUnused,
395                        6 => {
396                            let long_term_frame_idx = r.read_ue("long_term_frame_idx")?;
397                            MemoryManagementControlOperation::CurrentUsedForLongTerm {
398                                long_term_frame_idx,
399                            }
400                        }
401                        other => {
402                            return Err(SliceHeaderError::InvalidMemoryManagementControlOperation(
403                                other,
404                            ))
405                        }
406                    };
407                    ctl.push(op);
408                }
409                DecRefPicMarking::Adaptive(ctl)
410            } else {
411                DecRefPicMarking::SlidingWindow
412            },
413        )
414    }
415}
416
417#[derive(Debug)]
418pub struct SliceHeader {
419    pub first_mb_in_slice: u32,
420    pub slice_type: SliceType,
421    pub colour_plane: Option<ColourPlane>,
422    pub frame_num: u16,
423    pub field_pic: FieldPic,
424    pub idr_pic_id: Option<u32>,
425    pub pic_order_cnt_lsb: Option<PicOrderCountLsb>,
426    pub redundant_pic_cnt: Option<u32>,
427    pub direct_spatial_mv_pred_flag: Option<bool>,
428    pub num_ref_idx_active: Option<NumRefIdxActive>,
429    pub ref_pic_list_modification: Option<RefPicListModifications>, // may become an enum rather than Option in future (for ref_pic_list_mvc_modification)
430    pub pred_weight_table: Option<PredWeightTable>,
431    pub dec_ref_pic_marking: Option<DecRefPicMarking>,
432    pub cabac_init_idc: Option<u32>,
433    pub slice_qp_delta: i32,
434    pub sp_for_switch_flag: Option<bool>,
435    pub slice_qs: Option<u32>,
436    pub disable_deblocking_filter_idc: u8,
437}
438impl SliceHeader {
439    pub fn from_bits<'a, R: BitRead>(
440        ctx: &'a Context,
441        r: &mut R,
442        header: NalHeader,
443    ) -> Result<(SliceHeader, &'a SeqParameterSet, &'a PicParameterSet), SliceHeaderError> {
444        let first_mb_in_slice = r.read_ue("first_mb_in_slice")?;
445        let slice_type = SliceType::from_id(r.read_ue("slice_type")?)?;
446        let pic_parameter_set_id = PicParamSetId::from_u32(r.read_ue("pic_parameter_set_id")?)?;
447        let pps =
448            ctx.pps_by_id(pic_parameter_set_id)
449                .ok_or(SliceHeaderError::UndefinedPicParamSetId(
450                    pic_parameter_set_id,
451                ))?;
452        let sps = ctx.sps_by_id(pps.seq_parameter_set_id).ok_or(
453            SliceHeaderError::UndefinedSeqParamSetId(pps.seq_parameter_set_id),
454        )?;
455        let colour_plane = if sps.chroma_info.separate_colour_plane_flag {
456            Some(ColourPlane::from_id(r.read(2, "colour_plane_id")?)?)
457        } else {
458            None
459        };
460        let frame_num = r.read(u32::from(sps.log2_max_frame_num()), "frame_num")?;
461        let field_pic = if let sps::FrameMbsFlags::Fields { .. } = sps.frame_mbs_flags {
462            if r.read_bool("field_pic_flag")? {
463                if r.read_bool("bottom_field_flag")? {
464                    FieldPic::Field(Field::Bottom)
465                } else {
466                    FieldPic::Field(Field::Top)
467                }
468            } else {
469                FieldPic::Frame
470            }
471        } else {
472            FieldPic::Frame
473        };
474        let idr_pic_id =
475            if header.nal_unit_type() == crate::nal::UnitType::SliceLayerWithoutPartitioningIdr {
476                Some(r.read_ue("idr_pic_id")?)
477            } else {
478                None
479            };
480        let pic_order_cnt_lsb = match sps.pic_order_cnt {
481            sps::PicOrderCntType::TypeZero {
482                log2_max_pic_order_cnt_lsb_minus4,
483            } => {
484                let pic_order_cnt_lsb = r.read(
485                    u32::from(log2_max_pic_order_cnt_lsb_minus4) + 4,
486                    "pic_order_cnt_lsb",
487                )?;
488                Some(
489                    if pps.bottom_field_pic_order_in_frame_present_flag
490                        && field_pic == FieldPic::Frame
491                    {
492                        let delta_pic_order_cnt_bottom = r.read_se("delta_pic_order_cnt_bottom")?;
493                        PicOrderCountLsb::FieldsAbsolute {
494                            pic_order_cnt_lsb,
495                            delta_pic_order_cnt_bottom,
496                        }
497                    } else {
498                        PicOrderCountLsb::Frame(pic_order_cnt_lsb)
499                    },
500                )
501            }
502            sps::PicOrderCntType::TypeOne {
503                delta_pic_order_always_zero_flag,
504                ..
505            } => {
506                if delta_pic_order_always_zero_flag {
507                    Some(PicOrderCountLsb::FieldsDelta([0, 0]))
508                } else {
509                    let delta0 = r.read_se("delta_pic_order_cnt[0]")?;
510                    if pps.bottom_field_pic_order_in_frame_present_flag
511                        && field_pic == FieldPic::Frame
512                    {
513                        let delta1 = r.read_se("delta_pic_order_cnt[1]")?;
514                        Some(PicOrderCountLsb::FieldsDelta([delta0, delta1]))
515                    } else {
516                        Some(PicOrderCountLsb::FieldsDelta([delta0, 0]))
517                    }
518                }
519            }
520            sps::PicOrderCntType::TypeTwo => None,
521        };
522        let redundant_pic_cnt = if pps.redundant_pic_cnt_present_flag {
523            Some(r.read_ue("redundant_pic_cnt ")?)
524        } else {
525            None
526        };
527        let direct_spatial_mv_pred_flag = if slice_type.family == SliceFamily::B {
528            Some(r.read_bool("direct_spatial_mv_pred_flag")?)
529        } else {
530            None
531        };
532        let num_ref_idx_active = if slice_type.family == SliceFamily::P
533            || slice_type.family == SliceFamily::SP
534            || slice_type.family == SliceFamily::B
535        {
536            if r.read_bool("num_ref_idx_active_override_flag")? {
537                let num_ref_idx_l0_active_minus1 =
538                    read_num_ref_idx(r, "num_ref_idx_l0_active_minus1")?;
539                Some(if slice_type.family == SliceFamily::B {
540                    let num_ref_idx_l1_active_minus1 =
541                        read_num_ref_idx(r, "num_ref_idx_l1_active_minus1")?;
542                    NumRefIdxActive::B {
543                        num_ref_idx_l0_active_minus1,
544                        num_ref_idx_l1_active_minus1,
545                    }
546                } else {
547                    NumRefIdxActive::P {
548                        num_ref_idx_l0_active_minus1,
549                    }
550                })
551            } else {
552                None
553            }
554        } else {
555            None
556        };
557        let ref_pic_list_modification = if header.nal_unit_type()
558            == crate::nal::UnitType::SliceExtension
559            || header.nal_unit_type() == crate::nal::UnitType::SliceExtensionViewComponent
560        {
561            return Err(SliceHeaderError::UnsupportedSyntax(
562                "NALU types 20 and 21 not yet supported",
563            ));
564        } else {
565            RefPicListModifications::read(&slice_type.family, r)?
566        };
567        let pred_weight_table = if (pps.weighted_pred_flag && slice_type.family == SliceFamily::P
568            || slice_type.family == SliceFamily::SP)
569            || (pps.weighted_bipred_idc == 1 && slice_type.family == SliceFamily::B)
570        {
571            Some(PredWeightTable::read(
572                r,
573                &slice_type,
574                pps,
575                sps,
576                &num_ref_idx_active,
577            )?)
578        } else {
579            None
580        };
581        let dec_ref_pic_marking = if header.nal_ref_idc() == 0 {
582            None
583        } else {
584            Some(DecRefPicMarking::read(r, header)?)
585        };
586        let cabac_init_idc = if pps.entropy_coding_mode_flag
587            && slice_type.family != SliceFamily::I
588            && slice_type.family != SliceFamily::SI
589        {
590            Some(r.read_ue("cabac_init_idc")?)
591        } else {
592            None
593        };
594        let slice_qp_delta = r.read_se("slice_qp_delta")?;
595        if slice_qp_delta > 51 {
596            // TODO: or less than -qp_bd_offset
597            return Err(SliceHeaderError::InvalidSliceQpDelta(slice_qp_delta));
598        }
599        let mut sp_for_switch_flag = None;
600        let slice_qs =
601            if slice_type.family == SliceFamily::SP || slice_type.family == SliceFamily::SI {
602                if slice_type.family == SliceFamily::SP {
603                    sp_for_switch_flag = Some(r.read_bool("sp_for_switch_flag")?);
604                }
605                let slice_qs_delta = r.read_se("slice_qs_delta")?;
606                let qs_y = 26 + pps.pic_init_qs_minus26 + slice_qs_delta;
607                if qs_y < 0 || 51 < qs_y {
608                    return Err(SliceHeaderError::InvalidSliceQsDelta(slice_qs_delta));
609                }
610                Some(qs_y as u32)
611            } else {
612                None
613            };
614        let mut disable_deblocking_filter_idc = 0;
615        if pps.deblocking_filter_control_present_flag {
616            disable_deblocking_filter_idc = {
617                let v = r.read_ue("disable_deblocking_filter_idc")?;
618                if v > 6 {
619                    return Err(SliceHeaderError::InvalidDisableDeblockingFilterIdc(v));
620                }
621                v as u8
622            };
623            if disable_deblocking_filter_idc != 1 {
624                let slice_alpha_c0_offset_div2 = r.read_se("slice_alpha_c0_offset_div2")?;
625                if slice_alpha_c0_offset_div2 < -6 || 6 < slice_alpha_c0_offset_div2 {
626                    return Err(SliceHeaderError::InvalidSliceAlphaC0OffsetDiv2(
627                        slice_alpha_c0_offset_div2,
628                    ));
629                }
630                let _slice_beta_offset_div2 = r.read_se("slice_beta_offset_div2")?;
631            }
632        }
633        if !r.has_more_rbsp_data("slice_header")? {
634            return Err(SliceHeaderError::RbspError(BitReaderError::ReaderErrorFor(
635                "slice_header",
636                std::io::Error::new(
637                    std::io::ErrorKind::UnexpectedEof,
638                    "slice header overran rbsp trailing bits",
639                ),
640            )));
641        }
642        let header = SliceHeader {
643            first_mb_in_slice,
644            slice_type,
645            colour_plane,
646            frame_num,
647            field_pic,
648            idr_pic_id,
649            pic_order_cnt_lsb,
650            redundant_pic_cnt,
651            direct_spatial_mv_pred_flag,
652            num_ref_idx_active,
653            ref_pic_list_modification: Some(ref_pic_list_modification),
654            pred_weight_table,
655            dec_ref_pic_marking,
656            cabac_init_idc,
657            slice_qp_delta,
658            sp_for_switch_flag,
659            slice_qs,
660            disable_deblocking_filter_idc,
661        };
662        Ok((header, sps, pps))
663    }
664}
665
666fn read_num_ref_idx<R: BitRead>(r: &mut R, name: &'static str) -> Result<u32, SliceHeaderError> {
667    let val = r.read_ue(name)?;
668    if val > 31 {
669        return Err(SliceHeaderError::InvalidNumRefIdx(name, val));
670    }
671    Ok(val)
672}
673
674#[cfg(test)]
675mod test {
676    use super::*;
677    use crate::nal::{Nal, RefNal};
678    use hex_literal::hex;
679
680    #[test]
681    fn invalid_num_ref_idx() {
682        // Examples from fuzz testing.
683        let mut ctx = crate::Context::default();
684        let sps = RefNal::new(
685            &hex!("27 d2 d2 d6 d2 27 50 aa 27 01 56 56 08 41 c5")[..],
686            &[],
687            true,
688        );
689        let sps = SeqParameterSet::from_bits(sps.rbsp_bits()).unwrap();
690        ctx.put_seq_param_set(sps);
691        let pps = RefNal::new(&hex!("28 c5 56 6a 08 41 00 fd")[..], &[], true);
692        let pps = PicParameterSet::from_bits(&ctx, pps.rbsp_bits()).unwrap();
693        ctx.put_pic_param_set(pps);
694        let nal = RefNal::new(&hex!("41 26 25 03 00")[..], &[], true);
695        let r = SliceHeader::from_bits(&ctx, &mut nal.rbsp_bits(), nal.header().unwrap());
696        assert!(
697            matches!(r, Err(SliceHeaderError::InvalidNumRefIdx(_, _))),
698            "r={:#?}",
699            r
700        );
701    }
702}