Skip to content

Commit

Permalink
Add opt_set* methods mirroring av_opt_set*
Browse files Browse the repository at this point in the history
  • Loading branch information
ldm0 committed Jan 6, 2024
1 parent 0868171 commit 69ccc4a
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/avutil/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod imgutils;
mod media_type;
mod mem;
mod motion_vector;
mod opt;
mod pixdesc;
mod pixfmt;
mod rational;
Expand All @@ -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::*;
Expand Down
157 changes: 157 additions & 0 deletions src/avutil/opt.rs
Original file line number Diff line number Diff line change
@@ -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(())
}
114 changes: 65 additions & 49 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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,
Expand All @@ -130,53 +136,57 @@ pub enum RsmpegError {
impl RsmpegError {
pub fn raw_error(&self) -> Option<c_int> {
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,
}
}
}
Expand All @@ -189,6 +199,12 @@ pub type Ret = std::result::Result<c_int, c_int>;

impl From<c_int> for RsmpegError {
fn from(err: c_int) -> Self {
RsmpegError::AVError(err)
Self::AVError(err)
}
}

impl From<TryFromIntError> for RsmpegError {
fn from(err: TryFromIntError) -> Self {
Self::TryFromIntError(err)
}
}

0 comments on commit 69ccc4a

Please sign in to comment.