Skip to main content

oximedia_container/
packet.rs

1//! Packet types for compressed media data.
2
3use bitflags::bitflags;
4use bytes::Bytes;
5use oximedia_core::Timestamp;
6
7bitflags! {
8    /// Flags indicating packet properties.
9    ///
10    /// These flags provide information about the packet's role in the stream
11    /// and whether it can be decoded independently.
12    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13    pub struct PacketFlags: u32 {
14        /// Packet contains a keyframe (can be decoded independently).
15        ///
16        /// For video, this typically indicates an I-frame.
17        /// For audio, most packets are effectively keyframes.
18        const KEYFRAME = 0x0001;
19
20        /// Packet data may be corrupt.
21        ///
22        /// Set when the demuxer detects potential corruption but
23        /// still provides the data for attempted recovery.
24        const CORRUPT = 0x0002;
25
26        /// Packet should be discarded.
27        ///
28        /// Used for packets that are part of the stream but should
29        /// not be decoded (e.g., during seeking).
30        const DISCARD = 0x0004;
31    }
32}
33
34impl Default for PacketFlags {
35    fn default() -> Self {
36        Self::empty()
37    }
38}
39
40/// A compressed media packet from a container.
41///
42/// Packets are the fundamental unit of compressed data in a container.
43/// Each packet typically contains one or more compressed frames from
44/// a single stream.
45///
46/// # Examples
47///
48/// ```
49/// use oximedia_container::{Packet, PacketFlags};
50/// use oximedia_core::{Timestamp, Rational};
51/// use bytes::Bytes;
52///
53/// let packet = Packet::new(
54///     0,
55///     Bytes::from_static(&[0, 1, 2, 3]),
56///     Timestamp::new(1000, Rational::new(1, 1000)),
57///     PacketFlags::KEYFRAME,
58/// );
59///
60/// assert!(packet.is_keyframe());
61/// assert_eq!(packet.size(), 4);
62/// ```
63#[derive(Clone, Debug)]
64pub struct Packet {
65    /// Index of the stream this packet belongs to.
66    pub stream_index: usize,
67
68    /// Compressed packet data.
69    pub data: Bytes,
70
71    /// Presentation and decode timestamps.
72    pub timestamp: Timestamp,
73
74    /// Packet flags.
75    pub flags: PacketFlags,
76}
77
78impl Packet {
79    /// Creates a new packet.
80    ///
81    /// # Arguments
82    ///
83    /// * `stream_index` - Index of the stream this packet belongs to
84    /// * `data` - Compressed packet data
85    /// * `timestamp` - Presentation/decode timestamps
86    /// * `flags` - Packet flags (keyframe, corrupt, etc.)
87    #[must_use]
88    pub const fn new(
89        stream_index: usize,
90        data: Bytes,
91        timestamp: Timestamp,
92        flags: PacketFlags,
93    ) -> Self {
94        Self {
95            stream_index,
96            data,
97            timestamp,
98            flags,
99        }
100    }
101
102    /// Returns true if this packet is a keyframe.
103    ///
104    /// Keyframes can be decoded independently without reference to
105    /// other frames in the stream.
106    #[must_use]
107    pub const fn is_keyframe(&self) -> bool {
108        self.flags.contains(PacketFlags::KEYFRAME)
109    }
110
111    /// Returns true if this packet may be corrupt.
112    #[must_use]
113    pub const fn is_corrupt(&self) -> bool {
114        self.flags.contains(PacketFlags::CORRUPT)
115    }
116
117    /// Returns true if this packet should be discarded.
118    #[must_use]
119    pub const fn should_discard(&self) -> bool {
120        self.flags.contains(PacketFlags::DISCARD)
121    }
122
123    /// Returns the size of the packet data in bytes.
124    #[must_use]
125    pub fn size(&self) -> usize {
126        self.data.len()
127    }
128
129    /// Returns true if the packet data is empty.
130    #[must_use]
131    pub fn is_empty(&self) -> bool {
132        self.data.is_empty()
133    }
134
135    /// Returns the presentation timestamp in the stream's timebase.
136    #[must_use]
137    pub const fn pts(&self) -> i64 {
138        self.timestamp.pts
139    }
140
141    /// Returns the decode timestamp if available.
142    #[must_use]
143    pub const fn dts(&self) -> Option<i64> {
144        self.timestamp.dts
145    }
146
147    /// Returns the packet duration if available.
148    #[must_use]
149    pub const fn duration(&self) -> Option<i64> {
150        self.timestamp.duration
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157    use oximedia_core::Rational;
158
159    #[test]
160    fn test_packet_new() {
161        let data = Bytes::from_static(&[1, 2, 3, 4, 5]);
162        let timestamp = Timestamp::new(1000, Rational::new(1, 1000));
163        let packet = Packet::new(0, data, timestamp, PacketFlags::KEYFRAME);
164
165        assert_eq!(packet.stream_index, 0);
166        assert_eq!(packet.size(), 5);
167        assert!(packet.is_keyframe());
168        assert!(!packet.is_corrupt());
169    }
170
171    #[test]
172    fn test_packet_flags() {
173        let data = Bytes::new();
174        let timestamp = Timestamp::new(0, Rational::new(1, 1000));
175
176        let keyframe = Packet::new(0, data.clone(), timestamp, PacketFlags::KEYFRAME);
177        assert!(keyframe.is_keyframe());
178        assert!(!keyframe.is_corrupt());
179
180        let corrupt = Packet::new(
181            0,
182            data.clone(),
183            timestamp,
184            PacketFlags::CORRUPT | PacketFlags::KEYFRAME,
185        );
186        assert!(corrupt.is_keyframe());
187        assert!(corrupt.is_corrupt());
188
189        let discard = Packet::new(0, data, timestamp, PacketFlags::DISCARD);
190        assert!(discard.should_discard());
191    }
192
193    #[test]
194    fn test_packet_timestamps() {
195        let data = Bytes::new();
196        let mut timestamp = Timestamp::new(1000, Rational::new(1, 48000));
197        timestamp.dts = Some(999);
198        timestamp.duration = Some(1024);
199
200        let packet = Packet::new(0, data, timestamp, PacketFlags::empty());
201
202        assert_eq!(packet.pts(), 1000);
203        assert_eq!(packet.dts(), Some(999));
204        assert_eq!(packet.duration(), Some(1024));
205    }
206
207    #[test]
208    fn test_packet_is_empty() {
209        let timestamp = Timestamp::new(0, Rational::new(1, 1000));
210
211        let empty = Packet::new(0, Bytes::new(), timestamp, PacketFlags::empty());
212        assert!(empty.is_empty());
213        assert_eq!(empty.size(), 0);
214
215        let non_empty = Packet::new(0, Bytes::from_static(&[1]), timestamp, PacketFlags::empty());
216        assert!(!non_empty.is_empty());
217        assert_eq!(non_empty.size(), 1);
218    }
219}