scuffle_ffmpeg/
packet.rs

1use std::marker::PhantomData;
2
3use crate::error::{FfmpegError, FfmpegErrorCode};
4use crate::ffi::*;
5use crate::rational::Rational;
6use crate::smart_object::SmartPtr;
7use crate::utils::{check_i64, or_nopts};
8use crate::{AVPktFlags, AVRounding};
9
10/// A collection of packets. [`Packets`] implements [`Iterator`] and will yield packets until the end of the stream is reached.
11/// A wrapper around an [`AVFormatContext`].
12pub struct Packets<'a> {
13    context: *mut AVFormatContext,
14    _marker: PhantomData<&'a mut AVFormatContext>,
15}
16
17impl std::fmt::Debug for Packets<'_> {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        f.debug_struct("Packets").field("context", &self.context).finish()
20    }
21}
22
23/// Safety: `Packets` is safe to send between threads.
24unsafe impl Send for Packets<'_> {}
25
26impl Packets<'_> {
27    /// Creates a new `Packets` instance.
28    ///
29    /// # Safety
30    /// This function is unsafe because the caller must ensure that the lifetime & the mutablity
31    /// of the `AVFormatContext` matches the lifetime & mutability of the `Packets`.
32    pub const unsafe fn new(context: *mut AVFormatContext) -> Self {
33        Self {
34            context,
35            _marker: PhantomData,
36        }
37    }
38
39    /// Receives a packet from the context.
40    pub fn receive(&mut self) -> Result<Option<Packet>, FfmpegError> {
41        let mut packet = Packet::new()?;
42
43        // Safety: av_read_frame is safe to call, 'packet' is a valid pointer
44        match FfmpegErrorCode(unsafe { av_read_frame(self.context, packet.as_mut_ptr()) }) {
45            code if code.is_success() => Ok(Some(packet)),
46            FfmpegErrorCode::Eof => Ok(None),
47            code => Err(FfmpegError::Code(code)),
48        }
49    }
50}
51
52impl Iterator for Packets<'_> {
53    type Item = Result<Packet, FfmpegError>;
54
55    fn next(&mut self) -> Option<Self::Item> {
56        self.receive().transpose()
57    }
58}
59
60/// A packet is a wrapper around an [`AVPacket`].
61pub struct Packet(SmartPtr<AVPacket>);
62
63/// Safety: `Packet` is safe to send between threads.
64unsafe impl Send for Packet {}
65
66impl std::fmt::Debug for Packet {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.debug_struct("Packet")
69            .field("stream_index", &self.stream_index())
70            .field("pts", &self.pts())
71            .field("dts", &self.dts())
72            .field("duration", &self.duration())
73            .field("pos", &self.pos())
74            .field("is_key", &self.is_key())
75            .field("is_corrupt", &self.is_corrupt())
76            .field("is_discard", &self.is_discard())
77            .field("is_trusted", &self.is_trusted())
78            .field("is_disposable", &self.is_disposable())
79            .finish()
80    }
81}
82
83impl Clone for Packet {
84    fn clone(&self) -> Self {
85        // Safety: `av_packet_clone` is safe to call.
86        let clone = unsafe { av_packet_clone(self.0.as_ptr()) };
87
88        // Safety: The pointer is valid.
89        unsafe { Self::wrap(clone).expect("failed to clone packet") }
90    }
91}
92
93impl Packet {
94    /// Creates a new `Packet`.
95    pub fn new() -> Result<Self, FfmpegError> {
96        // Safety: `av_packet_alloc` is safe to call.
97        let packet = unsafe { av_packet_alloc() };
98
99        // Safety: The pointer is valid.
100        unsafe { Self::wrap(packet) }.ok_or(FfmpegError::Alloc)
101    }
102
103    /// Wraps a pointer to a packet.
104    ///
105    /// # Safety
106    /// `ptr` must be a valid pointer to a packet.
107    unsafe fn wrap(ptr: *mut AVPacket) -> Option<Self> {
108        SmartPtr::wrap_non_null(ptr, |ptr| av_packet_free(ptr)).map(Self)
109    }
110
111    /// Returns a pointer to the packet.
112    pub const fn as_ptr(&self) -> *const AVPacket {
113        self.0.as_ptr()
114    }
115
116    /// Returns a mutable pointer to the packet.
117    pub const fn as_mut_ptr(&mut self) -> *mut AVPacket {
118        self.0.as_mut_ptr()
119    }
120
121    /// Returns the stream index of the packet.
122    pub const fn stream_index(&self) -> i32 {
123        self.0.as_deref_except().stream_index
124    }
125
126    /// Sets the stream index of the packet.
127    pub const fn set_stream_index(&mut self, stream_index: i32) {
128        self.0.as_deref_mut_except().stream_index = stream_index as _;
129    }
130
131    /// Returns the presentation timestamp of the packet.
132    pub const fn pts(&self) -> Option<i64> {
133        check_i64(self.0.as_deref_except().pts)
134    }
135
136    /// Sets the presentation timestamp of the packet.
137    pub const fn set_pts(&mut self, pts: Option<i64>) {
138        self.0.as_deref_mut_except().pts = or_nopts(pts);
139    }
140
141    /// Returns the decoding timestamp of the packet.
142    pub const fn dts(&self) -> Option<i64> {
143        check_i64(self.0.as_deref_except().dts)
144    }
145
146    /// Sets the decoding timestamp of the packet.
147    pub const fn set_dts(&mut self, dts: Option<i64>) {
148        self.0.as_deref_mut_except().dts = or_nopts(dts);
149    }
150
151    /// Returns the duration of the packet.
152    pub const fn duration(&self) -> Option<i64> {
153        check_i64(self.0.as_deref_except().duration)
154    }
155
156    /// Sets the duration of the packet.
157    pub const fn set_duration(&mut self, duration: Option<i64>) {
158        self.0.as_deref_mut_except().duration = or_nopts(duration);
159    }
160
161    /// Converts the timebase of the packet.
162    pub fn convert_timebase(&mut self, from: impl Into<Rational>, to: impl Into<Rational>) {
163        let from = from.into();
164        let to = to.into();
165
166        // Safety: av_rescale_q_rnd is safe to call
167        self.set_pts(self.pts().map(|pts| {
168            // Safety: av_rescale_q_rnd is safe to call
169            unsafe { av_rescale_q_rnd(pts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as u32) }
170        }));
171
172        // Safety: av_rescale_q_rnd is safe to call
173        self.set_dts(self.dts().map(|dts| {
174            // Safety: av_rescale_q_rnd is safe to call
175            unsafe { av_rescale_q_rnd(dts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as u32) }
176        }));
177
178        self.set_duration(
179            self.duration()
180                // Safety: av_rescale_q is safe to call
181                .map(|duration| unsafe { av_rescale_q(duration, from.into(), to.into()) }),
182        );
183    }
184
185    /// Returns the position of the packet.
186    pub const fn pos(&self) -> Option<i64> {
187        check_i64(self.0.as_deref_except().pos)
188    }
189
190    /// Sets the position of the packet.
191    pub const fn set_pos(&mut self, pos: Option<i64>) {
192        self.0.as_deref_mut_except().pos = or_nopts(pos);
193    }
194
195    /// Returns the data of the packet.
196    pub const fn data(&self) -> &[u8] {
197        if self.0.as_deref_except().size <= 0 {
198            return &[];
199        }
200
201        // Safety: `self.0` is a valid pointer.
202        unsafe { std::slice::from_raw_parts(self.0.as_deref_except().data, self.0.as_deref_except().size as usize) }
203    }
204
205    /// Returns whether the packet is a key frame.
206    pub fn is_key(&self) -> bool {
207        self.flags() & AVPktFlags::Key != 0
208    }
209
210    /// Returns whether the packet is corrupt.
211    pub fn is_corrupt(&self) -> bool {
212        self.flags() & AVPktFlags::Corrupt != 0
213    }
214
215    /// Returns whether the packet should be discarded.
216    pub fn is_discard(&self) -> bool {
217        self.flags() & AVPktFlags::Discard != 0
218    }
219
220    /// Returns whether the packet is trusted.
221    pub fn is_trusted(&self) -> bool {
222        self.flags() & AVPktFlags::Trusted != 0
223    }
224
225    /// Returns whether the packet is disposable.
226    pub fn is_disposable(&self) -> bool {
227        self.flags() & AVPktFlags::Disposable != 0
228    }
229
230    /// Returns the flags of the packet.
231    pub const fn flags(&self) -> AVPktFlags {
232        AVPktFlags(self.0.as_deref_except().flags)
233    }
234}
235
236#[cfg(test)]
237#[cfg_attr(all(test, coverage_nightly), coverage(off))]
238mod tests {
239    use insta::assert_debug_snapshot;
240
241    use crate::ffi::AVRational;
242    use crate::packet::Packet;
243
244    #[test]
245    fn test_packet_clone_snapshot() {
246        let mut original_packet = Packet::new().expect("Failed to create original Packet");
247        original_packet.set_stream_index(1);
248        original_packet.set_pts(Some(12345));
249        original_packet.set_dts(Some(54321));
250        original_packet.set_duration(Some(1000));
251        original_packet.set_pos(Some(2000));
252
253        let cloned_packet = original_packet.clone();
254
255        assert_debug_snapshot!(cloned_packet, @r"
256        Packet {
257            stream_index: 1,
258            pts: Some(
259                12345,
260            ),
261            dts: Some(
262                54321,
263            ),
264            duration: Some(
265                1000,
266            ),
267            pos: Some(
268                2000,
269            ),
270            is_key: false,
271            is_corrupt: false,
272            is_discard: false,
273            is_trusted: false,
274            is_disposable: false,
275        }
276        ");
277
278        // ensure cloned packet is independent
279        original_packet.set_pts(Some(99999));
280        assert_ne!(
281            cloned_packet.pts(),
282            original_packet.pts(),
283            "Expected cloned packet PTS to remain unchanged after modifying the original"
284        );
285
286        assert_debug_snapshot!(original_packet, @r"
287        Packet {
288            stream_index: 1,
289            pts: Some(
290                99999,
291            ),
292            dts: Some(
293                54321,
294            ),
295            duration: Some(
296                1000,
297            ),
298            pos: Some(
299                2000,
300            ),
301            is_key: false,
302            is_corrupt: false,
303            is_discard: false,
304            is_trusted: false,
305            is_disposable: false,
306        }
307        ");
308    }
309
310    #[test]
311    fn test_packet_as_ptr() {
312        let packet = Packet::new().expect("Failed to create Packet");
313        let raw_ptr = packet.as_ptr();
314
315        assert!(!raw_ptr.is_null(), "Expected a non-null pointer from Packet::as_ptr");
316        // Safety: `raw_ptr` is a valid pointer.
317        unsafe {
318            assert_eq!(
319                (*raw_ptr).stream_index,
320                0,
321                "Expected the default stream_index to be 0 for a new Packet"
322            );
323        }
324    }
325
326    #[test]
327    fn test_packet_rescale_timebase() {
328        let mut packet = Packet::new().expect("Failed to create Packet");
329        packet.set_pts(Some(1000));
330        packet.set_dts(Some(900));
331        packet.set_duration(Some(100));
332        let from_time_base = AVRational { num: 1, den: 1000 };
333        let to_time_base = AVRational { num: 1, den: 48000 };
334
335        packet.convert_timebase(from_time_base, to_time_base);
336        assert_debug_snapshot!(packet, @r"
337        Packet {
338            stream_index: 0,
339            pts: Some(
340                48000,
341            ),
342            dts: Some(
343                43200,
344            ),
345            duration: Some(
346                4800,
347            ),
348            pos: Some(
349                -1,
350            ),
351            is_key: false,
352            is_corrupt: false,
353            is_discard: false,
354            is_trusted: false,
355            is_disposable: false,
356        }
357        ");
358    }
359
360    #[test]
361    fn test_packet_data_empty() {
362        let mut packet = Packet::new().expect("Failed to create Packet");
363        // Safety: `packet.as_mut_ptr()` is a valid pointer.
364        unsafe {
365            let av_packet = packet.as_mut_ptr().as_mut().unwrap();
366            av_packet.size = 0;
367        }
368
369        let data = packet.data();
370
371        assert!(
372            data.is_empty(),
373            "Expected the data slice to be empty when packet size is zero"
374        );
375    }
376}