Skip to content

Commit

Permalink
Merge pull request #3 from hanguk0726/master
Browse files Browse the repository at this point in the history
Support audio track
  • Loading branch information
darkskygit authored Apr 16, 2023
2 parents f3de131 + eabd02f commit c87f6d2
Show file tree
Hide file tree
Showing 5 changed files with 396 additions and 37 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ repository = "https://github.com/darkskygit/minimp4.rs"

[dependencies]
libc = "0.2.66"
minimp4-sys = "0.1.0"
minimp4-sys = {path = "minimp4-sys"}
fdk-aac-sys = "0.4.0"
4 changes: 2 additions & 2 deletions minimp4-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ repository = "https://github.com/darkskygit/minimp4.rs"
categories = ["external-ffi-bindings"]

[build-dependencies]
bindgen = "0.52.0"
cc = "1.0.48"
bindgen = "0.64.0"
cc = { version = "1.0.79", features = ["parallel"] }
200 changes: 200 additions & 0 deletions src/enc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
use std::cmp;
use std::fmt::{self, Display, Debug};
use std::mem::{self, MaybeUninit};
use std::os::raw::{c_void, c_uint, c_int};
use std::ptr;

use fdk_aac_sys as sys;

pub use sys::AACENC_InfoStruct as InfoStruct;

//mostly from https://github.com/haileys/fdk-aac-rs but with some changes

pub struct EncoderError(sys::AACENC_ERROR);

impl EncoderError {
fn message(&self) -> &'static str {
match self.0 {
sys::AACENC_ERROR_AACENC_OK => "Ok",
sys::AACENC_ERROR_AACENC_INVALID_HANDLE => "Handle passed to function call was invalid.",
sys::AACENC_ERROR_AACENC_MEMORY_ERROR => "Memory allocation failed.",
sys::AACENC_ERROR_AACENC_UNSUPPORTED_PARAMETER => "Parameter not available.",
sys::AACENC_ERROR_AACENC_INVALID_CONFIG => "Configuration not provided.",
sys::AACENC_ERROR_AACENC_INIT_ERROR => "General initialization error.",
sys::AACENC_ERROR_AACENC_INIT_AAC_ERROR => "AAC library initialization error.",
sys::AACENC_ERROR_AACENC_INIT_SBR_ERROR => "SBR library initialization error.",
sys::AACENC_ERROR_AACENC_INIT_TP_ERROR => "Transport library initialization error.",
sys::AACENC_ERROR_AACENC_INIT_META_ERROR => "Meta data library initialization error.",
sys::AACENC_ERROR_AACENC_INIT_MPS_ERROR => "MPS library initialization error.",
sys::AACENC_ERROR_AACENC_ENCODE_ERROR => "The encoding process was interrupted by an unexpected error.",
sys::AACENC_ERROR_AACENC_ENCODE_EOF => "End of file reached.",
_ => "Unknown error",
}
}
}

impl Debug for EncoderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "EncoderError {{ code: {:?}, message: {:?} }}", self.0 as c_int, self.message())
}
}

impl Display for EncoderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message())
}
}

fn check(e: sys::AACENC_ERROR) -> Result<(), EncoderError> {
if e == sys::AACENC_ERROR_AACENC_OK {
Ok(())
} else {
Err(EncoderError(e))
}
}

struct EncoderHandle {
ptr: sys::HANDLE_AACENCODER,
}

impl EncoderHandle {
pub fn alloc(max_modules: usize, max_channels: usize) -> Result<Self, EncoderError> {
let mut ptr: sys::HANDLE_AACENCODER = ptr::null_mut();
check(unsafe {
sys::aacEncOpen(&mut ptr as *mut _, max_modules as c_uint, max_channels as c_uint)
})?;
Ok(EncoderHandle { ptr })
}
}

impl Drop for EncoderHandle {
fn drop(&mut self) {
unsafe { sys::aacEncClose(&mut self.ptr as *mut _); }
}
}

#[derive(Debug, Clone, Copy)]
pub enum BitRate {
Cbr(u32),
VbrVeryLow,
VbrLow,
VbrMedium,
VbrHigh,
VbrVeryHigh,
}

#[derive(Debug, Clone, Copy)]
pub struct EncoderParams {
pub bit_rate: BitRate,
pub sample_rate: u32,
pub channel_count: u32
}

pub struct Encoder {
handle: EncoderHandle,
}

#[derive(Debug)]
pub enum Transport {
Adts,
Raw,
}

#[derive(Debug)]
pub struct EncodeInfo {
pub input_consumed: usize,
pub output_size: usize,
}

impl Encoder {
pub fn new(params: EncoderParams) -> Result<Self, EncoderError> {
let handle = EncoderHandle::alloc(0, 2 /* hardcode stereo */)?;
assert!(params.channel_count == 1 || params.channel_count == 2);
unsafe {
// hardcode MPEG-4 AAC Low Complexity for now:
check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_AOT, 2))?;

let bitrate_mode = match params.bit_rate {
BitRate::Cbr(bitrate) => {
check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_BITRATE, bitrate))?;
0
}
BitRate::VbrVeryLow => 1,
BitRate::VbrLow => 2,
BitRate::VbrMedium => 3,
BitRate::VbrHigh => 4,
BitRate::VbrVeryHigh => 5,
};

check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_BITRATEMODE, bitrate_mode))?;

check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_SAMPLERATE, params.sample_rate))?;

check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_TRANSMUX, 0))?;

// hardcode SBR off for now
check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_SBR_MODE, 0))?;

check(sys::aacEncoder_SetParam(handle.ptr, sys::AACENC_PARAM_AACENC_CHANNELMODE, params.channel_count))?;

// call encode once with all null params according to docs
check(sys::aacEncEncode(handle.ptr, ptr::null(), ptr::null(), ptr::null(), ptr::null_mut()))?;
}

Ok(Encoder { handle })
}

pub fn info(&self) -> Result<InfoStruct, EncoderError> {
let mut info = MaybeUninit::uninit();
check(unsafe { sys::aacEncInfo(self.handle.ptr, info.as_mut_ptr()) })?;
Ok(unsafe { info.assume_init() })
}

pub fn encode(&self, input: &[i16], output: &mut [u8]) -> Result<EncodeInfo, EncoderError> {
let input_len = cmp::min(i32::max_value() as usize, input.len()) as i32;

let mut input_buf = input.as_ptr() as *mut i16;
let mut input_buf_ident: c_int = sys::AACENC_BufferIdentifier_IN_AUDIO_DATA as c_int;
let mut input_buf_size: c_int = input_len as c_int;
let mut input_buf_el_size: c_int = mem::size_of::<i16>() as c_int;
let input_desc = sys::AACENC_BufDesc {
numBufs: 1,
bufs: &mut input_buf as *mut _ as *mut *mut c_void,
bufferIdentifiers: &mut input_buf_ident as *mut c_int,
bufSizes: &mut input_buf_size as *mut c_int,
bufElSizes: &mut input_buf_el_size as *mut c_int,
};

let mut output_buf = output.as_mut_ptr();
let mut output_buf_ident: c_int = sys::AACENC_BufferIdentifier_OUT_BITSTREAM_DATA as c_int;
let mut output_buf_size: c_int = output.len() as c_int;
let mut output_buf_el_size: c_int = mem::size_of::<i16>() as c_int;
let output_desc = sys::AACENC_BufDesc {
numBufs: 1,
bufs: &mut output_buf as *mut _ as *mut *mut c_void,
bufferIdentifiers: &mut output_buf_ident as *mut _,
bufSizes: &mut output_buf_size as *mut _,
bufElSizes: &mut output_buf_el_size as *mut _,
};

let in_args = sys::AACENC_InArgs {
numInSamples: input_len,
numAncBytes: 0,
};

let mut out_args = unsafe { mem::zeroed() };

check(unsafe { sys::aacEncEncode(self.handle.ptr, &input_desc, &output_desc, &in_args, &mut out_args) })?;

Ok(EncodeInfo {
output_size: out_args.numOutBytes as usize,
input_consumed: out_args.numInSamples as usize,
})
}
}

impl Debug for Encoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Encoder {{ handle: {:?} }}", self.handle.ptr)
}
}
Loading

0 comments on commit c87f6d2

Please sign in to comment.