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    /// We take ownership of the pointer and free it when the `Packet` is dropped.
105    ///
106    /// # Safety
107    /// `ptr` must be a valid pointer to a packet.
108    unsafe fn wrap(ptr: *mut AVPacket) -> Option<Self> {
109        let destructor = |ptr: &mut *mut AVPacket| {
110            // Safety: The pointer is valid.
111            unsafe { av_packet_free(ptr) };
112        };
113
114        // Safety: The pointer is valid.
115        unsafe { SmartPtr::wrap_non_null(ptr, destructor).map(Self) }
116    }
117
118    /// Returns a pointer to the packet.
119    pub const fn as_ptr(&self) -> *const AVPacket {
120        self.0.as_ptr()
121    }
122
123    /// Returns a mutable pointer to the packet.
124    pub const fn as_mut_ptr(&mut self) -> *mut AVPacket {
125        self.0.as_mut_ptr()
126    }
127
128    /// Returns the stream index of the packet.
129    pub const fn stream_index(&self) -> i32 {
130        self.0.as_deref_except().stream_index
131    }
132
133    /// Sets the stream index of the packet.
134    pub const fn set_stream_index(&mut self, stream_index: i32) {
135        self.0.as_deref_mut_except().stream_index = stream_index as _;
136    }
137
138    /// Returns the presentation timestamp of the packet.
139    pub const fn pts(&self) -> Option<i64> {
140        check_i64(self.0.as_deref_except().pts)
141    }
142
143    /// Sets the presentation timestamp of the packet.
144    pub const fn set_pts(&mut self, pts: Option<i64>) {
145        self.0.as_deref_mut_except().pts = or_nopts(pts);
146    }
147
148    /// Returns the decoding timestamp of the packet.
149    pub const fn dts(&self) -> Option<i64> {
150        check_i64(self.0.as_deref_except().dts)
151    }
152
153    /// Sets the decoding timestamp of the packet.
154    pub const fn set_dts(&mut self, dts: Option<i64>) {
155        self.0.as_deref_mut_except().dts = or_nopts(dts);
156    }
157
158    /// Returns the duration of the packet.
159    pub const fn duration(&self) -> Option<i64> {
160        check_i64(self.0.as_deref_except().duration)
161    }
162
163    /// Sets the duration of the packet.
164    pub const fn set_duration(&mut self, duration: Option<i64>) {
165        self.0.as_deref_mut_except().duration = or_nopts(duration);
166    }
167
168    /// Converts the timebase of the packet.
169    pub fn convert_timebase(&mut self, from: impl Into<Rational>, to: impl Into<Rational>) {
170        let from = from.into();
171        let to = to.into();
172
173        // Safety: av_rescale_q_rnd is safe to call
174        self.set_pts(self.pts().map(|pts| {
175            // Safety: av_rescale_q_rnd is safe to call
176            unsafe { av_rescale_q_rnd(pts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as _) }
177        }));
178
179        // Safety: av_rescale_q_rnd is safe to call
180        self.set_dts(self.dts().map(|dts| {
181            // Safety: av_rescale_q_rnd is safe to call
182            unsafe { av_rescale_q_rnd(dts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as _) }
183        }));
184
185        self.set_duration(
186            self.duration()
187                // Safety: av_rescale_q is safe to call
188                .map(|duration| unsafe { av_rescale_q(duration, from.into(), to.into()) }),
189        );
190    }
191
192    /// Returns the position of the packet.
193    pub const fn pos(&self) -> Option<i64> {
194        check_i64(self.0.as_deref_except().pos)
195    }
196
197    /// Sets the position of the packet.
198    pub const fn set_pos(&mut self, pos: Option<i64>) {
199        self.0.as_deref_mut_except().pos = or_nopts(pos);
200    }
201
202    /// Returns the data of the packet.
203    pub const fn data(&self) -> &[u8] {
204        if self.0.as_deref_except().size <= 0 {
205            return &[];
206        }
207
208        // Safety: `self.0` is a valid pointer.
209        unsafe { std::slice::from_raw_parts(self.0.as_deref_except().data, self.0.as_deref_except().size as usize) }
210    }
211
212    /// Returns whether the packet is a key frame.
213    pub fn is_key(&self) -> bool {
214        self.flags() & AVPktFlags::Key != 0
215    }
216
217    /// Returns whether the packet is corrupt.
218    pub fn is_corrupt(&self) -> bool {
219        self.flags() & AVPktFlags::Corrupt != 0
220    }
221
222    /// Returns whether the packet should be discarded.
223    pub fn is_discard(&self) -> bool {
224        self.flags() & AVPktFlags::Discard != 0
225    }
226
227    /// Returns whether the packet is trusted.
228    pub fn is_trusted(&self) -> bool {
229        self.flags() & AVPktFlags::Trusted != 0
230    }
231
232    /// Returns whether the packet is disposable.
233    pub fn is_disposable(&self) -> bool {
234        self.flags() & AVPktFlags::Disposable != 0
235    }
236
237    /// Returns the flags of the packet.
238    pub const fn flags(&self) -> AVPktFlags {
239        AVPktFlags(self.0.as_deref_except().flags)
240    }
241}
242
243#[cfg(test)]
244#[cfg_attr(all(test, coverage_nightly), coverage(off))]
245mod tests {
246    use insta::assert_debug_snapshot;
247
248    use crate::ffi::AVRational;
249    use crate::packet::Packet;
250
251    #[test]
252    fn test_packet_clone_snapshot() {
253        let mut original_packet = Packet::new().expect("Failed to create original Packet");
254        original_packet.set_stream_index(1);
255        original_packet.set_pts(Some(12345));
256        original_packet.set_dts(Some(54321));
257        original_packet.set_duration(Some(1000));
258        original_packet.set_pos(Some(2000));
259
260        let cloned_packet = original_packet.clone();
261
262        assert_debug_snapshot!(cloned_packet, @r"
263        Packet {
264            stream_index: 1,
265            pts: Some(
266                12345,
267            ),
268            dts: Some(
269                54321,
270            ),
271            duration: Some(
272                1000,
273            ),
274            pos: Some(
275                2000,
276            ),
277            is_key: false,
278            is_corrupt: false,
279            is_discard: false,
280            is_trusted: false,
281            is_disposable: false,
282        }
283        ");
284
285        // ensure cloned packet is independent
286        original_packet.set_pts(Some(99999));
287        assert_ne!(
288            cloned_packet.pts(),
289            original_packet.pts(),
290            "Expected cloned packet PTS to remain unchanged after modifying the original"
291        );
292
293        assert_debug_snapshot!(original_packet, @r"
294        Packet {
295            stream_index: 1,
296            pts: Some(
297                99999,
298            ),
299            dts: Some(
300                54321,
301            ),
302            duration: Some(
303                1000,
304            ),
305            pos: Some(
306                2000,
307            ),
308            is_key: false,
309            is_corrupt: false,
310            is_discard: false,
311            is_trusted: false,
312            is_disposable: false,
313        }
314        ");
315    }
316
317    #[test]
318    fn test_packet_as_ptr() {
319        let packet = Packet::new().expect("Failed to create Packet");
320        let raw_ptr = packet.as_ptr();
321
322        assert!(!raw_ptr.is_null(), "Expected a non-null pointer from Packet::as_ptr");
323        // Safety: `raw_ptr` is a valid pointer.
324        unsafe {
325            assert_eq!(
326                (*raw_ptr).stream_index,
327                0,
328                "Expected the default stream_index to be 0 for a new Packet"
329            );
330        }
331    }
332
333    #[test]
334    fn test_packet_rescale_timebase() {
335        let mut packet = Packet::new().expect("Failed to create Packet");
336        packet.set_pts(Some(1000));
337        packet.set_dts(Some(900));
338        packet.set_duration(Some(100));
339        let from_time_base = AVRational { num: 1, den: 1000 };
340        let to_time_base = AVRational { num: 1, den: 48000 };
341
342        packet.convert_timebase(from_time_base, to_time_base);
343        assert_debug_snapshot!(packet, @r"
344        Packet {
345            stream_index: 0,
346            pts: Some(
347                48000,
348            ),
349            dts: Some(
350                43200,
351            ),
352            duration: Some(
353                4800,
354            ),
355            pos: Some(
356                -1,
357            ),
358            is_key: false,
359            is_corrupt: false,
360            is_discard: false,
361            is_trusted: false,
362            is_disposable: false,
363        }
364        ");
365    }
366
367    #[test]
368    fn test_packet_data_empty() {
369        let mut packet = Packet::new().expect("Failed to create Packet");
370        // Safety: `packet.as_mut_ptr()` is a valid pointer.
371        unsafe {
372            let av_packet = packet.as_mut_ptr().as_mut().unwrap();
373            av_packet.size = 0;
374        }
375
376        let data = packet.data();
377
378        assert!(
379            data.is_empty(),
380            "Expected the data slice to be empty when packet size is zero"
381        );
382    }
383}