1use crate::nal::sei::HeaderType;
2use crate::nal::sei::SeiMessage;
3use crate::nal::sps;
4use crate::rbsp::BitRead;
5use crate::rbsp::BitReader;
6use crate::rbsp::BitReaderError;
7
8#[derive(Debug)]
9pub enum PicTimingError {
10 RbspError(BitReaderError),
11 InvalidPicStructId(u8),
12}
13impl From<BitReaderError> for PicTimingError {
14 fn from(e: BitReaderError) -> Self {
15 PicTimingError::RbspError(e)
16 }
17}
18
19#[derive(Debug, Eq, PartialEq)]
20pub struct Delays {
21 cpb_removal_delay: u32,
22 dpb_output_delay: u32,
23}
24
25#[derive(Debug, Eq, PartialEq)]
26pub enum PicStructType {
27 Frame,
28 TopField,
29 BottomField,
30 TopFieldBottomField,
31 BottomFieldTopField,
32 TopFieldBottomFieldTopFieldRepeated,
33 BottomFieldTopFieldBottomFieldRepeated,
34 FrameDoubling,
35 FrameTripling,
36 Reserved(u8),
37}
38impl PicStructType {
39 fn from_id(id: u8) -> Result<PicStructType, PicTimingError> {
40 match id {
41 0 => Ok(PicStructType::Frame),
42 1 => Ok(PicStructType::TopField),
43 2 => Ok(PicStructType::BottomField),
44 3 => Ok(PicStructType::TopFieldBottomField),
45 4 => Ok(PicStructType::BottomFieldTopField),
46 5 => Ok(PicStructType::TopFieldBottomFieldTopFieldRepeated),
47 6 => Ok(PicStructType::BottomFieldTopFieldBottomFieldRepeated),
48 7 => Ok(PicStructType::FrameDoubling),
49 8 => Ok(PicStructType::FrameTripling),
50 9..=15 => Ok(PicStructType::Reserved(id)),
51 _ => Err(PicTimingError::InvalidPicStructId(id)),
52 }
53 }
54
55 fn num_clock_timestamps(&self) -> u8 {
56 match *self {
57 PicStructType::Frame => 1,
58 PicStructType::TopField => 1,
59 PicStructType::BottomField => 1,
60 PicStructType::TopFieldBottomField => 2,
61 PicStructType::BottomFieldTopField => 2,
62 PicStructType::TopFieldBottomFieldTopFieldRepeated => 3,
63 PicStructType::BottomFieldTopFieldBottomFieldRepeated => 3,
64 PicStructType::FrameDoubling => 2,
65 PicStructType::FrameTripling => 3,
66 PicStructType::Reserved(_) => 0,
67 }
68 }
69}
70
71#[derive(Debug, Eq, PartialEq)]
72pub enum CtType {
73 Progressive,
74 Interlaced,
75 Unknown,
76 Reserved,
77}
78impl CtType {
79 fn from_id(id: u8) -> CtType {
80 match id {
81 0 => CtType::Progressive,
82 1 => CtType::Interlaced,
83 2 => CtType::Unknown,
84 3 => CtType::Reserved,
85 _ => panic!("unexpected ct_type {}", id),
86 }
87 }
88}
89
90#[derive(Debug, Eq, PartialEq)]
91pub enum CountingType {
92 NoDroppingNoOffset,
94 NoDropping,
96 DroppingIndividualZero,
98 DroppingIndividualMax,
100 DroppingTwoLowest,
102 DroppingIndividual,
104 Dropping,
106 Reserved(u8),
107}
108impl CountingType {
109 fn from_id(id: u8) -> CountingType {
110 match id {
111 0 => CountingType::NoDroppingNoOffset,
112 1 => CountingType::NoDropping,
113 2 => CountingType::DroppingIndividualZero,
114 3 => CountingType::DroppingIndividualMax,
115 4 => CountingType::DroppingTwoLowest,
116 5 => CountingType::DroppingIndividual,
117 6 => CountingType::Dropping,
118 7..=31 => CountingType::Reserved(id),
119 _ => panic!("unexpected counting_type {}", id),
120 }
121 }
122}
123
124#[derive(Debug, Eq, PartialEq)]
125pub enum SecMinHour {
126 None,
127 S(u8),
128 SM(u8, u8),
129 SMH(u8, u8, u8),
130}
131impl SecMinHour {
132 pub fn seconds(&self) -> u8 {
133 match self {
134 SecMinHour::None => 0,
135 SecMinHour::S(s) => *s,
136 SecMinHour::SM(s, _) => *s,
137 SecMinHour::SMH(s, _, _) => *s,
138 }
139 }
140 pub fn minutes(&self) -> u8 {
141 match self {
142 SecMinHour::None => 0,
143 SecMinHour::S(_) => 0,
144 SecMinHour::SM(_, m) => *m,
145 SecMinHour::SMH(_, m, _) => *m,
146 }
147 }
148 pub fn hours(&self) -> u8 {
149 match self {
150 SecMinHour::None => 0,
151 SecMinHour::S(_) => 0,
152 SecMinHour::SM(_, _) => 0,
153 SecMinHour::SMH(_, _, h) => *h,
154 }
155 }
156}
157
158#[derive(Debug, Eq, PartialEq)]
159pub struct ClockTimestamp {
160 pub ct_type: CtType,
161 pub nuit_field_based_flag: bool,
162 pub counting_type: CountingType,
163 pub discontinuity_flag: bool,
164 pub cnt_dropped_flag: bool,
165 pub n_frames: u8,
166 pub smh: SecMinHour,
167 pub time_offset: Option<i32>,
168}
169impl ClockTimestamp {
170 fn read<R: BitRead>(
171 r: &mut R,
172 sps: &sps::SeqParameterSet,
173 ) -> Result<ClockTimestamp, PicTimingError> {
174 let ct_type = CtType::from_id(r.read(2, "ct_type")?);
175 let nuit_field_based_flag = r.read_bool("nuit_field_based_flag")?;
176 let counting_type = CountingType::from_id(r.read(5, "counting_type")?);
177 let full_timestamp_flag = r.read_bool("full_timestamp_flag")?;
178 let discontinuity_flag = r.read_bool("discontinuity_flag")?;
179 let cnt_dropped_flag = r.read_bool("cnt_dropped_flag")?;
180 let n_frames = r.read(8, "n_frames")?;
181 let smh = if full_timestamp_flag {
182 SecMinHour::SMH(
183 r.read(6, "seconds_value")?,
184 r.read(6, "minutes_value")?,
185 r.read(5, "hours_value")?,
186 )
187 } else if r.read_bool("seconds_flag")? {
188 let seconds = r.read(6, "seconds_value")?;
189 if r.read_bool("minutes_flag")? {
190 let minutes = r.read(6, "minutes_value")?;
191 if r.read_bool("hours_flag")? {
192 let hours = r.read(5, "hours_value")?;
193 SecMinHour::SMH(seconds, minutes, hours)
194 } else {
195 SecMinHour::SM(seconds, minutes)
196 }
197 } else {
198 SecMinHour::S(seconds)
199 }
200 } else {
201 SecMinHour::None
202 };
203 let time_offset_length = if let Some(ref vui) = sps.vui_parameters {
204 if let Some(ref hrd) = vui.nal_hrd_parameters {
205 hrd.time_offset_length
206 } else if let Some(ref hrd) = vui.vcl_hrd_parameters {
207 hrd.time_offset_length
208 } else {
209 24
210 }
211 } else {
212 24
213 };
214 let time_offset = if time_offset_length == 0 {
215 None
216 } else {
217 Some(r.read(u32::from(time_offset_length), "time_offset_length")?)
218 };
219 Ok(ClockTimestamp {
220 ct_type,
221 nuit_field_based_flag,
222 counting_type,
223 discontinuity_flag,
224 cnt_dropped_flag,
225 n_frames,
226 smh,
227 time_offset,
228 })
229 }
230}
231
232#[derive(Debug, Eq, PartialEq)]
233pub struct PicStruct {
234 pub pic_struct: PicStructType,
235 pub clock_timestamps: Vec<Option<ClockTimestamp>>,
236}
237
238#[derive(Debug, Eq, PartialEq)]
239pub struct PicTiming {
240 pub delays: Option<Delays>,
241 pub pic_struct: Option<PicStruct>,
242}
243impl PicTiming {
244 pub fn read(
248 sps: &sps::SeqParameterSet,
249 msg: &SeiMessage<'_>,
250 ) -> Result<PicTiming, PicTimingError> {
251 assert_eq!(msg.payload_type, HeaderType::PicTiming);
252 let mut r = BitReader::new(msg.payload);
253 let pic_timing = PicTiming {
254 delays: Self::read_delays(&mut r, sps)?,
255 pic_struct: Self::read_pic_struct(&mut r, sps)?,
256 };
257 r.finish_sei_payload()?;
258 Ok(pic_timing)
259 }
260
261 fn read_delays<R: BitRead>(
262 r: &mut R,
263 sps: &sps::SeqParameterSet,
264 ) -> Result<Option<Delays>, PicTimingError> {
265 Ok(if let Some(ref vui_params) = sps.vui_parameters {
266 if let Some(ref hrd) = vui_params
267 .nal_hrd_parameters
268 .as_ref()
269 .or_else(|| vui_params.nal_hrd_parameters.as_ref())
270 {
271 Some(Delays {
272 cpb_removal_delay: r.read(
273 u32::from(hrd.cpb_removal_delay_length_minus1) + 1,
274 "cpb_removal_delay",
275 )?,
276 dpb_output_delay: r.read(
277 u32::from(hrd.dpb_output_delay_length_minus1) + 1,
278 "dpb_output_delay",
279 )?,
280 })
281 } else {
282 None
283 }
284 } else {
285 None
286 })
287 }
288
289 fn read_pic_struct<R: BitRead>(
290 r: &mut R,
291 sps: &sps::SeqParameterSet,
292 ) -> Result<Option<PicStruct>, PicTimingError> {
293 Ok(if let Some(ref vui_params) = sps.vui_parameters {
294 if vui_params.pic_struct_present_flag {
295 let pic_struct = PicStructType::from_id(r.read(4, "pic_struct")?)?;
296 let clock_timestamps = Self::read_clock_timestamps(r, &pic_struct, sps)?;
297
298 Some(PicStruct {
299 pic_struct,
300 clock_timestamps,
301 })
302 } else {
303 None
304 }
305 } else {
306 None
307 })
308 }
309
310 fn read_clock_timestamps<R: BitRead>(
311 r: &mut R,
312 pic_struct: &PicStructType,
313 sps: &sps::SeqParameterSet,
314 ) -> Result<Vec<Option<ClockTimestamp>>, PicTimingError> {
315 let mut res = Vec::new();
316 for _ in 0..pic_struct.num_clock_timestamps() {
317 res.push(if r.read_bool("clock_timestamp_flag")? {
318 Some(ClockTimestamp::read(r, sps)?)
319 } else {
320 None
321 });
322 }
323 Ok(res)
324 }
325}
326#[cfg(test)]
327mod test {
328 use crate::rbsp;
329 use hex_literal::hex;
330
331 use super::*;
332
333 #[test]
334 fn parse() {
335 let sps = hex!(
338 "
339 4d 60 15 8d 8d 28 58 9d 08 00 00 0f a0 00 07 53
340 07 00 00 00 92 7c 00 00 12 4f 80 fb dc 18 00 00
341 0f 42 40 00 07 a1 20 7d ee 07 c6 0c 62 60
342 "
343 );
344 let sps = sps::SeqParameterSet::from_bits(rbsp::BitReader::new(&sps[..])).unwrap();
345 let msg = SeiMessage {
346 payload_type: HeaderType::PicTiming,
347 payload: &hex!("00 00 00 00 00 0c 72")[..],
348 };
349 let pic_timing = PicTiming::read(&sps, &msg).unwrap();
350 assert_eq!(
351 pic_timing,
352 PicTiming {
353 delays: Some(Delays {
354 cpb_removal_delay: 0,
355 dpb_output_delay: 12,
356 }),
357 pic_struct: Some(PicStruct {
358 pic_struct: PicStructType::FrameDoubling,
359 clock_timestamps: vec![None, None],
360 }),
361 }
362 );
363 }
364}