Skip to main content

h264_reader/nal/slice/
data.rs

1//! Slice data access (currently baseline profile - CAVLC only, no MBAFF).
2//!
3//! Implements the `slice_data()` syntax from spec section 7.3.4.
4//!
5//! 1. Parse context-free parts of `macroblock_layer()` — `mb_type`, `mb_pred`/`sub_mb_pred`,
6//!    `coded_block_pattern`, `mb_qp_delta`.
7//! 2. The caller takes over the `BitRead` stream to parse `residual()` using CAVLC with
8//!    decoder-computed `nC` values.
9
10pub use crate::nal::slice::cavlc::{CavlcContext, CavlcError};
11use crate::nal::slice::macroblock::{
12    coded_block_pattern_from_me, i_mb_type_info, p_mb_type_info, p_sub_mb_type_info, IMbTypeInfo,
13    MbPartPredMode, MbTypeError, PMbTypeInfo, SubMbTypeInfo,
14};
15use crate::nal::slice::{cavlc, SliceFamily};
16use crate::rbsp::{BitRead, BitReaderError};
17use std::convert::TryFrom;
18use std::fmt;
19
20#[derive(Debug)]
21pub enum SliceDataError {
22    BitReaderError(BitReaderError),
23    InvalidMbType(MbTypeError),
24    InvalidSubMbType(MbTypeError),
25    InvalidCodedBlockPattern(u32),
26    InvalidParameter { field: &'static str, value: i64 },
27}
28
29impl fmt::Display for SliceDataError {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            SliceDataError::BitReaderError(e) => write!(f, "bitstream I/O: {e:?}"),
33            SliceDataError::InvalidMbType(e) => write!(f, "{e}"),
34            SliceDataError::InvalidSubMbType(e) => write!(f, "{e}"),
35            SliceDataError::InvalidCodedBlockPattern(v) => {
36                write!(f, "invalid coded_block_pattern code_num {v}")
37            }
38            SliceDataError::InvalidParameter { field, value } => {
39                write!(f, "{field} out of range: {value}")
40            }
41        }
42    }
43}
44
45impl std::error::Error for SliceDataError {}
46
47impl From<BitReaderError> for SliceDataError {
48    fn from(e: BitReaderError) -> Self {
49        SliceDataError::BitReaderError(e)
50    }
51}
52
53impl From<MbTypeError> for SliceDataError {
54    fn from(e: MbTypeError) -> Self {
55        match e {
56            MbTypeError::InvalidPSubMbType(_) => SliceDataError::InvalidSubMbType(e),
57            _ => SliceDataError::InvalidMbType(e),
58        }
59    }
60}
61
62#[derive(Debug)]
63pub struct InterPrediction {
64    pub num_parts: u8,
65    pub part_width: u8,
66    pub part_height: u8,
67    pub ref_idx_l0: [i8; 4],
68    pub mvd_l0: [[[i16; 2]; 4]; 4],
69    pub sub_mb_info: Option<SubMbInfo>,
70}
71
72#[derive(Debug)]
73pub struct SubMbInfo {
74    pub sub_mb_type: [u8; 4],
75    pub info: [SubMbTypeInfo; 4],
76    pub ref_idx_l0: [i8; 4],
77}
78
79#[derive(Debug)]
80pub enum MbPrediction {
81    Intra4x4 {
82        prev_intra4x4_pred_mode_flag: [bool; 16],
83        rem_intra4x4_pred_mode: [u8; 16],
84        intra_chroma_pred_mode: u8,
85    },
86    Intra16x16 {
87        intra_chroma_pred_mode: u8,
88    },
89    IntraPCM {
90        pcm_sample_luma: [u8; 256],
91        pcm_sample_chroma: [u8; 128],
92    },
93    Inter(InterPrediction),
94}
95
96#[derive(Debug)]
97pub enum MbTypeInfo {
98    I(IMbTypeInfo),
99    P(PMbTypeInfo),
100}
101
102#[derive(Debug)]
103pub struct MacroblockHeader {
104    pub mb_addr: u32,
105    pub mb_type: MbTypeInfo,
106    pub coded_block_pattern_luma: u8,
107    pub coded_block_pattern_chroma: u8,
108    pub mb_qp_delta: i32,
109    pub mb_pred: MbPrediction,
110}
111
112pub enum SliceEvent<'a, R: BitRead> {
113    End,
114    Skip {
115        mb_addr: u32,
116        next: SliceDataReader<'a, R>,
117    },
118    Macroblock(MacroblockResidual<'a, R>),
119}
120
121struct SliceDataCore<'a, R: BitRead> {
122    reader: &'a mut R,
123    slice_family: SliceFamily,
124    curr_mb_addr: u32,
125    pic_size_in_mbs: u32,
126    num_ref_idx_l0_active_minus1: u32,
127    pending_skips: u32,
128    after_skip_run: bool,
129    done: bool,
130}
131
132impl<R: BitRead> SliceDataCore<'_, R> {
133    fn next_mb_address(&self, addr: u32) -> u32 {
134        addr + 1
135    }
136
137    fn parse_macroblock_header(
138        &mut self,
139        mb_addr: u32,
140    ) -> Result<MacroblockHeader, SliceDataError> {
141        let raw_mb_type = self.reader.read_ue("mb_type")?;
142        log::trace!(
143            "MB {}: raw_mb_type={}, slice_family={:?}",
144            mb_addr,
145            raw_mb_type,
146            self.slice_family
147        );
148
149        match self.slice_family {
150            SliceFamily::I | SliceFamily::SI => {
151                let info = i_mb_type_info(raw_mb_type)?;
152                self.parse_i_macroblock(mb_addr, info)
153            }
154            SliceFamily::P | SliceFamily::SP => {
155                let info = p_mb_type_info(raw_mb_type)?;
156                self.parse_p_macroblock(mb_addr, info)
157            }
158            SliceFamily::B => {
159                // B slices not supported yet (baseline profile only)
160                Err(SliceDataError::InvalidParameter {
161                    field: "slice_type",
162                    value: 1,
163                })
164            }
165        }
166    }
167
168    fn parse_i_macroblock(
169        &mut self,
170        mb_addr: u32,
171        info: IMbTypeInfo,
172    ) -> Result<MacroblockHeader, SliceDataError> {
173        let (mb_pred, cbp_luma, cbp_chroma) = self.parse_i_mb_body(&info)?;
174
175        let mb_qp_delta =
176            if cbp_luma > 0 || cbp_chroma > 0 || matches!(info, IMbTypeInfo::I16x16 { .. }) {
177                self.read_mb_qp_delta()?
178            } else {
179                0
180            };
181
182        Ok(MacroblockHeader {
183            mb_addr,
184            mb_type: MbTypeInfo::I(info),
185            coded_block_pattern_luma: cbp_luma,
186            coded_block_pattern_chroma: cbp_chroma,
187            mb_qp_delta,
188            mb_pred,
189        })
190    }
191
192    fn parse_p_macroblock(
193        &mut self,
194        mb_addr: u32,
195        info: PMbTypeInfo,
196    ) -> Result<MacroblockHeader, SliceDataError> {
197        match info {
198            PMbTypeInfo::I(ref i_info) => {
199                let (mb_pred, cbp_luma, cbp_chroma) = self.parse_i_mb_body(i_info)?;
200
201                let mb_qp_delta = if cbp_luma > 0
202                    || cbp_chroma > 0
203                    || matches!(i_info, IMbTypeInfo::I16x16 { .. })
204                {
205                    self.read_mb_qp_delta()?
206                } else {
207                    0
208                };
209
210                Ok(MacroblockHeader {
211                    mb_addr,
212                    mb_type: MbTypeInfo::P(info),
213                    coded_block_pattern_luma: cbp_luma,
214                    coded_block_pattern_chroma: cbp_chroma,
215                    mb_qp_delta,
216                    mb_pred,
217                })
218            }
219            PMbTypeInfo::P {
220                num_parts,
221                part_width,
222                part_height,
223                ref_idx_forced_zero,
224                ..
225            } => {
226                let is_8x8 = num_parts == 4;
227
228                let mb_pred = if is_8x8 {
229                    self.parse_sub_mb_pred(ref_idx_forced_zero)?
230                } else {
231                    self.parse_inter_mb_pred(num_parts, part_width, part_height)?
232                };
233
234                // coded_block_pattern is read as ue(v), then mapped.
235                let code_num = self.reader.read_ue("coded_block_pattern")?;
236                let (cbp_luma, cbp_chroma) = coded_block_pattern_from_me(code_num, false)
237                    .ok_or(SliceDataError::InvalidCodedBlockPattern(code_num))?;
238
239                let mb_qp_delta = if cbp_luma > 0 || cbp_chroma > 0 {
240                    self.read_mb_qp_delta()?
241                } else {
242                    0
243                };
244
245                Ok(MacroblockHeader {
246                    mb_addr,
247                    mb_type: MbTypeInfo::P(info),
248                    coded_block_pattern_luma: cbp_luma,
249                    coded_block_pattern_chroma: cbp_chroma,
250                    mb_qp_delta,
251                    mb_pred,
252                })
253            }
254        }
255    }
256
257    fn parse_i_mb_body(
258        &mut self,
259        info: &IMbTypeInfo,
260    ) -> Result<(MbPrediction, u8, u8), SliceDataError> {
261        match info {
262            IMbTypeInfo::INxN => {
263                let mut prev_flags = [false; 16];
264                let mut rem_modes = [0u8; 16];
265                for i in 0..16 {
266                    prev_flags[i] = self.reader.read_bit("prev_intra4x4_pred_mode_flag")?;
267                    if !prev_flags[i] {
268                        rem_modes[i] = self.reader.read::<3, u8>("rem_intra4x4_pred_mode")?;
269                    }
270                }
271                let intra_chroma_pred_mode_val = self.reader.read_ue("intra_chroma_pred_mode")?;
272                if intra_chroma_pred_mode_val > 3 {
273                    return Err(SliceDataError::InvalidParameter {
274                        field: "intra_chroma_pred_mode",
275                        value: intra_chroma_pred_mode_val as i64,
276                    });
277                }
278                let intra_chroma_pred_mode = intra_chroma_pred_mode_val as u8;
279
280                let code_num = self.reader.read_ue("coded_block_pattern")?;
281                let (cbp_luma, cbp_chroma) = coded_block_pattern_from_me(code_num, true)
282                    .ok_or(SliceDataError::InvalidCodedBlockPattern(code_num))?;
283
284                Ok((
285                    MbPrediction::Intra4x4 {
286                        prev_intra4x4_pred_mode_flag: prev_flags,
287                        rem_intra4x4_pred_mode: rem_modes,
288                        intra_chroma_pred_mode,
289                    },
290                    cbp_luma,
291                    cbp_chroma,
292                ))
293            }
294            IMbTypeInfo::I16x16 {
295                coded_block_pattern_luma,
296                coded_block_pattern_chroma,
297                ..
298            } => {
299                let intra_chroma_pred_mode_val = self.reader.read_ue("intra_chroma_pred_mode")?;
300                if intra_chroma_pred_mode_val > 3 {
301                    return Err(SliceDataError::InvalidParameter {
302                        field: "intra_chroma_pred_mode",
303                        value: intra_chroma_pred_mode_val as i64,
304                    });
305                }
306                let intra_chroma_pred_mode = intra_chroma_pred_mode_val as u8;
307
308                Ok((
309                    MbPrediction::Intra16x16 {
310                        intra_chroma_pred_mode,
311                    },
312                    *coded_block_pattern_luma,
313                    *coded_block_pattern_chroma,
314                ))
315            }
316            IMbTypeInfo::IPCM => {
317                while !self.reader.byte_aligned() {
318                    if self.reader.read_bit("pcm_alignment_zero_bit")? {
319                        return Err(SliceDataError::InvalidParameter {
320                            field: "pcm_alignment_zero_bit",
321                            value: 1,
322                        });
323                    }
324                }
325
326                let mut pcm_sample_luma = [0u8; 256];
327                for sample in &mut pcm_sample_luma {
328                    *sample = self.reader.read::<8, u8>("pcm_sample_luma")?;
329                }
330                let mut pcm_sample_chroma = [0u8; 128];
331                for sample in &mut pcm_sample_chroma {
332                    *sample = self.reader.read::<8, u8>("pcm_sample_chroma")?;
333                }
334
335                Ok((
336                    MbPrediction::IntraPCM {
337                        pcm_sample_luma,
338                        pcm_sample_chroma,
339                    },
340                    0,
341                    0,
342                ))
343            }
344        }
345    }
346
347    fn parse_inter_mb_pred(
348        &mut self,
349        num_parts: u8,
350        part_width: u8,
351        part_height: u8,
352    ) -> Result<MbPrediction, SliceDataError> {
353        let mut ref_idx_l0 = [0i8; 4];
354        let mut mvd_l0 = [[[0i16; 2]; 4]; 4];
355
356        for item in ref_idx_l0.iter_mut().take(num_parts as usize) {
357            *item = self.read_te("ref_idx_l0", self.num_ref_idx_l0_active_minus1)?;
358        }
359
360        for item in mvd_l0.iter_mut().take(num_parts as usize) {
361            let x = self.reader.read_se("mvd_l0_x")?;
362            item[0][0] = i16::try_from(x).map_err(|_| SliceDataError::InvalidParameter {
363                field: "mvd_l0_x",
364                value: x as i64,
365            })?;
366            let y = self.reader.read_se("mvd_l0_y")?;
367            item[0][1] = i16::try_from(y).map_err(|_| SliceDataError::InvalidParameter {
368                field: "mvd_l0_y",
369                value: y as i64,
370            })?;
371        }
372
373        Ok(MbPrediction::Inter(InterPrediction {
374            num_parts,
375            part_width,
376            part_height,
377            ref_idx_l0,
378            mvd_l0,
379            sub_mb_info: None,
380        }))
381    }
382
383    fn parse_sub_mb_pred(
384        &mut self,
385        ref_idx_forced_zero: bool,
386    ) -> Result<MbPrediction, SliceDataError> {
387        let mut sub_mb_type_raw = [0u8; 4];
388        let mut sub_info: [SubMbTypeInfo; 4] = [
389            SubMbTypeInfo {
390                num_sub_parts: 1,
391                sub_part_width: 8,
392                sub_part_height: 8,
393                pred_mode: MbPartPredMode::PredL0,
394            },
395            SubMbTypeInfo {
396                num_sub_parts: 1,
397                sub_part_width: 8,
398                sub_part_height: 8,
399                pred_mode: MbPartPredMode::PredL0,
400            },
401            SubMbTypeInfo {
402                num_sub_parts: 1,
403                sub_part_width: 8,
404                sub_part_height: 8,
405                pred_mode: MbPartPredMode::PredL0,
406            },
407            SubMbTypeInfo {
408                num_sub_parts: 1,
409                sub_part_width: 8,
410                sub_part_height: 8,
411                pred_mode: MbPartPredMode::PredL0,
412            },
413        ];
414        for i in 0..4 {
415            let raw = self.reader.read_ue("sub_mb_type")?;
416            sub_mb_type_raw[i] = raw as u8;
417            sub_info[i] = p_sub_mb_type_info(raw)?;
418        }
419
420        let mut sub_ref_idx_l0 = [0i8; 4];
421        if !ref_idx_forced_zero {
422            for item in &mut sub_ref_idx_l0 {
423                *item = self.read_te("ref_idx_l0", self.num_ref_idx_l0_active_minus1)?;
424            }
425        }
426
427        let mut mvd_l0 = [[[0i16; 2]; 4]; 4];
428        for mb_part in 0..4 {
429            for sub_part in 0..sub_info[mb_part].num_sub_parts as usize {
430                let x = self.reader.read_se("mvd_l0_x")?;
431                mvd_l0[mb_part][sub_part][0] =
432                    i16::try_from(x).map_err(|_| SliceDataError::InvalidParameter {
433                        field: "mvd_l0_x",
434                        value: x as i64,
435                    })?;
436                let y = self.reader.read_se("mvd_l0_y")?;
437                mvd_l0[mb_part][sub_part][1] =
438                    i16::try_from(y).map_err(|_| SliceDataError::InvalidParameter {
439                        field: "mvd_l0_y",
440                        value: y as i64,
441                    })?;
442            }
443        }
444
445        Ok(MbPrediction::Inter(InterPrediction {
446            num_parts: 4,
447            part_width: 8,
448            part_height: 8,
449            ref_idx_l0: [0; 4],
450            mvd_l0,
451            sub_mb_info: Some(SubMbInfo {
452                sub_mb_type: sub_mb_type_raw,
453                info: sub_info,
454                ref_idx_l0: sub_ref_idx_l0,
455            }),
456        }))
457    }
458
459    fn read_mb_qp_delta(&mut self) -> Result<i32, SliceDataError> {
460        let val = self.reader.read_se("mb_qp_delta")?;
461        if !(-26..=25).contains(&val) {
462            return Err(SliceDataError::InvalidParameter {
463                field: "mb_qp_delta",
464                value: val as i64,
465            });
466        }
467        Ok(val)
468    }
469
470    /// Read a `te(v)` (truncated Exp-Golomb) value.
471    ///
472    /// - If `max == 0`: the value is always 0 (nothing is read).
473    /// - If `max == 1`: read 1 bit and invert (0 -> 1, 1 -> 0).
474    /// - If `max > 1`: read as `ue(v)`.
475    fn read_te(&mut self, name: &'static str, max: u32) -> Result<i8, SliceDataError> {
476        if max == 0 {
477            Ok(0)
478        } else if max == 1 {
479            let bit = self.reader.read_bit(name)?;
480            Ok(if bit { 0 } else { 1 })
481        } else {
482            let val = self.reader.read_ue(name)?;
483            if val > max {
484                return Err(SliceDataError::InvalidParameter {
485                    field: name,
486                    value: val as i64,
487                });
488            }
489            Ok(val as i8)
490        }
491    }
492}
493
494pub struct SliceDataReader<'a, R: BitRead> {
495    core: SliceDataCore<'a, R>,
496}
497
498impl<'a, R: BitRead> SliceDataReader<'a, R> {
499    pub fn new(
500        reader: &'a mut R,
501        slice_family: SliceFamily,
502        first_mb_in_slice: u32,
503        pic_size_in_mbs: u32,
504        num_ref_idx_l0_active_minus1: u32,
505    ) -> Self {
506        SliceDataReader {
507            core: SliceDataCore {
508                reader,
509                slice_family,
510                curr_mb_addr: first_mb_in_slice,
511                pic_size_in_mbs,
512                num_ref_idx_l0_active_minus1,
513                pending_skips: 0,
514                after_skip_run: false,
515                done: false,
516            },
517        }
518    }
519
520    pub fn next(mut self) -> Result<SliceEvent<'a, R>, SliceDataError> {
521        if self.core.done {
522            return Ok(SliceEvent::End);
523        }
524
525        if self.core.curr_mb_addr >= self.core.pic_size_in_mbs {
526            self.core.done = true;
527            return Ok(SliceEvent::End);
528        }
529
530        if self.core.pending_skips > 0 {
531            self.core.pending_skips -= 1;
532            let addr = self.core.curr_mb_addr;
533            self.core.curr_mb_addr = self.core.next_mb_address(addr);
534            if self.core.pending_skips == 0 {
535                if !self.core.reader.has_more_rbsp_data("slice_data")? {
536                    self.core.done = true;
537                } else {
538                    self.core.after_skip_run = true;
539                }
540            }
541            return Ok(SliceEvent::Skip {
542                mb_addr: addr,
543                next: self,
544            });
545        }
546
547        if self.core.after_skip_run {
548            self.core.after_skip_run = false;
549        } else if self.core.slice_family != SliceFamily::I
550            && self.core.slice_family != SliceFamily::SI
551        {
552            let mb_skip_run = self.core.reader.read_ue("mb_skip_run")?;
553            if mb_skip_run > 0 {
554                self.core.pending_skips = mb_skip_run;
555                self.core.pending_skips -= 1;
556                let addr = self.core.curr_mb_addr;
557                self.core.curr_mb_addr = self.core.next_mb_address(addr);
558                if self.core.pending_skips == 0 {
559                    if !self.core.reader.has_more_rbsp_data("slice_data")? {
560                        self.core.done = true;
561                    } else {
562                        self.core.after_skip_run = true;
563                    }
564                }
565                return Ok(SliceEvent::Skip {
566                    mb_addr: addr,
567                    next: self,
568                });
569            }
570            if !self.core.reader.has_more_rbsp_data("slice_data")? {
571                self.core.done = true;
572                return Ok(SliceEvent::End);
573            }
574        }
575
576        let mb_addr = self.core.curr_mb_addr;
577        let header = self.core.parse_macroblock_header(mb_addr)?;
578        self.core.curr_mb_addr = self.core.next_mb_address(mb_addr);
579
580        Ok(SliceEvent::Macroblock(MacroblockResidual {
581            core: self.core,
582            header,
583        }))
584    }
585
586    pub fn curr_mb_addr(&self) -> u32 {
587        self.core.curr_mb_addr
588    }
589
590    pub fn pic_size_in_mbs(&self) -> u32 {
591        self.core.pic_size_in_mbs
592    }
593}
594
595pub struct MacroblockResidual<'a, R: BitRead> {
596    core: SliceDataCore<'a, R>,
597    header: MacroblockHeader,
598}
599
600impl<'a, R: BitRead> MacroblockResidual<'a, R> {
601    pub fn header(&self) -> &MacroblockHeader {
602        &self.header
603    }
604
605    pub fn residual_block_cavlc(
606        &mut self,
607        coeff_level: &mut [i32],
608        start_idx: usize,
609        end_idx: usize,
610        max_num_coeff: usize,
611        nc: CavlcContext,
612    ) -> Result<u8, CavlcError> {
613        cavlc::residual_block_cavlc(
614            self.core.reader,
615            coeff_level,
616            start_idx,
617            end_idx,
618            max_num_coeff,
619            nc,
620        )
621    }
622
623    pub fn curr_mb_addr(&self) -> u32 {
624        self.core.curr_mb_addr
625    }
626
627    pub fn finish(mut self) -> Result<SliceDataReader<'a, R>, SliceDataError> {
628        match self.core.reader.has_more_rbsp_data("slice_data") {
629            Ok(false) => {
630                self.core.done = true;
631            }
632            Ok(true) => {}
633            Err(_) => {
634                self.core.done = true;
635            }
636        }
637        Ok(SliceDataReader { core: self.core })
638    }
639}