Skip to main content

ffmpeg_next/codec/packet/
packet.rs

1use std::marker::PhantomData;
2use std::mem;
3use std::slice;
4
5use super::{Borrow, Flags, Mut, Ref, SideData};
6use crate::ffi::*;
7use crate::{Error, Rational, format};
8use libc::c_int;
9
10pub struct Packet(AVPacket);
11
12unsafe impl Send for Packet {}
13unsafe impl Sync for Packet {}
14
15impl Packet {
16    #[inline(always)]
17    pub unsafe fn is_empty(&self) -> bool {
18        self.0.size == 0
19    }
20
21    #[inline(always)]
22    fn lacks_payload_and_side_data(&self) -> bool {
23        self.0.size == 0 && self.0.side_data_elems == 0
24    }
25}
26
27impl Packet {
28    #[inline]
29    pub fn empty() -> Self {
30        unsafe {
31            let mut pkt: AVPacket = mem::zeroed();
32
33            av_init_packet(&mut pkt);
34
35            Packet(pkt)
36        }
37    }
38
39    #[inline]
40    pub fn new(size: usize) -> Self {
41        unsafe {
42            let mut pkt: AVPacket = mem::zeroed();
43
44            av_init_packet(&mut pkt);
45            av_new_packet(&mut pkt, size as c_int);
46
47            Packet(pkt)
48        }
49    }
50
51    #[inline]
52    pub fn copy(data: &[u8]) -> Self {
53        use std::io::Write;
54
55        let mut packet = Packet::new(data.len());
56        packet.data_mut().unwrap().write_all(data).unwrap();
57
58        packet
59    }
60
61    #[inline]
62    pub fn borrow(data: &[u8]) -> Borrow<'_> {
63        Borrow::new(data)
64    }
65
66    #[inline]
67    pub fn shrink(&mut self, size: usize) {
68        unsafe {
69            av_shrink_packet(&mut self.0, size as c_int);
70        }
71    }
72
73    #[inline]
74    pub fn grow(&mut self, size: usize) {
75        unsafe {
76            av_grow_packet(&mut self.0, size as c_int);
77        }
78    }
79
80    #[inline]
81    pub fn rescale_ts<S, D>(&mut self, source: S, destination: D)
82    where
83        S: Into<Rational>,
84        D: Into<Rational>,
85    {
86        unsafe {
87            av_packet_rescale_ts(
88                self.as_mut_ptr(),
89                source.into().into(),
90                destination.into().into(),
91            );
92        }
93    }
94
95    #[inline]
96    pub fn flags(&self) -> Flags {
97        Flags::from_bits_truncate(self.0.flags)
98    }
99
100    #[inline]
101    pub fn set_flags(&mut self, value: Flags) {
102        self.0.flags = value.bits();
103    }
104
105    #[inline]
106    pub fn is_key(&self) -> bool {
107        self.flags().contains(Flags::KEY)
108    }
109
110    #[inline]
111    pub fn is_corrupt(&self) -> bool {
112        self.flags().contains(Flags::CORRUPT)
113    }
114
115    #[inline]
116    pub fn stream(&self) -> usize {
117        self.0.stream_index as usize
118    }
119
120    #[inline]
121    pub fn set_stream(&mut self, index: usize) {
122        self.0.stream_index = index as c_int;
123    }
124
125    #[inline]
126    pub fn pts(&self) -> Option<i64> {
127        match self.0.pts {
128            AV_NOPTS_VALUE => None,
129            pts => Some(pts),
130        }
131    }
132
133    #[inline]
134    pub fn set_pts(&mut self, value: Option<i64>) {
135        self.0.pts = value.unwrap_or(AV_NOPTS_VALUE);
136    }
137
138    #[inline]
139    pub fn dts(&self) -> Option<i64> {
140        match self.0.dts {
141            AV_NOPTS_VALUE => None,
142            dts => Some(dts),
143        }
144    }
145
146    #[inline]
147    pub fn set_dts(&mut self, value: Option<i64>) {
148        self.0.dts = value.unwrap_or(AV_NOPTS_VALUE);
149    }
150
151    #[inline]
152    #[cfg(feature = "ffmpeg_5_0")]
153    pub fn time_base(&self) -> Rational {
154        self.0.time_base.into()
155    }
156
157    #[inline]
158    #[cfg(feature = "ffmpeg_5_0")]
159    pub fn set_time_base(&mut self, value: Rational) {
160        self.0.time_base = value.into();
161    }
162
163    #[inline]
164    pub fn size(&self) -> usize {
165        self.0.size as usize
166    }
167
168    #[inline]
169    pub fn duration(&self) -> i64 {
170        self.0.duration
171    }
172
173    #[inline]
174    pub fn set_duration(&mut self, value: i64) {
175        self.0.duration = value;
176    }
177
178    #[inline]
179    pub fn position(&self) -> isize {
180        self.0.pos as isize
181    }
182
183    #[inline]
184    pub fn set_position(&mut self, value: isize) {
185        self.0.pos = value as i64
186    }
187
188    #[inline]
189    #[cfg(not(feature = "ffmpeg_5_0"))]
190    pub fn convergence(&self) -> isize {
191        self.0.convergence_duration as isize
192    }
193
194    #[inline]
195    pub fn side_data(&self) -> SideDataIter<'_> {
196        SideDataIter::new(&self.0)
197    }
198
199    #[inline]
200    pub fn data(&self) -> Option<&[u8]> {
201        unsafe {
202            if self.0.data.is_null() {
203                None
204            } else {
205                Some(slice::from_raw_parts(self.0.data, self.0.size as usize))
206            }
207        }
208    }
209
210    #[inline]
211    pub fn data_mut(&mut self) -> Option<&mut [u8]> {
212        unsafe {
213            if self.0.data.is_null() {
214                None
215            } else {
216                Some(slice::from_raw_parts_mut(self.0.data, self.0.size as usize))
217            }
218        }
219    }
220
221    #[inline]
222    pub fn read(&mut self, format: &mut format::context::Input) -> Result<(), Error> {
223        unsafe {
224            match av_read_frame(format.as_mut_ptr(), self.as_mut_ptr()) {
225                0 => Ok(()),
226                e => Err(Error::from(e)),
227            }
228        }
229    }
230
231    #[inline]
232    pub fn write(&self, format: &mut format::context::Output) -> Result<bool, Error> {
233        unsafe {
234            // FFmpeg allows zero-size packets that still carry side data, such as
235            // FLAC encoder flush packets with AV_PKT_DATA_NEW_EXTRADATA.
236            if self.lacks_payload_and_side_data() {
237                return Err(Error::InvalidData);
238            }
239
240            match av_write_frame(format.as_mut_ptr(), self.as_ptr() as *mut _) {
241                1 => Ok(true),
242                0 => Ok(false),
243                e => Err(Error::from(e)),
244            }
245        }
246    }
247
248    #[inline]
249    pub fn write_interleaved(&self, format: &mut format::context::Output) -> Result<(), Error> {
250        unsafe {
251            // Keep wrapper behavior aligned with av_interleaved_write_frame():
252            // zero-size packets are still valid when they only carry side data.
253            if self.lacks_payload_and_side_data() {
254                return Err(Error::InvalidData);
255            }
256
257            match av_interleaved_write_frame(format.as_mut_ptr(), self.as_ptr() as *mut _) {
258                0 => Ok(()),
259                e => Err(Error::from(e)),
260            }
261        }
262    }
263}
264
265impl Ref for Packet {
266    fn as_ptr(&self) -> *const AVPacket {
267        &self.0
268    }
269}
270
271impl Mut for Packet {
272    fn as_mut_ptr(&mut self) -> *mut AVPacket {
273        &mut self.0
274    }
275}
276
277impl Clone for Packet {
278    #[inline]
279    fn clone(&self) -> Self {
280        let mut pkt = Packet::empty();
281        pkt.clone_from(self);
282
283        pkt
284    }
285
286    #[inline]
287    fn clone_from(&mut self, source: &Self) {
288        #[cfg(feature = "ffmpeg_4_0")]
289        unsafe {
290            av_packet_ref(&mut self.0, &source.0);
291            av_packet_make_writable(&mut self.0);
292        }
293        #[cfg(not(feature = "ffmpeg_4_0"))]
294        unsafe {
295            av_copy_packet(&mut self.0, &source.0);
296        }
297    }
298}
299
300impl Drop for Packet {
301    fn drop(&mut self) {
302        unsafe {
303            av_packet_unref(&mut self.0);
304        }
305    }
306}
307
308pub struct SideDataIter<'a> {
309    ptr: *const AVPacket,
310    cur: c_int,
311
312    _marker: PhantomData<&'a Packet>,
313}
314
315impl<'a> SideDataIter<'a> {
316    pub fn new(ptr: *const AVPacket) -> Self {
317        SideDataIter {
318            ptr,
319            cur: 0,
320            _marker: PhantomData,
321        }
322    }
323}
324
325impl<'a> Iterator for SideDataIter<'a> {
326    type Item = SideData<'a>;
327
328    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
329        unsafe {
330            if self.cur >= (*self.ptr).side_data_elems {
331                None
332            } else {
333                self.cur += 1;
334                Some(SideData::wrap(
335                    (*self.ptr).side_data.offset((self.cur - 1) as isize),
336                ))
337            }
338        }
339    }
340
341    fn size_hint(&self) -> (usize, Option<usize>) {
342        unsafe {
343            let length = (*self.ptr).side_data_elems as usize;
344
345            (length - self.cur as usize, Some(length - self.cur as usize))
346        }
347    }
348}
349
350impl<'a> ExactSizeIterator for SideDataIter<'a> {}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355
356    #[test]
357    fn empty_packet_without_side_data_is_still_empty_for_write_checks() {
358        let packet = Packet::empty();
359
360        assert!(unsafe { packet.is_empty() });
361        assert!(packet.lacks_payload_and_side_data());
362    }
363
364    #[test]
365    fn zero_sized_packet_with_side_data_is_not_treated_as_invalid_empty_packet() {
366        let mut packet = Packet::empty();
367        let side_data = unsafe {
368            av_packet_new_side_data(
369                &mut packet.0,
370                AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
371                1,
372            )
373        };
374
375        assert!(!side_data.is_null());
376        assert!(unsafe { packet.is_empty() });
377        assert!(!packet.lacks_payload_and_side_data());
378    }
379}