use std::os::raw::c_int;
use crate::{
AVChannelLayout, AVSampleFormat, SwrContext, ensure_initialized, swr_alloc as ffi_swr_alloc,
swr_alloc_set_opts2 as ffi_swr_alloc_set_opts2, swr_free as ffi_swr_free,
swr_init as ffi_swr_init, swr_is_initialized as ffi_swr_is_initialized,
};
pub unsafe fn alloc() -> Result<*mut SwrContext, c_int> {
ensure_initialized();
let ctx = ffi_swr_alloc();
if ctx.is_null() {
Err(crate::error_codes::ENOMEM)
} else {
Ok(ctx)
}
}
pub unsafe fn alloc_set_opts2(
out_ch_layout: *const AVChannelLayout,
out_sample_fmt: AVSampleFormat,
out_sample_rate: c_int,
in_ch_layout: *const AVChannelLayout,
in_sample_fmt: AVSampleFormat,
in_sample_rate: c_int,
) -> Result<*mut SwrContext, c_int> {
ensure_initialized();
if out_ch_layout.is_null() || in_ch_layout.is_null() {
return Err(crate::error_codes::EINVAL);
}
if out_sample_rate <= 0 || in_sample_rate <= 0 {
return Err(crate::error_codes::EINVAL);
}
let mut ctx: *mut SwrContext = std::ptr::null_mut();
let ret = ffi_swr_alloc_set_opts2(
&mut ctx,
out_ch_layout,
out_sample_fmt,
out_sample_rate,
in_ch_layout,
in_sample_fmt,
in_sample_rate,
0, std::ptr::null_mut(), );
if ret < 0 {
Err(ret)
} else if ctx.is_null() {
Err(crate::error_codes::ENOMEM)
} else {
Ok(ctx)
}
}
pub unsafe fn init(ctx: *mut SwrContext) -> Result<(), c_int> {
if ctx.is_null() {
return Err(crate::error_codes::EINVAL);
}
let ret = ffi_swr_init(ctx);
if ret < 0 { Err(ret) } else { Ok(()) }
}
pub unsafe fn is_initialized(ctx: *const SwrContext) -> bool {
if ctx.is_null() {
return false;
}
ffi_swr_is_initialized(ctx.cast_mut()) != 0
}
pub unsafe fn free(ctx: *mut *mut SwrContext) {
if !ctx.is_null() && !(*ctx).is_null() {
ffi_swr_free(ctx);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::swresample::{channel_layout, sample_format};
#[test]
fn test_alloc_and_free() {
unsafe {
let ctx_result = alloc();
assert!(ctx_result.is_ok(), "Context allocation should succeed");
let mut ctx = ctx_result.unwrap();
assert!(!ctx.is_null());
free(&mut ctx);
assert!(ctx.is_null(), "Context should be null after free");
}
}
#[test]
fn test_free_null_safety() {
unsafe {
free(std::ptr::null_mut());
let mut null_ctx: *mut SwrContext = std::ptr::null_mut();
free(&mut null_ctx);
}
}
#[test]
fn test_alloc_set_opts2_and_init() {
unsafe {
let out_layout = channel_layout::stereo();
let in_layout = channel_layout::stereo();
let ctx_result = alloc_set_opts2(
&out_layout,
sample_format::FLTP,
48000,
&in_layout,
sample_format::S16,
44100,
);
assert!(ctx_result.is_ok(), "Context creation should succeed");
let mut ctx = ctx_result.unwrap();
assert!(!ctx.is_null());
assert!(!is_initialized(ctx));
let init_result = init(ctx);
assert!(init_result.is_ok(), "Context initialization should succeed");
assert!(is_initialized(ctx));
free(&mut ctx);
}
}
#[test]
fn test_alloc_set_opts2_mono_to_stereo() {
unsafe {
let out_layout = channel_layout::stereo();
let in_layout = channel_layout::mono();
let ctx_result = alloc_set_opts2(
&out_layout,
sample_format::FLT,
48000,
&in_layout,
sample_format::FLT,
48000,
);
assert!(
ctx_result.is_ok(),
"Mono to stereo conversion should be supported"
);
let mut ctx = ctx_result.unwrap();
let init_result = init(ctx);
assert!(init_result.is_ok());
free(&mut ctx);
}
}
#[test]
fn test_alloc_set_opts2_invalid_null_layout() {
unsafe {
let out_layout = channel_layout::stereo();
let result = alloc_set_opts2(
&out_layout,
sample_format::FLT,
48000,
std::ptr::null(),
sample_format::FLT,
44100,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), crate::error_codes::EINVAL);
}
}
#[test]
fn test_alloc_set_opts2_invalid_sample_rate() {
unsafe {
let out_layout = channel_layout::stereo();
let in_layout = channel_layout::stereo();
let result = alloc_set_opts2(
&out_layout,
sample_format::FLT,
0,
&in_layout,
sample_format::FLT,
44100,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), crate::error_codes::EINVAL);
let result = alloc_set_opts2(
&out_layout,
sample_format::FLT,
-1,
&in_layout,
sample_format::FLT,
44100,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), crate::error_codes::EINVAL);
}
}
#[test]
fn test_init_null() {
unsafe {
let result = init(std::ptr::null_mut());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), crate::error_codes::EINVAL);
}
}
#[test]
fn test_is_initialized_null() {
unsafe {
assert!(!is_initialized(std::ptr::null()));
}
}
}