1use bytes::{Buf, Bytes};
12
13use crate::error::{MediaError, Result};
14use crate::media::fourcc::VideoFourCc;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[repr(u8)]
19pub enum VideoPacketType {
20 SequenceStart = 0,
22 CodedFrames = 1,
24 SequenceEnd = 2,
26 CodedFramesX = 3,
28 Metadata = 4,
30 Mpeg2TsSequenceStart = 5,
32 Multitrack = 6,
34 ModEx = 7,
36}
37
38impl VideoPacketType {
39 pub fn from_byte(b: u8) -> Option<Self> {
41 match b & 0x0F {
42 0 => Some(VideoPacketType::SequenceStart),
43 1 => Some(VideoPacketType::CodedFrames),
44 2 => Some(VideoPacketType::SequenceEnd),
45 3 => Some(VideoPacketType::CodedFramesX),
46 4 => Some(VideoPacketType::Metadata),
47 5 => Some(VideoPacketType::Mpeg2TsSequenceStart),
48 6 => Some(VideoPacketType::Multitrack),
49 7 => Some(VideoPacketType::ModEx),
50 _ => None,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59#[repr(u8)]
60pub enum ExVideoFrameType {
61 Keyframe = 1,
63 InterFrame = 2,
65 DisposableInterFrame = 3,
67 GeneratedKeyframe = 4,
69 CommandFrame = 5,
71}
72
73impl ExVideoFrameType {
74 pub fn from_byte(b: u8) -> Option<Self> {
76 match (b >> 4) & 0x07 {
77 1 => Some(ExVideoFrameType::Keyframe),
78 2 => Some(ExVideoFrameType::InterFrame),
79 3 => Some(ExVideoFrameType::DisposableInterFrame),
80 4 => Some(ExVideoFrameType::GeneratedKeyframe),
81 5 => Some(ExVideoFrameType::CommandFrame),
82 _ => None,
83 }
84 }
85
86 pub fn is_keyframe(&self) -> bool {
88 matches!(
89 self,
90 ExVideoFrameType::Keyframe | ExVideoFrameType::GeneratedKeyframe
91 )
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97#[repr(u8)]
98pub enum AvMultitrackType {
99 OneTrack = 0,
101 ManyTracks = 1,
103 ManyTracksManyCodecs = 2,
105}
106
107impl AvMultitrackType {
108 pub fn from_byte(b: u8) -> Option<Self> {
110 match b {
111 0 => Some(AvMultitrackType::OneTrack),
112 1 => Some(AvMultitrackType::ManyTracks),
113 2 => Some(AvMultitrackType::ManyTracksManyCodecs),
114 _ => None,
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
121pub enum EnhancedVideoData {
122 SequenceHeader {
124 codec: VideoFourCc,
126 frame_type: ExVideoFrameType,
128 config: Bytes,
130 },
131
132 Frame {
134 codec: VideoFourCc,
136 frame_type: ExVideoFrameType,
138 composition_time: i32,
140 data: Bytes,
142 },
143
144 SequenceEnd {
146 codec: VideoFourCc,
148 },
149
150 Metadata {
152 data: Bytes,
154 },
155
156 Multitrack {
158 multitrack_type: AvMultitrackType,
160 tracks: Vec<VideoTrack>,
162 },
163}
164
165#[derive(Debug, Clone)]
167pub struct VideoTrack {
168 pub track_id: u8,
170 pub codec: VideoFourCc,
172 pub data: EnhancedVideoTrackData,
174}
175
176#[derive(Debug, Clone)]
178pub enum EnhancedVideoTrackData {
179 SequenceHeader { config: Bytes },
181 Frame {
183 frame_type: ExVideoFrameType,
184 composition_time: i32,
185 data: Bytes,
186 },
187 SequenceEnd,
189}
190
191impl EnhancedVideoData {
192 #[inline]
194 pub fn is_enhanced(first_byte: u8) -> bool {
195 (first_byte & 0x80) != 0
196 }
197
198 pub fn parse(data: Bytes) -> Result<Self> {
202 if data.is_empty() {
203 return Err(MediaError::InvalidEnhancedVideoPacket.into());
204 }
205
206 let first_byte = data[0];
207
208 if !Self::is_enhanced(first_byte) {
210 return Err(MediaError::InvalidEnhancedVideoPacket.into());
211 }
212
213 let frame_type = ExVideoFrameType::from_byte(first_byte)
214 .ok_or(MediaError::InvalidEnhancedVideoPacket)?;
215
216 let packet_type =
217 VideoPacketType::from_byte(first_byte).ok_or(MediaError::InvalidEnhancedVideoPacket)?;
218
219 let mut cursor = data.slice(1..);
220
221 match packet_type {
223 VideoPacketType::ModEx => {
224 Self::parse_with_modex(cursor, frame_type)
227 }
228 VideoPacketType::Multitrack => Self::parse_multitrack(cursor, frame_type),
229 VideoPacketType::Metadata => Ok(EnhancedVideoData::Metadata { data: cursor }),
230 _ => {
231 if cursor.len() < 4 {
233 return Err(MediaError::InvalidEnhancedVideoPacket.into());
234 }
235
236 let fourcc_bytes = [cursor[0], cursor[1], cursor[2], cursor[3]];
237 let codec = VideoFourCc::from_bytes(&fourcc_bytes)
238 .ok_or(MediaError::UnsupportedVideoCodec)?;
239 cursor.advance(4);
240
241 Self::parse_by_packet_type(packet_type, codec, frame_type, cursor)
242 }
243 }
244 }
245
246 fn parse_with_modex(mut data: Bytes, frame_type: ExVideoFrameType) -> Result<Self> {
248 if data.is_empty() {
253 return Err(MediaError::InvalidEnhancedVideoPacket.into());
254 }
255
256 let modex_type = data[0];
257 data.advance(1);
258
259 if modex_type == 0 {
261 if data.len() < 3 {
262 return Err(MediaError::InvalidEnhancedVideoPacket.into());
263 }
264 data.advance(3);
266 }
267
268 if data.len() < 4 {
270 return Err(MediaError::InvalidEnhancedVideoPacket.into());
271 }
272
273 let fourcc_bytes = [data[0], data[1], data[2], data[3]];
275 if let Some(codec) = VideoFourCc::from_bytes(&fourcc_bytes) {
276 data.advance(4);
277 Ok(EnhancedVideoData::Frame {
279 codec,
280 frame_type,
281 composition_time: 0,
282 data,
283 })
284 } else {
285 Err(MediaError::InvalidEnhancedVideoPacket.into())
286 }
287 }
288
289 fn parse_multitrack(mut data: Bytes, _frame_type: ExVideoFrameType) -> Result<Self> {
291 if data.is_empty() {
292 return Err(MediaError::InvalidEnhancedVideoPacket.into());
293 }
294
295 let multitrack_byte = data[0];
296 data.advance(1);
297
298 let multitrack_type = AvMultitrackType::from_byte(multitrack_byte >> 4)
299 .ok_or(MediaError::InvalidEnhancedVideoPacket)?;
300 let packet_type = VideoPacketType::from_byte(multitrack_byte)
301 .ok_or(MediaError::InvalidEnhancedVideoPacket)?;
302
303 let mut tracks = Vec::new();
304
305 match multitrack_type {
306 AvMultitrackType::OneTrack => {
307 if data.len() < 5 {
309 return Err(MediaError::InvalidEnhancedVideoPacket.into());
310 }
311 let track_id = data[0];
312 data.advance(1);
313
314 let fourcc_bytes = [data[0], data[1], data[2], data[3]];
315 let codec = VideoFourCc::from_bytes(&fourcc_bytes)
316 .ok_or(MediaError::UnsupportedVideoCodec)?;
317 data.advance(4);
318
319 let track_data = Self::parse_track_data(packet_type, &mut data)?;
320 tracks.push(VideoTrack {
321 track_id,
322 codec,
323 data: track_data,
324 });
325 }
326 AvMultitrackType::ManyTracks => {
327 if data.len() < 4 {
329 return Err(MediaError::InvalidEnhancedVideoPacket.into());
330 }
331 let fourcc_bytes = [data[0], data[1], data[2], data[3]];
332 let codec = VideoFourCc::from_bytes(&fourcc_bytes)
333 .ok_or(MediaError::UnsupportedVideoCodec)?;
334 data.advance(4);
335
336 while !data.is_empty() {
338 if data.len() < 4 {
339 break;
340 }
341 let track_id = data[0];
342 data.advance(1);
343
344 let track_size =
345 ((data[0] as usize) << 16) | ((data[1] as usize) << 8) | (data[2] as usize);
346 data.advance(3);
347
348 if data.len() < track_size {
349 break;
350 }
351 let track_bytes = data.slice(..track_size);
352 data.advance(track_size);
353
354 tracks.push(VideoTrack {
355 track_id,
356 codec,
357 data: EnhancedVideoTrackData::Frame {
358 frame_type: ExVideoFrameType::InterFrame, composition_time: 0,
360 data: track_bytes,
361 },
362 });
363 }
364 }
365 AvMultitrackType::ManyTracksManyCodecs => {
366 while !data.is_empty() {
368 if data.len() < 8 {
369 break;
370 }
371 let track_id = data[0];
372 data.advance(1);
373
374 let fourcc_bytes = [data[0], data[1], data[2], data[3]];
375 let codec = VideoFourCc::from_bytes(&fourcc_bytes)
376 .ok_or(MediaError::UnsupportedVideoCodec)?;
377 data.advance(4);
378
379 let track_size =
380 ((data[0] as usize) << 16) | ((data[1] as usize) << 8) | (data[2] as usize);
381 data.advance(3);
382
383 if data.len() < track_size {
384 break;
385 }
386 let track_bytes = data.slice(..track_size);
387 data.advance(track_size);
388
389 tracks.push(VideoTrack {
390 track_id,
391 codec,
392 data: EnhancedVideoTrackData::Frame {
393 frame_type: ExVideoFrameType::InterFrame,
394 composition_time: 0,
395 data: track_bytes,
396 },
397 });
398 }
399 }
400 }
401
402 Ok(EnhancedVideoData::Multitrack {
403 multitrack_type,
404 tracks,
405 })
406 }
407
408 fn parse_track_data(
410 packet_type: VideoPacketType,
411 data: &mut Bytes,
412 ) -> Result<EnhancedVideoTrackData> {
413 match packet_type {
414 VideoPacketType::SequenceStart => Ok(EnhancedVideoTrackData::SequenceHeader {
415 config: data.clone(),
416 }),
417 VideoPacketType::SequenceEnd => Ok(EnhancedVideoTrackData::SequenceEnd),
418 VideoPacketType::CodedFramesX => Ok(EnhancedVideoTrackData::Frame {
419 frame_type: ExVideoFrameType::InterFrame,
420 composition_time: 0,
421 data: data.clone(),
422 }),
423 VideoPacketType::CodedFrames => {
424 if data.len() < 3 {
425 return Err(MediaError::InvalidEnhancedVideoPacket.into());
426 }
427 let ct = read_si24(data)?;
428 Ok(EnhancedVideoTrackData::Frame {
429 frame_type: ExVideoFrameType::InterFrame,
430 composition_time: ct,
431 data: data.clone(),
432 })
433 }
434 _ => Err(MediaError::InvalidEnhancedVideoPacket.into()),
435 }
436 }
437
438 fn parse_by_packet_type(
440 packet_type: VideoPacketType,
441 codec: VideoFourCc,
442 frame_type: ExVideoFrameType,
443 mut data: Bytes,
444 ) -> Result<Self> {
445 match packet_type {
446 VideoPacketType::SequenceStart => Ok(EnhancedVideoData::SequenceHeader {
447 codec,
448 frame_type,
449 config: data,
450 }),
451 VideoPacketType::SequenceEnd => Ok(EnhancedVideoData::SequenceEnd { codec }),
452 VideoPacketType::CodedFramesX => {
453 Ok(EnhancedVideoData::Frame {
455 codec,
456 frame_type,
457 composition_time: 0,
458 data,
459 })
460 }
461 VideoPacketType::CodedFrames => {
462 if data.len() < 3 {
464 return Err(MediaError::InvalidEnhancedVideoPacket.into());
465 }
466 let composition_time = read_si24(&mut data)?;
467 Ok(EnhancedVideoData::Frame {
468 codec,
469 frame_type,
470 composition_time,
471 data,
472 })
473 }
474 VideoPacketType::Mpeg2TsSequenceStart => {
475 Ok(EnhancedVideoData::SequenceHeader {
477 codec,
478 frame_type,
479 config: data,
480 })
481 }
482 _ => Err(MediaError::InvalidEnhancedVideoPacket.into()),
483 }
484 }
485
486 pub fn is_keyframe(&self) -> bool {
488 match self {
489 EnhancedVideoData::SequenceHeader { frame_type, .. } => frame_type.is_keyframe(),
490 EnhancedVideoData::Frame { frame_type, .. } => frame_type.is_keyframe(),
491 EnhancedVideoData::SequenceEnd { .. } => false,
492 EnhancedVideoData::Metadata { .. } => false,
493 EnhancedVideoData::Multitrack { .. } => false, }
495 }
496
497 pub fn is_sequence_header(&self) -> bool {
499 matches!(self, EnhancedVideoData::SequenceHeader { .. })
500 }
501
502 pub fn codec(&self) -> Option<VideoFourCc> {
504 match self {
505 EnhancedVideoData::SequenceHeader { codec, .. } => Some(*codec),
506 EnhancedVideoData::Frame { codec, .. } => Some(*codec),
507 EnhancedVideoData::SequenceEnd { codec } => Some(*codec),
508 EnhancedVideoData::Metadata { .. } => None,
509 EnhancedVideoData::Multitrack { .. } => None,
510 }
511 }
512}
513
514fn read_si24(data: &mut Bytes) -> Result<i32> {
516 if data.len() < 3 {
517 return Err(MediaError::InvalidEnhancedVideoPacket.into());
518 }
519
520 let b0 = data.get_u8() as i32;
521 let b1 = data.get_u8() as i32;
522 let b2 = data.get_u8() as i32;
523
524 let value = (b0 << 16) | (b1 << 8) | b2;
525
526 if value & 0x800000 != 0 {
528 Ok(value | !0xFFFFFF)
529 } else {
530 Ok(value)
531 }
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537
538 #[test]
539 fn test_is_enhanced() {
540 assert!(EnhancedVideoData::is_enhanced(0x80));
542 assert!(EnhancedVideoData::is_enhanced(0x90));
543 assert!(EnhancedVideoData::is_enhanced(0xFF));
544
545 assert!(!EnhancedVideoData::is_enhanced(0x17)); assert!(!EnhancedVideoData::is_enhanced(0x27)); assert!(!EnhancedVideoData::is_enhanced(0x00));
549 }
550
551 #[test]
552 fn test_video_packet_type_parsing() {
553 assert_eq!(
554 VideoPacketType::from_byte(0x80),
555 Some(VideoPacketType::SequenceStart)
556 );
557 assert_eq!(
558 VideoPacketType::from_byte(0x81),
559 Some(VideoPacketType::CodedFrames)
560 );
561 assert_eq!(
562 VideoPacketType::from_byte(0x82),
563 Some(VideoPacketType::SequenceEnd)
564 );
565 assert_eq!(
566 VideoPacketType::from_byte(0x83),
567 Some(VideoPacketType::CodedFramesX)
568 );
569 assert_eq!(
570 VideoPacketType::from_byte(0x84),
571 Some(VideoPacketType::Metadata)
572 );
573 assert_eq!(
574 VideoPacketType::from_byte(0x85),
575 Some(VideoPacketType::Mpeg2TsSequenceStart)
576 );
577 assert_eq!(
578 VideoPacketType::from_byte(0x86),
579 Some(VideoPacketType::Multitrack)
580 );
581 assert_eq!(
582 VideoPacketType::from_byte(0x87),
583 Some(VideoPacketType::ModEx)
584 );
585
586 assert_eq!(VideoPacketType::from_byte(0x88), None);
588 assert_eq!(VideoPacketType::from_byte(0x8F), None);
589 }
590
591 #[test]
592 fn test_ex_video_frame_type_parsing() {
593 assert_eq!(
595 ExVideoFrameType::from_byte(0x90),
596 Some(ExVideoFrameType::Keyframe)
597 ); assert_eq!(
599 ExVideoFrameType::from_byte(0xA0),
600 Some(ExVideoFrameType::InterFrame)
601 ); assert_eq!(
603 ExVideoFrameType::from_byte(0xB0),
604 Some(ExVideoFrameType::DisposableInterFrame)
605 );
606 assert_eq!(
607 ExVideoFrameType::from_byte(0xC0),
608 Some(ExVideoFrameType::GeneratedKeyframe)
609 );
610 assert_eq!(
611 ExVideoFrameType::from_byte(0xD0),
612 Some(ExVideoFrameType::CommandFrame)
613 );
614
615 assert_eq!(ExVideoFrameType::from_byte(0x80), None);
617 assert_eq!(ExVideoFrameType::from_byte(0xE0), None);
619 assert_eq!(ExVideoFrameType::from_byte(0xF0), None);
620 }
621
622 #[test]
623 fn test_frame_type_is_keyframe() {
624 assert!(ExVideoFrameType::Keyframe.is_keyframe());
625 assert!(ExVideoFrameType::GeneratedKeyframe.is_keyframe());
626 assert!(!ExVideoFrameType::InterFrame.is_keyframe());
627 assert!(!ExVideoFrameType::DisposableInterFrame.is_keyframe());
628 assert!(!ExVideoFrameType::CommandFrame.is_keyframe());
629 }
630
631 #[test]
632 fn test_multitrack_type_parsing() {
633 assert_eq!(
634 AvMultitrackType::from_byte(0),
635 Some(AvMultitrackType::OneTrack)
636 );
637 assert_eq!(
638 AvMultitrackType::from_byte(1),
639 Some(AvMultitrackType::ManyTracks)
640 );
641 assert_eq!(
642 AvMultitrackType::from_byte(2),
643 Some(AvMultitrackType::ManyTracksManyCodecs)
644 );
645 assert_eq!(AvMultitrackType::from_byte(3), None);
646 }
647
648 #[test]
649 fn test_parse_sequence_header() {
650 let mut data = vec![0x90];
653 data.extend_from_slice(b"hvc1"); data.extend_from_slice(&[0x01, 0x02, 0x03, 0x04]); let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
657
658 match parsed {
659 EnhancedVideoData::SequenceHeader {
660 codec,
661 frame_type,
662 config,
663 } => {
664 assert_eq!(codec, VideoFourCc::Hevc);
665 assert_eq!(frame_type, ExVideoFrameType::Keyframe);
666 assert_eq!(config.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
667 }
668 _ => panic!("Expected SequenceHeader"),
669 }
670 }
671
672 #[test]
673 fn test_parse_coded_frames_x() {
674 let mut data = vec![0xA3];
677 data.extend_from_slice(b"av01"); data.extend_from_slice(&[0xAA, 0xBB, 0xCC]); let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
681
682 match parsed {
683 EnhancedVideoData::Frame {
684 codec,
685 frame_type,
686 composition_time,
687 data,
688 } => {
689 assert_eq!(codec, VideoFourCc::Av1);
690 assert_eq!(frame_type, ExVideoFrameType::InterFrame);
691 assert_eq!(composition_time, 0);
692 assert_eq!(data.as_ref(), &[0xAA, 0xBB, 0xCC]);
693 }
694 _ => panic!("Expected Frame"),
695 }
696 }
697
698 #[test]
699 fn test_parse_coded_frames_with_composition_time() {
700 let mut data = vec![0x91];
703 data.extend_from_slice(b"vp09"); data.extend_from_slice(&[0x00, 0x01, 0x00]); data.extend_from_slice(&[0xDD, 0xEE, 0xFF]); let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
708
709 match parsed {
710 EnhancedVideoData::Frame {
711 codec,
712 frame_type,
713 composition_time,
714 data,
715 } => {
716 assert_eq!(codec, VideoFourCc::Vp9);
717 assert_eq!(frame_type, ExVideoFrameType::Keyframe);
718 assert_eq!(composition_time, 256);
719 assert_eq!(data.as_ref(), &[0xDD, 0xEE, 0xFF]);
720 }
721 _ => panic!("Expected Frame"),
722 }
723 }
724
725 #[test]
726 fn test_parse_negative_composition_time() {
727 let mut data = vec![0x91]; data.extend_from_slice(b"avc1"); data.extend_from_slice(&[0xFF, 0xFF, 0x00]); data.extend_from_slice(&[0x11, 0x22]); let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
734
735 match parsed {
736 EnhancedVideoData::Frame {
737 composition_time, ..
738 } => {
739 assert_eq!(composition_time, -256);
740 }
741 _ => panic!("Expected Frame"),
742 }
743 }
744
745 #[test]
746 fn test_parse_sequence_end() {
747 let mut data = vec![0x92];
750 data.extend_from_slice(b"hvc1");
751
752 let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
753
754 match parsed {
755 EnhancedVideoData::SequenceEnd { codec } => {
756 assert_eq!(codec, VideoFourCc::Hevc);
757 }
758 _ => panic!("Expected SequenceEnd"),
759 }
760 }
761
762 #[test]
763 fn test_parse_metadata() {
764 let data = vec![0x94, 0x01, 0x02, 0x03];
767
768 let parsed = EnhancedVideoData::parse(Bytes::from(data)).unwrap();
769
770 match parsed {
771 EnhancedVideoData::Metadata { data } => {
772 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
773 }
774 _ => panic!("Expected Metadata"),
775 }
776 }
777
778 #[test]
779 fn test_parse_error_empty() {
780 let result = EnhancedVideoData::parse(Bytes::new());
781 assert!(result.is_err());
782 }
783
784 #[test]
785 fn test_parse_error_not_enhanced() {
786 let data = Bytes::from_static(&[0x17, 0x00, 0x00, 0x00, 0x00]);
788 let result = EnhancedVideoData::parse(data);
789 assert!(result.is_err());
790 }
791
792 #[test]
793 fn test_parse_error_no_fourcc() {
794 let data = Bytes::from_static(&[0x90, 0x01, 0x02]);
796 let result = EnhancedVideoData::parse(data);
797 assert!(result.is_err());
798 }
799
800 #[test]
801 fn test_parse_error_unknown_fourcc() {
802 let mut data = vec![0x90];
804 data.extend_from_slice(b"xxxx"); let result = EnhancedVideoData::parse(Bytes::from(data));
806 assert!(result.is_err());
807 }
808
809 #[test]
810 fn test_is_keyframe() {
811 let data = EnhancedVideoData::SequenceHeader {
813 codec: VideoFourCc::Hevc,
814 frame_type: ExVideoFrameType::Keyframe,
815 config: Bytes::new(),
816 };
817 assert!(data.is_keyframe());
818
819 let data = EnhancedVideoData::Frame {
821 codec: VideoFourCc::Av1,
822 frame_type: ExVideoFrameType::Keyframe,
823 composition_time: 0,
824 data: Bytes::new(),
825 };
826 assert!(data.is_keyframe());
827
828 let data = EnhancedVideoData::Frame {
830 codec: VideoFourCc::Av1,
831 frame_type: ExVideoFrameType::InterFrame,
832 composition_time: 0,
833 data: Bytes::new(),
834 };
835 assert!(!data.is_keyframe());
836
837 let data = EnhancedVideoData::SequenceEnd {
839 codec: VideoFourCc::Hevc,
840 };
841 assert!(!data.is_keyframe());
842 }
843
844 #[test]
845 fn test_is_sequence_header() {
846 let header = EnhancedVideoData::SequenceHeader {
847 codec: VideoFourCc::Hevc,
848 frame_type: ExVideoFrameType::Keyframe,
849 config: Bytes::new(),
850 };
851 assert!(header.is_sequence_header());
852
853 let frame = EnhancedVideoData::Frame {
854 codec: VideoFourCc::Hevc,
855 frame_type: ExVideoFrameType::Keyframe,
856 composition_time: 0,
857 data: Bytes::new(),
858 };
859 assert!(!frame.is_sequence_header());
860 }
861
862 #[test]
863 fn test_codec_accessor() {
864 let header = EnhancedVideoData::SequenceHeader {
865 codec: VideoFourCc::Av1,
866 frame_type: ExVideoFrameType::Keyframe,
867 config: Bytes::new(),
868 };
869 assert_eq!(header.codec(), Some(VideoFourCc::Av1));
870
871 let metadata = EnhancedVideoData::Metadata { data: Bytes::new() };
872 assert_eq!(metadata.codec(), None);
873 }
874
875 #[test]
876 fn test_read_si24_positive() {
877 let mut data = Bytes::from_static(&[0x00, 0x01, 0x00]); assert_eq!(read_si24(&mut data).unwrap(), 256);
879
880 let mut data = Bytes::from_static(&[0x7F, 0xFF, 0xFF]); assert_eq!(read_si24(&mut data).unwrap(), 8388607);
882 }
883
884 #[test]
885 fn test_read_si24_negative() {
886 let mut data = Bytes::from_static(&[0xFF, 0xFF, 0x00]); assert_eq!(read_si24(&mut data).unwrap(), -256);
888
889 let mut data = Bytes::from_static(&[0x80, 0x00, 0x00]); assert_eq!(read_si24(&mut data).unwrap(), -8388608);
891 }
892
893 #[test]
894 fn test_read_si24_zero() {
895 let mut data = Bytes::from_static(&[0x00, 0x00, 0x00]);
896 assert_eq!(read_si24(&mut data).unwrap(), 0);
897 }
898
899 #[test]
900 fn test_read_si24_too_short() {
901 let mut data = Bytes::from_static(&[0x00, 0x01]);
902 assert!(read_si24(&mut data).is_err());
903 }
904}