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