use std::{mem::MaybeUninit, num::NonZeroU32};
use aotuv_lancer_vorbis_sys::{
vorbis_analysis_headerout, vorbis_analysis_init, vorbis_block, vorbis_block_clear,
vorbis_block_init, vorbis_dsp_clear, vorbis_dsp_state
};
use crate::common::{OggPacket, VorbisComments, VorbisError, VorbisInfo};
pub struct VorbisEncodingState {
pub(crate) vorbis_info: VorbisInfo,
pub(crate) vorbis_dsp_state: *mut vorbis_dsp_state,
pub(crate) vorbis_block: *mut vorbis_block
}
impl VorbisEncodingState {
pub fn new(vorbis_info: VorbisInfo) -> Result<Self, VorbisError> {
let vorbis_dsp_state = Box::into_raw(Box::<vorbis_dsp_state>::new_uninit());
let vorbis_block = Box::into_raw(Box::<vorbis_block>::new_uninit());
let init_error = 'init: {
if let Err(err) = unsafe {
libvorbis_return_value_to_result!(vorbis_analysis_init(
vorbis_dsp_state.cast(),
vorbis_info.vorbis_info
))
} {
break 'init Some(err);
}
if let Err(err) = unsafe {
libvorbis_return_value_to_result!(vorbis_block_init(
vorbis_dsp_state.cast(),
vorbis_block.cast()
))
} {
break 'init Some(err);
}
None
};
match init_error {
Some(err) => {
unsafe {
drop(Box::from_raw(vorbis_dsp_state));
drop(Box::from_raw(vorbis_block));
}
Err(err)?
}
None => Ok(Self {
vorbis_info,
vorbis_dsp_state: vorbis_dsp_state.cast(),
vorbis_block: vorbis_block.cast()
})
}
}
pub fn get_header_packets(
&mut self,
vorbis_comments: &mut VorbisComments
) -> Result<[OggPacket; 3], VorbisError> {
let mut identification_header = MaybeUninit::uninit();
let mut comment_header = MaybeUninit::uninit();
let mut setup_header = MaybeUninit::uninit();
unsafe {
libvorbis_return_value_to_result!(vorbis_analysis_headerout(
self.vorbis_dsp_state,
&raw mut vorbis_comments.vorbis_comment,
identification_header.as_mut_ptr(),
comment_header.as_mut_ptr(),
setup_header.as_mut_ptr()
))?;
Ok([
OggPacket::new(identification_header.assume_init()),
OggPacket::new(comment_header.assume_init()),
OggPacket::new(setup_header.assume_init())
])
}
}
}
impl Drop for VorbisEncodingState {
fn drop(&mut self) {
unsafe {
vorbis_block_clear(self.vorbis_block);
vorbis_dsp_clear(self.vorbis_dsp_state);
drop(Box::from_raw(self.vorbis_block));
drop(Box::from_raw(self.vorbis_dsp_state));
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum VorbisBitrateManagementStrategy {
Vbr {
target_bitrate: NonZeroU32
},
QualityVbr {
target_quality: f32
},
Abr {
average_bitrate: NonZeroU32
},
ConstrainedAbr {
maximum_bitrate: NonZeroU32
}
}
impl Default for VorbisBitrateManagementStrategy {
fn default() -> Self {
Self::QualityVbr {
target_quality: 0.5
}
}
}