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