1use crate::Result;
2
3#[derive(Debug, Clone)]
4pub enum SeiPayload {
5 BufferingPeriod,
6 PicTiming,
7 PanScanRect,
8 FillerPayload,
9 UserDataRegistered,
10 UserDataUnregistered(Vec<u8>),
11 RecoveryPoint {
12 recovery_frame_cnt: u32,
13 exact_match_flag: bool,
14 broken_link_flag: bool,
15 changing_slice_group_idc: u8,
16 },
17 DecRefPicMarkingRepetition,
18 SparePic,
19 SceneInfo,
20 SubSeqInfo,
21 SubSeqLayerCharacteristics,
22 SubSeqCharacteristics,
23 FullFrameFreeze,
24 FullFrameFreezeRelease,
25 FullFrameSnapshot,
26 ProgressiveRefinementSegmentStart,
27 ProgressiveRefinementSegmentEnd,
28 MotionConstrainedSliceGroupSet,
29 FilmGrainCharacteristics,
30 DeblockingFilterDisplayPreference,
31 StereoVideoInfo,
32 PostFilterHint,
33 ToneMappingInfo,
34 ScalabilityInfo,
35 SubPicScalableLayer,
36 NonRequiredLayerRep,
37 PriorityLayerInfo,
38 LayersNotPresent,
39 LayerDependencyChange,
40 ScalableNesting,
41 BaseLayerTemporalHrd,
42 QualityLayerIntegrityCheck,
43 RedundantPicProperty,
44 Tl0DepRepIndex,
45 TlSwitchingPoint,
46 ParallelDecodingInfo,
47 MvcScalableNesting,
48 ViewScalabilityInfo,
49 MultiviewSceneInfo,
50 MultiviewAcquisitionInfo,
51 NonRequiredViewComponent,
52 ViewDependencyChange,
53 OperationPointsNotPresent,
54 BaseViewTemporalHrd,
55 FramePackingArrangement,
56 MultiviewViewPosition,
57 DisplayOrientation,
58 MvcdScalableNesting,
59 MvcdViewScalabilityInfo,
60 DepthRepresentationInfo,
61 ThreeDimensionalReferenceDisplaysInfo,
62 DepthTiming,
63 DepthSamplingInfo,
64 ConstrainedDepthParameterSetIdentifier,
65 Unknown(u32, Vec<u8>),
66}
67
68#[derive(Debug, Clone)]
69pub struct SeiMessage {
70 pub payload_type: u32,
71 pub payload_size: u32,
72 pub payload: SeiPayload,
73}
74
75impl SeiMessage {
76 pub fn parse(rbsp: &[u8]) -> Result<Vec<SeiMessage>> {
77 let mut messages = Vec::new();
78 let mut pos = 0;
79
80 while pos < rbsp.len() && rbsp[pos] != 0x80 {
81 let mut payload_type = 0u32;
82 while pos < rbsp.len() && rbsp[pos] == 0xFF {
83 payload_type += 255;
84 pos += 1;
85 }
86 if pos < rbsp.len() {
87 payload_type += rbsp[pos] as u32;
88 pos += 1;
89 }
90
91 let mut payload_size = 0u32;
92 while pos < rbsp.len() && rbsp[pos] == 0xFF {
93 payload_size += 255;
94 pos += 1;
95 }
96 if pos < rbsp.len() {
97 payload_size += rbsp[pos] as u32;
98 pos += 1;
99 }
100
101 let payload_end = (pos + payload_size as usize).min(rbsp.len());
102 let payload_data = &rbsp[pos..payload_end];
103
104 let payload = match payload_type {
105 6 => parse_recovery_point(payload_data)?,
106 5 => {
107 if payload_data.len() >= 16 {
108 SeiPayload::UserDataUnregistered(payload_data.to_vec())
109 } else {
110 SeiPayload::Unknown(payload_type, payload_data.to_vec())
111 }
112 }
113 _ => SeiPayload::Unknown(payload_type, payload_data.to_vec()),
114 };
115
116 messages.push(SeiMessage {
117 payload_type,
118 payload_size,
119 payload,
120 });
121
122 pos = payload_end;
123 }
124
125 Ok(messages)
126 }
127}
128
129fn parse_recovery_point(data: &[u8]) -> Result<SeiPayload> {
130 if data.is_empty() {
131 return Ok(SeiPayload::Unknown(6, data.to_vec()));
132 }
133
134 let mut recovery_frame_cnt = 0u32;
135 let mut pos = 0;
136
137 while pos < data.len() {
138 let byte = data[pos];
139 recovery_frame_cnt = (recovery_frame_cnt << 7) | ((byte & 0x7F) as u32);
140 pos += 1;
141 if (byte & 0x80) == 0 {
142 break;
143 }
144 }
145
146 let mut flags = 0u8;
147 if pos < data.len() {
148 flags = data[pos];
149 }
150
151 let exact_match_flag = (flags & 0x80) != 0;
152 let broken_link_flag = (flags & 0x40) != 0;
153 let changing_slice_group_idc = (flags & 0x30) >> 4;
154
155 Ok(SeiPayload::RecoveryPoint {
156 recovery_frame_cnt,
157 exact_match_flag,
158 broken_link_flag,
159 changing_slice_group_idc,
160 })
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_sei_parse_empty() {
169 let rbsp = vec![0x80];
170 let messages = SeiMessage::parse(&rbsp).unwrap();
171 assert_eq!(messages.len(), 0);
172 }
173
174 #[test]
175 fn test_sei_parse_recovery_point() {
176 let rbsp = vec![
177 0x06,
178 0x02,
179 0x00,
180 0x40,
181 0x80,
182 ];
183
184 let messages = SeiMessage::parse(&rbsp).unwrap();
185 assert_eq!(messages.len(), 1);
186 assert_eq!(messages[0].payload_type, 6);
187
188 if let SeiPayload::RecoveryPoint { recovery_frame_cnt, .. } = &messages[0].payload {
189 assert_eq!(*recovery_frame_cnt, 0);
190 } else {
191 panic!("Expected RecoveryPoint payload");
192 }
193 }
194}