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
10pub 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
23unsafe impl Send for Packets<'_> {}
25
26impl Packets<'_> {
27    pub const unsafe fn new(context: *mut AVFormatContext) -> Self {
33        Self {
34            context,
35            _marker: PhantomData,
36        }
37    }
38
39    pub fn receive(&mut self) -> Result<Option<Packet>, FfmpegError> {
41        let mut packet = Packet::new()?;
42
43        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
60pub struct Packet(SmartPtr<AVPacket>);
62
63unsafe 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        let clone = unsafe { av_packet_clone(self.0.as_ptr()) };
87
88        unsafe { Self::wrap(clone).expect("failed to clone packet") }
90    }
91}
92
93impl Packet {
94    pub fn new() -> Result<Self, FfmpegError> {
96        let packet = unsafe { av_packet_alloc() };
98
99        unsafe { Self::wrap(packet) }.ok_or(FfmpegError::Alloc)
101    }
102
103    unsafe fn wrap(ptr: *mut AVPacket) -> Option<Self> {
109        let destructor = |ptr: &mut *mut AVPacket| {
110            unsafe { av_packet_free(ptr) };
112        };
113
114        unsafe { SmartPtr::wrap_non_null(ptr, destructor).map(Self) }
116    }
117
118    pub const fn as_ptr(&self) -> *const AVPacket {
120        self.0.as_ptr()
121    }
122
123    pub const fn as_mut_ptr(&mut self) -> *mut AVPacket {
125        self.0.as_mut_ptr()
126    }
127
128    pub const fn stream_index(&self) -> i32 {
130        self.0.as_deref_except().stream_index
131    }
132
133    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    pub const fn pts(&self) -> Option<i64> {
140        check_i64(self.0.as_deref_except().pts)
141    }
142
143    pub const fn set_pts(&mut self, pts: Option<i64>) {
145        self.0.as_deref_mut_except().pts = or_nopts(pts);
146    }
147
148    pub const fn dts(&self) -> Option<i64> {
150        check_i64(self.0.as_deref_except().dts)
151    }
152
153    pub const fn set_dts(&mut self, dts: Option<i64>) {
155        self.0.as_deref_mut_except().dts = or_nopts(dts);
156    }
157
158    pub const fn duration(&self) -> Option<i64> {
160        check_i64(self.0.as_deref_except().duration)
161    }
162
163    pub const fn set_duration(&mut self, duration: Option<i64>) {
165        self.0.as_deref_mut_except().duration = or_nopts(duration);
166    }
167
168    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        self.set_pts(self.pts().map(|pts| {
175            unsafe { av_rescale_q_rnd(pts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as _) }
177        }));
178
179        self.set_dts(self.dts().map(|dts| {
181            unsafe { av_rescale_q_rnd(dts, from.into(), to.into(), AVRounding::NearestAwayFromZero.0 as _) }
183        }));
184
185        self.set_duration(
186            self.duration()
187                .map(|duration| unsafe { av_rescale_q(duration, from.into(), to.into()) }),
189        );
190    }
191
192    pub const fn pos(&self) -> Option<i64> {
194        check_i64(self.0.as_deref_except().pos)
195    }
196
197    pub const fn set_pos(&mut self, pos: Option<i64>) {
199        self.0.as_deref_mut_except().pos = or_nopts(pos);
200    }
201
202    pub const fn data(&self) -> &[u8] {
204        if self.0.as_deref_except().size <= 0 {
205            return &[];
206        }
207
208        unsafe { std::slice::from_raw_parts(self.0.as_deref_except().data, self.0.as_deref_except().size as usize) }
210    }
211
212    pub fn is_key(&self) -> bool {
214        self.flags() & AVPktFlags::Key != 0
215    }
216
217    pub fn is_corrupt(&self) -> bool {
219        self.flags() & AVPktFlags::Corrupt != 0
220    }
221
222    pub fn is_discard(&self) -> bool {
224        self.flags() & AVPktFlags::Discard != 0
225    }
226
227    pub fn is_trusted(&self) -> bool {
229        self.flags() & AVPktFlags::Trusted != 0
230    }
231
232    pub fn is_disposable(&self) -> bool {
234        self.flags() & AVPktFlags::Disposable != 0
235    }
236
237    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        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        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        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}