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