1use crate::bit_reader::BitReader;
31use crate::BitstreamError;
32
33pub const OBU_RESERVED_0: u8 = 0;
37pub const OBU_SEQUENCE_HEADER: u8 = 1;
38pub const OBU_TEMPORAL_DELIMITER: u8 = 2;
39pub const OBU_FRAME_HEADER: u8 = 3;
40pub const OBU_TILE_GROUP: u8 = 4;
41pub const OBU_METADATA: u8 = 5;
42pub const OBU_FRAME: u8 = 6;
43pub const OBU_REDUNDANT_FRAME_HEADER: u8 = 7;
44pub const OBU_TILE_LIST: u8 = 8;
45pub const OBU_PADDING: u8 = 15;
46
47pub const FRAME_TYPE_KEY: u8 = 0;
51pub const FRAME_TYPE_INTER: u8 = 1;
52pub const FRAME_TYPE_INTRA_ONLY: u8 = 2;
53pub const FRAME_TYPE_SWITCH: u8 = 3;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct ObuHeader {
60 pub obu_type: u8,
61 pub extension_flag: bool,
62 pub has_size_field: bool,
63 pub temporal_id: u8,
64 pub spatial_id: u8,
65}
66
67pub fn read_obu(
79 bytes: &[u8],
80 offset: usize,
81) -> Result<(ObuHeader, usize, usize, usize), BitstreamError> {
82 if offset >= bytes.len() {
83 return Err(BitstreamError::unexpected_end(
84 "OBU offset past end of buffer",
85 ));
86 }
87 let h = bytes[offset];
88 let forbidden = (h >> 7) & 1;
89 if forbidden != 0 {
90 return Err(BitstreamError::invalid(
91 "OBU header has obu_forbidden_bit=1",
92 ));
93 }
94 let obu_type = (h >> 3) & 0xf;
95 let extension_flag = ((h >> 2) & 1) != 0;
96 let has_size_field = ((h >> 1) & 1) != 0;
97 let _reserved = h & 1;
98
99 let mut cur = offset + 1;
100 let (temporal_id, spatial_id) = if extension_flag {
101 if cur >= bytes.len() {
102 return Err(BitstreamError::unexpected_end("OBU extension byte missing"));
103 }
104 let e = bytes[cur];
105 cur += 1;
106 ((e >> 5) & 0x7, (e >> 3) & 0x3)
107 } else {
108 (0, 0)
109 };
110
111 if !has_size_field {
112 return Err(BitstreamError::unsupported(
113 "OBU without obu_has_size_field=1 (LOBF requires it)",
114 ));
115 }
116 let (size, size_len) = read_leb128(bytes, cur)?;
117 cur += size_len;
118 let payload_start = cur;
119 let payload_end = cur
120 .checked_add(size as usize)
121 .ok_or_else(|| BitstreamError::invalid("OBU size overflow"))?;
122 if payload_end > bytes.len() {
123 return Err(BitstreamError::unexpected_end(
124 "OBU payload extends past buffer end",
125 ));
126 }
127 Ok((
128 ObuHeader {
129 obu_type,
130 extension_flag,
131 has_size_field,
132 temporal_id,
133 spatial_id,
134 },
135 payload_start,
136 payload_end,
137 payload_end,
138 ))
139}
140
141pub fn read_leb128(bytes: &[u8], offset: usize) -> Result<(u64, usize), BitstreamError> {
145 let mut value: u64 = 0;
146 for i in 0..8 {
147 if offset + i >= bytes.len() {
148 return Err(BitstreamError::unexpected_end("leb128 truncated"));
149 }
150 let b = bytes[offset + i];
151 value |= ((b & 0x7f) as u64) << (i * 7);
152 if (b & 0x80) == 0 {
153 return Ok((value, i + 1));
154 }
155 }
156 Err(BitstreamError::invalid("leb128 longer than 8 bytes"))
157}
158
159pub const LEB128_MAX: u64 = (1u64 << 56) - 1;
164
165pub fn write_leb128(out: &mut Vec<u8>, value: u64) -> Result<usize, BitstreamError> {
178 if value > LEB128_MAX {
179 return Err(BitstreamError::invalid(
180 "write_leb128: value exceeds AV1 §4.10 56-bit leb128 limit",
181 ));
182 }
183 let mut v = value;
184 let mut n = 0usize;
185 loop {
186 let mut byte = (v & 0x7f) as u8;
187 v >>= 7;
188 if v != 0 {
189 byte |= 0x80;
190 out.push(byte);
191 n += 1;
192 } else {
193 out.push(byte);
194 n += 1;
195 return Ok(n);
196 }
197 }
198}
199
200pub const OBU_TYPE_MAX: u8 = 0xf;
202pub const OBU_TEMPORAL_ID_MAX: u8 = 0x7;
204pub const OBU_SPATIAL_ID_MAX: u8 = 0x3;
206
207pub fn write_obu(
235 out: &mut Vec<u8>,
236 header: ObuHeader,
237 payload: &[u8],
238) -> Result<(usize, usize), BitstreamError> {
239 if !header.has_size_field {
240 return Err(BitstreamError::invalid(
241 "write_obu: LOBF requires obu_has_size_field=1",
242 ));
243 }
244 if header.obu_type > OBU_TYPE_MAX {
245 return Err(BitstreamError::invalid(
246 "write_obu: obu_type exceeds 4-bit field",
247 ));
248 }
249 if header.extension_flag {
250 if header.temporal_id > OBU_TEMPORAL_ID_MAX {
251 return Err(BitstreamError::invalid(
252 "write_obu: temporal_id exceeds 3-bit field",
253 ));
254 }
255 if header.spatial_id > OBU_SPATIAL_ID_MAX {
256 return Err(BitstreamError::invalid(
257 "write_obu: spatial_id exceeds 2-bit field",
258 ));
259 }
260 } else if header.temporal_id != 0 || header.spatial_id != 0 {
261 return Err(BitstreamError::invalid(
265 "write_obu: temporal/spatial_id set with extension_flag=0",
266 ));
267 }
268 if payload.len() as u64 > LEB128_MAX {
269 return Err(BitstreamError::invalid(
270 "write_obu: payload length exceeds AV1 §4.10 56-bit leb128 limit",
271 ));
272 }
273
274 let start = out.len();
275 let mut h = (header.obu_type & OBU_TYPE_MAX) << 3;
278 if header.extension_flag {
279 h |= 1 << 2;
280 }
281 h |= 1 << 1;
283 out.push(h);
284 if header.extension_flag {
285 let e = ((header.temporal_id & OBU_TEMPORAL_ID_MAX) << 5)
288 | ((header.spatial_id & OBU_SPATIAL_ID_MAX) << 3);
289 out.push(e);
290 }
291 if let Err(e) = write_leb128(out, payload.len() as u64) {
296 out.truncate(start);
297 return Err(e);
298 }
299 out.extend_from_slice(payload);
300 Ok((start, out.len()))
301}
302
303#[derive(Debug, Clone, Default, PartialEq, Eq)]
308pub struct Av1ColorConfig {
309 pub bit_depth: u8,
310 pub monochrome: bool,
311 pub color_range: bool,
312 pub subsampling_x: bool,
313 pub subsampling_y: bool,
314 pub chroma_sample_position: u8,
315}
316
317#[derive(Debug, Clone, Default, PartialEq, Eq)]
319pub struct Av1SequenceHeader {
320 pub seq_profile: u8,
321 pub still_picture: bool,
322 pub reduced_still_picture_header: bool,
323
324 pub seq_level_idx_0: u8,
325 pub seq_tier_0: bool,
326 pub operating_point_idc_0: u16,
327
328 pub frame_width_bits: u8,
329 pub frame_height_bits: u8,
330 pub max_frame_width_minus_1: u32,
331 pub max_frame_height_minus_1: u32,
332
333 pub frame_id_numbers_present_flag: bool,
334 pub delta_frame_id_length_minus_2: u8,
335 pub additional_frame_id_length_minus_1: u8,
336
337 pub use_128x128_superblock: bool,
338 pub enable_filter_intra: bool,
339 pub enable_intra_edge_filter: bool,
340 pub enable_interintra_compound: bool,
341 pub enable_masked_compound: bool,
342 pub enable_warped_motion: bool,
343 pub enable_dual_filter: bool,
344 pub enable_order_hint: bool,
345 pub enable_jnt_comp: bool,
346 pub enable_ref_frame_mvs: bool,
347 pub seq_choose_screen_content_tools: bool,
348 pub seq_force_screen_content_tools: u8,
349 pub seq_choose_integer_mv: bool,
350 pub seq_force_integer_mv: u8,
351 pub order_hint_bits: u8,
352
353 pub enable_superres: bool,
354 pub enable_cdef: bool,
355 pub enable_restoration: bool,
356
357 pub color_config: Av1ColorConfig,
358 pub film_grain_params_present: bool,
359}
360
361impl Av1SequenceHeader {
362 pub fn max_frame_width(&self) -> u32 {
364 self.max_frame_width_minus_1 + 1
365 }
366
367 pub fn max_frame_height(&self) -> u32 {
369 self.max_frame_height_minus_1 + 1
370 }
371}
372
373#[derive(Debug, Clone, Default, PartialEq, Eq)]
375pub struct Av1FrameHeader {
376 pub show_existing_frame: bool,
377 pub frame_type: u8,
378 pub show_frame: bool,
379 pub showable_frame: bool,
380 pub error_resilient_mode: bool,
381 pub disable_cdf_update: bool,
382 pub allow_screen_content_tools: bool,
383 pub force_integer_mv: bool,
384 pub frame_width: u32,
385 pub frame_height: u32,
386 pub render_width: u32,
387 pub render_height: u32,
388 pub allow_intrabc: bool,
389}
390
391#[derive(Debug, Clone)]
393pub struct Av1KeyframeParse<'a> {
394 pub sequence_header: Av1SequenceHeader,
395 pub frame_header: Av1FrameHeader,
396 pub keyframe_obus: &'a [u8],
402}
403
404pub fn parse_sequence_header(payload: &[u8]) -> Result<Av1SequenceHeader, BitstreamError> {
408 let mut r = BitReader::new(payload);
409 let mut s = Av1SequenceHeader {
410 seq_profile: r.u(3) as u8,
411 ..Av1SequenceHeader::default()
412 };
413 if s.seq_profile > 2 {
414 return Err(BitstreamError::invalid(format!(
415 "invalid seq_profile={}",
416 s.seq_profile
417 )));
418 }
419 s.still_picture = r.u(1) != 0;
420 s.reduced_still_picture_header = r.u(1) != 0;
421 if s.reduced_still_picture_header && !s.still_picture {
422 return Err(BitstreamError::invalid(
423 "reduced_still_picture_header=1 with still_picture=0",
424 ));
425 }
426
427 if s.reduced_still_picture_header {
428 s.seq_level_idx_0 = r.u(5) as u8;
429 s.seq_tier_0 = false;
430 s.operating_point_idc_0 = 0;
431 } else {
432 let timing_info_present_flag = r.u(1) != 0;
433 if timing_info_present_flag {
434 let _num_units_in_display_tick = r.u(32);
436 let _time_scale = r.u(32);
437 let equal_picture_interval = r.u(1) != 0;
438 if equal_picture_interval {
439 let _num_ticks_per_picture_minus_1 = read_uvlc(&mut r)?;
440 }
441 let decoder_model_info_present_flag = r.u(1) != 0;
442 if decoder_model_info_present_flag {
443 return Err(BitstreamError::unsupported(
444 "AV1 decoder_model_info_present_flag=1 not supported",
445 ));
446 }
447 }
448 let initial_display_delay_present_flag = r.u(1) != 0;
449 let operating_points_cnt_minus_1 = r.u(5) as u8;
450 if operating_points_cnt_minus_1 > 0 {
451 return Err(BitstreamError::unsupported(
452 "AV1 operating_points_cnt_minus_1>0 not supported by minimal parser",
453 ));
454 }
455 s.operating_point_idc_0 = r.u(12) as u16;
457 s.seq_level_idx_0 = r.u(5) as u8;
458 if s.seq_level_idx_0 > 7 {
459 s.seq_tier_0 = r.u(1) != 0;
460 }
461 if initial_display_delay_present_flag {
462 let initial_display_delay_present_for_this_op = r.u(1) != 0;
463 if initial_display_delay_present_for_this_op {
464 let _initial_display_delay_minus_1 = r.u(4);
465 }
466 }
467 }
468
469 s.frame_width_bits = (r.u(4) + 1) as u8;
470 s.frame_height_bits = (r.u(4) + 1) as u8;
471 s.max_frame_width_minus_1 = r.u(s.frame_width_bits as u32);
472 s.max_frame_height_minus_1 = r.u(s.frame_height_bits as u32);
473
474 if s.reduced_still_picture_header {
475 s.frame_id_numbers_present_flag = false;
476 } else {
477 s.frame_id_numbers_present_flag = r.u(1) != 0;
478 }
479 if s.frame_id_numbers_present_flag {
480 s.delta_frame_id_length_minus_2 = r.u(4) as u8;
481 s.additional_frame_id_length_minus_1 = r.u(3) as u8;
482 }
483
484 s.use_128x128_superblock = r.u(1) != 0;
485 s.enable_filter_intra = r.u(1) != 0;
486 s.enable_intra_edge_filter = r.u(1) != 0;
487
488 if s.reduced_still_picture_header {
489 s.enable_interintra_compound = false;
490 s.enable_masked_compound = false;
491 s.enable_warped_motion = false;
492 s.enable_dual_filter = false;
493 s.enable_order_hint = false;
494 s.enable_jnt_comp = false;
495 s.enable_ref_frame_mvs = false;
496 s.seq_force_screen_content_tools = 2; s.seq_force_integer_mv = 2; s.order_hint_bits = 0;
499 } else {
500 s.enable_interintra_compound = r.u(1) != 0;
501 s.enable_masked_compound = r.u(1) != 0;
502 s.enable_warped_motion = r.u(1) != 0;
503 s.enable_dual_filter = r.u(1) != 0;
504 s.enable_order_hint = r.u(1) != 0;
505 if s.enable_order_hint {
506 s.enable_jnt_comp = r.u(1) != 0;
507 s.enable_ref_frame_mvs = r.u(1) != 0;
508 }
509 s.seq_choose_screen_content_tools = r.u(1) != 0;
510 s.seq_force_screen_content_tools = if s.seq_choose_screen_content_tools {
511 2 } else {
513 r.u(1) as u8
514 };
515 if s.seq_force_screen_content_tools > 0 {
516 s.seq_choose_integer_mv = r.u(1) != 0;
517 s.seq_force_integer_mv = if s.seq_choose_integer_mv {
518 2 } else {
520 r.u(1) as u8
521 };
522 } else {
523 s.seq_force_integer_mv = 2;
524 }
525 if s.enable_order_hint {
526 s.order_hint_bits = (r.u(3) + 1) as u8;
527 }
528 }
529
530 s.enable_superres = r.u(1) != 0;
531 s.enable_cdef = r.u(1) != 0;
532 s.enable_restoration = r.u(1) != 0;
533
534 let high_bitdepth = r.u(1) != 0;
536 if s.seq_profile == 2 && high_bitdepth {
537 let twelve_bit = r.u(1) != 0;
538 s.color_config.bit_depth = if twelve_bit { 12 } else { 10 };
539 } else {
540 s.color_config.bit_depth = if high_bitdepth { 10 } else { 8 };
541 }
542 s.color_config.monochrome = if s.seq_profile == 1 {
543 false
544 } else {
545 r.u(1) != 0
546 };
547 let color_description_present_flag = r.u(1) != 0;
548 if color_description_present_flag {
549 let _color_primaries = r.u(8);
550 let _transfer_characteristics = r.u(8);
551 let _matrix_coefficients = r.u(8);
552 }
553 if s.color_config.monochrome {
554 s.color_config.color_range = r.u(1) != 0;
555 s.color_config.subsampling_x = true;
556 s.color_config.subsampling_y = true;
557 s.color_config.chroma_sample_position = 0;
558 } else {
559 s.color_config.color_range = r.u(1) != 0;
563 if s.seq_profile == 0 {
564 s.color_config.subsampling_x = true;
565 s.color_config.subsampling_y = true;
566 } else if s.seq_profile == 1 {
567 s.color_config.subsampling_x = false;
568 s.color_config.subsampling_y = false;
569 } else {
570 if s.color_config.bit_depth == 12 {
572 s.color_config.subsampling_x = r.u(1) != 0;
573 s.color_config.subsampling_y = if s.color_config.subsampling_x {
574 r.u(1) != 0
575 } else {
576 false
577 };
578 } else {
579 s.color_config.subsampling_x = true;
580 s.color_config.subsampling_y = false;
581 }
582 }
583 if s.color_config.subsampling_x && s.color_config.subsampling_y {
584 s.color_config.chroma_sample_position = r.u(2) as u8;
585 }
586 let _separate_uv_deltas_present = r.u(1);
587 }
588 s.film_grain_params_present = r.u(1) != 0;
589 Ok(s)
591}
592
593fn read_uvlc(r: &mut BitReader<'_>) -> Result<u32, BitstreamError> {
595 let mut leading_zeros = 0u32;
596 while !r.at_end() {
597 if r.u(1) != 0 {
598 break;
599 }
600 leading_zeros += 1;
601 if leading_zeros >= 32 {
602 return Ok(u32::MAX);
604 }
605 }
606 let value = r.u(leading_zeros);
607 Ok(value + (1u32 << leading_zeros) - 1)
608}
609
610pub fn parse_frame_header(
622 payload: &[u8],
623 seq: &Av1SequenceHeader,
624) -> Result<Av1FrameHeader, BitstreamError> {
625 let mut r = BitReader::new(payload);
626 let mut fh = Av1FrameHeader::default();
627
628 if seq.reduced_still_picture_header {
629 fh.show_existing_frame = false;
630 fh.frame_type = FRAME_TYPE_KEY;
631 fh.show_frame = true;
632 fh.showable_frame = false;
633 fh.error_resilient_mode = true;
634 } else {
635 fh.show_existing_frame = r.u(1) != 0;
636 if fh.show_existing_frame {
637 return Err(BitstreamError::unsupported(
638 "AV1 show_existing_frame=1 not supported by minimal parser",
639 ));
640 }
641 fh.frame_type = r.u(2) as u8;
642 if fh.frame_type != FRAME_TYPE_KEY {
643 return Err(BitstreamError::unsupported(format!(
644 "AV1 frame_type={} not a KEY_FRAME (minimal parser is keyframe-only)",
645 fh.frame_type
646 )));
647 }
648 fh.show_frame = r.u(1) != 0;
649 if fh.show_frame {
650 fh.showable_frame = false;
652 } else {
653 fh.showable_frame = r.u(1) != 0;
654 }
655 fh.error_resilient_mode = r.u(1) != 0;
658 }
659
660 let _disable_cdf_update = r.u(1);
661 fh.disable_cdf_update = _disable_cdf_update != 0;
662
663 let allow_screen_content_tools = if seq.seq_force_screen_content_tools == 2 {
664 r.u(1) != 0
665 } else {
666 seq.seq_force_screen_content_tools != 0
667 };
668 fh.allow_screen_content_tools = allow_screen_content_tools;
669 if allow_screen_content_tools {
670 fh.force_integer_mv = if seq.seq_force_integer_mv == 2 {
671 r.u(1) != 0
672 } else {
673 seq.seq_force_integer_mv != 0
674 };
675 } else {
676 fh.force_integer_mv = false;
677 }
678
679 if seq.frame_id_numbers_present_flag {
680 let id_len = seq.additional_frame_id_length_minus_1 as u32
681 + seq.delta_frame_id_length_minus_2 as u32
682 + 3;
683 let _current_frame_id = r.u(id_len);
684 }
685
686 let frame_size_override_flag = if fh.frame_type == FRAME_TYPE_SWITCH {
687 true
688 } else if seq.reduced_still_picture_header {
689 false
690 } else {
691 r.u(1) != 0
692 };
693
694 let _order_hint = if seq.enable_order_hint {
695 r.u(seq.order_hint_bits as u32)
696 } else {
697 0
698 };
699
700 if !(fh.frame_type == FRAME_TYPE_KEY && fh.show_frame) {
703 let _primary_ref_frame = r.u(3);
704 }
705
706 if frame_size_override_flag {
708 fh.frame_width = r.u(seq.frame_width_bits as u32) + 1;
709 fh.frame_height = r.u(seq.frame_height_bits as u32) + 1;
710 } else {
711 fh.frame_width = seq.max_frame_width();
712 fh.frame_height = seq.max_frame_height();
713 }
714 if seq.enable_superres {
715 let use_superres = r.u(1) != 0;
716 if use_superres {
717 let _coded_denom = r.u(3);
719 }
720 }
721 let render_and_frame_size_different = r.u(1) != 0;
723 if render_and_frame_size_different {
724 fh.render_width = r.u(16) + 1;
725 fh.render_height = r.u(16) + 1;
726 } else {
727 fh.render_width = fh.frame_width;
728 fh.render_height = fh.frame_height;
729 }
730
731 if allow_screen_content_tools && fh.frame_type == FRAME_TYPE_KEY {
733 fh.allow_intrabc = r.u(1) != 0;
734 }
735
736 Ok(fh)
743}
744
745pub fn parse_obu_stream(bytes: &[u8]) -> Result<Av1KeyframeParse<'_>, BitstreamError> {
751 let mut offset = 0;
752 let mut sequence_header: Option<Av1SequenceHeader> = None;
753 let mut frame_header: Option<Av1FrameHeader> = None;
754 let mut keyframe_start: Option<usize> = None;
755 let mut keyframe_end: Option<usize> = None;
756 let mut last_was_frame_header = false;
757
758 while offset < bytes.len() {
759 let (h, p_start, p_end, next) = read_obu(bytes, offset)?;
760 match h.obu_type {
761 OBU_SEQUENCE_HEADER => {
762 if sequence_header.is_none() {
763 sequence_header = Some(parse_sequence_header(&bytes[p_start..p_end])?);
764 }
765 }
766 OBU_TEMPORAL_DELIMITER => {
767 }
769 OBU_FRAME => {
770 let seq = sequence_header.as_ref().ok_or_else(|| {
771 BitstreamError::invalid("OBU_FRAME without preceding sequence header")
772 })?;
773 if frame_header.is_none() {
774 let fh = parse_frame_header(&bytes[p_start..p_end], seq)?;
775 frame_header = Some(fh);
776 keyframe_start = Some(offset);
777 keyframe_end = Some(next);
778 }
779 }
780 OBU_FRAME_HEADER => {
781 let seq = sequence_header.as_ref().ok_or_else(|| {
782 BitstreamError::invalid("OBU_FRAME_HEADER without preceding sequence header")
783 })?;
784 if frame_header.is_none() {
785 let fh = parse_frame_header(&bytes[p_start..p_end], seq)?;
786 frame_header = Some(fh);
787 keyframe_start = Some(offset);
788 keyframe_end = Some(next);
789 last_was_frame_header = true;
790 }
791 }
792 OBU_TILE_GROUP => {
793 if last_was_frame_header {
794 keyframe_end = Some(next);
795 }
796 }
797 _ => {
798 last_was_frame_header = false;
801 }
802 }
803 offset = next;
804 }
805
806 let sequence_header = sequence_header
807 .ok_or_else(|| BitstreamError::invalid("stream has no sequence header OBU"))?;
808 let frame_header =
809 frame_header.ok_or_else(|| BitstreamError::invalid("stream has no key-frame OBU"))?;
810 let start = keyframe_start.expect("keyframe bounds set when frame_header set");
811 let end = keyframe_end.expect("keyframe bounds set when frame_header set");
812 Ok(Av1KeyframeParse {
813 sequence_header,
814 frame_header,
815 keyframe_obus: &bytes[start..end],
816 })
817}
818
819#[cfg(test)]
822mod tests {
823 use super::*;
824
825 #[test]
826 fn leb128_roundtrip_small_values() {
827 let bytes = [0x00, 0x01, 0x7f, 0x80, 0x01];
829 let (v0, n0) = read_leb128(&bytes, 0).unwrap();
830 assert_eq!((v0, n0), (0, 1));
831 let (v1, n1) = read_leb128(&bytes, 1).unwrap();
832 assert_eq!((v1, n1), (1, 1));
833 let (v127, n127) = read_leb128(&bytes, 2).unwrap();
834 assert_eq!((v127, n127), (127, 1));
835 let (v128, n128) = read_leb128(&bytes, 3).unwrap();
836 assert_eq!((v128, n128), (128, 2));
837 }
838
839 #[test]
840 fn write_leb128_encodes_minimal_known_values() {
841 let mut out = Vec::new();
843 assert_eq!(write_leb128(&mut out, 0).unwrap(), 1);
844 assert_eq!(out.as_slice(), &[0x00]);
845 out.clear();
846 assert_eq!(write_leb128(&mut out, 1).unwrap(), 1);
847 assert_eq!(out.as_slice(), &[0x01]);
848 out.clear();
849 assert_eq!(write_leb128(&mut out, 127).unwrap(), 1);
850 assert_eq!(out.as_slice(), &[0x7f]);
851 out.clear();
853 assert_eq!(write_leb128(&mut out, 128).unwrap(), 2);
854 assert_eq!(out.as_slice(), &[0x80, 0x01]);
855 out.clear();
857 assert_eq!(write_leb128(&mut out, 16384).unwrap(), 3);
858 assert_eq!(out.as_slice(), &[0x80, 0x80, 0x01]);
859 }
860
861 #[test]
862 fn write_leb128_appends_without_clobbering() {
863 let mut out = vec![0xAA, 0xBB];
867 let n = write_leb128(&mut out, 300).unwrap();
868 assert_eq!(out[0..2], [0xAA, 0xBB]);
869 let (val, consumed) = read_leb128(&out, 2).unwrap();
870 assert_eq!(val, 300);
871 assert_eq!(consumed, n);
872 assert_eq!(out[2..], [0xAC, 0x02]);
874 }
875
876 #[test]
877 fn write_leb128_at_maximum_value_emits_eight_bytes() {
878 let mut out = Vec::new();
879 let n = write_leb128(&mut out, LEB128_MAX).unwrap();
880 assert_eq!(n, 8);
881 assert_eq!(out.len(), 8);
882 assert_eq!(out[0..7], [0xff; 7]);
885 assert_eq!(out[7], 0x7f);
886 let (val, consumed) = read_leb128(&out, 0).unwrap();
887 assert_eq!(val, LEB128_MAX);
888 assert_eq!(consumed, 8);
889 }
890
891 #[test]
892 fn write_leb128_rejects_over_56_bits() {
893 let mut out = Vec::new();
894 let err = write_leb128(&mut out, LEB128_MAX + 1).unwrap_err();
897 assert!(
898 matches!(err, BitstreamError::InvalidData(_)),
899 "expected InvalidData, got {err:?}"
900 );
901 let err = write_leb128(&mut out, u64::MAX).unwrap_err();
903 assert!(matches!(err, BitstreamError::InvalidData(_)));
904 assert!(out.is_empty());
906 }
907
908 #[test]
909 fn write_leb128_round_trips_against_read() {
910 let cases: &[u64] = &[
913 0,
914 1,
915 127,
916 128,
917 16_383,
918 16_384,
919 2_097_151,
920 2_097_152,
921 268_435_455,
922 268_435_456,
923 34_359_738_367,
924 34_359_738_368,
925 4_398_046_511_103,
926 4_398_046_511_104,
927 562_949_953_421_311,
928 LEB128_MAX,
929 ];
930 for &v in cases {
931 let mut buf = Vec::new();
932 let n = write_leb128(&mut buf, v).unwrap();
933 assert_eq!(buf.len(), n, "writer length matches returned size");
934 let (got, consumed) = read_leb128(&buf, 0).unwrap();
935 assert_eq!(got, v, "round-trip value for {v}");
936 assert_eq!(consumed, n, "round-trip byte count for {v}");
937 }
938 }
939
940 #[test]
941 fn read_obu_decodes_temporal_delimiter() {
942 let bytes = [0x12, 0x00];
944 let (h, ps, pe, next) = read_obu(&bytes, 0).unwrap();
945 assert_eq!(h.obu_type, OBU_TEMPORAL_DELIMITER);
946 assert!(h.has_size_field);
947 assert_eq!(ps, 2);
948 assert_eq!(pe, 2);
949 assert_eq!(next, 2);
950 }
951
952 #[test]
953 fn read_obu_rejects_forbidden_bit() {
954 let bytes = [0x80, 0x00];
956 let err = read_obu(&bytes, 0).unwrap_err();
957 match err {
958 BitstreamError::InvalidData(_) => {}
959 e => panic!("expected InvalidData, got {e:?}"),
960 }
961 }
962
963 fn td_header() -> ObuHeader {
964 ObuHeader {
965 obu_type: OBU_TEMPORAL_DELIMITER,
966 extension_flag: false,
967 has_size_field: true,
968 temporal_id: 0,
969 spatial_id: 0,
970 }
971 }
972
973 #[test]
974 fn write_obu_emits_empty_temporal_delimiter_canonically() {
975 let mut out = Vec::new();
979 let (start, end) = write_obu(&mut out, td_header(), &[]).unwrap();
980 assert_eq!(start, 0);
981 assert_eq!(end, 2);
982 assert_eq!(out.as_slice(), &[0x12, 0x00]);
983 }
984
985 #[test]
986 fn write_obu_round_trips_through_read_obu() {
987 for &len in &[0usize, 1, 16, 127, 128, 1024] {
991 let payload: Vec<u8> = (0..len).map(|i| (i as u8).wrapping_mul(31)).collect();
992 let header = ObuHeader {
993 obu_type: OBU_FRAME,
994 extension_flag: false,
995 has_size_field: true,
996 temporal_id: 0,
997 spatial_id: 0,
998 };
999 let mut out = Vec::new();
1000 let (start, end) = write_obu(&mut out, header, &payload).unwrap();
1001 let (got, p_start, p_end, next) = read_obu(&out, start).unwrap();
1002 assert_eq!(got, header, "header round-trip for len={len}");
1003 assert_eq!(p_end - p_start, len);
1004 assert_eq!(&out[p_start..p_end], payload.as_slice());
1005 assert_eq!(next, end);
1006 }
1007 }
1008
1009 #[test]
1010 fn write_obu_extension_byte_round_trips_ids() {
1011 for t in 0..=OBU_TEMPORAL_ID_MAX {
1015 for s in 0..=OBU_SPATIAL_ID_MAX {
1016 let header = ObuHeader {
1017 obu_type: OBU_FRAME_HEADER,
1018 extension_flag: true,
1019 has_size_field: true,
1020 temporal_id: t,
1021 spatial_id: s,
1022 };
1023 let payload = [0xaa, 0xbb, 0xcc];
1024 let mut out = Vec::new();
1025 let (start, _end) = write_obu(&mut out, header, &payload).unwrap();
1026 let (got, p_start, p_end, _next) = read_obu(&out, start).unwrap();
1027 assert_eq!(got.temporal_id, t, "t={t} s={s}");
1028 assert_eq!(got.spatial_id, s, "t={t} s={s}");
1029 assert!(got.extension_flag);
1030 assert_eq!(&out[p_start..p_end], &payload);
1031 }
1032 }
1033 }
1034
1035 #[test]
1036 fn write_obu_appends_after_existing_prefix() {
1037 let mut out = vec![0xde, 0xad, 0xbe, 0xef];
1041 let (start, end) = write_obu(&mut out, td_header(), &[]).unwrap();
1042 assert_eq!(start, 4);
1043 assert_eq!(end, 6);
1044 assert_eq!(&out[0..4], &[0xde, 0xad, 0xbe, 0xef]);
1045 let (got, _, _, next) = read_obu(&out, start).unwrap();
1046 assert_eq!(got.obu_type, OBU_TEMPORAL_DELIMITER);
1047 assert_eq!(next, end);
1048 }
1049
1050 #[test]
1051 fn write_obu_rejects_no_size_field() {
1052 let mut h = td_header();
1053 h.has_size_field = false;
1054 let mut out = Vec::new();
1055 let err = write_obu(&mut out, h, &[]).unwrap_err();
1056 assert!(matches!(err, BitstreamError::InvalidData(_)));
1057 assert!(out.is_empty(), "rejected write must not append");
1058 }
1059
1060 #[test]
1061 fn write_obu_rejects_oversized_obu_type() {
1062 let mut h = td_header();
1063 h.obu_type = 16; let mut out = Vec::new();
1065 assert!(matches!(
1066 write_obu(&mut out, h, &[]),
1067 Err(BitstreamError::InvalidData(_))
1068 ));
1069 assert!(out.is_empty());
1070 }
1071
1072 #[test]
1073 fn write_obu_rejects_oversized_ids() {
1074 let mut h = ObuHeader {
1076 obu_type: OBU_FRAME,
1077 extension_flag: true,
1078 has_size_field: true,
1079 temporal_id: 8,
1080 spatial_id: 0,
1081 };
1082 let mut out = Vec::new();
1083 assert!(matches!(
1084 write_obu(&mut out, h, &[]),
1085 Err(BitstreamError::InvalidData(_))
1086 ));
1087 assert!(out.is_empty());
1088 h.temporal_id = 0;
1090 h.spatial_id = 4;
1091 assert!(matches!(
1092 write_obu(&mut out, h, &[]),
1093 Err(BitstreamError::InvalidData(_))
1094 ));
1095 assert!(out.is_empty());
1096 }
1097
1098 #[test]
1099 fn write_obu_rejects_nonzero_ids_without_extension_flag() {
1100 let mut h = td_header();
1105 h.temporal_id = 1;
1106 let mut out = Vec::new();
1107 assert!(matches!(
1108 write_obu(&mut out, h, &[]),
1109 Err(BitstreamError::InvalidData(_))
1110 ));
1111 assert!(out.is_empty());
1112
1113 let mut h = td_header();
1114 h.spatial_id = 1;
1115 assert!(matches!(
1116 write_obu(&mut out, h, &[]),
1117 Err(BitstreamError::InvalidData(_))
1118 ));
1119 assert!(out.is_empty());
1120 }
1121
1122 #[test]
1123 fn write_obu_accepts_max_legal_ids() {
1124 let header = ObuHeader {
1125 obu_type: OBU_TYPE_MAX,
1126 extension_flag: true,
1127 has_size_field: true,
1128 temporal_id: OBU_TEMPORAL_ID_MAX,
1129 spatial_id: OBU_SPATIAL_ID_MAX,
1130 };
1131 let mut out = Vec::new();
1132 let (start, _) = write_obu(&mut out, header, &[]).unwrap();
1133 let (got, _, _, _) = read_obu(&out, start).unwrap();
1134 assert_eq!(got, header);
1135 }
1136
1137 #[test]
1138 fn write_obu_emits_multi_byte_leb128_size() {
1139 let payload = vec![0u8; 128];
1143 let mut out = Vec::new();
1144 let (_start, end) = write_obu(&mut out, td_header(), &payload).unwrap();
1145 assert_eq!(end, 1 + 2 + 128);
1147 assert_eq!(out[0], 0x12);
1148 assert_eq!(out[1], 0x80);
1149 assert_eq!(out[2], 0x01);
1150 assert_eq!(&out[3..], payload.as_slice());
1151 }
1152
1153 #[test]
1154 fn write_obu_concatenates_into_obu_stream() {
1155 let mut out = Vec::new();
1158 let (s1, e1) = write_obu(&mut out, td_header(), &[]).unwrap();
1159 let seq_header = ObuHeader {
1160 obu_type: OBU_SEQUENCE_HEADER,
1161 extension_flag: false,
1162 has_size_field: true,
1163 temporal_id: 0,
1164 spatial_id: 0,
1165 };
1166 let seq_payload = [0x11, 0x22, 0x33, 0x44];
1167 let (s2, e2) = write_obu(&mut out, seq_header, &seq_payload).unwrap();
1168 assert_eq!(s2, e1, "second OBU starts where the first ended");
1169 assert_eq!(e2, out.len());
1170
1171 let (h1, _, _, n1) = read_obu(&out, s1).unwrap();
1172 assert_eq!(h1.obu_type, OBU_TEMPORAL_DELIMITER);
1173 assert_eq!(n1, s2);
1174 let (h2, ps2, pe2, n2) = read_obu(&out, n1).unwrap();
1175 assert_eq!(h2.obu_type, OBU_SEQUENCE_HEADER);
1176 assert_eq!(&out[ps2..pe2], &seq_payload);
1177 assert_eq!(n2, e2);
1178 }
1179}