Skip to content

Commit

Permalink
Add SwsContext::get_cached_context, add filter parameters for `SwsC…
Browse files Browse the repository at this point in the history
…ontext::get_context`
  • Loading branch information
ldm0 committed Jan 29, 2024
1 parent ec482bd commit 6f9b278
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 6 deletions.
110 changes: 104 additions & 6 deletions src/swscale/swscale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use std::ptr;
wrap!(SwsContext: ffi::SwsContext);

impl SwsContext {
/// Return None when input is invalid. Parameter `flags` can be
/// Allocate and return an [`SwsContext`]. You need it to perform
/// scaling/conversion operations using [`Self::scale()`].
///
/// Return `None` when input is invalid. Parameter `flags` can be set to
/// `rsmpeg::ffi::SWS_FAST_BILINEAR` etc.
pub fn get_context(
src_w: i32,
Expand All @@ -18,9 +21,10 @@ impl SwsContext {
dst_h: i32,
dst_format: AVPixelFormat,
flags: u32,
src_filter: Option<&ffi::SwsFilter>,
dst_filter: Option<&ffi::SwsFilter>,
param: Option<&[f64; 2]>,
) -> Option<Self> {
// TODO: no src_filter and dst_filter and param filter, implement them
// after wrapping SwsFilter.
let context = unsafe {
ffi::sws_getContext(
src_w,
Expand All @@ -30,15 +34,67 @@ impl SwsContext {
dst_h,
dst_format,
flags as i32,
ptr::null_mut(),
ptr::null_mut(),
ptr::null(),
src_filter
.map(|x| x as *const _ as *mut _)
.unwrap_or_else(|| ptr::null_mut()),
dst_filter
.map(|x| x as *const _ as *mut _)
.unwrap_or_else(|| ptr::null_mut()),
param.map(|x| x.as_ptr()).unwrap_or_else(|| ptr::null()),
)
}
.upgrade()?;
unsafe { Some(Self::from_raw(context)) }
}

/// Check if context can be reused, otherwise reallocate a new one.
///
/// Checks if the parameters are the ones already
/// saved in context. If that is the case, returns the current
/// context. Otherwise, frees context and gets a new context with
/// the new parameters.
///
/// Be warned that `src_filter` and `dst_filter` are not checked, they
/// are assumed to remain the same.
///
/// Returns `None` when context allocation or initiation failed.
pub fn get_cached_context(
self,
src_w: i32,
src_h: i32,
src_format: AVPixelFormat,
dst_w: i32,
dst_h: i32,
dst_format: AVPixelFormat,
flags: u32,
src_filter: Option<&ffi::SwsFilter>,
dst_filter: Option<&ffi::SwsFilter>,
param: Option<&[f64; 2]>,
) -> Option<Self> {
// Note that if sws_getCachedContext fails, context is freed, so we use into_raw here.
let context = unsafe {
ffi::sws_getCachedContext(
self.into_raw().as_ptr(),
src_w,
src_h,
src_format,
dst_w,
dst_h,
dst_format,
flags as i32,
src_filter
.map(|x| x as *const _ as *mut _)
.unwrap_or_else(|| ptr::null_mut()),
dst_filter
.map(|x| x as *const _ as *mut _)
.unwrap_or_else(|| ptr::null_mut()),
param.map(|x| x.as_ptr()).unwrap_or_else(|| ptr::null()),
)
}
.upgrade()?;
Some(unsafe { Self::from_raw(context) })
}

/// Scale the image slice in `src_slice` and put the resulting scaled
/// slice in the image in `dst`. A slice is a sequence of consecutive
/// rows in an image.
Expand Down Expand Up @@ -104,3 +160,45 @@ impl Drop for SwsContext {
unsafe { ffi::sws_freeContext(self.as_mut_ptr()) }
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::ffi::{
AVPixelFormat_AV_PIX_FMT_RGB24, SWS_BICUBIC, SWS_FULL_CHR_H_INT, SWS_PARAM_DEFAULT,
};

#[test]
fn test_cached_sws_context() {
let context = SwsContext::get_context(
10,
10,
AVPixelFormat_AV_PIX_FMT_RGB24,
10,
10,
AVPixelFormat_AV_PIX_FMT_RGB24,
SWS_FULL_CHR_H_INT | SWS_BICUBIC,
None,
None,
Some(&[SWS_PARAM_DEFAULT as f64, SWS_PARAM_DEFAULT as f64]),
)
.unwrap();
let old_ptr = context.as_ptr();
let context = context
.get_cached_context(
10,
10,
AVPixelFormat_AV_PIX_FMT_RGB24,
10,
10,
AVPixelFormat_AV_PIX_FMT_RGB24,
SWS_FULL_CHR_H_INT | SWS_BICUBIC,
None,
None,
None,
)
.unwrap();
let new_ptr = context.as_ptr();
assert_eq!(old_ptr, new_ptr);
}
}
3 changes: 3 additions & 0 deletions tests/thumbnail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ fn thumbnail(
encode_context.height,
encode_context.pix_fmt,
ffi::SWS_FAST_BILINEAR | ffi::SWS_PRINT_INFO,
None,
None,
None,
)
.context("Invalid swscontext parameter.")?;

Expand Down
3 changes: 3 additions & 0 deletions tests/tutorial01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ fn _main(file: &CStr, out_dir: &str) -> Result<()> {
decode_context.height,
ffi::AVPixelFormat_AV_PIX_FMT_RGB24,
ffi::SWS_BILINEAR,
None,
None,
None,
)
.context("Failed to create a swscale context.")?;

Expand Down

0 comments on commit 6f9b278

Please sign in to comment.