xref: /aosp_15_r20/external/virtio-media/extras/ffmpeg-decoder/src/ffmpeg/avcodec.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
1 // Copyright 2022-2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! This module implements a lightweight and safe decoder interface over `libavcodec`. It is
6 //! designed to concentrate all calls to unsafe methods in one place, while providing the same
7 //! low-level access as the libavcodec functions do.
8 
9 use std::ffi::CStr;
10 use std::fmt::Debug;
11 use std::fmt::Display;
12 use std::marker::PhantomData;
13 use std::mem::ManuallyDrop;
14 use std::ops::Deref;
15 
16 use libc::c_char;
17 use libc::c_int;
18 use libc::c_void;
19 use thiserror::Error as ThisError;
20 
21 use super::*;
22 use crate::ffmpeg::ffi::AVPictureType;
23 
24 /// An error returned by a low-level libavcodec function.
25 #[derive(Debug, ThisError)]
26 pub struct AvError(pub libc::c_int);
27 
28 impl AvError {
result(ret: c_int) -> Result<(), Self>29     pub fn result(ret: c_int) -> Result<(), Self> {
30         if ret >= 0 {
31             Ok(())
32         } else {
33             Err(AvError(ret))
34         }
35     }
36 }
37 
38 impl Display for AvError {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result39     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40         let mut buffer = [0u8; 255];
41         let ret =
42             // SAFETY:
43             // Safe because we are passing valid bounds for the buffer.
44             unsafe { ffi::av_strerror(self.0, buffer.as_mut_ptr() as *mut c_char, buffer.len()) };
45         match ret {
46             ret if ret >= 0 => {
47                 let end_of_string = buffer.iter().position(|i| *i == 0).unwrap_or(buffer.len());
48                 let error_string = std::string::String::from_utf8_lossy(&buffer[..end_of_string]);
49                 f.write_str(&error_string)
50             }
51             _ => f.write_fmt(format_args!("Unknown avcodec error {}", self.0)),
52         }
53     }
54 }
55 
56 /// Lightweight abstraction over libavcodec's `AVCodec` struct, allowing the query the capabilities
57 /// of supported codecs and opening a session to work with them.
58 ///
59 /// `AVCodec` instances in libavcodec are all static, hence we can safely use a static reference
60 /// lifetime here.
61 #[derive(Copy, Clone)]
62 pub struct AvCodec(&'static ffi::AVCodec);
63 
64 /// SAFETY: `AVCodec` is static and thus safe to share.
65 unsafe impl Send for AvCodec {}
66 
67 #[derive(Debug, ThisError)]
68 pub enum AvCodecOpenError {
69     #[error("failed to allocate AVContext object")]
70     ContextAllocation,
71     #[error("failed to open AVContext object")]
72     ContextOpen,
73     #[error("ContextBuilder variant does not match codec type")]
74     UnexpectedCodecType,
75 }
76 
77 /// Dimensions of a frame, used in AvCodecContext and AvFrame.
78 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
79 pub struct Dimensions {
80     pub width: u32,
81     pub height: u32,
82 }
83 
84 impl AvCodec {
85     /// Returns whether the codec is a decoder.
is_decoder(&self) -> bool86     pub fn is_decoder(&self) -> bool {
87         // SAFETY:
88         // Safe because `av_codec_is_decoder` is called on a valid static `AVCodec` reference.
89         (unsafe { ffi::av_codec_is_decoder(self.0) } != 0)
90     }
91 
92     /// Returns whether the codec is an encoder.
is_encoder(&self) -> bool93     pub fn is_encoder(&self) -> bool {
94         // SAFETY:
95         // Safe because `av_codec_is_encoder` is called on a valid static `AVCodec` reference.
96         (unsafe { ffi::av_codec_is_encoder(self.0) } != 0)
97     }
98 
99     /// Returns the name of the codec.
name(&self) -> &'static str100     pub fn name(&self) -> &'static str {
101         const INVALID_CODEC_STR: &str = "invalid codec";
102 
103         // SAFETY:
104         // Safe because `CStr::from_ptr` is called on a valid zero-terminated C string.
105         unsafe { CStr::from_ptr(self.0.name).to_str() }.unwrap_or(INVALID_CODEC_STR)
106     }
107 
108     /// Returns the capabilities of the codec, as a mask of AV_CODEC_CAP_* bits.
capabilities(&self) -> u32109     pub fn capabilities(&self) -> u32 {
110         self.0.capabilities as u32
111     }
112 
113     /// Returns an iterator over the profiles supported by this codec.
profile_iter(&self) -> AvProfileIterator114     pub fn profile_iter(&self) -> AvProfileIterator {
115         AvProfileIterator(self.0.profiles)
116     }
117 
118     /// Returns an iterator over the pixel formats supported by this codec.
119     ///
120     /// For a decoder, the returned array will likely be empty. This means that ffmpeg's native
121     /// pixel format (YUV420) will be used.
pixel_format_iter(&self) -> AvPixelFormatIterator122     pub fn pixel_format_iter(&self) -> AvPixelFormatIterator {
123         AvPixelFormatIterator(self.0.pix_fmts)
124     }
125 
126     /// Get a builder for a encoder [`AvCodecContext`] using this codec.
build_encoder(&self) -> Result<EncoderContextBuilder, AvCodecOpenError>127     pub fn build_encoder(&self) -> Result<EncoderContextBuilder, AvCodecOpenError> {
128         if !self.is_encoder() {
129             return Err(AvCodecOpenError::UnexpectedCodecType);
130         }
131 
132         Ok(EncoderContextBuilder {
133             codec: self.0,
134             context: self.alloc_context()?,
135         })
136     }
137 
138     /// Get a builder for a decoder [`AvCodecContext`] using this codec.
build_decoder(&self) -> Result<DecoderContextBuilder, AvCodecOpenError>139     pub fn build_decoder(&self) -> Result<DecoderContextBuilder, AvCodecOpenError> {
140         if !self.is_decoder() {
141             return Err(AvCodecOpenError::UnexpectedCodecType);
142         }
143 
144         Ok(DecoderContextBuilder {
145             codec: self.0,
146             context: self.alloc_context()?,
147         })
148     }
149 
150     /// Internal helper for `build_decoder` to allocate an [`AvCodecContext`]. This needs to be
151     /// paired with a later call to [`AvCodecContext::init`].
alloc_context(&self) -> Result<AvCodecContext, AvCodecOpenError>152     fn alloc_context(&self) -> Result<AvCodecContext, AvCodecOpenError> {
153         // TODO(b:315859322): add safety doc string
154         #[allow(clippy::undocumented_unsafe_blocks)]
155         let context = unsafe { ffi::avcodec_alloc_context3(self.0).as_mut() }
156             .ok_or(AvCodecOpenError::ContextAllocation)?;
157 
158         Ok(AvCodecContext(context))
159     }
160 }
161 
162 /// A builder to create a [`AvCodecContext`] suitable for decoding.
163 // This struct wraps an AvCodecContext directly, but the only way it can be taken out is to call
164 // `build()`, which finalizes the context and prevent further modification to the callback, etc.
165 pub struct DecoderContextBuilder {
166     codec: *const ffi::AVCodec,
167     context: AvCodecContext,
168 }
169 
170 impl DecoderContextBuilder {
171     /// Set a custom callback that provides output buffers.
172     ///
173     /// `get_buffer2` is a function that decides which buffer is used to render a frame (see
174     /// libavcodec's documentation for `get_buffer2` for more details). If provided, this function
175     /// must be thread-safe.
176     /// `opaque` is a pointer that will be passed as first argument to `get_buffer2` when it is
177     /// called.
set_get_buffer_2( &mut self, get_buffer2: unsafe extern "C" fn(*mut ffi::AVCodecContext, *mut ffi::AVFrame, i32) -> i32, opaque: *mut libc::c_void, )178     pub fn set_get_buffer_2(
179         &mut self,
180         get_buffer2: unsafe extern "C" fn(*mut ffi::AVCodecContext, *mut ffi::AVFrame, i32) -> i32,
181         opaque: *mut libc::c_void,
182     ) {
183         // SAFETY:
184         // Safe because self.context.0 is a pointer to a live AVCodecContext allocation.
185         let context = unsafe { &mut *(self.context.0) };
186         context.get_buffer2 = Some(get_buffer2);
187         context.opaque = opaque;
188     }
189 
190     /// Set the initial format for the context.
191     ///
192     /// This ensures the context has a valid resolution and pixel format right after its creation.
set_initial_format(&self, coded_format: (u32, u32), pix_fmt: AvPixelFormat)193     pub fn set_initial_format(&self, coded_format: (u32, u32), pix_fmt: AvPixelFormat) {
194         // SAFETY:
195         // Safe because self.context.0 is a pointer to a live AVCodecContext allocation.
196         let context = unsafe { &mut *(self.context.0) };
197         context.width = coded_format.0 as i32;
198         context.height = coded_format.1 as i32;
199         context.coded_width = coded_format.0 as i32;
200         context.coded_height = coded_format.1 as i32;
201         context.pix_fmt = pix_fmt.0;
202     }
203 
204     /// Build a decoder AvCodecContext from the configured options.
build(mut self) -> Result<AvCodecContext, AvCodecOpenError>205     pub fn build(mut self) -> Result<AvCodecContext, AvCodecOpenError> {
206         self.context.init(self.codec)?;
207         Ok(self.context)
208     }
209 }
210 
211 /// A builder to create a [`AvCodecContext`] suitable for encoding.
212 // This struct wraps an AvCodecContext directly, but the only way it can be taken out is to call
213 // `build()`, which finalizes the context and prevent further modification to the callback, etc.
214 pub struct EncoderContextBuilder {
215     codec: *const ffi::AVCodec,
216     context: AvCodecContext,
217 }
218 
219 impl EncoderContextBuilder {
220     /// Set the width of input frames for this encoding context.
set_dimensions(&mut self, dimensions: Dimensions)221     pub fn set_dimensions(&mut self, dimensions: Dimensions) {
222         // TODO(b:315859322): add safety doc string
223         #[allow(clippy::undocumented_unsafe_blocks)]
224         let context = unsafe { &mut *(self.context.0) };
225         context.width = dimensions.width as _;
226         context.height = dimensions.height as _;
227     }
228 
229     /// Set the time base for this encoding context.
set_time_base(&mut self, time_base: ffi::AVRational)230     pub fn set_time_base(&mut self, time_base: ffi::AVRational) {
231         // TODO(b:315859322): add safety doc string
232         #[allow(clippy::undocumented_unsafe_blocks)]
233         let context = unsafe { &mut *(self.context.0) };
234         context.time_base = time_base;
235     }
236 
237     /// Set the input pixel format for this encoding context.
set_pix_fmt(&mut self, fmt: AvPixelFormat)238     pub fn set_pix_fmt(&mut self, fmt: AvPixelFormat) {
239         // TODO(b:315859322): add safety doc string
240         #[allow(clippy::undocumented_unsafe_blocks)]
241         let context = unsafe { &mut *(self.context.0) };
242         context.pix_fmt = fmt.pix_fmt();
243     }
244 
245     /// Build a encoder AvCodecContext from the configured options.
build(mut self) -> Result<AvCodecContext, AvCodecOpenError>246     pub fn build(mut self) -> Result<AvCodecContext, AvCodecOpenError> {
247         self.context.init(self.codec)?;
248         Ok(self.context)
249     }
250 }
251 
252 impl Default for AvCodecIterator {
default() -> Self253     fn default() -> Self {
254         Self::new()
255     }
256 }
257 
258 /// Lightweight abstraction over libavcodec's `av_codec_iterate` function that can be used to
259 /// enumerate all the supported codecs.
260 pub struct AvCodecIterator(*mut libc::c_void);
261 
262 impl AvCodecIterator {
new() -> Self263     pub fn new() -> Self {
264         Self(std::ptr::null_mut())
265     }
266 }
267 
268 impl Iterator for AvCodecIterator {
269     type Item = AvCodec;
270 
next(&mut self) -> Option<Self::Item>271     fn next(&mut self) -> Option<Self::Item> {
272         // SAFETY:
273         // Safe because our pointer was initialized to `NULL` and we only use it with
274         // `av_codec_iterate`, which will update it to a valid value.
275         unsafe { ffi::av_codec_iterate(&mut self.0 as *mut *mut libc::c_void).as_ref() }
276             .map(AvCodec)
277     }
278 }
279 
280 /// Simple wrapper over `AVProfile` that provides helpful methods.
281 pub struct AvProfile(&'static ffi::AVProfile);
282 
283 impl AvProfile {
284     /// Return the profile id, which can be matched against FF_PROFILE_*.
profile(&self) -> u32285     pub fn profile(&self) -> u32 {
286         self.0.profile as u32
287     }
288 
289     /// Return the name of this profile.
name(&self) -> &'static str290     pub fn name(&self) -> &'static str {
291         const INVALID_PROFILE_STR: &str = "invalid profile";
292 
293         // SAFETY:
294         // Safe because `CStr::from_ptr` is called on a valid zero-terminated C string.
295         unsafe { CStr::from_ptr(self.0.name).to_str() }.unwrap_or(INVALID_PROFILE_STR)
296     }
297 }
298 
299 impl Display for AvProfile {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result300     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301         f.write_str(self.name())
302     }
303 }
304 
305 impl Debug for AvProfile {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result306     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307         Display::fmt(self, f)
308     }
309 }
310 
311 /// Lightweight abstraction over the array of supported profiles for a given codec.
312 pub struct AvProfileIterator(*const ffi::AVProfile);
313 
314 impl Iterator for AvProfileIterator {
315     type Item = AvProfile;
316 
next(&mut self) -> Option<Self::Item>317     fn next(&mut self) -> Option<Self::Item> {
318         // SAFETY:
319         // Safe because the contract of `new` stipulates we have received a valid `AVCodec`
320         // reference, thus the `profiles` pointer must either be NULL or point to a valid array
321         // or `VAProfile`s.
322         match unsafe { self.0.as_ref() } {
323             None => None,
324             Some(profile) => {
325                 match profile.profile {
326                     ffi::FF_PROFILE_UNKNOWN => None,
327                     _ => {
328                         // SAFETY:
329                         // Safe because we have been initialized to a static, valid profiles array
330                         // which is terminated by FF_PROFILE_UNKNOWN.
331                         self.0 = unsafe { self.0.offset(1) };
332                         Some(AvProfile(profile))
333                     }
334                 }
335             }
336         }
337     }
338 }
339 
340 #[derive(Clone, Copy)]
341 /// Simple wrapper over `AVPixelFormat` that provides helpful methods.
342 pub struct AvPixelFormat(pub ffi::AVPixelFormat);
343 
344 pub const AV_PIXEL_FORMAT_YUV420P: AvPixelFormat =
345     AvPixelFormat(ffi::AVPixelFormat_AV_PIX_FMT_YUV420P);
346 pub const AV_PIXEL_FORMAT_NV12: AvPixelFormat = AvPixelFormat(ffi::AVPixelFormat_AV_PIX_FMT_NV12);
347 
348 impl From<AvPixelFormat> for ffi::AVPixelFormat {
from(val: AvPixelFormat) -> Self349     fn from(val: AvPixelFormat) -> Self {
350         val.0
351     }
352 }
353 
354 impl AvPixelFormat {
355     /// Return the name of this pixel format.
name(&self) -> &'static str356     pub fn name(&self) -> &'static str {
357         const INVALID_FORMAT_STR: &str = "invalid pixel format";
358 
359         // SAFETY:
360         // Safe because `av_get_pix_fmt_name` returns either NULL or a valid C string.
361         let pix_fmt_name = unsafe { ffi::av_get_pix_fmt_name(self.0) };
362         // SAFETY:
363         // Safe because `pix_fmt_name` is a valid pointer to a C string.
364         match unsafe {
365             pix_fmt_name
366                 .as_ref()
367                 .and_then(|s| CStr::from_ptr(s).to_str().ok())
368         } {
369             None => INVALID_FORMAT_STR,
370             Some(string) => string,
371         }
372     }
373 
374     /// Return the avcodec profile id, which can be matched against AV_PIX_FMT_*.
375     ///
376     /// Note that this is **not** the same as a fourcc.
pix_fmt(&self) -> ffi::AVPixelFormat377     pub fn pix_fmt(&self) -> ffi::AVPixelFormat {
378         self.0
379     }
380 
381     /// Return the fourcc of the pixel format, or a series of zeros if its fourcc is unknown.
fourcc(&self) -> [u8; 4]382     pub fn fourcc(&self) -> [u8; 4] {
383         // SAFETY:
384         // Safe because `avcodec_pix_fmt_to_codec_tag` does not take any pointer as input and
385         // handles any value passed as argument.
386         unsafe { ffi::avcodec_pix_fmt_to_codec_tag(self.0) }.to_le_bytes()
387     }
388 
389     /// Given the width and plane index, returns the line size (data pointer increment per row) in
390     /// bytes.
line_size(&self, width: u32, plane: usize) -> usize391     pub fn line_size(&self, width: u32, plane: usize) -> usize {
392         // This should not fail if the format is correct.
393         av_image_line_size(*self, width, plane).unwrap_or_default()
394     }
395 
396     /// Given an iterator of line sizes and height, return the size required for each plane's buffer
397     /// in bytes.
plane_sizes<I: IntoIterator<Item = u32>>( &self, linesizes: I, height: u32, ) -> Vec<usize>398     pub fn plane_sizes<I: IntoIterator<Item = u32>>(
399         &self,
400         linesizes: I,
401         height: u32,
402     ) -> Vec<usize> {
403         av_image_plane_sizes(*self, linesizes, height).unwrap_or_default()
404     }
405 }
406 
407 #[derive(Debug)]
408 pub struct FromAVPixelFormatError(());
409 
410 impl TryFrom<ffi::AVPixelFormat> for AvPixelFormat {
411     type Error = FromAVPixelFormatError;
412 
try_from(value: ffi::AVPixelFormat) -> Result<Self, Self::Error>413     fn try_from(value: ffi::AVPixelFormat) -> Result<Self, Self::Error> {
414         if value > ffi::AVPixelFormat_AV_PIX_FMT_NONE && value < ffi::AVPixelFormat_AV_PIX_FMT_NB {
415             Ok(AvPixelFormat(value))
416         } else {
417             Err(FromAVPixelFormatError(()))
418         }
419     }
420 }
421 
422 impl Display for AvPixelFormat {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result423     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424         f.write_str(self.name())
425     }
426 }
427 
428 impl Debug for AvPixelFormat {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result429     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
430         let fourcc = self.fourcc();
431         f.write_fmt(format_args!(
432             "{}{}{}{}",
433             fourcc[0] as char, fourcc[1] as char, fourcc[2] as char, fourcc[3] as char
434         ))
435     }
436 }
437 
438 /// Lightweight abstraction over the array of supported pixel formats for a given codec.
439 pub struct AvPixelFormatIterator(*const ffi::AVPixelFormat);
440 
441 impl Iterator for AvPixelFormatIterator {
442     type Item = AvPixelFormat;
443 
next(&mut self) -> Option<Self::Item>444     fn next(&mut self) -> Option<Self::Item> {
445         // SAFETY:
446         // Safe because the contract of `AvCodec::new` and `AvCodec::pixel_format_iter` guarantees
447         // that we have been built from a valid `AVCodec` reference, which `pix_fmts` pointer
448         // must either be NULL or point to a valid array or `VAPixelFormat`s.
449         match unsafe { self.0.as_ref() } {
450             None => None,
451             Some(&pixfmt) => {
452                 match pixfmt {
453                     // Array of pixel formats is terminated by AV_PIX_FMT_NONE.
454                     ffi::AVPixelFormat_AV_PIX_FMT_NONE => None,
455                     _ => {
456                         // SAFETY:
457                         // Safe because we have been initialized to a static, valid profiles array
458                         // which is terminated by AV_PIX_FMT_NONE.
459                         self.0 = unsafe { self.0.offset(1) };
460                         Some(AvPixelFormat(pixfmt))
461                     }
462                 }
463             }
464         }
465     }
466 }
467 
468 /// A codec context from which decoding can be performed.
469 pub struct AvCodecContext(*mut ffi::AVCodecContext);
470 
471 impl Drop for AvCodecContext {
drop(&mut self)472     fn drop(&mut self) {
473         // SAFETY:
474         // Safe because our context member is properly allocated and owned by us.
475         // Note: `avcodec_open2` might not have been called in case we're wrapped by a
476         //       `DecoderContextBuilder` but avcodec_free_context works on both opened and closed
477         //       contexts.
478         unsafe { ffi::avcodec_free_context(&mut self.0) };
479     }
480 }
481 
482 impl AsRef<ffi::AVCodecContext> for AvCodecContext {
as_ref(&self) -> &ffi::AVCodecContext483     fn as_ref(&self) -> &ffi::AVCodecContext {
484         // SAFETY:
485         // Safe because our context member is properly initialized and fully owned by us.
486         unsafe { &*self.0 }
487     }
488 }
489 
490 pub enum TryReceiveResult {
491     Received,
492     TryAgain,
493     FlushCompleted,
494 }
495 
496 impl AvCodecContext {
497     /// Internal helper for [`DecoderContextBuilder`] to initialize the context.
init(&mut self, codec: *const ffi::AVCodec) -> Result<(), AvCodecOpenError>498     fn init(&mut self, codec: *const ffi::AVCodec) -> Result<(), AvCodecOpenError> {
499         // SAFETY:
500         // Safe because `codec` is a valid static AVCodec reference, and `self.0` is a valid
501         // AVCodecContext allocation.
502         if unsafe { ffi::avcodec_open2(self.0, codec, std::ptr::null_mut()) } < 0 {
503             return Err(AvCodecOpenError::ContextOpen);
504         }
505 
506         Ok(())
507     }
508 
509     /// Send a packet to be decoded by the codec.
510     ///
511     /// Returns `true` if the packet has been accepted and will be decoded, `false` if the codec can
512     /// not accept frames at the moment - in this case `try_receive_frame` must be called before
513     /// the packet can be submitted again.
514     ///
515     /// Error codes are the same as those returned by `avcodec_send_packet` with the exception of
516     /// EAGAIN which is converted into `Ok(false)` as it is not actually an error.
try_send_packet(&mut self, packet: &AvPacket) -> Result<bool, AvError>517     pub fn try_send_packet(&mut self, packet: &AvPacket) -> Result<bool, AvError> {
518         // SAFETY:
519         // Safe because the context is valid through the life of this object, and `packet`'s
520         // lifetime properties ensures its memory area is readable.
521         match unsafe { ffi::avcodec_send_packet(self.0, &packet.packet) } {
522             AVERROR_EAGAIN => Ok(false),
523             ret if ret >= 0 => Ok(true),
524             err => Err(AvError(err)),
525         }
526     }
527 
528     /// Attempt to write a decoded frame in `frame` if the codec has enough data to do so.
529     ///
530     /// Returns `Received` if `frame` has been filled with the next decoded frame, `TryAgain` if
531     /// no frame could be returned at that time (in which case `try_send_packet` should be called to
532     /// submit more input to decode), or `FlushCompleted` to signal that a previous flush triggered
533     /// by calling the `flush` method has completed.
534     ///
535     /// Error codes are the same as those returned by `avcodec_receive_frame` with the exception of
536     /// EAGAIN and EOF which are handled as `TryAgain` and `FlushCompleted` respectively.
try_receive_frame(&mut self, frame: &mut AvFrame) -> Result<TryReceiveResult, AvError>537     pub fn try_receive_frame(&mut self, frame: &mut AvFrame) -> Result<TryReceiveResult, AvError> {
538         // SAFETY:
539         // Safe because the context is valid through the life of this object, and `avframe` is
540         // guaranteed to contain a properly initialized frame.
541         match unsafe { ffi::avcodec_receive_frame(self.0, frame.0) } {
542             AVERROR_EAGAIN => Ok(TryReceiveResult::TryAgain),
543             AVERROR_EOF => Ok(TryReceiveResult::FlushCompleted),
544             ret if ret >= 0 => Ok(TryReceiveResult::Received),
545             err => Err(AvError(err)),
546         }
547     }
548 
549     /// Send a frame to be encoded by the codec.
550     ///
551     /// Returns `true` if the frame has been accepted and will be encoded, `false` if the codec can
552     /// not accept input at the moment - in this case `try_receive_frame` must be called before
553     /// the frame can be submitted again.
554     ///
555     /// Error codes are the same as those returned by `avcodec_send_frame` with the exception of
556     /// EAGAIN which is converted into `Ok(false)` as it is not actually an error.
try_send_frame(&mut self, frame: &AvFrame) -> Result<bool, AvError>557     pub fn try_send_frame(&mut self, frame: &AvFrame) -> Result<bool, AvError> {
558         // TODO(b:315859322): add safety doc string
559         #[allow(clippy::undocumented_unsafe_blocks)]
560         match unsafe { ffi::avcodec_send_frame(self.0, frame.0 as *const _) } {
561             AVERROR_EAGAIN => Ok(false),
562             ret if ret >= 0 => Ok(true),
563             err => Err(AvError(err)),
564         }
565     }
566 
567     /// Attempt to write an encoded frame in `packet` if the codec has enough data to do so.
568     ///
569     /// Returns `Received` if `packet` has been filled with encoded data, `TryAgain` if
570     /// no packet could be returned at that time (in which case `try_send_frame` should be called to
571     /// submit more input to decode), or `FlushCompleted` to signal that a previous flush triggered
572     /// by calling the `flush` method has completed.
573     ///
574     /// Error codes are the same as those returned by `avcodec_receive_packet` with the exception of
575     /// EAGAIN and EOF which are handled as `TryAgain` and `FlushCompleted` respectively.
try_receive_packet( &mut self, packet: &mut AvPacket, ) -> Result<TryReceiveResult, AvError>576     pub fn try_receive_packet(
577         &mut self,
578         packet: &mut AvPacket,
579     ) -> Result<TryReceiveResult, AvError> {
580         // SAFETY:
581         // Safe because the context is valid through the life of this object, and `avframe` is
582         // guaranteed to contain a properly initialized frame.
583         match unsafe { ffi::avcodec_receive_packet(self.0, &mut packet.packet) } {
584             AVERROR_EAGAIN => Ok(TryReceiveResult::TryAgain),
585             AVERROR_EOF => Ok(TryReceiveResult::FlushCompleted),
586             ret if ret >= 0 => Ok(TryReceiveResult::Received),
587             err => Err(AvError(err)),
588         }
589     }
590 
591     /// Reset the internal codec state/flush internal buffers.
592     /// Should be called e.g. when seeking or switching to a different stream.
reset(&mut self)593     pub fn reset(&mut self) {
594         // SAFETY:
595         // Safe because the context is valid through the life of this object.
596         unsafe { ffi::avcodec_flush_buffers(self.0) }
597     }
598 
599     /// Ask the context to start flushing, i.e. to process all pending input packets and produce
600     /// frames for them.
601     ///
602     /// The flush process is complete when `try_receive_frame` returns `FlushCompleted`,
flush_decoder(&mut self) -> Result<(), AvError>603     pub fn flush_decoder(&mut self) -> Result<(), AvError> {
604         // SAFETY:
605         // Safe because the context is valid through the life of this object.
606         AvError::result(unsafe { ffi::avcodec_send_packet(self.0, std::ptr::null()) })
607     }
608 
609     /// Ask the context to start flushing, i.e. to process all pending input frames and produce
610     /// packets for them.
611     ///
612     /// The flush process is complete when `try_receive_packet` returns `FlushCompleted`,
flush_encoder(&mut self) -> Result<(), AvError>613     pub fn flush_encoder(&mut self) -> Result<(), AvError> {
614         // SAFETY:
615         // Safe because the context is valid through the life of this object.
616         AvError::result(unsafe { ffi::avcodec_send_frame(self.0, std::ptr::null()) })
617     }
618 
619     /// Set the time base for this context.
set_time_base(&mut self, time_base: AVRational)620     pub fn set_time_base(&mut self, time_base: AVRational) {
621         // TODO(b:315859322): add safety doc string
622         #[allow(clippy::undocumented_unsafe_blocks)]
623         let context = unsafe { &mut *(self.0) };
624         context.time_base = time_base;
625     }
626 
627     /// Set the bit rate for this context.
set_bit_rate(&mut self, bit_rate: u64)628     pub fn set_bit_rate(&mut self, bit_rate: u64) {
629         // TODO(b:315859322): add safety doc string
630         #[allow(clippy::undocumented_unsafe_blocks)]
631         let context = unsafe { &mut *(self.0) };
632         context.bit_rate = bit_rate as _;
633     }
634 
635     /// Set the max bit rate (rc_max_rate) for this context.
set_max_bit_rate(&mut self, bit_rate: u64)636     pub fn set_max_bit_rate(&mut self, bit_rate: u64) {
637         // TODO(b:315859322): add safety doc string
638         #[allow(clippy::undocumented_unsafe_blocks)]
639         let context = unsafe { &mut *(self.0) };
640         context.rc_max_rate = bit_rate as _;
641     }
642 }
643 
644 /// Trait for types that can be used as data provider for a `AVBuffer`.
645 ///
646 /// `AVBuffer` is an owned buffer type, so all the type needs to do is being able to provide a
647 /// stable pointer to its own data as well as its length. Implementors need to be sendable across
648 /// threads because avcodec is allowed to use threads in its codec implementations.
649 pub trait AvBufferSource: Send {
as_ptr(&self) -> *const u8650     fn as_ptr(&self) -> *const u8;
as_mut_ptr(&mut self) -> *mut u8651     fn as_mut_ptr(&mut self) -> *mut u8;
652 
len(&self) -> usize653     fn len(&self) -> usize;
654 
is_empty(&self) -> bool655     fn is_empty(&self) -> bool {
656         self.len() == 0
657     }
658 }
659 
660 impl AvBufferSource for Vec<u8> {
as_ptr(&self) -> *const u8661     fn as_ptr(&self) -> *const u8 {
662         self.as_ptr()
663     }
664 
as_mut_ptr(&mut self) -> *mut u8665     fn as_mut_ptr(&mut self) -> *mut u8 {
666         self.as_mut_ptr()
667     }
668 
len(&self) -> usize669     fn len(&self) -> usize {
670         self.len()
671     }
672 }
673 
674 /// Wrapper around `AVBuffer` and `AVBufferRef`.
675 ///
676 /// libavcodec can manage its own memory for input and output data. Doing so implies a transparent
677 /// copy of user-provided data (packets or frames) from and to this memory, which is wasteful.
678 ///
679 /// This copy can be avoided by explicitly providing our own buffers to libavcodec using
680 /// `AVBufferRef`. Doing so means that the lifetime of these buffers becomes managed by avcodec.
681 /// This struct helps make this process safe by taking full ownership of an `AvBufferSource` and
682 /// dropping it when libavcodec is done with it.
683 pub struct AvBuffer(*mut ffi::AVBufferRef);
684 
685 impl AvBuffer {
686     /// Create a new `AvBuffer` from an `AvBufferSource`.
687     ///
688     /// Ownership of `source` is transferred to libavcodec, which will drop it when the number of
689     /// references to this buffer reaches zero.
690     ///
691     /// Returns `None` if the buffer could not be created due to an error in libavcodec.
new<D: AvBufferSource + 'static>(source: D) -> Option<Self>692     pub fn new<D: AvBufferSource + 'static>(source: D) -> Option<Self> {
693         // Move storage to the heap so we find it at the same place in `avbuffer_free`
694         let mut storage = Box::new(source);
695 
696         extern "C" fn avbuffer_free<D>(opaque: *mut c_void, _data: *mut u8) {
697             // SAFETY:
698             // Safe because `opaque` has been created from `Box::into_raw`. `storage` will be
699             // dropped immediately which will release any resources held by the storage.
700             let _ = unsafe { Box::from_raw(opaque as *mut D) };
701         }
702 
703         // SAFETY:
704         // Safe because storage points to valid data throughout the lifetime of AVBuffer and we are
705         // checking the return value against NULL, which signals an error.
706         Some(Self(unsafe {
707             ffi::av_buffer_create(
708                 storage.as_mut_ptr(),
709                 storage.len(),
710                 Some(avbuffer_free::<D>),
711                 Box::into_raw(storage) as *mut c_void,
712                 0,
713             )
714             .as_mut()?
715         }))
716     }
717 
718     /// Return a slice to the data contained in this buffer.
as_mut_slice(&mut self) -> &mut [u8]719     pub fn as_mut_slice(&mut self) -> &mut [u8] {
720         // SAFETY:
721         // Safe because the data has been initialized from valid storage in the constructor.
722         unsafe { std::slice::from_raw_parts_mut((*self.0).data, (*self.0).size) }
723     }
724 
725     /// Consumes the `AVBuffer`, returning a `AVBufferRef` that can be used in `AVFrame`, `AVPacket`
726     /// and others.
727     ///
728     /// After calling, the caller is responsible for unref-ing the returned AVBufferRef, either
729     /// directly or through one of the automatic management facilities in `AVFrame`, `AVPacket` or
730     /// others.
into_raw(self) -> *mut ffi::AVBufferRef731     pub fn into_raw(self) -> *mut ffi::AVBufferRef {
732         ManuallyDrop::new(self).0
733     }
734 }
735 
736 impl Drop for AvBuffer {
drop(&mut self)737     fn drop(&mut self) {
738         // SAFETY:
739         // Safe because `self.0` is a valid pointer to an AVBufferRef.
740         unsafe { ffi::av_buffer_unref(&mut self.0) };
741     }
742 }
743 
744 /// An encoded input packet that can be submitted to `AvCodecContext::try_send_packet`.
745 pub struct AvPacket<'a> {
746     packet: ffi::AVPacket,
747     _buffer_data: PhantomData<&'a ()>,
748 }
749 
750 impl<'a> Drop for AvPacket<'a> {
drop(&mut self)751     fn drop(&mut self) {
752         // SAFETY:
753         // Safe because `self.packet` is a valid `AVPacket` instance.
754         unsafe {
755             ffi::av_packet_unref(&mut self.packet);
756         }
757     }
758 }
759 
760 impl<'a> AsRef<ffi::AVPacket> for AvPacket<'a> {
as_ref(&self) -> &ffi::AVPacket761     fn as_ref(&self) -> &ffi::AVPacket {
762         &self.packet
763     }
764 }
765 
766 impl<'a> AvPacket<'a> {
767     /// Create an empty AvPacket without buffers.
768     ///
769     /// This packet should be only used with an encoder; in which case the encoder will
770     /// automatically allocate a buffer of appropriate size and store it inside this `AvPacket`.
empty() -> Self771     pub fn empty() -> Self {
772         Self {
773             packet: ffi::AVPacket {
774                 pts: AV_NOPTS_VALUE as i64,
775                 dts: AV_NOPTS_VALUE as i64,
776                 pos: -1,
777                 // SAFETY:
778                 // Safe because all the other elements of this struct can be zeroed.
779                 ..unsafe { std::mem::zeroed() }
780             },
781             _buffer_data: PhantomData,
782         }
783     }
784 
785     /// Create a new AvPacket that borrows the `input_data`.
786     ///
787     /// The returned `AvPacket` will hold a reference to `input_data`, meaning that libavcodec might
788     /// perform a copy from/to it.
new<T: AvBufferSource>(pts: i64, input_data: &'a mut T) -> Self789     pub fn new<T: AvBufferSource>(pts: i64, input_data: &'a mut T) -> Self {
790         Self {
791             packet: ffi::AVPacket {
792                 buf: std::ptr::null_mut(),
793                 pts,
794                 dts: AV_NOPTS_VALUE as i64,
795                 data: input_data.as_mut_ptr(),
796                 size: input_data.len() as c_int,
797                 side_data: std::ptr::null_mut(),
798                 pos: -1,
799                 // SAFETY:
800                 // Safe because all the other elements of this struct can be zeroed.
801                 ..unsafe { std::mem::zeroed() }
802             },
803             _buffer_data: PhantomData,
804         }
805     }
806 
807     /// Create a new AvPacket that owns the `av_buffer`.
808     ///
809     /// The returned `AvPacket` will have a `'static` lifetime and will keep `input_data` alive for
810     /// as long as libavcodec needs it.
new_owned(pts: i64, mut av_buffer: AvBuffer) -> Self811     pub fn new_owned(pts: i64, mut av_buffer: AvBuffer) -> Self {
812         let data_slice = av_buffer.as_mut_slice();
813         let data = data_slice.as_mut_ptr();
814         let size = data_slice.len() as i32;
815 
816         Self {
817             packet: ffi::AVPacket {
818                 buf: av_buffer.into_raw(),
819                 pts,
820                 dts: AV_NOPTS_VALUE as i64,
821                 data,
822                 size,
823                 side_data: std::ptr::null_mut(),
824                 pos: -1,
825                 // SAFETY:
826                 // Safe because all the other elements of this struct can be zeroed.
827                 ..unsafe { std::mem::zeroed() }
828             },
829             _buffer_data: PhantomData,
830         }
831     }
832 }
833 
834 /// An owned AVFrame, i.e. one decoded frame from libavcodec that can be converted into a
835 /// destination buffer.
836 pub struct AvFrame(*mut ffi::AVFrame);
837 
838 /// A builder for AVFrame that allows specifying buffers and image metadata.
839 pub struct AvFrameBuilder(AvFrame);
840 
841 /// A descriptor describing a subslice of `buffers` in [`AvFrameBuilder::build_owned`] that
842 /// represents a plane's image data.
843 #[derive(Debug, Clone)]
844 pub struct PlaneDescriptor {
845     /// The index within `buffers`.
846     pub buffer_index: usize,
847     /// The offset from the start of `buffers[buffer_index]`.
848     pub offset: usize,
849     /// The increment of data pointer in bytes per row of the plane.
850     pub stride: usize,
851 }
852 
853 #[derive(Debug, ThisError)]
854 pub enum AvFrameError {
855     #[error("failed to allocate AVFrame object")]
856     FrameAllocationFailed,
857     #[error("dimension is negative or too large")]
858     DimensionOverflow,
859     #[error("a row does not fit in the specified stride")]
860     InvalidStride,
861     #[error("buffer index out of range")]
862     BufferOutOfRange,
863     #[error("specified dimensions overflow the buffer size")]
864     BufferTooSmall,
865     #[error("plane reference to buffer alias each other")]
866     BufferAlias,
867     #[error("error while calling libavcodec")]
868     AvError(#[from] AvError),
869 }
870 
871 impl AvFrame {
872     /// Create a new AvFrame. The frame's parameters and backing memory will be assigned when it is
873     /// decoded into.
new() -> Result<Self, AvFrameError>874     pub fn new() -> Result<Self, AvFrameError> {
875         Ok(Self(
876             // SAFETY:
877             // Safe because `av_frame_alloc` does not take any input.
878             unsafe { ffi::av_frame_alloc().as_mut() }.ok_or(AvFrameError::FrameAllocationFailed)?,
879         ))
880     }
881 
882     /// Create a new AvFrame builder that allows setting the frame's parameters and backing memory
883     /// through its methods.
builder() -> Result<AvFrameBuilder, AvFrameError>884     pub fn builder() -> Result<AvFrameBuilder, AvFrameError> {
885         AvFrame::new().map(AvFrameBuilder)
886     }
887 
888     /// Return the frame's width and height.
dimensions(&self) -> Dimensions889     pub fn dimensions(&self) -> Dimensions {
890         Dimensions {
891             width: self.as_ref().width as _,
892             height: self.as_ref().height as _,
893         }
894     }
895 
896     /// Return the frame's pixel format.
format(&self) -> AvPixelFormat897     pub fn format(&self) -> AvPixelFormat {
898         AvPixelFormat(self.as_ref().format)
899     }
900 
901     /// Set the picture type (I-frame, P-frame etc.) on this frame.
set_pict_type(&mut self, ty: AVPictureType)902     pub fn set_pict_type(&mut self, ty: AVPictureType) {
903         // SAFETY:
904         // Safe because self.0 is a valid AVFrame reference.
905         unsafe {
906             (*self.0).pict_type = ty;
907         }
908     }
909 
910     /// Set the presentation timestamp (PTS) of this frame.
set_pts(&mut self, ts: i64)911     pub fn set_pts(&mut self, ts: i64) {
912         // SAFETY:
913         // Safe because self.0 is a valid AVFrame reference.
914         unsafe {
915             (*self.0).pts = ts;
916         }
917     }
918 
919     /// Query if this AvFrame is writable, i.e. it is refcounted and the refcounts are 1.
is_writable(&self) -> bool920     pub fn is_writable(&self) -> bool {
921         // SAFETY:
922         // Safe because self.0 is a valid AVFrame reference.
923         unsafe { ffi::av_frame_is_writable(self.0) != 0 }
924     }
925 
926     /// If the frame is not writable already (see [`is_writable`]), make a copy of its buffer to
927     /// make it writable.
928     ///
929     /// [`is_writable`]: AvFrame::is_writable
make_writable(&mut self) -> Result<(), AvFrameError>930     pub fn make_writable(&mut self) -> Result<(), AvFrameError> {
931         // SAFETY:
932         // Safe because self.0 is a valid AVFrame reference.
933         AvError::result(unsafe { ffi::av_frame_make_writable(self.0) }).map_err(Into::into)
934     }
935 }
936 
937 impl AvFrameBuilder {
938     /// Set the frame's width and height.
939     ///
940     /// The dimensions must not be greater than `i32::MAX`.
set_dimensions(&mut self, dimensions: Dimensions) -> Result<(), AvFrameError>941     pub fn set_dimensions(&mut self, dimensions: Dimensions) -> Result<(), AvFrameError> {
942         // SAFETY:
943         // Safe because self.0 is a valid AVFrame instance and width and height are in range.
944         unsafe {
945             (*self.0 .0).width = dimensions
946                 .width
947                 .try_into()
948                 .map_err(|_| AvFrameError::DimensionOverflow)?;
949             (*self.0 .0).height = dimensions
950                 .height
951                 .try_into()
952                 .map_err(|_| AvFrameError::DimensionOverflow)?;
953         }
954         Ok(())
955     }
956 
957     /// Set the frame's format.
set_format(&mut self, format: AvPixelFormat) -> Result<(), AvFrameError>958     pub fn set_format(&mut self, format: AvPixelFormat) -> Result<(), AvFrameError> {
959         // SAFETY:
960         // Safe because self.0 is a valid AVFrame instance and format is a valid pixel format.
961         unsafe {
962             (*self.0 .0).format = format.pix_fmt();
963         }
964         Ok(())
965     }
966 
967     /// Build an AvFrame from iterators of [`AvBuffer`]s and subslice of buffers describing the
968     /// planes.
969     ///
970     /// The frame will own the `buffers`.
971     ///
972     /// This function checks that:
973     /// - Each plane fits inside the bounds of the associated buffer.
974     /// - Different planes do not overlap each other's buffer slice. In this check, all planes are
975     ///   assumed to be potentially mutable, regardless of whether the AvFrame is actually used for
976     ///   read or write access. Aliasing reference to the same buffer will be rejected, since it can
977     ///   potentially allow routines to overwrite each
978     //    other's result.
979     ///   An exception to this is when the same buffer is passed multiple times in `buffers`. In
980     ///   this case, each buffer is treated as a different buffer. Since clones have to be made to
981     ///   be passed multiple times in `buffers`, the frame will not be considered [writable]. Hence
982     ///   aliasing is safe in this case, but the caller is required to explicit opt-in to this
983     ///   read-only handling by passing clones of the buffer into `buffers` and have a different
984     ///   buffer index for each plane combination that could overlap in their range.
985     ///
986     /// [writable]: AvFrame::is_writable
build_owned< BI: IntoIterator<Item = AvBuffer>, PI: IntoIterator<Item = PlaneDescriptor>, >( self, buffers: BI, planes: PI, ) -> Result<AvFrame, AvFrameError>987     pub fn build_owned<
988         BI: IntoIterator<Item = AvBuffer>,
989         PI: IntoIterator<Item = PlaneDescriptor>,
990     >(
991         self,
992         buffers: BI,
993         planes: PI,
994     ) -> Result<AvFrame, AvFrameError> {
995         let mut buffers: Vec<_> = buffers.into_iter().collect();
996         let planes: Vec<_> = planes.into_iter().collect();
997         let format = self.0.format();
998         let plane_sizes = format.plane_sizes(
999             planes.iter().map(|x| x.stride as u32),
1000             self.0.dimensions().height,
1001         );
1002         let mut ranges = vec![];
1003 
1004         for (
1005             plane,
1006             PlaneDescriptor {
1007                 buffer_index,
1008                 offset,
1009                 stride,
1010             },
1011         ) in planes.into_iter().enumerate()
1012         {
1013             if buffer_index > buffers.len() {
1014                 return Err(AvFrameError::BufferOutOfRange);
1015             }
1016             let end = offset + plane_sizes[plane];
1017             if end > buffers[buffer_index].as_mut_slice().len() {
1018                 return Err(AvFrameError::BufferTooSmall);
1019             }
1020             if stride < format.line_size(self.0.dimensions().width, plane) {
1021                 return Err(AvFrameError::InvalidStride);
1022             }
1023             // TODO(b:315859322): add safety doc string
1024             #[allow(clippy::undocumented_unsafe_blocks)]
1025             unsafe {
1026                 (*self.0 .0).data[plane] =
1027                     buffers[buffer_index].as_mut_slice()[offset..].as_mut_ptr();
1028                 (*self.0 .0).linesize[plane] = stride as c_int;
1029             }
1030             ranges.push((buffer_index, offset, end));
1031         }
1032 
1033         // Check for range overlaps.
1034         // See function documentation for the exact rule and reasoning.
1035         ranges.sort_unstable();
1036         for pair in ranges.windows(2) {
1037             // (buffer_index, start, end)
1038             let (b0, _s0, e0) = pair[0];
1039             let (b1, s1, _e1) = pair[1];
1040 
1041             if b0 != b1 {
1042                 continue;
1043             }
1044             // Note that s0 <= s1 always holds, so we only need to check
1045             // that the start of the second range is before the end of the first range.
1046             if s1 < e0 {
1047                 return Err(AvFrameError::BufferAlias);
1048             }
1049         }
1050 
1051         for (i, buf) in buffers.into_iter().enumerate() {
1052             // SAFETY:
1053             // Safe because self.0 is a valid AVFrame instance and buffers contains valid AvBuffers.
1054             unsafe {
1055                 (*self.0 .0).buf[i] = buf.into_raw();
1056             }
1057         }
1058         Ok(self.0)
1059     }
1060 }
1061 
1062 impl AsRef<ffi::AVFrame> for AvFrame {
as_ref(&self) -> &ffi::AVFrame1063     fn as_ref(&self) -> &ffi::AVFrame {
1064         // SAFETY:
1065         // Safe because the AVFrame has been properly initialized during construction.
1066         unsafe { &*self.0 }
1067     }
1068 }
1069 
1070 impl Deref for AvFrame {
1071     type Target = ffi::AVFrame;
1072 
deref(&self) -> &Self::Target1073     fn deref(&self) -> &Self::Target {
1074         // SAFETY:
1075         // Safe because the AVFrame has been properly initialized during construction.
1076         unsafe { self.0.as_ref().unwrap() }
1077     }
1078 }
1079 
1080 impl Drop for AvFrame {
drop(&mut self)1081     fn drop(&mut self) {
1082         // SAFETY:
1083         // Safe because the AVFrame is valid through the life of this object and fully owned by us.
1084         unsafe { ffi::av_frame_free(&mut self.0) };
1085     }
1086 }
1087 
1088 #[cfg(test)]
1089 mod tests {
1090     use std::sync::atomic::AtomicBool;
1091     use std::sync::atomic::Ordering;
1092     use std::sync::Arc;
1093 
1094     use super::*;
1095 
1096     #[test]
test_averror()1097     fn test_averror() {
1098         // Just test that the error is wrapper properly. The bindings test module already checks
1099         // that the error bindings correspond to the right ffmpeg errors.
1100         let averror = AvError(AVERROR_EOF);
1101         let msg = format!("{}", averror);
1102         assert_eq!(msg, "End of file");
1103 
1104         let averror = AvError(0);
1105         let msg = format!("{}", averror);
1106         assert_eq!(msg, "Success");
1107 
1108         let averror = AvError(10);
1109         let msg = format!("{}", averror);
1110         assert_eq!(msg, "Unknown avcodec error 10");
1111     }
1112 
1113     // Test that the AVPacket wrapper frees the owned AVBuffer on drop.
1114     #[test]
test_avpacket_drop()1115     fn test_avpacket_drop() {
1116         struct DropTestBufferSource {
1117             dropped: Arc<AtomicBool>,
1118         }
1119         impl Drop for DropTestBufferSource {
1120             fn drop(&mut self) {
1121                 self.dropped.store(true, Ordering::SeqCst);
1122             }
1123         }
1124         impl AvBufferSource for DropTestBufferSource {
1125             fn as_ptr(&self) -> *const u8 {
1126                 self as *const _ as *const u8
1127             }
1128 
1129             fn as_mut_ptr(&mut self) -> *mut u8 {
1130                 self as *mut _ as *mut u8
1131             }
1132 
1133             fn len(&self) -> usize {
1134                 0
1135             }
1136         }
1137 
1138         let dropped = Arc::new(AtomicBool::new(false));
1139 
1140         let pkt = AvPacket::new_owned(
1141             0,
1142             AvBuffer::new(DropTestBufferSource {
1143                 dropped: dropped.clone(),
1144             })
1145             .unwrap(),
1146         );
1147         assert!(!dropped.load(Ordering::SeqCst));
1148         drop(pkt);
1149         assert!(dropped.load(Ordering::SeqCst));
1150     }
1151 }
1152