h264_parser/
sei.rs

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}