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 UnsupportedBitstream,
17 UnsupportedFrame,
19 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 #[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}