Skip to main content

vpx/
lib.rs

1use std::borrow::Cow;
2use std::ffi::CStr;
3use std::mem::transmute;
4
5use vpx_sys as ffi;
6
7pub mod encoder;
8
9#[derive(Clone, Copy, Eq, PartialEq, Debug)]
10pub enum Error {
11    Generic(u32),
12    Mem,
13    AbiMismatch,
14    Incapable,
15    /// The bitstream was unable to be parsed at the highest level. The decoder is unable to proceed. This error SHOULD be treated as fatal to the stream.
16    UnsupportedBitstream,
17    /// The decoder does not implement a feature required by the encoder. This return code should only be used for features that prevent future pictures from being properly decoded. This error MAY be treated as fatal to the stream or MAY be treated as fatal to the current GOP.
18    UnsupportedFrame,
19    /// There was a problem decoding the current frame. This return code should only be used for failures that prevent future pictures from being properly decoded. This error MAY be treated as fatal to the stream or MAY be treated as fatal to the current GOP. If decoding is continued for the current GOP, artifacts may be present.
20    CorruptFrame,
21    InvalidParam,
22    ListEnd,
23}
24
25use crate::ffi::vpx_codec_err_t as ErrorEnum;
26impl From<ErrorEnum> for Error {
27    fn from(v: ErrorEnum) -> Self {
28        match v {
29            ffi::VPX_CODEC_MEM_ERROR => Self::Mem,
30            ffi::VPX_CODEC_ABI_MISMATCH => Self::AbiMismatch,
31            ffi::VPX_CODEC_INCAPABLE => Self::Incapable,
32            ffi::VPX_CODEC_UNSUP_BITSTREAM => Self::UnsupportedBitstream,
33            ffi::VPX_CODEC_UNSUP_FEATURE => Self::UnsupportedFrame,
34            ffi::VPX_CODEC_CORRUPT_FRAME => Self::CorruptFrame,
35            ffi::VPX_CODEC_INVALID_PARAM => Self::InvalidParam,
36            ffi::VPX_CODEC_LIST_END => Self::ListEnd,
37            n => Self::Generic(n as u32),
38        }
39    }
40}
41
42impl std::fmt::Display for Error {
43    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        <Self as std::fmt::Debug>::fmt(self, fmt)
45    }
46}
47impl std::error::Error for Error {
48    fn description(&self) -> &str {
49        match *self {
50            Self::Generic(_) => "Unspecified error",
51            Self::Mem => "Memory operation failed",
52            Self::AbiMismatch => "ABI version mismatch",
53            Self::Incapable => "Algorithm does not have required capability",
54            Self::UnsupportedBitstream => "The given bitstream is not supported",
55            Self::UnsupportedFrame => "Encoded bitstream uses an unsupported feature",
56            Self::CorruptFrame => "The coded data for this stream is corrupt or incomplete",
57            Self::InvalidParam => "An application-supplied parameter is not valid",
58            Self::ListEnd => "An iterator reached the end of list",
59        }
60    }
61}
62
63pub type Rect = ffi::vpx_image_rect_t;
64
65#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
66#[allow(non_camel_case_types)]
67pub enum Format {
68    YV12_VPX,
69    I420_VPX,
70
71    YV12,
72
73    I420 { hi_bit_depth: bool },
74    I422 { hi_bit_depth: bool },
75    I440 { hi_bit_depth: bool },
76    I444 { hi_bit_depth: bool },
77}
78impl From<Format> for ffi::vpx_img_fmt_t {
79    fn from(val: Format) -> Self {
80        use crate::Format::{I420, I420_VPX, I422, I440, I444, YV12, YV12_VPX};
81        use crate::ffi::vpx_img_fmt::*;
82
83        match val {
84            YV12_VPX => VPX_IMG_FMT_YV12,
85            I420_VPX => VPX_IMG_FMT_I420,
86
87            YV12 => VPX_IMG_FMT_YV12,
88
89            I420 { hi_bit_depth: false } => VPX_IMG_FMT_I420,
90            I422 { hi_bit_depth: false } => VPX_IMG_FMT_I422,
91            I440 { hi_bit_depth: false } => VPX_IMG_FMT_I444,
92            I444 { hi_bit_depth: false } => VPX_IMG_FMT_I440,
93
94            I420 { hi_bit_depth: true } => VPX_IMG_FMT_I42016,
95            I422 { hi_bit_depth: true } => VPX_IMG_FMT_I42216,
96            I440 { hi_bit_depth: true } => VPX_IMG_FMT_I44416,
97            I444 { hi_bit_depth: true } => VPX_IMG_FMT_I44016,
98        }
99    }
100}
101
102#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
103#[allow(non_camel_case_types)]
104pub enum ColorSpace {
105    BT601,
106    BT709,
107    SMPTE170,
108    SMPTE240,
109    BT2020,
110    SRGB,
111}
112
113impl From<ColorSpace> for ffi::vpx_color_space_t {
114    fn from(val: ColorSpace) -> Self {
115        match val {
116            ColorSpace::BT601 => Self::VPX_CS_BT_601,
117            ColorSpace::BT709 => Self::VPX_CS_BT_709,
118            ColorSpace::SMPTE170 => Self::VPX_CS_SMPTE_170,
119            ColorSpace::SMPTE240 => Self::VPX_CS_SMPTE_240,
120            ColorSpace::BT2020 => Self::VPX_CS_BT_2020,
121            ColorSpace::SRGB => Self::VPX_CS_SRGB,
122        }
123    }
124}
125
126pub struct Image<'a>(ffi::vpx_image_t, Format, #[allow(unused)] Cow<'a, [u8]>);
127
128impl<'a> Image<'a> {
129    /// XXX this function doesn't check that `data` is long enough for the
130    /// format or view size.
131    #[must_use]
132    pub fn new(data: Cow<'a, [u8]>, fmt: Format,
133               color_space: ColorSpace,
134               width: u32, height: u32,
135               stride: u32) -> Self
136    {
137        let mut t: ffi::vpx_image_t = Default::default();
138        unsafe {
139            ffi::vpx_img_wrap(std::ptr::from_mut(&mut t),
140                              fmt.into(), width,
141                              height, stride,
142                              data.as_ptr().cast_mut());
143        };
144        t.cs = color_space.into();
145        Image(t, fmt, data)
146    }
147
148    #[must_use]
149    pub fn get_format(&self) -> Format { self.1 }
150
151    pub fn set_rect(&mut self, rect: Rect) -> Result<(), ()> {
152        let res = unsafe { ffi::vpx_img_set_rect(std::ptr::from_mut(&mut self.0), rect.x, rect.y, rect.w, rect.h) };
153        if res == 0 {
154            Ok(())
155        } else {
156            Err(())
157        }
158    }
159
160    pub fn flip(&mut self) {
161        unsafe {
162            ffi::vpx_img_flip(std::ptr::from_mut(&mut self.0));
163        }
164    }
165}
166impl Drop for Image<'_> {
167    fn drop(&mut self) {
168        unsafe { ffi::vpx_img_free(std::ptr::from_mut(&mut self.0)) }
169    }
170}
171#[derive(Debug, Clone)]
172pub struct Frame<'a> {
173    data: &'a [u8],
174    pub pts: u64,
175    pub duration: u64,
176    pub flags: ffi::vpx_codec_frame_flags_t,
177    pub partition_id: i32,
178}
179pub const FRAME_IS_KEY: u32 = 0x1;
180pub const FRAME_IS_DROPPABLE: u32 = 0x2;
181pub const FRAME_IS_INVISIBLE: u32 = 0x4;
182pub const FRAME_IS_FRAGMENT: u32 = 0x8;
183impl<'a> Frame<'a> {
184    #[must_use]
185    pub fn data(&self) -> &'a [u8] { self.data }
186
187    #[must_use]
188    pub fn is_keyframe(&self) -> bool {
189        self.flags & FRAME_IS_KEY != 0
190    }
191
192    #[must_use]
193    pub fn is_droppable(&self) -> bool {
194        self.flags & FRAME_IS_DROPPABLE != 0
195    }
196
197    #[must_use]
198    pub fn is_invisible(&self) -> bool {
199        self.flags & FRAME_IS_INVISIBLE != 0
200    }
201
202    #[must_use]
203    pub fn is_fragment(&self) -> bool {
204        self.flags & FRAME_IS_FRAGMENT != 0
205    }
206}
207impl<'a> From<&'a ffi::vpx_codec_cx_pkt__bindgen_ty_1__bindgen_ty_1> for Frame<'a> {
208    fn from(v: &'a ffi::vpx_codec_cx_pkt__bindgen_ty_1__bindgen_ty_1) -> Self {
209        let data: &'a [u8] = unsafe { std::slice::from_raw_parts(v.buf as *const u8, v.sz) };
210
211        Frame {
212            data,
213            pts: v.pts as u64,
214            duration: v.duration,
215            flags: v.flags,
216            partition_id: v.partition_id,
217        }
218    }
219}
220
221pub use crate::ffi::vpx_bit_depth::*;
222pub use crate::ffi::vpx_codec_err_t::*;
223pub use crate::ffi::vpx_rational;
224pub use crate::ffi::vpx_rc_mode::*;
225
226#[derive(Copy, Clone, Eq, PartialEq, Debug)]
227pub enum Kind {
228    Decoder,
229    Encoder,
230}
231
232pub trait Interface: InternalInterface + Default {
233    type Context;
234    type Cfg;
235    fn name(&self) -> &'static str {
236        let pname = unsafe { ffi::vpx_codec_iface_name(self.iface()) };
237        let str = unsafe { CStr::from_ptr(pname).to_str().unwrap() };
238        unsafe { transmute(str) }
239    }
240    fn kind(&self) -> Kind;
241
242    fn create(
243        &self, cfg: <Self as Interface>::Cfg, flags: ffi::vpx_codec_flags_t,
244    ) -> Result<<Self as Interface>::Context, Error>;
245}
246#[doc(hidden)]
247pub trait InternalInterface {
248    fn iface(&self) -> *mut ffi::vpx_codec_iface_t;
249}