diff --git a/src/lib.rs b/src/lib.rs index a8e7cdc..9264247 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,3 +12,4 @@ pub use util::rational::Rational; pub use util::color_space::ColorSpace; pub use util::color_range::ColorRange; pub use util::media; +pub use util::sample_format::SampleFormat; diff --git a/src/util/mod.rs b/src/util/mod.rs index a68c8bc..ed834e6 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -4,6 +4,7 @@ pub mod rational; pub mod media; pub mod color_space; pub mod color_range; +pub mod sample_format; use std::ffi::CStr; use std::str::from_utf8_unchecked; diff --git a/src/util/sample_format.rs b/src/util/sample_format.rs new file mode 100644 index 0000000..cd14248 --- /dev/null +++ b/src/util/sample_format.rs @@ -0,0 +1,184 @@ +use std::ffi::{CStr, CString}; +use std::str::from_utf8_unchecked; +use std::ops::Index; +use std::ptr; +use std::slice; +use std::mem; + +use libc::{c_int, uint8_t}; +use ffi::*; + +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub enum SampleFormat { + None, + U8, + S16, + S32, + FLT, + DBL, + + U8P, + S16P, + S32P, + FLTP, + DBLP, +} + +impl SampleFormat { + pub fn name(&self) -> &'static str { + unsafe { + from_utf8_unchecked(CStr::from_ptr(av_get_sample_fmt_name((*self).into())).to_bytes()) + } + } + + pub fn packed(&self) -> Self { + unsafe { + SampleFormat::from(av_get_packed_sample_fmt((*self).into())) + } + } + + pub fn planar(&self) -> Self { + unsafe { + SampleFormat::from(av_get_planar_sample_fmt((*self).into())) + } + } + + pub fn is_planar(&self) -> bool { + unsafe { + av_sample_fmt_is_planar((*self).into()) == 1 + } + } + + pub fn bytes(&self) -> usize { + unsafe { + av_get_bytes_per_sample((*self).into()) as usize + } + } + + pub fn buffer(&self, channels: usize, samples: usize, align: bool) -> Buffer { + Buffer::new(*self, channels, samples, align) + } +} + +impl From for SampleFormat { + fn from(value: AVSampleFormat) -> Self { + match value { + AV_SAMPLE_FMT_NONE => SampleFormat::None, + AV_SAMPLE_FMT_U8 => SampleFormat::U8, + AV_SAMPLE_FMT_S16 => SampleFormat::S16, + AV_SAMPLE_FMT_S32 => SampleFormat::S32, + AV_SAMPLE_FMT_FLT => SampleFormat::FLT, + AV_SAMPLE_FMT_DBL => SampleFormat::DBL, + + AV_SAMPLE_FMT_U8P => SampleFormat::U8P, + AV_SAMPLE_FMT_S16P => SampleFormat::S16P, + AV_SAMPLE_FMT_S32P => SampleFormat::S32P, + AV_SAMPLE_FMT_FLTP => SampleFormat::FLTP, + AV_SAMPLE_FMT_DBLP => SampleFormat::DBLP, + + AV_SAMPLE_FMT_NB => SampleFormat::None + } + } +} + +impl From<&'static str> for SampleFormat { + fn from(value: &'static str) -> Self { + unsafe { + SampleFormat::from(av_get_sample_fmt(CString::new(value).unwrap().as_ptr())) + } + } +} + +impl Into for SampleFormat { + fn into(self) -> AVSampleFormat { + match self { + SampleFormat::None => AV_SAMPLE_FMT_NONE, + SampleFormat::U8 => AV_SAMPLE_FMT_U8, + SampleFormat::S16 => AV_SAMPLE_FMT_S16, + SampleFormat::S32 => AV_SAMPLE_FMT_S32, + SampleFormat::FLT => AV_SAMPLE_FMT_FLT, + SampleFormat::DBL => AV_SAMPLE_FMT_DBL, + + SampleFormat::U8P => AV_SAMPLE_FMT_U8P, + SampleFormat::S16P => AV_SAMPLE_FMT_S16P, + SampleFormat::S32P => AV_SAMPLE_FMT_S32P, + SampleFormat::FLTP => AV_SAMPLE_FMT_FLTP, + SampleFormat::DBLP => AV_SAMPLE_FMT_DBLP, + } + } +} + +pub struct Buffer { + pub format: SampleFormat, + pub channels: usize, + pub samples: usize, + pub align: bool, + + buffer: *mut *mut uint8_t, + size: c_int, +} + +impl Buffer { + pub fn size(format: SampleFormat, channels: usize, samples: usize, align: bool) -> usize { + unsafe { + av_samples_get_buffer_size(ptr::null_mut(), channels as c_int, samples as c_int, format.into(), !align as c_int) as usize + } + } + + pub fn new(format: SampleFormat, channels: usize, samples: usize, align: bool) -> Self { + unsafe { + let mut buf = Buffer { + format: format, + channels: channels, + samples: samples, + align: align, + + buffer: ptr::null_mut(), + size: 0, + }; + + av_samples_alloc_array_and_samples(&mut buf.buffer, &mut buf.size, + channels as c_int, samples as c_int, + format.into(), !align as c_int); + + buf + } + } +} + +impl Index for Buffer { + type Output = [u8]; + + fn index<'a>(&'a self, index: usize) -> &'a [u8] { + if index >= self.samples { + panic!("out of bounds"); + } + + unsafe { + slice::from_raw_parts(*self.buffer.offset(index as isize), self.size as usize) + } + } +} + +impl Clone for Buffer { + fn clone(&self) -> Self { + let mut buf = Buffer::new(self.format, self.channels, self.samples, self.align); + buf.clone_from(self); + + buf + } + + fn clone_from(&mut self, source: &Self) { + unsafe { + av_samples_copy(self.buffer, mem::transmute(source.buffer), 0, 0, source.samples as c_int, source.channels as c_int, source.format.into()); + } + } +} + +impl Drop for Buffer { + fn drop(&mut self) { + unsafe { + av_freep(mem::transmute(self.buffer)); + } + } +}