1use crate::bit_reader::BitReader;
47use crate::BitstreamError;
48
49pub const BDU_SEQUENCE_HEADER: u8 = 0x0F;
52pub const BDU_ENTRY_POINT: u8 = 0x0E;
53pub const BDU_FRAME: u8 = 0x0D;
54pub const BDU_FIELD: u8 = 0x0C;
55pub const BDU_SLICE: u8 = 0x0B;
56pub const BDU_END_OF_SEQUENCE: u8 = 0x1F;
57
58pub const PROFILE_SIMPLE: u8 = 0;
61pub const PROFILE_MAIN: u8 = 1;
62pub const PROFILE_ADVANCED: u8 = 3;
63
64#[derive(Debug, Clone, Copy)]
67pub struct VcBdu<'a> {
68 pub bdu_type: u8,
69 pub payload: &'a [u8],
70}
71
72pub fn split_bdus(stream: &[u8]) -> Vec<VcBdu<'_>> {
76 let mut out = Vec::new();
77 let mut i = 0;
78 let n = stream.len();
79 let mut current: Option<(u8, usize)> = None; while i + 3 < n {
81 if stream[i] == 0 && stream[i + 1] == 0 && stream[i + 2] == 1 {
82 if let Some((t, body_start)) = current.take() {
83 out.push(VcBdu {
84 bdu_type: t,
85 payload: &stream[body_start..i],
86 });
87 }
88 let bdu_type = stream[i + 3];
89 i += 4;
90 current = Some((bdu_type, i));
91 continue;
92 }
93 i += 1;
94 }
95 if let Some((t, body_start)) = current.take() {
96 out.push(VcBdu {
97 bdu_type: t,
98 payload: &stream[body_start..n],
99 });
100 }
101 out
102}
103
104#[derive(Debug, Clone, Default, PartialEq, Eq)]
108pub struct Vc1SequenceHeader {
109 pub profile: u8,
112 pub level: u8,
113 pub colordiff_format: u8,
115 pub frmrtq_postproc: u8,
116 pub bitrtq_postproc: u8,
117 pub postprocflag: bool,
118 pub max_coded_width: u32,
121 pub max_coded_height: u32,
123 pub pulldown: bool,
124 pub interlace: bool,
125 pub tfcntrflag: bool,
126 pub finterpflag: bool,
127 pub psf: bool,
129 pub display_ext: bool,
132 pub display_horiz_size: u32,
134 pub display_vert_size: u32,
136 pub aspect_ratio_flag: bool,
137 pub aspect_ratio: u8,
138 pub aspect_horiz_size: u8,
139 pub aspect_vert_size: u8,
140 pub framerate_flag: bool,
141 pub framerateind: u8,
142 pub frameratenr: u32,
143 pub frameratedr: u8,
144 pub color_format_flag: bool,
145 pub color_primaries: u8,
146 pub transfer_char: u8,
147 pub matrix_coef: u8,
148 pub hrd_param_flag: bool,
149 pub hrd_num_leaky_buckets: u8,
150 pub hrd_bit_rate_exponent: u8,
151 pub hrd_buffer_size_exponent: u8,
152}
153
154#[derive(Debug, Clone, Default, PartialEq, Eq)]
156pub struct Vc1EntryPointHeader {
157 pub broken_link: bool,
158 pub closed_entry: bool,
159 pub panscan_flag: bool,
160 pub refdist_flag: bool,
161 pub loopfilter: bool,
162 pub fastuvmc: bool,
163 pub extended_mv: bool,
164 pub dquant: u8,
165 pub vstransform: bool,
166 pub overlap: bool,
167 pub quantizer: u8,
168 pub coded_size_flag: bool,
169 pub coded_width: u32,
173 pub coded_height: u32,
175 pub extended_dmv: bool,
176 pub range_mapy_flag: bool,
177 pub range_mapy: u8,
178 pub range_mapuv_flag: bool,
179 pub range_mapuv: u8,
180}
181
182#[derive(Debug, Clone, Default, PartialEq, Eq)]
188pub struct Vc1PictureHeader {
189 pub fcm: u8,
192 pub picture_type: u8,
197}
198
199#[derive(Debug)]
201pub struct Vc1FirstPictureParse<'a> {
202 pub sequence_header: Vc1SequenceHeader,
203 pub entry_point: Vc1EntryPointHeader,
204 pub picture_header: Vc1PictureHeader,
205 pub frame_payload: &'a [u8],
206}
207
208pub fn parse_sequence_header_advanced(bytes: &[u8]) -> Result<Vc1SequenceHeader, BitstreamError> {
214 if bytes.len() < 6 {
215 return Err(BitstreamError::unexpected_end(
216 "VC-1 sequence header shorter than 6 bytes",
217 ));
218 }
219 let mut r = BitReader::new(bytes);
220 let mut s = Vc1SequenceHeader {
221 profile: r.u(2) as u8,
222 ..Vc1SequenceHeader::default()
223 };
224 if s.profile != PROFILE_ADVANCED {
225 return Err(BitstreamError::unsupported(format!(
226 "VC-1 profile {} not supported (only Advanced/3)",
227 s.profile
228 )));
229 }
230 s.level = r.u(3) as u8;
231 s.colordiff_format = r.u(2) as u8;
232 s.frmrtq_postproc = r.u(3) as u8;
233 s.bitrtq_postproc = r.u(5) as u8;
234 s.postprocflag = r.u(1) != 0;
235 s.max_coded_width = r.u(12) + 1;
236 s.max_coded_height = r.u(12) + 1;
237 s.pulldown = r.u(1) != 0;
238 s.interlace = r.u(1) != 0;
239 s.tfcntrflag = r.u(1) != 0;
240 s.finterpflag = r.u(1) != 0;
241 let _reserved = r.u(1);
242 s.psf = r.u(1) != 0;
243 s.display_ext = r.u(1) != 0;
244 if s.display_ext {
245 s.display_horiz_size = r.u(14) + 1;
246 s.display_vert_size = r.u(14) + 1;
247 s.aspect_ratio_flag = r.u(1) != 0;
248 if s.aspect_ratio_flag {
249 s.aspect_ratio = r.u(4) as u8;
250 if s.aspect_ratio == 15 {
251 s.aspect_horiz_size = r.u(8) as u8;
252 s.aspect_vert_size = r.u(8) as u8;
253 }
254 }
255 s.framerate_flag = r.u(1) != 0;
256 if s.framerate_flag {
257 s.framerateind = r.u(1) as u8;
258 if s.framerateind == 0 {
259 s.frameratenr = r.u(8);
260 s.frameratedr = r.u(4) as u8;
261 } else {
262 s.frameratenr = r.u(16);
263 }
264 }
265 s.color_format_flag = r.u(1) != 0;
266 if s.color_format_flag {
267 s.color_primaries = r.u(8) as u8;
268 s.transfer_char = r.u(8) as u8;
269 s.matrix_coef = r.u(8) as u8;
270 }
271 }
272 s.hrd_param_flag = r.u(1) != 0;
273 if s.hrd_param_flag {
274 s.hrd_num_leaky_buckets = r.u(5) as u8;
275 s.hrd_bit_rate_exponent = r.u(4) as u8;
276 s.hrd_buffer_size_exponent = r.u(4) as u8;
277 for _ in 0..s.hrd_num_leaky_buckets {
280 let _hrd_rate = r.u(16);
281 let _hrd_buffer = r.u(16);
282 }
283 }
284 Ok(s)
285}
286
287pub fn parse_entry_point_header(
293 bytes: &[u8],
294 seq: &Vc1SequenceHeader,
295) -> Result<Vc1EntryPointHeader, BitstreamError> {
296 if bytes.is_empty() {
297 return Err(BitstreamError::unexpected_end(
298 "VC-1 entry-point header empty",
299 ));
300 }
301 let mut r = BitReader::new(bytes);
302 let mut e = Vc1EntryPointHeader {
303 broken_link: r.u(1) != 0,
304 closed_entry: r.u(1) != 0,
305 panscan_flag: r.u(1) != 0,
306 refdist_flag: r.u(1) != 0,
307 loopfilter: r.u(1) != 0,
308 fastuvmc: r.u(1) != 0,
309 extended_mv: r.u(1) != 0,
310 dquant: r.u(2) as u8,
311 vstransform: r.u(1) != 0,
312 overlap: r.u(1) != 0,
313 quantizer: r.u(2) as u8,
314 ..Vc1EntryPointHeader::default()
315 };
316 if seq.hrd_param_flag {
319 for _ in 0..seq.hrd_num_leaky_buckets {
320 let _hrd_full = r.u(8);
321 }
322 }
323 e.coded_size_flag = r.u(1) != 0;
324 if e.coded_size_flag {
325 e.coded_width = r.u(12) + 1;
326 e.coded_height = r.u(12) + 1;
327 }
328 if e.extended_mv {
329 e.extended_dmv = r.u(1) != 0;
330 }
331 e.range_mapy_flag = r.u(1) != 0;
332 if e.range_mapy_flag {
333 e.range_mapy = r.u(3) as u8;
334 }
335 e.range_mapuv_flag = r.u(1) != 0;
336 if e.range_mapuv_flag {
337 e.range_mapuv = r.u(3) as u8;
338 }
339 Ok(e)
340}
341
342pub fn parse_picture_header(
349 bytes: &[u8],
350 seq: &Vc1SequenceHeader,
351) -> Result<Vc1PictureHeader, BitstreamError> {
352 if bytes.is_empty() {
353 return Err(BitstreamError::unexpected_end("VC-1 picture header empty"));
354 }
355 let mut r = BitReader::new(bytes);
356 let mut h = Vc1PictureHeader::default();
357 if seq.interlace {
362 let fcm0 = r.u(1);
363 if fcm0 == 0 {
364 h.fcm = 0;
365 } else {
366 let fcm1 = r.u(1);
367 h.fcm = if fcm1 == 0 { 2 } else { 3 };
368 }
369 } else {
370 h.fcm = 0;
371 }
372 if h.fcm == 0 {
390 let b0 = r.u(1);
392 if b0 == 0 {
393 h.picture_type = 1; } else {
395 let b1 = r.u(1);
396 if b1 == 0 {
397 h.picture_type = 2; } else {
399 let b2 = r.u(1);
400 if b2 == 0 {
401 h.picture_type = 0; } else {
403 let b3 = r.u(1);
404 h.picture_type = if b3 == 0 { 3 } else { 4 }; }
406 }
407 }
408 } else {
409 h.picture_type = r.u(3) as u8;
411 }
412 Ok(h)
413}
414
415pub fn parse_first_picture(stream: &[u8]) -> Result<Vc1FirstPictureParse<'_>, BitstreamError> {
422 let bdus = split_bdus(stream);
423 let seq = bdus
424 .iter()
425 .find(|b| b.bdu_type == BDU_SEQUENCE_HEADER)
426 .ok_or_else(|| BitstreamError::invalid("VC-1: no sequence header BDU in stream"))?;
427 let sequence_header = parse_sequence_header_advanced(seq.payload)?;
428 let entry = bdus
429 .iter()
430 .find(|b| b.bdu_type == BDU_ENTRY_POINT)
431 .ok_or_else(|| BitstreamError::invalid("VC-1: no entry-point BDU in stream"))?;
432 let entry_point = parse_entry_point_header(entry.payload, &sequence_header)?;
433 let frame = bdus
434 .iter()
435 .find(|b| b.bdu_type == BDU_FRAME)
436 .ok_or_else(|| BitstreamError::invalid("VC-1: no frame BDU in stream"))?;
437 let picture_header = parse_picture_header(frame.payload, &sequence_header)?;
438 Ok(Vc1FirstPictureParse {
439 sequence_header,
440 entry_point,
441 picture_header,
442 frame_payload: frame.payload,
443 })
444}
445
446#[cfg(test)]
447mod tests {
448 use super::*;
449
450 #[test]
451 fn split_bdus_finds_seq_entry_frame() {
452 let stream = [
453 0,
454 0,
455 1,
456 BDU_SEQUENCE_HEADER,
457 0xaa,
458 0,
459 0,
460 1,
461 BDU_ENTRY_POINT,
462 0xbb,
463 0,
464 0,
465 1,
466 BDU_FRAME,
467 0xcc,
468 0xdd,
469 ];
470 let bdus = split_bdus(&stream);
471 assert_eq!(bdus.len(), 3);
472 assert_eq!(bdus[0].bdu_type, BDU_SEQUENCE_HEADER);
473 assert_eq!(bdus[0].payload, &[0xaa]);
474 assert_eq!(bdus[1].bdu_type, BDU_ENTRY_POINT);
475 assert_eq!(bdus[1].payload, &[0xbb]);
476 assert_eq!(bdus[2].bdu_type, BDU_FRAME);
477 assert_eq!(bdus[2].payload, &[0xcc, 0xdd]);
478 }
479
480 #[test]
481 fn parse_sequence_header_rejects_simple_profile() {
482 let buf = [0u8; 6];
484 assert!(matches!(
485 parse_sequence_header_advanced(&buf),
486 Err(BitstreamError::Unsupported(_))
487 ));
488 }
489
490 #[test]
491 fn parse_sequence_header_rejects_short_input() {
492 assert!(matches!(
493 parse_sequence_header_advanced(&[0u8; 2]),
494 Err(BitstreamError::UnexpectedEnd(_))
495 ));
496 }
497}