1pub mod buffering_period;
2pub mod pic_timing;
3pub mod recovery_point;
4pub mod user_data_registered_itu_t_t35;
5pub mod user_data_unregistered;
6
7use crate::rbsp::BitReaderError;
8use hex_slice::AsHex;
9use std::fmt::{Debug, Formatter};
10use std::io::BufRead;
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum HeaderType {
14 BufferingPeriod,
15 PicTiming,
16 PanScanRect,
17 FillerPayload,
18 UserDataRegisteredItuTT35,
19 UserDataUnregistered,
20 RecoveryPoint,
21 DecRefPicMarkingRepetition,
22 SparePic,
23 SceneInfo,
24 SubSeqInfo,
25 SubSeqLayerCharacteristics,
26 SubSeqCharacteristics,
27 FullFrameFreeze,
28 FullFrameFreezeRelease,
29 FullFrameSnapshot,
30 ProgressiveRefinementSegmentStart,
31 ProgressiveRefinementSegmentEnd,
32 MotionConstrainedSliceGroupSet,
33 FilmGrainCharacteristics,
34 DeblockingFilterDisplayPreference,
35 StereoVideoInfo,
36 PostFilterHint,
37 ToneMappingInfo,
38 ScalabilityInfo,
39 SubPicScalableLayer,
40 NonRequiredLayerRep,
41 PriorityLayerInfo,
42 LayersNotPresent,
43 LayerDependencyChange,
44 ScalableNesting,
45 BaseLayerTemporalHrd,
46 QualityLayerIntegrityCheck,
47 RedundantPicProperty,
48 Tl0DepRepIndex,
49 TlSwitchingPoint,
50 ParallelDecodingInfo,
51 MvcScalableNesting,
52 ViewScalabilityInfo,
53 MultiviewSceneInfo,
54 MultiviewAcquisitionInfo,
55 NonRequiredViewComponent,
56 ViewDependencyChange,
57 OperationPointsNotPresent,
58 BaseViewTemporalHrd,
59 FramePackingArrangement,
60 MultiviewViewPosition,
61 DisplayOrientation,
62 MvcdScalableNesting,
63 MvcdViewScalabilityInfo,
64 DepthRepresentationInfo,
65 ThreeDimensionalReferenceDisplaysInfo,
66 DepthTiming,
67 DepthSamplingInfo,
68 ConstrainedDepthParameterSetIdentifier,
69 GreenMetadata,
70 MasteringDisplayColourVolume,
71 ColourRemappingInfo,
72 AlternativeTransferCharacteristics,
73 AlternativeDepthInfo,
74 ReservedSeiMessage(u32),
75}
76impl HeaderType {
77 fn from_id(id: u32) -> HeaderType {
78 match id {
79 0 => HeaderType::BufferingPeriod,
80 1 => HeaderType::PicTiming,
81 2 => HeaderType::PanScanRect,
82 3 => HeaderType::FillerPayload,
83 4 => HeaderType::UserDataRegisteredItuTT35,
84 5 => HeaderType::UserDataUnregistered,
85 6 => HeaderType::RecoveryPoint,
86 7 => HeaderType::DecRefPicMarkingRepetition,
87 8 => HeaderType::SparePic,
88 9 => HeaderType::SceneInfo,
89 10 => HeaderType::SubSeqInfo,
90 11 => HeaderType::SubSeqLayerCharacteristics,
91 12 => HeaderType::SubSeqCharacteristics,
92 13 => HeaderType::FullFrameFreeze,
93 14 => HeaderType::FullFrameFreezeRelease,
94 15 => HeaderType::FullFrameSnapshot,
95 16 => HeaderType::ProgressiveRefinementSegmentStart,
96 17 => HeaderType::ProgressiveRefinementSegmentEnd,
97 18 => HeaderType::MotionConstrainedSliceGroupSet,
98 19 => HeaderType::FilmGrainCharacteristics,
99 20 => HeaderType::DeblockingFilterDisplayPreference,
100 21 => HeaderType::StereoVideoInfo,
101 22 => HeaderType::PostFilterHint,
102 23 => HeaderType::ToneMappingInfo,
103 24 => HeaderType::ScalabilityInfo,
104 25 => HeaderType::SubPicScalableLayer,
105 26 => HeaderType::NonRequiredLayerRep,
106 27 => HeaderType::PriorityLayerInfo,
107 28 => HeaderType::LayersNotPresent,
108 29 => HeaderType::LayerDependencyChange,
109 30 => HeaderType::ScalableNesting,
110 31 => HeaderType::BaseLayerTemporalHrd,
111 32 => HeaderType::QualityLayerIntegrityCheck,
112 33 => HeaderType::RedundantPicProperty,
113 34 => HeaderType::Tl0DepRepIndex,
114 35 => HeaderType::TlSwitchingPoint,
115 36 => HeaderType::ParallelDecodingInfo,
116 37 => HeaderType::MvcScalableNesting,
117 38 => HeaderType::ViewScalabilityInfo,
118 39 => HeaderType::MultiviewSceneInfo,
119 40 => HeaderType::MultiviewAcquisitionInfo,
120 41 => HeaderType::NonRequiredViewComponent,
121 42 => HeaderType::ViewDependencyChange,
122 43 => HeaderType::OperationPointsNotPresent,
123 44 => HeaderType::BaseViewTemporalHrd,
124 45 => HeaderType::FramePackingArrangement,
125 46 => HeaderType::MultiviewViewPosition,
126 47 => HeaderType::DisplayOrientation,
127 48 => HeaderType::MvcdScalableNesting,
128 49 => HeaderType::MvcdViewScalabilityInfo,
129 50 => HeaderType::DepthRepresentationInfo,
130 51 => HeaderType::ThreeDimensionalReferenceDisplaysInfo,
131 52 => HeaderType::DepthTiming,
132 53 => HeaderType::DepthSamplingInfo,
133 54 => HeaderType::ConstrainedDepthParameterSetIdentifier,
134 56 => HeaderType::GreenMetadata,
135 137 => HeaderType::MasteringDisplayColourVolume,
136 142 => HeaderType::ColourRemappingInfo,
137 147 => HeaderType::AlternativeTransferCharacteristics,
138 188 => HeaderType::AlternativeDepthInfo,
139 _ => HeaderType::ReservedSeiMessage(id),
140 }
141 }
142}
143
144const MAX_SEI_PAYLOAD_LEN: u32 = 1024 * 1024;
148
149pub struct SeiReader<'a, R: BufRead + Clone> {
151 reader: R,
152 scratch: &'a mut Vec<u8>,
153 payloads_seen: usize,
154 done: bool,
155}
156
157impl<'a, R: BufRead + Clone> SeiReader<'a, R> {
158 pub fn from_rbsp_bytes(reader: R, scratch: &'a mut Vec<u8>) -> Self {
159 Self {
160 reader,
161 scratch,
162 payloads_seen: 0,
163 done: false,
164 }
165 }
166
167 pub fn next(&mut self) -> Result<Option<SeiMessage<'_>>, BitReaderError> {
172 if self.done {
173 return Ok(None);
174 }
175
176 self.done = true;
180 let payload_type = read_u32(&mut self.reader, "payload_type")?;
181
182 if payload_type == 0x80 && self.payloads_seen > 0 {
185 let buf = self
186 .reader
187 .fill_buf()
188 .map_err(|e| BitReaderError::ReaderError("payload_type", e))?;
189 if buf.is_empty() {
190 return Ok(None);
191 }
192 }
193 let payload_type = HeaderType::from_id(payload_type);
194 let payload_len = read_u32(&mut self.reader, "payload_len")?;
195 if payload_len > MAX_SEI_PAYLOAD_LEN {
196 return Err(BitReaderError::ReaderError(
197 "payload_len",
198 std::io::Error::new(
199 std::io::ErrorKind::InvalidData,
200 "SEI payload length exceeds 1 MB limit",
201 ),
202 ));
203 }
204 let payload_len = payload_len as usize;
205
206 self.scratch.resize(payload_len, 0);
211 self.reader
212 .read_exact(&mut self.scratch)
213 .map_err(|e| BitReaderError::ReaderError("payload", e))?;
214
215 self.payloads_seen += 1;
216 self.done = false;
217 Ok(Some(SeiMessage {
218 payload_type,
219 payload: &self.scratch[..],
220 }))
221 }
222}
223
224#[derive(PartialEq, Eq)]
225pub struct SeiMessage<'a> {
226 pub payload_type: HeaderType,
227 pub payload: &'a [u8],
228}
229
230impl<'a> Debug for SeiMessage<'a> {
231 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
232 f.debug_struct("SeiMessage")
233 .field("payload_type", &self.payload_type)
234 .field("payload", &format!("{:02x}", self.payload.plain_hex(false)))
235 .finish()
236 }
237}
238
239fn read_u32<R: BufRead>(reader: &mut R, name: &'static str) -> Result<u32, BitReaderError> {
241 let mut acc = 0u32;
242 loop {
243 let mut buf = [0];
244 reader
245 .read_exact(&mut buf[..])
246 .map_err(|e| BitReaderError::ReaderError(name, e))?;
247 let byte = buf[0];
248 acc = acc.checked_add(u32::from(byte)).ok_or_else(|| {
249 BitReaderError::ReaderError(
250 name,
251 std::io::Error::new(std::io::ErrorKind::InvalidData, "overflowed u32"),
252 )
253 })?;
254 if byte != 0xFF {
255 return Ok(acc);
256 }
257 }
258}
259
260#[cfg(test)]
261mod test {
262 use crate::nal::{Nal, RefNal};
263
264 use super::*;
265
266 #[test]
267 fn it_works() {
268 let data = [
269 0x06, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x80, ];
280 let nal = RefNal::new(&data[..], &[], true);
281 let mut scratch = Vec::new();
282 let mut r = SeiReader::from_rbsp_bytes(nal.rbsp_bytes(), &mut scratch);
283 let m1 = r.next().unwrap().unwrap();
284 assert_eq!(m1.payload_type, HeaderType::PicTiming);
285 assert_eq!(m1.payload, &[0x01]);
286 let m2 = r.next().unwrap().unwrap();
287 assert_eq!(m2.payload_type, HeaderType::PanScanRect);
288 assert_eq!(m2.payload, &[0x02, 0x02]);
289 assert_eq!(r.next().unwrap(), None);
290 assert_eq!(r.next().unwrap(), None);
291 }
292}