From 69ccc4a3a4fba6de1e6aafb1c5ac12fcb6ae43a8 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Sat, 6 Jan 2024 09:22:58 -0800 Subject: [PATCH] Add `opt_set*` methods mirroring `av_opt_set*` --- src/avutil/mod.rs | 2 + src/avutil/opt.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++ src/error.rs | 114 ++++++++++++++++++--------------- 3 files changed, 224 insertions(+), 49 deletions(-) create mode 100644 src/avutil/opt.rs diff --git a/src/avutil/mod.rs b/src/avutil/mod.rs index 10a399f..5ad9a67 100644 --- a/src/avutil/mod.rs +++ b/src/avutil/mod.rs @@ -8,6 +8,7 @@ mod imgutils; mod media_type; mod mem; mod motion_vector; +mod opt; mod pixdesc; mod pixfmt; mod rational; @@ -23,6 +24,7 @@ pub use imgutils::*; pub use media_type::*; pub use mem::*; pub use motion_vector::*; +pub use opt::*; pub use pixdesc::*; pub use pixfmt::*; pub use rational::*; diff --git a/src/avutil/opt.rs b/src/avutil/opt.rs new file mode 100644 index 0000000..15a3a27 --- /dev/null +++ b/src/avutil/opt.rs @@ -0,0 +1,157 @@ +use crate::error::Result; +use crate::ffi; +use crate::ffi::AVPixelFormat; +use crate::ffi::AVRational; +use crate::ffi::AVSampleFormat; +use crate::shared::RetUpgrade; +use std::ffi::{c_double, c_int, c_void, CStr}; + +/// - `name`: the name of the field to set +/// - `val`: if the field is not of a string type, then the given string is parsed. +/// SI postfixes and some named scalars are supported. +/// If the field is of a numeric type, it has to be a numeric or named +/// scalar. Behavior with more than one scalar and +- infix operators +/// is undefined. +/// If the field is of a flags type, it has to be a sequence of numeric +/// scalars or named flags separated by '+' or '-'. Prefixing a flag +/// with '+' causes it to be set without affecting the other flags; +/// similarly, '-' unsets a flag. +/// If the field is of a dictionary type, it has to be a ':' separated list of +/// key=value parameters. Values containing ':' special characters must be +/// escaped. +/// - `search_flags`: flags passed to `av_opt_find2`. I.e. if `AV_OPT_SEARCH_CHILDREN`` +/// is passed here, then the option may be set on a child of obj. +/// +/// This function returns `Ok(())` if the value has been set, or an AVERROR code in case of error: +/// `AVERROR_OPTION_NOT_FOUND` if no matching option exists +/// `AVERROR(ERANGE)` if the value is out of range +/// `AVERROR(EINVAL)` if the value is not valid +/// +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set( + obj: *mut c_void, + name: &CStr, + val: &CStr, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set(obj, name.as_ptr(), val.as_ptr(), search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_int( + obj: *mut c_void, + name: &CStr, + val: i64, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_int(obj, name.as_ptr(), val, search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_double( + obj: *mut c_void, + name: &CStr, + val: c_double, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_double(obj, name.as_ptr(), val, search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_q( + obj: *mut c_void, + name: &CStr, + val: AVRational, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_q(obj, name.as_ptr(), val, search_flags) }.upgrade()?; + Ok(()) +} + +/// Note: if `val.len()` extends [`i32::MAX`], this function returns [`RsmpegError::TryFromIntError`]. +/// +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_bin( + obj: *mut c_void, + name: &CStr, + val: &[u8], + search_flags: c_int, +) -> Result<()> { + unsafe { + ffi::av_opt_set_bin( + obj, + name.as_ptr(), + val.as_ptr(), + val.len().try_into()?, + search_flags, + ) + } + .upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_image_size( + obj: *mut c_void, + name: &CStr, + w: c_int, + h: c_int, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_image_size(obj, name.as_ptr(), w, h, search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_pixel_fmt( + obj: *mut c_void, + name: &CStr, + fmt: AVPixelFormat, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_pixel_fmt(obj, name.as_ptr(), fmt, search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_sample_fmt( + obj: *mut c_void, + name: &CStr, + fmt: AVSampleFormat, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_sample_fmt(obj, name.as_ptr(), fmt, search_flags) }.upgrade()?; + Ok(()) +} + +/// # Safety +/// +/// `obj` should points to a struct whose first element is a pointer to an AVClass. +pub unsafe fn opt_set_video_rate( + obj: *mut c_void, + name: &CStr, + val: AVRational, + search_flags: c_int, +) -> Result<()> { + unsafe { ffi::av_opt_set_video_rate(obj, name.as_ptr(), val, search_flags) }.upgrade()?; + Ok(()) +} diff --git a/src/error.rs b/src/error.rs index 71b43f0..8b902d0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,9 @@ //! Errors of the rsmpeg. use libc::c_int; -use std::cmp::{Eq, PartialEq}; +use std::{ + cmp::{Eq, PartialEq}, + num::TryFromIntError, +}; use thiserror::Error; use crate::{ffi, shared::AVERROR_EAGAIN}; @@ -122,6 +125,9 @@ pub enum RsmpegError { #[error("Failed to fill data to image buffer. ({0})")] AVImageFillArrayError(c_int), + #[error("{0}")] + TryFromIntError(TryFromIntError), + // Non exhaustive #[error("Unknown error, contact ldm0 when you see this.")] Unknown, @@ -130,53 +136,57 @@ pub enum RsmpegError { impl RsmpegError { pub fn raw_error(&self) -> Option { match self { - RsmpegError::AVError(err) => Some(*err), - RsmpegError::CustomError(_) => None, - RsmpegError::OpenInputError(err) => Some(*err), - RsmpegError::OpenOutputError(err) => Some(*err), - RsmpegError::FindStreamInfoError(err) => Some(*err), - RsmpegError::WriteHeaderError(err) => Some(*err), - RsmpegError::WriteTrailerError(err) => Some(*err), - RsmpegError::CodecOpenError(err) => Some(*err), - RsmpegError::CodecSetParameterError(err) => Some(*err), - RsmpegError::FilterNotFound => None, - RsmpegError::CreateFilterError(err) => Some(*err), - RsmpegError::SetPropertyError(err) => Some(*err), - RsmpegError::SendPacketError(err) => Some(*err), - RsmpegError::DecoderFullError => Some(AVERROR_EAGAIN), - RsmpegError::ReceiveFrameError(err) => Some(*err), - RsmpegError::DecoderDrainError => Some(AVERROR_EAGAIN), - RsmpegError::DecoderFlushedError => Some(ffi::AVERROR_EOF), - RsmpegError::SendFrameError(err) => Some(*err), - RsmpegError::SendFrameAgainError => Some(AVERROR_EAGAIN), - RsmpegError::ReceivePacketError(err) => Some(*err), - RsmpegError::EncoderDrainError => Some(AVERROR_EAGAIN), - RsmpegError::EncoderFlushedError => Some(ffi::AVERROR_EOF), - RsmpegError::BitstreamFullError => Some(AVERROR_EAGAIN), - RsmpegError::BitstreamDrainError => Some(AVERROR_EAGAIN), - RsmpegError::BitstreamFlushedError => Some(ffi::AVERROR_EOF), - RsmpegError::BitstreamSendPacketError(err) => Some(*err), - RsmpegError::BitstreamReceivePacketError(err) => Some(*err), - RsmpegError::BitstreamInitializationError(err) => Some(*err), - RsmpegError::ReadFrameError(err) => Some(*err), - RsmpegError::WriteFrameError(err) => Some(*err), - RsmpegError::InterleavedWriteFrameError(err) => Some(*err), - RsmpegError::BufferSrcAddFrameError(err) => Some(*err), - RsmpegError::BufferSinkGetFrameError(err) => Some(*err), - RsmpegError::BufferSinkDrainError => Some(AVERROR_EAGAIN), - RsmpegError::BufferSinkEofError => Some(ffi::AVERROR_EOF), - RsmpegError::DictionaryParseError(err) => Some(*err), - RsmpegError::DictionaryGetStringError(err) => Some(*err), - RsmpegError::AVIOOpenError(err) => Some(*err), - RsmpegError::SwrContextInitError(err) => Some(*err), - RsmpegError::SwrConvertError(err) => Some(*err), - RsmpegError::SwsScaleError(err) => Some(*err), - RsmpegError::AudioFifoWriteError(err) => Some(*err), - RsmpegError::AudioFifoReadError(err) => Some(*err), - RsmpegError::AVFrameDoubleAllocatingError => None, - RsmpegError::AVFrameInvalidAllocatingError(err) => Some(*err), - RsmpegError::AVImageFillArrayError(err) => Some(*err), - RsmpegError::Unknown => None, + Self::AVError(err) + | Self::OpenInputError(err) + | Self::OpenOutputError(err) + | Self::FindStreamInfoError(err) + | Self::WriteHeaderError(err) + | Self::WriteTrailerError(err) + | Self::CodecOpenError(err) + | Self::CodecSetParameterError(err) + | Self::CreateFilterError(err) + | Self::SetPropertyError(err) + | Self::SendPacketError(err) + | Self::ReceiveFrameError(err) + | Self::SendFrameError(err) + | Self::ReceivePacketError(err) + | Self::BitstreamSendPacketError(err) + | Self::BitstreamReceivePacketError(err) + | Self::BitstreamInitializationError(err) + | Self::ReadFrameError(err) + | Self::WriteFrameError(err) + | Self::InterleavedWriteFrameError(err) + | Self::BufferSrcAddFrameError(err) + | Self::BufferSinkGetFrameError(err) + | Self::DictionaryParseError(err) + | Self::DictionaryGetStringError(err) + | Self::AVIOOpenError(err) + | Self::SwrContextInitError(err) + | Self::SwrConvertError(err) + | Self::SwsScaleError(err) + | Self::AudioFifoWriteError(err) + | Self::AudioFifoReadError(err) + | Self::AVFrameInvalidAllocatingError(err) + | Self::AVImageFillArrayError(err) => Some(*err), + + Self::DecoderFullError + | Self::BufferSinkDrainError + | Self::DecoderDrainError + | Self::SendFrameAgainError + | Self::BitstreamFullError + | Self::BitstreamDrainError + | Self::EncoderDrainError => Some(AVERROR_EAGAIN), + + Self::BufferSinkEofError + | Self::DecoderFlushedError + | Self::EncoderFlushedError + | Self::BitstreamFlushedError => Some(ffi::AVERROR_EOF), + + Self::AVFrameDoubleAllocatingError + | Self::FilterNotFound + | Self::CustomError(_) + | Self::TryFromIntError(_) + | Self::Unknown => None, } } } @@ -189,6 +199,12 @@ pub type Ret = std::result::Result; impl From for RsmpegError { fn from(err: c_int) -> Self { - RsmpegError::AVError(err) + Self::AVError(err) + } +} + +impl From for RsmpegError { + fn from(err: TryFromIntError) -> Self { + Self::TryFromIntError(err) } }