software/resampling: add wrapper

This commit is contained in:
meh 2015-06-08 15:53:21 +02:00
parent 2439e67fd0
commit 6c7db403f2
9 changed files with 325 additions and 0 deletions

View File

@ -1,2 +1,5 @@
#[cfg(feature = "software-scaling")]
pub mod scaling;
#[cfg(feature = "software-resampling")]
pub mod resampling;

View File

@ -0,0 +1,127 @@
use std::ptr;
use libc::{c_int, int64_t};
use ffi::*;
use ::util::format;
use ::{Error, ChannelLayout, frame};
use super::Delay;
#[derive(Eq, PartialEq, Copy, Clone)]
pub struct Definition {
pub format: format::Sample,
pub channel_layout: ChannelLayout,
pub rate: u32,
}
pub struct Context {
ptr: *mut SwrContext,
input: Definition,
output: Definition,
}
impl Context {
pub unsafe fn as_ptr(&self) -> *const SwrContext {
self.ptr as *const _
}
pub unsafe fn as_mut_ptr(&mut self) -> *mut SwrContext {
self.ptr
}
}
impl Context {
pub fn get(src_format: format::Sample, src_channel_layout: ChannelLayout, src_rate: u32,
dst_format: format::Sample, dst_channel_layout: ChannelLayout, dst_rate: u32) -> Result<Self, Error> {
unsafe {
let ptr = swr_alloc_set_opts(ptr::null_mut(),
dst_channel_layout.bits() as int64_t, dst_format.into(), dst_rate as c_int,
src_channel_layout.bits() as int64_t, src_format.into(), src_rate as c_int,
0, ptr::null_mut());
if ptr != ptr::null_mut() {
match swr_init(ptr) {
e if e < 0 =>
Err(Error::from(e)),
_ =>
Ok(Context {
ptr: ptr,
input: Definition {
format: src_format,
channel_layout: src_channel_layout,
rate: src_rate,
},
output: Definition {
format: dst_format,
channel_layout: dst_channel_layout,
rate: dst_rate,
}
})
}
}
else {
Err(Error::InvalidData)
}
}
}
pub fn input(&self) -> &Definition {
&self.input
}
pub fn output(&self) -> &Definition {
&self.output
}
pub fn delay(&self) -> Option<Delay> {
unsafe {
match swr_get_delay(self.as_ptr(), 1) {
0 => None,
_ => Some(Delay::from(self))
}
}
}
pub fn run(&mut self, input: &frame::Audio, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
output.set_rate(self.output.rate);
unsafe {
if output.is_empty() {
output.alloc(self.output.format, input.samples(), self.output.channel_layout);
}
match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) {
0 =>
Ok(self.delay()),
e =>
Err(Error::from(e))
}
}
}
pub fn next(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
output.set_rate(self.output.rate);
unsafe {
match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) {
0 =>
Ok(self.delay()),
e =>
Err(Error::from(e))
}
}
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
swr_free(&mut self.as_mut_ptr());
}
}
}

View File

@ -0,0 +1,24 @@
use libc::int64_t;
use ffi::*;
use super::Context;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct Delay {
pub seconds: i64,
pub milliseconds: i64,
pub input: i64,
pub output: i64,
}
impl Delay {
pub fn from(context: &Context) -> Self {
unsafe {
Delay {
seconds: swr_get_delay(context.as_ptr(), 1),
milliseconds: swr_get_delay(context.as_ptr(), 1000),
input: swr_get_delay(context.as_ptr(), context.input().rate as int64_t),
output: swr_get_delay(context.as_ptr(), context.output().rate as int64_t),
}
}
}
}

View File

@ -0,0 +1,57 @@
use ffi::*;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Dither {
None,
Rectangular,
Triangular,
TriangularHighPass,
NoiseShapingLipshitz,
NoiseShapingFWeighted,
NoiseShapingModifiedEWeighted,
NoiseShapingImprovedEWeighted,
NoiseShapingShibata,
NoiseShapingLowShibata,
NoiseShapingHighShibata,
}
impl From<SwrDitherType> for Dither {
fn from(value: SwrDitherType) -> Dither {
match value {
SWR_DITHER_NONE => Dither::None,
SWR_DITHER_RECTANGULAR => Dither::Rectangular,
SWR_DITHER_TRIANGULAR => Dither::Triangular,
SWR_DITHER_TRIANGULAR_HIGHPASS => Dither::TriangularHighPass,
SWR_DITHER_NS => Dither::None,
SWR_DITHER_NS_LIPSHITZ => Dither::NoiseShapingLipshitz,
SWR_DITHER_NS_F_WEIGHTED => Dither::NoiseShapingFWeighted,
SWR_DITHER_NS_MODIFIED_E_WEIGHTED => Dither::NoiseShapingModifiedEWeighted,
SWR_DITHER_NS_IMPROVED_E_WEIGHTED => Dither::NoiseShapingImprovedEWeighted,
SWR_DITHER_NS_SHIBATA => Dither::NoiseShapingShibata,
SWR_DITHER_NS_LOW_SHIBATA => Dither::NoiseShapingLowShibata,
SWR_DITHER_NS_HIGH_SHIBATA => Dither::NoiseShapingHighShibata,
SWR_DITHER_NB => Dither::None,
}
}
}
impl Into<SwrDitherType> for Dither {
fn into(self) -> SwrDitherType {
match self {
Dither::None => SWR_DITHER_NONE,
Dither::Rectangular => SWR_DITHER_RECTANGULAR,
Dither::Triangular => SWR_DITHER_TRIANGULAR,
Dither::TriangularHighPass => SWR_DITHER_TRIANGULAR_HIGHPASS,
Dither::NoiseShapingLipshitz => SWR_DITHER_NS_LIPSHITZ,
Dither::NoiseShapingFWeighted => SWR_DITHER_NS_F_WEIGHTED,
Dither::NoiseShapingModifiedEWeighted => SWR_DITHER_NS_MODIFIED_E_WEIGHTED,
Dither::NoiseShapingImprovedEWeighted => SWR_DITHER_NS_IMPROVED_E_WEIGHTED,
Dither::NoiseShapingShibata => SWR_DITHER_NS_SHIBATA,
Dither::NoiseShapingLowShibata => SWR_DITHER_NS_LOW_SHIBATA,
Dither::NoiseShapingHighShibata => SWR_DITHER_NS_HIGH_SHIBATA,
}
}
}

View File

@ -0,0 +1,26 @@
use ffi::*;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Engine {
Software,
SoundExchange,
}
impl From<SwrEngine> for Engine {
fn from(value: SwrEngine) -> Engine {
match value {
SWR_ENGINE_SWR => Engine::Software,
SWR_ENGINE_SOXR => Engine::SoundExchange,
SWR_ENGINE_NB => Engine::Software,
}
}
}
impl Into<SwrEngine> for Engine {
fn into(self) -> SwrEngine {
match self {
Engine::Software => SWR_ENGINE_SWR,
Engine::SoundExchange => SWR_ENGINE_SOXR,
}
}
}

View File

@ -0,0 +1,10 @@
use util::format;
use ::{decoder, Error, ChannelLayout};
use super::Context;
impl decoder::Audio {
pub fn resampler(&self, format: format::Sample, channel_layout: ChannelLayout, rate: u32) -> Result<Context, Error> {
Context::get(self.format(), self.channel_layout(), self.rate(),
format, channel_layout, rate)
}
}

View File

@ -0,0 +1,28 @@
use ffi::*;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Filter {
Cubic,
BlackmanNuttall,
Kaiser,
}
impl From<SwrFilterType> for Filter {
fn from(value: SwrFilterType) -> Filter {
match value {
SWR_FILTER_TYPE_CUBIC => Filter::Cubic,
SWR_FILTER_TYPE_BLACKMAN_NUTTALL => Filter::BlackmanNuttall,
SWR_FILTER_TYPE_KAISER => Filter::Kaiser,
}
}
}
impl Into<SwrFilterType> for Filter {
fn into(self) -> SwrFilterType {
match self {
Filter::Cubic => SWR_FILTER_TYPE_CUBIC,
Filter::BlackmanNuttall => SWR_FILTER_TYPE_BLACKMAN_NUTTALL,
Filter::Kaiser => SWR_FILTER_TYPE_KAISER,
}
}
}

View File

@ -0,0 +1,8 @@
use libc::c_int;
use ffi::*;
bitflags! {
flags Flags: c_int {
const FORCE = SWR_FLAG_RESAMPLE,
}
}

View File

@ -0,0 +1,42 @@
pub mod flag;
pub use self::flag::Flags;
pub mod dither;
pub use self::dither::Dither;
pub mod engine;
pub use self::engine::Engine;
pub mod filter;
pub use self::filter::Filter;
pub mod delay;
pub use self::delay::Delay;
pub mod context;
pub use self::context::Context;
mod extensions;
use std::ffi::CStr;
use std::str::from_utf8_unchecked;
use ffi::*;
pub fn version() -> u32 {
unsafe {
swresample_version()
}
}
pub fn configuration() -> &'static str {
unsafe {
from_utf8_unchecked(CStr::from_ptr(swresample_configuration()).to_bytes())
}
}
pub fn license() -> &'static str {
unsafe {
from_utf8_unchecked(CStr::from_ptr(swresample_license()).to_bytes())
}
}