use bitflags::bitflags;
bitflags! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PacketFlags: u8 {
const KEY = 0b001;
const CORRUPT = 0b010;
const DISCARD = 0b100;
}
}
use crate::Timestamp;
pub struct VideoPacket<E, D> {
pts: Option<Timestamp>,
dts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> VideoPacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
dts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn dts(&self) -> Option<Timestamp> {
self.dts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
pub struct AudioPacket<E, D> {
pts: Option<Timestamp>,
dts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> AudioPacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
dts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn dts(&self) -> Option<Timestamp> {
self.dts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_dts(mut self, v: Option<Timestamp>) -> Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_dts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.dts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
pub struct SubtitlePacket<E, D> {
pts: Option<Timestamp>,
duration: Option<Timestamp>,
flags: PacketFlags,
data: D,
extra: E,
}
impl<E, D> SubtitlePacket<E, D> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: D, extra: E) -> Self {
Self {
pts: None,
duration: None,
flags: PacketFlags::empty(),
data,
extra,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn flags(&self) -> PacketFlags {
self.flags
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn extra(&self) -> &E {
&self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn extra_mut(&mut self) -> &mut E {
&mut self.extra
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> D {
self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_parts(self) -> (D, E) {
(self.data, self.extra)
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_pts(mut self, v: Option<Timestamp>) -> Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_duration(mut self, v: Option<Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[must_use]
pub const fn with_flags(mut self, v: PacketFlags) -> Self {
self.flags = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: Option<Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: Option<Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_flags(&mut self, v: PacketFlags) -> &mut Self {
self.flags = v;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flag_bits_are_stable() {
assert_eq!(PacketFlags::KEY.bits(), 0b001);
assert_eq!(PacketFlags::CORRUPT.bits(), 0b010);
assert_eq!(PacketFlags::DISCARD.bits(), 0b100);
}
#[test]
fn flags_combine() {
let f = PacketFlags::KEY | PacketFlags::CORRUPT;
assert!(f.contains(PacketFlags::KEY));
assert!(f.contains(PacketFlags::CORRUPT));
assert!(!f.contains(PacketFlags::DISCARD));
}
#[test]
fn empty_default() {
assert_eq!(PacketFlags::default(), PacketFlags::empty());
}
use crate::Timebase;
use core::num::NonZeroU32;
fn ms_tb() -> Timebase {
Timebase::new(1, NonZeroU32::new(1000).unwrap())
}
#[test]
fn video_packet_construct_and_access() {
let data: &[u8] = &[1, 2, 3];
let p: VideoPacket<_, &[u8]> = VideoPacket::new(data, ());
assert_eq!(p.pts(), None);
assert_eq!(p.flags(), PacketFlags::empty());
assert_eq!(*p.data(), data);
}
#[test]
fn video_packet_builders_chain() {
let pts = crate::Timestamp::new(1500, ms_tb());
let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[][..], ())
.with_pts(Some(pts))
.with_flags(PacketFlags::KEY);
assert_eq!(p.pts(), Some(pts));
assert!(p.flags().contains(PacketFlags::KEY));
}
#[test]
fn video_packet_into_parts() {
let p: VideoPacket<_, &[u8]> = VideoPacket::new(&[1u8, 2][..], ());
let (data, _extra) = p.into_parts();
assert_eq!(data, &[1, 2]);
}
#[test]
fn audio_packet_round_trip() {
let data: &[u8] = &[7, 8, 9];
let p: AudioPacket<_, &[u8]> = AudioPacket::new(data, ()).with_flags(PacketFlags::KEY);
assert_eq!(*p.data(), data);
assert!(p.flags().contains(PacketFlags::KEY));
let (recovered, _) = p.into_parts();
assert_eq!(recovered, data);
}
#[test]
fn subtitle_packet_round_trip() {
let data: &[u8] = b"hi";
let p: SubtitlePacket<_, &[u8]> = SubtitlePacket::new(data, ());
assert_eq!(*p.data(), data);
}
}