92 lines
2.4 KiB
Rust
92 lines
2.4 KiB
Rust
use crate::bail_ffmpeg;
|
|
use anyhow::Error;
|
|
use ffmpeg_sys_the_third::{
|
|
av_channel_layout_default, av_frame_alloc, av_frame_copy_props, av_frame_free,
|
|
swr_alloc_set_opts2, swr_convert_frame, swr_free, swr_init, AVChannelLayout, AVFrame,
|
|
AVSampleFormat, SwrContext,
|
|
};
|
|
use libc::malloc;
|
|
use std::mem::transmute;
|
|
use std::ptr;
|
|
|
|
pub struct Resample {
|
|
format: AVSampleFormat,
|
|
sample_rate: u32,
|
|
channels: usize,
|
|
ctx: *mut SwrContext,
|
|
}
|
|
|
|
impl Drop for Resample {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
if !self.ctx.is_null() {
|
|
swr_free(&mut self.ctx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Resample {
|
|
pub fn new(format: AVSampleFormat, rate: u32, channels: usize) -> Self {
|
|
Self {
|
|
format,
|
|
channels,
|
|
sample_rate: rate,
|
|
ctx: ptr::null_mut(),
|
|
}
|
|
}
|
|
|
|
unsafe fn setup_swr(&mut self, frame: *mut AVFrame) -> Result<(), Error> {
|
|
if !self.ctx.is_null() {
|
|
return Ok(());
|
|
}
|
|
let layout = malloc(size_of::<AVChannelLayout>()) as *mut AVChannelLayout;
|
|
av_channel_layout_default(layout, self.channels as libc::c_int);
|
|
|
|
let ret = swr_alloc_set_opts2(
|
|
&mut self.ctx,
|
|
layout,
|
|
self.format,
|
|
self.sample_rate as libc::c_int,
|
|
&(*frame).ch_layout,
|
|
transmute((*frame).format),
|
|
(*frame).sample_rate,
|
|
0,
|
|
ptr::null_mut(),
|
|
);
|
|
bail_ffmpeg!(ret);
|
|
|
|
let ret = swr_init(self.ctx);
|
|
bail_ffmpeg!(ret);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Resample an audio frame
|
|
pub unsafe fn process_frame(
|
|
&mut self,
|
|
frame: *mut AVFrame,
|
|
frame_size: i32,
|
|
) -> Result<*mut AVFrame, Error> {
|
|
if !(*frame).hw_frames_ctx.is_null() {
|
|
anyhow::bail!("Hardware frames are not supported in this software re-sampler");
|
|
}
|
|
self.setup_swr(frame)?;
|
|
|
|
let mut out_frame = av_frame_alloc();
|
|
av_frame_copy_props(out_frame, frame);
|
|
(*out_frame).sample_rate = self.sample_rate as libc::c_int;
|
|
(*out_frame).format = transmute(self.format);
|
|
(*out_frame).nb_samples = frame_size;
|
|
|
|
av_channel_layout_default(&mut (*out_frame).ch_layout, self.channels as libc::c_int);
|
|
|
|
let ret = swr_convert_frame(self.ctx, out_frame, frame);
|
|
bail_ffmpeg!(ret, {
|
|
av_frame_free(&mut out_frame);
|
|
});
|
|
|
|
Ok(out_frame)
|
|
}
|
|
}
|