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}