h264_reader/nal/sei/
mod.rs

1pub mod buffering_period;
2pub mod pic_timing;
3pub mod user_data_registered_itu_t_t35;
4
5use crate::rbsp::BitReaderError;
6use hex_slice::AsHex;
7use std::convert::TryFrom;
8use std::fmt::{Debug, Formatter};
9use std::io::BufRead;
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum HeaderType {
13    BufferingPeriod,
14    PicTiming,
15    PanScanRect,
16    FillerPayload,
17    UserDataRegisteredItuTT35,
18    UserDataUnregistered,
19    RecoveryPoint,
20    DecRefPicMarkingRepetition,
21    SparePic,
22    SceneInfo,
23    SubSeqInfo,
24    SubSeqLayerCharacteristics,
25    SubSeqCharacteristics,
26    FullFrameFreeze,
27    FullFrameFreezeRelease,
28    FullFrameSnapshot,
29    ProgressiveRefinementSegmentStart,
30    ProgressiveRefinementSegmentEnd,
31    MotionConstrainedSliceGroupSet,
32    FilmGrainCharacteristics,
33    DeblockingFilterDisplayPreference,
34    StereoVideoInfo,
35    PostFilterHint,
36    ToneMappingInfo,
37    ScalabilityInfo,
38    SubPicScalableLayer,
39    NonRequiredLayerRep,
40    PriorityLayerInfo,
41    LayersNotPresent,
42    LayerDependencyChange,
43    ScalableNesting,
44    BaseLayerTemporalHrd,
45    QualityLayerIntegrityCheck,
46    RedundantPicProperty,
47    Tl0DepRepIndex,
48    TlSwitchingPoint,
49    ParallelDecodingInfo,
50    MvcScalableNesting,
51    ViewScalabilityInfo,
52    MultiviewSceneInfo,
53    MultiviewAcquisitionInfo,
54    NonRequiredViewComponent,
55    ViewDependencyChange,
56    OperationPointsNotPresent,
57    BaseViewTemporalHrd,
58    FramePackingArrangement,
59    MultiviewViewPosition,
60    DisplayOrientation,
61    MvcdScalableNesting,
62    MvcdViewScalabilityInfo,
63    DepthRepresentationInfo,
64    ThreeDimensionalReferenceDisplaysInfo,
65    DepthTiming,
66    DepthSamplingInfo,
67    ConstrainedDepthParameterSetIdentifier,
68    GreenMetadata,
69    MasteringDisplayColourVolume,
70    ColourRemappingInfo,
71    AlternativeTransferCharacteristics,
72    AlternativeDepthInfo,
73    ReservedSeiMessage(u32),
74}
75impl HeaderType {
76    fn from_id(id: u32) -> HeaderType {
77        match id {
78            0 => HeaderType::BufferingPeriod,
79            1 => HeaderType::PicTiming,
80            2 => HeaderType::PanScanRect,
81            3 => HeaderType::FillerPayload,
82            4 => HeaderType::UserDataRegisteredItuTT35,
83            5 => HeaderType::UserDataUnregistered,
84            6 => HeaderType::RecoveryPoint,
85            7 => HeaderType::DecRefPicMarkingRepetition,
86            8 => HeaderType::SparePic,
87            9 => HeaderType::SceneInfo,
88            10 => HeaderType::SubSeqInfo,
89            11 => HeaderType::SubSeqLayerCharacteristics,
90            12 => HeaderType::SubSeqCharacteristics,
91            13 => HeaderType::FullFrameFreeze,
92            14 => HeaderType::FullFrameFreezeRelease,
93            15 => HeaderType::FullFrameSnapshot,
94            16 => HeaderType::ProgressiveRefinementSegmentStart,
95            17 => HeaderType::ProgressiveRefinementSegmentEnd,
96            18 => HeaderType::MotionConstrainedSliceGroupSet,
97            19 => HeaderType::FilmGrainCharacteristics,
98            20 => HeaderType::DeblockingFilterDisplayPreference,
99            21 => HeaderType::StereoVideoInfo,
100            22 => HeaderType::PostFilterHint,
101            23 => HeaderType::ToneMappingInfo,
102            24 => HeaderType::ScalabilityInfo,
103            25 => HeaderType::SubPicScalableLayer,
104            26 => HeaderType::NonRequiredLayerRep,
105            27 => HeaderType::PriorityLayerInfo,
106            28 => HeaderType::LayersNotPresent,
107            29 => HeaderType::LayerDependencyChange,
108            30 => HeaderType::ScalableNesting,
109            31 => HeaderType::BaseLayerTemporalHrd,
110            32 => HeaderType::QualityLayerIntegrityCheck,
111            33 => HeaderType::RedundantPicProperty,
112            34 => HeaderType::Tl0DepRepIndex,
113            35 => HeaderType::TlSwitchingPoint,
114            36 => HeaderType::ParallelDecodingInfo,
115            37 => HeaderType::MvcScalableNesting,
116            38 => HeaderType::ViewScalabilityInfo,
117            39 => HeaderType::MultiviewSceneInfo,
118            40 => HeaderType::MultiviewAcquisitionInfo,
119            41 => HeaderType::NonRequiredViewComponent,
120            42 => HeaderType::ViewDependencyChange,
121            43 => HeaderType::OperationPointsNotPresent,
122            44 => HeaderType::BaseViewTemporalHrd,
123            45 => HeaderType::FramePackingArrangement,
124            46 => HeaderType::MultiviewViewPosition,
125            47 => HeaderType::DisplayOrientation,
126            48 => HeaderType::MvcdScalableNesting,
127            49 => HeaderType::MvcdViewScalabilityInfo,
128            50 => HeaderType::DepthRepresentationInfo,
129            51 => HeaderType::ThreeDimensionalReferenceDisplaysInfo,
130            52 => HeaderType::DepthTiming,
131            53 => HeaderType::DepthSamplingInfo,
132            54 => HeaderType::ConstrainedDepthParameterSetIdentifier,
133            56 => HeaderType::GreenMetadata,
134            137 => HeaderType::MasteringDisplayColourVolume,
135            142 => HeaderType::ColourRemappingInfo,
136            147 => HeaderType::AlternativeTransferCharacteristics,
137            188 => HeaderType::AlternativeDepthInfo,
138            _ => HeaderType::ReservedSeiMessage(id),
139        }
140    }
141}
142
143/// Reader of messages in an SEI NAL.
144pub struct SeiReader<'a, R: BufRead + Clone> {
145    reader: R,
146    scratch: &'a mut Vec<u8>,
147    payloads_seen: usize,
148    done: bool,
149}
150
151impl<'a, R: BufRead + Clone> SeiReader<'a, R> {
152    pub fn from_rbsp_bytes(reader: R, scratch: &'a mut Vec<u8>) -> Self {
153        Self {
154            reader,
155            scratch,
156            payloads_seen: 0,
157            done: false,
158        }
159    }
160
161    /// Returns the next payload.
162    ///
163    /// This is unfortunately not compatible with `std::iter::Iterator` because
164    /// of lifetime constraints.
165    pub fn next(&mut self) -> Result<Option<SeiMessage<'_>>, BitReaderError> {
166        if self.done {
167            return Ok(None);
168        }
169
170        // Fused iterator: once this returns `None` or `Err`, don't try to parse
171        // again and return a strange result. (Set done preemptively then clear
172        // it on success, rather than adjust each failure path.)
173        self.done = true;
174        let payload_type = read_u32(&mut self.reader, "payload_type")?;
175
176        // If this is not the first payload, the byte we just read may actually
177        // be a rbsp_trailing_bits (which is always byte-aligned). Check for EOF.
178        if payload_type == 0x80 && self.payloads_seen > 0 {
179            let buf = self
180                .reader
181                .fill_buf()
182                .map_err(|e| BitReaderError::ReaderErrorFor("payload_type", e))?;
183            if buf.is_empty() {
184                return Ok(None);
185            }
186        }
187        let payload_type = HeaderType::from_id(payload_type);
188        let payload_len = usize::try_from(read_u32(&mut self.reader, "payload_len")?).unwrap();
189
190        // Read into scratch. We could instead directly use reader's buffer if
191        // the next chunk is long enough, or pass along a BufRead that uses
192        // something like std::io::Take, but it's probably not worth the
193        // complexity.
194        self.scratch.resize(payload_len, 0);
195        self.reader
196            .read_exact(&mut self.scratch)
197            .map_err(|e| BitReaderError::ReaderErrorFor("payload", e))?;
198
199        self.payloads_seen += 1;
200        self.done = false;
201        Ok(Some(SeiMessage {
202            payload_type,
203            payload: &self.scratch[..],
204        }))
205    }
206}
207
208#[derive(PartialEq, Eq)]
209pub struct SeiMessage<'a> {
210    pub payload_type: HeaderType,
211    pub payload: &'a [u8],
212}
213
214impl<'a> Debug for SeiMessage<'a> {
215    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
216        f.debug_struct("SeiMessage")
217            .field("payload_type", &self.payload_type)
218            .field("payload", &format!("{:02x}", self.payload.plain_hex(false)))
219            .finish()
220    }
221}
222
223/// Reads a u32 in the special `sei_message` format used for payload type and size.
224fn read_u32<R: BufRead>(reader: &mut R, name: &'static str) -> Result<u32, BitReaderError> {
225    let mut acc = 0u32;
226    loop {
227        let mut buf = [0];
228        reader
229            .read_exact(&mut buf[..])
230            .map_err(|e| BitReaderError::ReaderErrorFor(name, e))?;
231        let byte = buf[0];
232        acc = acc.checked_add(u32::from(byte)).ok_or_else(|| {
233            BitReaderError::ReaderErrorFor(
234                name,
235                std::io::Error::new(std::io::ErrorKind::InvalidData, "overflowed u32"),
236            )
237        })?;
238        if byte != 0xFF {
239            return Ok(acc);
240        }
241    }
242}
243
244#[cfg(test)]
245mod test {
246    use crate::nal::{Nal, RefNal};
247
248    use super::*;
249
250    #[test]
251    fn it_works() {
252        let data = [
253            0x06, // SEI
254            // header 1
255            0x01, // type
256            0x01, // len
257            0x01, // payload
258            // header 2
259            0x02, // type
260            0x02, // len
261            0x02, 0x02, // payload
262            0x80, // rbsp_trailing_bits
263        ];
264        let nal = RefNal::new(&data[..], &[], true);
265        let mut scratch = Vec::new();
266        let mut r = SeiReader::from_rbsp_bytes(nal.rbsp_bytes(), &mut scratch);
267        let m1 = r.next().unwrap().unwrap();
268        assert_eq!(m1.payload_type, HeaderType::PicTiming);
269        assert_eq!(m1.payload, &[0x01]);
270        let m2 = r.next().unwrap().unwrap();
271        assert_eq!(m2.payload_type, HeaderType::PanScanRect);
272        assert_eq!(m2.payload, &[0x02, 0x02]);
273        assert_eq!(r.next().unwrap(), None);
274        assert_eq!(r.next().unwrap(), None);
275    }
276}