1use bitflags::bitflags;
7
8bitflags! {
9 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
34 pub struct PacketFlags: u8 {
35 const KEY = 0b001;
37 const CORRUPT = 0b010;
39 const DISCARD = 0b100;
41 }
42}
43
44use crate::Timestamp;
45
46#[derive(Clone, Debug)]
62pub struct VideoPacket<E, D> {
63 pts: Option<Timestamp>,
64 dts: Option<Timestamp>,
65 duration: Option<Timestamp>,
66 flags: PacketFlags,
67 data: D,
68 extra: E,
69}
70
71impl<E, D> VideoPacket<E, D> {
72 #[cfg_attr(not(tarpaulin), inline(always))]
75 pub const fn new(data: D, extra: E) -> Self {
76 Self {
77 pts: None,
78 dts: None,
79 duration: None,
80 flags: PacketFlags::empty(),
81 data,
82 extra,
83 }
84 }
85
86 #[cfg_attr(not(tarpaulin), inline(always))]
88 pub const fn pts(&self) -> Option<Timestamp> {
89 self.pts
90 }
91 #[cfg_attr(not(tarpaulin), inline(always))]
93 pub const fn dts(&self) -> Option<Timestamp> {
94 self.dts
95 }
96 #[cfg_attr(not(tarpaulin), inline(always))]
98 pub const fn duration(&self) -> Option<Timestamp> {
99 self.duration
100 }
101 #[cfg_attr(not(tarpaulin), inline(always))]
103 pub const fn flags(&self) -> PacketFlags {
104 self.flags
105 }
106 #[cfg_attr(not(tarpaulin), inline(always))]
108 pub const fn data(&self) -> &D {
109 &self.data
110 }
111 #[cfg_attr(not(tarpaulin), inline(always))]
113 pub const fn extra(&self) -> &E {
114 &self.extra
115 }
116 #[cfg_attr(not(tarpaulin), inline(always))]
118 pub fn extra_mut(&mut self) -> &mut E {
119 &mut self.extra
120 }
121 #[cfg_attr(not(tarpaulin), inline(always))]
123 pub fn into_data(self) -> D {
124 self.data
125 }
126 #[cfg_attr(not(tarpaulin), inline(always))]
128 pub fn into_parts(self) -> (D, E) {
129 (self.data, self.extra)
130 }
131
132 #[cfg_attr(not(tarpaulin), inline(always))]
134 #[must_use]
135 pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
136 self.pts = v;
137 self
138 }
139 #[cfg_attr(not(tarpaulin), inline(always))]
141 #[must_use]
142 pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
143 self.dts = v;
144 self
145 }
146 #[cfg_attr(not(tarpaulin), inline(always))]
148 #[must_use]
149 pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
150 self.duration = v;
151 self
152 }
153 #[cfg_attr(not(tarpaulin), inline(always))]
155 #[must_use]
156 pub const fn with_flags(mut self, v: PacketFlags) -> Self {
157 self.flags = v;
158 self
159 }
160
161 #[cfg_attr(not(tarpaulin), inline(always))]
163 pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
164 self.pts = v;
165 self
166 }
167 #[cfg_attr(not(tarpaulin), inline(always))]
169 pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
170 self.dts = v;
171 self
172 }
173 #[cfg_attr(not(tarpaulin), inline(always))]
175 pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
176 self.duration = v;
177 self
178 }
179 #[cfg_attr(not(tarpaulin), inline(always))]
181 pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
182 self.flags = v;
183 self
184 }
185}
186
187#[derive(Clone, Debug)]
189pub struct AudioPacket<E, D> {
190 pts: Option<Timestamp>,
191 dts: Option<Timestamp>,
192 duration: Option<Timestamp>,
193 flags: PacketFlags,
194 data: D,
195 extra: E,
196}
197
198impl<E, D> AudioPacket<E, D> {
199 #[cfg_attr(not(tarpaulin), inline(always))]
201 pub const fn new(data: D, extra: E) -> Self {
202 Self {
203 pts: None,
204 dts: None,
205 duration: None,
206 flags: PacketFlags::empty(),
207 data,
208 extra,
209 }
210 }
211
212 #[cfg_attr(not(tarpaulin), inline(always))]
214 pub const fn pts(&self) -> Option<Timestamp> {
215 self.pts
216 }
217 #[cfg_attr(not(tarpaulin), inline(always))]
219 pub const fn dts(&self) -> Option<Timestamp> {
220 self.dts
221 }
222 #[cfg_attr(not(tarpaulin), inline(always))]
224 pub const fn duration(&self) -> Option<Timestamp> {
225 self.duration
226 }
227 #[cfg_attr(not(tarpaulin), inline(always))]
229 pub const fn flags(&self) -> PacketFlags {
230 self.flags
231 }
232 #[cfg_attr(not(tarpaulin), inline(always))]
234 pub const fn data(&self) -> &D {
235 &self.data
236 }
237 #[cfg_attr(not(tarpaulin), inline(always))]
239 pub const fn extra(&self) -> &E {
240 &self.extra
241 }
242 #[cfg_attr(not(tarpaulin), inline(always))]
244 pub fn extra_mut(&mut self) -> &mut E {
245 &mut self.extra
246 }
247 #[cfg_attr(not(tarpaulin), inline(always))]
249 pub fn into_data(self) -> D {
250 self.data
251 }
252 #[cfg_attr(not(tarpaulin), inline(always))]
254 pub fn into_parts(self) -> (D, E) {
255 (self.data, self.extra)
256 }
257
258 #[cfg_attr(not(tarpaulin), inline(always))]
260 #[must_use]
261 pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
262 self.pts = v;
263 self
264 }
265 #[cfg_attr(not(tarpaulin), inline(always))]
267 #[must_use]
268 pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
269 self.dts = v;
270 self
271 }
272 #[cfg_attr(not(tarpaulin), inline(always))]
274 #[must_use]
275 pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
276 self.duration = v;
277 self
278 }
279 #[cfg_attr(not(tarpaulin), inline(always))]
281 #[must_use]
282 pub const fn with_flags(mut self, v: PacketFlags) -> Self {
283 self.flags = v;
284 self
285 }
286
287 #[cfg_attr(not(tarpaulin), inline(always))]
289 pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
290 self.pts = v;
291 self
292 }
293 #[cfg_attr(not(tarpaulin), inline(always))]
295 pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
296 self.dts = v;
297 self
298 }
299 #[cfg_attr(not(tarpaulin), inline(always))]
301 pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
302 self.duration = v;
303 self
304 }
305 #[cfg_attr(not(tarpaulin), inline(always))]
307 pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
308 self.flags = v;
309 self
310 }
311}
312
313#[derive(Clone, Debug)]
315pub struct SubtitlePacket<E, D> {
316 pts: Option<Timestamp>,
317 duration: Option<Timestamp>,
318 flags: PacketFlags,
319 data: D,
320 extra: E,
321}
322
323impl<E, D> SubtitlePacket<E, D> {
324 #[cfg_attr(not(tarpaulin), inline(always))]
326 pub const fn new(data: D, extra: E) -> Self {
327 Self {
328 pts: None,
329 duration: None,
330 flags: PacketFlags::empty(),
331 data,
332 extra,
333 }
334 }
335
336 #[cfg_attr(not(tarpaulin), inline(always))]
338 pub const fn pts(&self) -> Option<Timestamp> {
339 self.pts
340 }
341 #[cfg_attr(not(tarpaulin), inline(always))]
343 pub const fn duration(&self) -> Option<Timestamp> {
344 self.duration
345 }
346 #[cfg_attr(not(tarpaulin), inline(always))]
348 pub const fn flags(&self) -> PacketFlags {
349 self.flags
350 }
351 #[cfg_attr(not(tarpaulin), inline(always))]
353 pub const fn data(&self) -> &D {
354 &self.data
355 }
356 #[cfg_attr(not(tarpaulin), inline(always))]
358 pub const fn extra(&self) -> &E {
359 &self.extra
360 }
361 #[cfg_attr(not(tarpaulin), inline(always))]
363 pub fn extra_mut(&mut self) -> &mut E {
364 &mut self.extra
365 }
366 #[cfg_attr(not(tarpaulin), inline(always))]
368 pub fn into_data(self) -> D {
369 self.data
370 }
371 #[cfg_attr(not(tarpaulin), inline(always))]
373 pub fn into_parts(self) -> (D, E) {
374 (self.data, self.extra)
375 }
376
377 #[cfg_attr(not(tarpaulin), inline(always))]
379 #[must_use]
380 pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
381 self.pts = v;
382 self
383 }
384 #[cfg_attr(not(tarpaulin), inline(always))]
386 #[must_use]
387 pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
388 self.duration = v;
389 self
390 }
391 #[cfg_attr(not(tarpaulin), inline(always))]
393 #[must_use]
394 pub const fn with_flags(mut self, v: PacketFlags) -> Self {
395 self.flags = v;
396 self
397 }
398
399 #[cfg_attr(not(tarpaulin), inline(always))]
401 pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
402 self.pts = v;
403 self
404 }
405 #[cfg_attr(not(tarpaulin), inline(always))]
407 pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
408 self.duration = v;
409 self
410 }
411 #[cfg_attr(not(tarpaulin), inline(always))]
413 pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
414 self.flags = v;
415 self
416 }
417}
418
419#[cfg(feature = "serde")]
426#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
427mod serde_impls {
428 use serde::{Deserialize, Deserializer, Serialize, Serializer};
444
445 use super::PacketFlags;
446
447 impl Serialize for PacketFlags {
448 #[cfg_attr(not(tarpaulin), inline(always))]
449 fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
450 ser.serialize_u8(self.bits())
451 }
452 }
453
454 impl<'de> Deserialize<'de> for PacketFlags {
455 #[cfg_attr(not(tarpaulin), inline(always))]
456 fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
457 u8::deserialize(de).map(Self::from_bits_retain)
458 }
459 }
460}
461
462#[cfg(feature = "arbitrary")]
463#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
464mod arbitrary_impls {
465 use arbitrary::{Arbitrary, Result, Unstructured};
476
477 use super::PacketFlags;
478
479 impl<'a> Arbitrary<'a> for PacketFlags {
480 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
481 Ok(Self::from_bits_retain(u8::arbitrary(u)?))
482 }
483 }
484}
485
486#[cfg(feature = "quickcheck")]
487#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))]
488mod quickcheck_impls {
489 use quickcheck::{Arbitrary, Gen};
493
494 use super::PacketFlags;
495
496 impl Arbitrary for PacketFlags {
497 fn arbitrary(g: &mut Gen) -> Self {
498 Self::from_bits_retain(u8::arbitrary(g))
499 }
500 }
501}
502
503#[cfg(test)]
504mod tests {
505 use super::*;
506
507 #[cfg(any(feature = "std", feature = "alloc"))]
517 extern crate alloc;
518 #[cfg(any(feature = "std", feature = "alloc"))]
519 use alloc::format;
520
521 #[test]
522 fn flag_bits_are_stable() {
523 assert_eq!(PacketFlags::KEY.bits(), 0b001);
524 assert_eq!(PacketFlags::CORRUPT.bits(), 0b010);
525 assert_eq!(PacketFlags::DISCARD.bits(), 0b100);
526 }
527
528 #[test]
529 fn flags_combine() {
530 let f = PacketFlags::KEY | PacketFlags::CORRUPT;
531 assert!(f.contains(PacketFlags::KEY));
532 assert!(f.contains(PacketFlags::CORRUPT));
533 assert!(!f.contains(PacketFlags::DISCARD));
534 }
535
536 #[test]
537 fn empty_default() {
538 assert_eq!(PacketFlags::default(), PacketFlags::empty());
539 }
540
541 use crate::Timebase;
542 use core::num::NonZeroI32;
543
544 fn ms_tb() -> Timebase {
545 Timebase::new(1, NonZeroI32::new(1000).unwrap())
546 }
547
548 #[test]
549 fn video_packet_construct_and_access() {
550 let data: &[u8] = &[1, 2, 3];
551 let p: VideoPacket<_, &[u8]> = VideoPacket::new(data, ());
552 assert_eq!(p.pts(), None);
553 assert_eq!(p.flags(), PacketFlags::empty());
554 assert_eq!(*p.data(), data);
555 }
556
557 #[test]
558 fn video_packet_builders_chain() {
559 let pts = crate::Timestamp::new(1500, ms_tb());
560 let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[][..], ())
561 .with_pts(Some(pts))
562 .with_flags(PacketFlags::KEY);
563 assert_eq!(p.pts(), Some(pts));
564 assert!(p.flags().contains(PacketFlags::KEY));
565 }
566
567 #[test]
568 fn video_packet_into_parts() {
569 let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[1u8, 2][..], ());
570 let (data, _extra) = p.into_parts();
571 assert_eq!(data, &[1, 2]);
572 }
573
574 #[cfg(any(feature = "std", feature = "alloc"))]
576 #[test]
577 fn video_packet_clone_matches_the_original() {
578 let pts = crate::Timestamp::new(1500, ms_tb());
579 let original: VideoPacket<_, &[u8]> = VideoPacket::new(&[1u8, 2, 3][..], ())
580 .with_pts(Some(pts))
581 .with_dts(Some(pts))
582 .with_flags(PacketFlags::KEY);
583 let cloned = original.clone();
584 assert_eq!(cloned.pts(), original.pts());
585 assert_eq!(cloned.dts(), original.dts());
586 assert_eq!(cloned.duration(), original.duration());
587 assert_eq!(cloned.flags(), original.flags());
588 assert_eq!(cloned.data(), original.data());
589 assert!(format!("{cloned:?}").contains("VideoPacket"));
590 }
591
592 #[test]
593 fn audio_packet_round_trip() {
594 let data: &[u8] = &[7, 8, 9];
595 let p: AudioPacket<_, &[u8]> = AudioPacket::new(data, ()).with_flags(PacketFlags::KEY);
596 assert_eq!(*p.data(), data);
597 assert!(p.flags().contains(PacketFlags::KEY));
598 let (recovered, _) = p.into_parts();
599 assert_eq!(recovered, data);
600 }
601
602 #[cfg(any(feature = "std", feature = "alloc"))]
604 #[test]
605 fn audio_packet_clone_matches_the_original() {
606 let data: &[u8] = &[7, 8, 9];
607 let original: AudioPacket<_, &[u8]> = AudioPacket::new(data, ()).with_flags(PacketFlags::KEY);
608 let cloned = original.clone();
609 assert_eq!(cloned.flags(), original.flags());
610 assert_eq!(cloned.data(), original.data());
611 assert!(format!("{cloned:?}").contains("AudioPacket"));
612 }
613
614 #[test]
615 fn subtitle_packet_round_trip() {
616 let data: &[u8] = b"hi";
617 let p: SubtitlePacket<_, &[u8]> = SubtitlePacket::new(data, ());
618 assert_eq!(*p.data(), data);
619 }
620
621 #[cfg(any(feature = "std", feature = "alloc"))]
623 #[test]
624 fn subtitle_packet_clone_matches_the_original() {
625 let data: &[u8] = b"hi";
626 let original: SubtitlePacket<_, &[u8]> = SubtitlePacket::new(data, ());
627 let cloned = original.clone();
628 assert_eq!(cloned.data(), original.data());
629 assert!(format!("{cloned:?}").contains("SubtitlePacket"));
630 }
631
632 #[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
639 mod serde_tests {
640 extern crate alloc;
646
647 use alloc::string::ToString;
648
649 use super::*;
650
651 #[test]
652 fn the_wire_is_a_number_not_a_flag_grammar() {
653 let flags = PacketFlags::KEY | PacketFlags::CORRUPT;
658 assert_eq!(
659 serde_json::to_string(&flags).expect("flags always serialize"),
660 "3"
661 );
662 assert_eq!(
663 serde_json::to_string(&PacketFlags::empty()).expect("flags always serialize"),
664 "0"
665 );
666 }
667
668 #[test]
669 fn a_name_is_not_a_number() {
670 assert!(serde_json::from_str::<PacketFlags>(r#""KEY""#).is_err());
671 assert!(serde_json::from_str::<PacketFlags>(r#""key|corrupt""#).is_err());
672 }
673
674 #[test]
675 fn every_bit_pattern_round_trips_including_the_unnamed_ones() {
676 for bits in 0..=u8::MAX {
680 let flags = PacketFlags::from_bits_retain(bits);
681 let json = serde_json::to_string(&flags).expect("flags always serialize");
682 assert_eq!(json, bits.to_string());
683 assert_eq!(
684 serde_json::from_str::<PacketFlags>(&json).expect("its own output parses"),
685 flags,
686 "round-trip failed for {bits:#010b}"
687 );
688 }
689 }
690
691 #[test]
692 fn a_value_no_u8_can_hold_is_refused() {
693 assert!(serde_json::from_str::<PacketFlags>("256").is_err());
694 assert!(serde_json::from_str::<PacketFlags>("-1").is_err());
695 }
696 }
697
698 #[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
710 mod mediaframe_serde_forwarding_tests {
711 #[test]
712 fn pixel_format_round_trips_through_json() {
713 let value = crate::PixelFormat::Yuv420p;
714 let json = serde_json::to_string(&value).expect("mediaframe/serde forwards PixelFormat");
715 assert_eq!(json, "\"yuv420p\"");
716 assert_eq!(
717 serde_json::from_str::<crate::PixelFormat>(&json).expect("its own output parses"),
718 value
719 );
720 }
721
722 #[test]
723 fn bayer_pattern_round_trips_through_json() {
724 let value = crate::cfa::BayerPattern::Rggb;
725 let json = serde_json::to_string(&value).expect("mediaframe/serde forwards BayerPattern");
726 assert_eq!(json, "\"rggb\"");
727 assert_eq!(
728 serde_json::from_str::<crate::cfa::BayerPattern>(&json).expect("its own output parses"),
729 value
730 );
731 }
732 }
733
734 #[cfg(feature = "arbitrary")]
735 mod arbitrary_tests {
736 use arbitrary::{Arbitrary, Unstructured};
737
738 use super::*;
739
740 #[test]
741 fn every_bit_pattern_is_reachable() {
742 let mut seen = [false; 256];
743 for byte in 0..=u8::MAX {
744 let data = [byte];
745 let mut u = Unstructured::new(&data);
746 let flags = PacketFlags::arbitrary(&mut u).expect("the generator is total");
747 seen[flags.bits() as usize] = true;
748 }
749 assert!(
750 seen.iter().all(|&s| s),
751 "a bit pattern the generator never produces"
752 );
753 }
754 }
755
756 #[cfg(feature = "quickcheck")]
757 mod quickcheck_tests {
758 use quickcheck::{Arbitrary, Gen};
759
760 use super::*;
761
762 #[test]
763 fn the_named_flags_and_the_unnamed_bits_are_both_reachable() {
764 let mut g = Gen::new(16);
767 let mut union = PacketFlags::empty();
768 let mut saw_unnamed = false;
769 for _ in 0..4000 {
770 let flags = PacketFlags::arbitrary(&mut g);
771 union |= flags;
772 saw_unnamed |= !PacketFlags::all().contains(flags);
773 }
774 assert_eq!(
775 union,
776 PacketFlags::from_bits_retain(u8::MAX),
777 "a bit the generator never sets"
778 );
779 assert!(saw_unnamed, "an unnamed bit is never produced");
780 }
781 }
782}