scuffle_h265/sps/
sps_range_extension.rs

1use std::io;
2
3use scuffle_bytes_util::BitReader;
4
5/// Sequence parameter set range extension.
6///
7/// `sps_range_extension()`
8///
9/// - ISO/IEC 23008-2 - 7.3.2.2.2
10/// - ISO/IEC 23008-2 - 7.4.3.2.2
11#[derive(Debug, Clone, PartialEq)]
12pub struct SpsRangeExtension {
13    /// Equal to `true` specifies that a rotation is applied to the residual data
14    /// block for intra 4x4 blocks coded using a transform skip operation.
15    ///
16    /// Equal to `false` specifies that this rotation is not applied.
17    pub transform_skip_rotation_enabled_flag: bool,
18    /// Equal to `true` specifies that a particular context is used for the
19    /// parsing of the `sig_coeff_flag` for transform blocks with a skipped transform.
20    ///
21    /// Equal to `false` specifies that the presence or absence of transform
22    /// skipping or a transform bypass for transform blocks is not used in the context selection for this flag.
23    pub transform_skip_context_enabled_flag: bool,
24    /// Equal to `true` specifies that the residual modification process for blocks using
25    /// a transform bypass may be used for intra blocks in the CVS.
26    ///
27    /// Equal to `false` specifies that the residual modification process is not used for intra blocks in the CVS.
28    pub implicit_rdpcm_enabled_flag: bool,
29    /// Equal to `true` specifies that the residual modification process for blocks using
30    /// a transform bypass may be used for inter blocks in the CVS.
31    ///
32    /// Equal to `false` specifies that the residual modification process is not used for inter blocks in the CVS.
33    pub explicit_rdpcm_enabled_flag: bool,
34    /// Equal to `true` specifies that an extended dynamic range is used for
35    /// transform coefficients and transform processing.
36    ///
37    /// Equal to `false` specifies that the extended dynamic range is not used.
38    ///
39    /// Defines [`CoeffMinY`](SpsRangeExtension::coeff_min_y), [`CoeffMinC`](SpsRangeExtension::coeff_min_c),
40    /// [`CoeffMaxY`](SpsRangeExtension::coeff_max_y), and [`CoeffMaxC`](SpsRangeExtension::coeff_max_c).
41    pub extended_precision_processing_flag: bool,
42    /// Equal to `true` specifies that the filtering process of neighbouring samples is
43    /// unconditionally disabled for intra prediction.
44    ///
45    /// Equal to `false` specifies that the filtering process of neighbouring samples is not disabled.
46    pub intra_smoothing_disabled_flag: bool,
47    /// Equal to `true` specifies that weighted prediction offset values are
48    /// signalled using a bit-depth-dependent precision.
49    ///
50    /// Equal to `false` specifies that weighted prediction offset values are signalled with
51    /// a precision equivalent to eight bit processing.
52    ///
53    /// Defines [`WpOffsetBdShiftY`](SpsRangeExtension::wp_offset_bd_shift_y),
54    /// [`WpOffsetBdShiftC`](SpsRangeExtension::wp_offset_bd_shift_c),
55    /// [`WpOffsetHalfRangeY`](SpsRangeExtension::wp_offset_half_range_y), and
56    /// [`WpOffsetHalfRangeC`](SpsRangeExtension::wp_offset_half_range_c).
57    pub high_precision_offsets_enabled_flag: bool,
58    /// Equal to `true` specifies that the Rice parameter derivation for the
59    /// binarization of `coeff_abs_level_remaining[]` is initialized at the start of each sub-block using mode
60    /// dependent statistics accumulated from previous sub-blocks.
61    ///
62    /// Equal to `false` specifies that no previous sub-block state is used in Rice parameter derivation.
63    pub persistent_rice_adaptation_enabled_flag: bool,
64    /// Equal to `true` specifies that a CABAC alignment process is used
65    /// prior to bypass decoding of the syntax elements `coeff_sign_flag[]` and `coeff_abs_level_remaining[]`.
66    ///
67    /// Equal to `false` specifies that no CABAC alignment process is used prior to bypass decoding.
68    pub cabac_bypass_alignment_enabled_flag: bool,
69}
70
71impl SpsRangeExtension {
72    pub(crate) fn parse<R: io::Read>(bit_reader: &mut BitReader<R>) -> io::Result<Self> {
73        Ok(Self {
74            transform_skip_rotation_enabled_flag: bit_reader.read_bit()?,
75            transform_skip_context_enabled_flag: bit_reader.read_bit()?,
76            implicit_rdpcm_enabled_flag: bit_reader.read_bit()?,
77            explicit_rdpcm_enabled_flag: bit_reader.read_bit()?,
78            extended_precision_processing_flag: bit_reader.read_bit()?,
79            intra_smoothing_disabled_flag: bit_reader.read_bit()?,
80            high_precision_offsets_enabled_flag: bit_reader.read_bit()?,
81            persistent_rice_adaptation_enabled_flag: bit_reader.read_bit()?,
82            cabac_bypass_alignment_enabled_flag: bit_reader.read_bit()?,
83        })
84    }
85
86    /// `CoeffMinY = −(1 << (extended_precision_processing_flag ? Max(15, BitDepthY + 6) : 15))` (7-27)
87    ///
88    /// ISO/IEC 23008-2 - 7.4.3.2.2
89    pub fn coeff_min_y(&self, bit_depth_y: u8) -> i64 {
90        let n = if self.extended_precision_processing_flag {
91            15.max(bit_depth_y + 6)
92        } else {
93            15
94        };
95        -(1 << n)
96    }
97
98    /// `CoeffMinC = −(1 << (extended_precision_processing_flag ? Max(15, BitDepthC + 6) : 15))` (7-28)
99    ///
100    /// ISO/IEC 23008-2 - 7.4.3.2.2
101    pub fn coeff_min_c(&self, bit_depth_c: u8) -> i64 {
102        let n = if self.extended_precision_processing_flag {
103            15.max(bit_depth_c + 6)
104        } else {
105            15
106        };
107        -(1 << n)
108    }
109
110    /// `CoeffMaxY = (1 << (extended_precision_processing_flag ? Max(15, BitDepthY + 6) : 15)) - 1` (7-29)
111    ///
112    /// ISO/IEC 23008-2 - 7.4.3.2.2
113    pub fn coeff_max_y(&self, bit_depth_y: u8) -> i64 {
114        let n = if self.extended_precision_processing_flag {
115            15.max(bit_depth_y + 6)
116        } else {
117            15
118        };
119        (1 << n) - 1
120    }
121
122    /// `CoeffMaxC = (1 << (extended_precision_processing_flag ? Max(15, BitDepthC + 6) : 15)) − 1` (7-30)
123    ///
124    /// ISO/IEC 23008-2 - 7.4.3.2.2
125    pub fn coeff_max_c(&self, bit_depth_c: u8) -> i64 {
126        let n = if self.extended_precision_processing_flag {
127            15.max(bit_depth_c + 6)
128        } else {
129            15
130        };
131        (1 << n) - 1
132    }
133
134    /// `WpOffsetBdShiftY = high_precision_offsets_enabled_flag ? 0 : (BitDepthY − 8)` (7-31)
135    ///
136    /// ISO/IEC 23008-2 - 7.4.3.2.2
137    pub fn wp_offset_bd_shift_y(&self, bit_depth_y: u8) -> i8 {
138        if self.high_precision_offsets_enabled_flag {
139            0
140        } else {
141            bit_depth_y as i8 - 8
142        }
143    }
144
145    /// `WpOffsetBdShiftC = high_precision_offsets_enabled_flag ? 0 : (BitDepthC − 8)` (7-32)
146    ///
147    /// ISO/IEC 23008-2 - 7.4.3.2.2
148    pub fn wp_offset_bd_shift_c(&self, bit_depth_c: u8) -> i8 {
149        if self.high_precision_offsets_enabled_flag {
150            0
151        } else {
152            bit_depth_c as i8 - 8
153        }
154    }
155
156    /// `WpOffsetHalfRangeY = 1 << (high_precision_offsets_enabled_flag ? (BitDepthY − 1) : 7)` (7-33)
157    ///
158    /// ISO/IEC 23008-2 - 7.4.3.2.2
159    pub fn wp_offset_half_range_y(&self, bit_depth_y: u8) -> i8 {
160        let n = if self.high_precision_offsets_enabled_flag {
161            bit_depth_y.saturating_sub(1)
162        } else {
163            7
164        };
165        1 << n
166    }
167
168    /// `WpOffsetHalfRangeC = 1 << (high_precision_offsets_enabled_flag ? (BitDepthC − 1) : 7)` (7-34)
169    ///
170    /// ISO/IEC 23008-2 - 7.4.3.2.2
171    pub fn wp_offset_half_range_c(&self, bit_depth_c: u8) -> i8 {
172        let n = if self.high_precision_offsets_enabled_flag {
173            bit_depth_c.saturating_sub(1)
174        } else {
175            7
176        };
177        1 << n
178    }
179}