use bitflags::bitflags;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use crate::common::StreamInfo;
use crate::image::YUVImageData;
use crate::NoDebugWrapper;
use crate::{call_vpx, call_vpx_ptr};
use crate::{Error, Result};
#[allow(missing_docs)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CodecId {
VP8,
VP9,
}
impl CodecId {
pub(crate) fn iface(&self) -> Result<*const vpx_sys::vpx_codec_iface_t> {
match self {
Self::VP8 => call_vpx_ptr!(
vpx_sys::vpx_codec_vp8_dx(),
Error::CodecInterfaceNotAvailable,
),
Self::VP9 => call_vpx_ptr!(
vpx_sys::vpx_codec_vp9_dx(),
Error::CodecInterfaceNotAvailable,
),
}
}
}
#[derive(Debug)]
pub struct Decoder {
ctx: NoDebugWrapper<vpx_sys::vpx_codec_ctx_t>,
}
unsafe impl Send for Decoder {}
unsafe impl Sync for Decoder {}
impl Decoder {
pub fn new(config: DecoderConfig) -> Result<Self> {
let mut ctx = unsafe { MaybeUninit::zeroed().assume_init() };
let (iface, cfg) = config.cfg()?;
call_vpx!(
vpx_sys::vpx_codec_dec_init_ver(
&mut ctx,
iface,
&cfg,
config.flags.bits() as _,
vpx_sys::VPX_DECODER_ABI_VERSION as _,
),
Error::VpxCodecInitFailed,
)?;
Ok(Self {
ctx: NoDebugWrapper(ctx),
})
}
pub fn decode(&mut self, data: &[u8]) -> Result<DecodedImageIterator> {
call_vpx!(
vpx_sys::vpx_codec_decode(
&mut self.ctx.0,
data.as_ptr(),
data.len() as _,
std::ptr::null_mut(),
0,
),
Error::ErrorDecodingBitstream,
)?;
Ok(DecodedImageIterator {
ctx: &mut self.ctx.0,
iter: std::ptr::null_mut(),
})
}
pub fn stream_info(&mut self) -> Option<StreamInfo> {
crate::common::get_stream_info(&mut self.ctx.0)
}
}
impl Drop for Decoder {
fn drop(&mut self) {
unsafe {
let error = vpx_sys::vpx_codec_destroy(&mut self.ctx.0);
assert_eq!(error, vpx_sys::VPX_CODEC_OK);
}
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct DecoderConfig {
pub codec: CodecId,
pub width: u32,
pub height: u32,
pub threads: u32,
pub flags: DecoderFlags,
}
impl DecoderConfig {
pub fn new(codec: CodecId, width: u32, height: u32) -> Self {
Self {
codec,
width,
height,
threads: 1,
flags: DecoderFlags::default(),
}
}
fn cfg(
&self,
) -> Result<(*const vpx_sys::vpx_codec_iface, vpx_sys::vpx_codec_dec_cfg)>
{
Ok((
self.codec.iface()?,
vpx_sys::vpx_codec_dec_cfg {
w: self.width,
h: self.height,
threads: self.threads,
},
))
}
}
bitflags! {
#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct DecoderFlags: u32 {
const POSTPROC = vpx_sys::VPX_CODEC_USE_POSTPROC;
const ERROR_CONCEALMENT = vpx_sys::VPX_CODEC_USE_ERROR_CONCEALMENT;
const INPUT_FRAGMENTS = vpx_sys::VPX_CODEC_USE_INPUT_FRAGMENTS;
const FRAME_THREADING = vpx_sys::VPX_CODEC_USE_FRAME_THREADING;
}
}
pub struct DecodedImageIterator<'a> {
ctx: &'a mut vpx_sys::vpx_codec_ctx,
iter: vpx_sys::vpx_codec_iter_t,
}
unsafe impl Send for DecodedImageIterator<'_> {}
unsafe impl Sync for DecodedImageIterator<'_> {}
impl Iterator for DecodedImageIterator<'_> {
type Item = DecodedImage;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let img = vpx_sys::vpx_codec_get_frame(self.ctx, &mut self.iter);
Some(DecodedImage {
img: NonNull::new(img)?,
})
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct DecodedImage {
img: NonNull<vpx_sys::vpx_image>,
}
unsafe impl Send for DecodedImage {}
unsafe impl Sync for DecodedImage {}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DecodedImageData<'a> {
Data8b(YUVImageData<'a, u8>),
Data16b(YUVImageData<'a, u16>),
}
impl DecodedImage {
pub fn color_space(&self) -> vpx_sys::vpx_color_space {
unsafe { self.img.as_ref().cs }
}
pub fn width(&self) -> u32 {
unsafe { self.img.as_ref().d_w }
}
pub fn height(&self) -> u32 {
unsafe { self.img.as_ref().d_h }
}
pub fn data(&self) -> DecodedImageData {
unsafe {
use vpx_sys::vpx_img_fmt::*;
let img = self.img.as_ref();
match img.fmt {
VPX_IMG_FMT_YV12 | VPX_IMG_FMT_NV12 | VPX_IMG_FMT_I420
| VPX_IMG_FMT_I422 | VPX_IMG_FMT_I444 | VPX_IMG_FMT_I440 => {
DecodedImageData::Data8b(
YUVImageData::<u8>::from_vpx_image(img),
)
}
VPX_IMG_FMT_I42016 | VPX_IMG_FMT_I42216
| VPX_IMG_FMT_I44416 | VPX_IMG_FMT_I44016 => {
DecodedImageData::Data16b(
YUVImageData::<u16>::from_vpx_image(img),
)
}
_ => unreachable!(
"libvpx returned invalid image format: {:?}",
img.fmt,
),
}
}
}
}
impl Drop for DecodedImage {
fn drop(&mut self) {
unsafe { vpx_sys::vpx_img_free(self.img.as_ptr()) }
}
}
#[cfg(test)]
mod test {
use super::{
DecodedImage, DecodedImageIterator, Decoder, DecoderConfig,
DecoderFlags,
};
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Decoder>();
assert_send::<DecoderConfig>();
assert_send::<DecoderFlags>();
assert_send::<DecodedImage>();
assert_send::<DecodedImageIterator>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Decoder>();
assert_sync::<DecoderConfig>();
assert_sync::<DecoderFlags>();
assert_sync::<DecodedImage>();
assert_sync::<DecodedImageIterator>();
}
}