vpx_rs/lib.rs
1/*
2 * Copyright (c) 2025, Saso Kiselkov. All rights reserved.
3 *
4 * Use of this source code is governed by the 2-clause BSD license,
5 * which can be found in a file named LICENSE, located at the root
6 * of this source tree.
7 */
8
9#![warn(missing_docs)]
10
11//! This crate provides a Rusty interface to Google's libvpx library
12//! for handling VP8 and VP9 video streams. The low-level bindings to
13//! libvpx are provided by the
14//! [env-libvpx-sys](https://crates.io/crates/env-libvpx-sys) crate,
15//! which this crate then wraps in Rust types, hopefully making the
16//! experience a bit neater and less error-prone.
17//!
18//! While an effort was made to hopefully cover most usecases of libvpx,
19//! this crate doesn't cover *all* of libvpx's API, as some of it is
20//! rather esoteric and difficult to make feel natural and safe to use
21//! in Rust. If you find a particular set of features of libvpx's API
22//! is missing, please contact the crate's author.
23//!
24//! # Usage Examples
25//!
26//! Refer to the [`Encoder`] and [`Decoder`] structs for examples on
27//! how to use the library to encode and decode video frames.
28//!
29//! The library supports a variety of YUV image formats. Have a look at
30//! [`ImageFormat`] for more information on the exact list, as well as
31//! tips on how to convert between YUV and non-YUV formats.
32
33/// Common types and structs shared between the encoder, decoder and
34/// image processing portions of the crate.
35pub mod common;
36
37/// Contains the decoding portion of the library. See [`Decoder`] for
38/// a simple example on how to decode images.
39pub mod dec;
40
41/// Contains the encoding portion of the library. See [`Encoder`] for
42/// a simple example on how to encode images.
43pub mod enc;
44
45/// Contains definitions for the various YUV image formats supported by
46/// the crate. You should take a look at [`YUVImageData`] especially,
47/// since it is what the [`Encoder`] expects as its input. The list of
48/// supported formats is detailed in [`ImageFormat`].
49pub mod image;
50
51pub use crate::common::StreamInfo;
52pub use crate::dec::{DecodedImage, DecodedImageData, Decoder, DecoderConfig};
53pub use crate::enc::{
54 CompressedFrame, Encoder, EncoderConfig, EncoderFlags, EncoderFrameFlags,
55 EncodingDeadline, Packet, RateControl, Timebase,
56};
57pub use crate::image::{ImageFormat, YUVImageData, YUVImageDataOwned};
58
59// Re-export the vpx_sys crate, because the low-level bindings are used
60// in some calls in enc::ctrl.
61pub use vpx_sys;
62
63#[doc(hidden)]
64#[macro_export]
65macro_rules! call_vpx_ptr {
66 ($e: expr, $errenum: expr $(,)?) => {{
67 #[allow(clippy::macro_metavars_in_unsafe)]
68 let retval = unsafe { $e };
69 if !retval.is_null() {
70 Ok(retval)
71 } else {
72 Err($errenum)
73 }
74 }};
75}
76
77#[doc(hidden)]
78#[macro_export]
79macro_rules! call_vpx {
80 ($e: expr, $errenum: expr $(,)?) => {{
81 #[allow(clippy::macro_metavars_in_unsafe)]
82 let err: vpx_sys::vpx_codec_err_t = unsafe { $e };
83 if err == vpx_sys::VPX_CODEC_OK {
84 Ok(())
85 } else {
86 Err($errenum(err, unsafe {
87 std::ffi::CStr::from_ptr(vpx_sys::vpx_codec_err_to_string(err))
88 .to_string_lossy()
89 .to_string()
90 }))
91 }
92 }};
93}
94
95/// Error enums returned by this crate. Many variants include a
96/// `vpx_codec_err_t` - this encodes the underlying `libvpx` library
97/// error code. You can use this to fine-tune error reporting if you
98/// so desire. The included string is a human-readable representation
99/// of the error code as returned from libvpx.
100#[derive(Clone, Debug, thiserror::Error, PartialEq, Eq, Hash)]
101pub enum Error {
102 /// An attempt to instantiate a given codec interface failed,
103 /// probably because libvpx was compiled with that codec disabled.
104 #[error("Codec interface not available")]
105 CodecInterfaceNotAvailable,
106 /// A call to [`Encoder::codec_control_set()`] failed. The attached
107 /// libvpx error code might tell you more information about why the
108 /// call failed (usually this is due to an argument value being invalid).
109 #[error("Codec control call failed: {0:?}: {1}")]
110 CodecControlFailed(vpx_sys::vpx_codec_err_t, String),
111 /// There was an error initializing the encoder configuration.
112 #[error("Failed to initialize the encoder configuration: {0:?}: {1}")]
113 EncoderConfigInitFailed(vpx_sys::vpx_codec_err_t, String),
114 /// Failed to initialize encoder or decoder context.
115 #[error("Codec initialization failed with code {0:?}: {1}")]
116 VpxCodecInitFailed(vpx_sys::vpx_codec_err_t, String),
117 /// The specified rate control mode (lossless) isn't supported by the
118 /// codec (VP8).
119 #[error("Unsupported rate control mode for this codec")]
120 UnsupportedRateControlMode,
121 /// libvpx returned an error trying to wrap an image for encoding.
122 #[error("Error wrapping YUV image")]
123 ErrorWrappingImage,
124 /// libvpx returned an error trying to encode the image we passed
125 /// it in [`Encoder::encode()`].
126 #[error("VPX encode failed with {0:?}: {1}")]
127 ErrorEncodingImage(vpx_sys::vpx_codec_err_t, String),
128 /// libvpx returned an error trying to decode the bitstream we passed
129 /// it in [`Decoder::decode()`].
130 #[error("Error decoding bitstream: {0:?}: {1}")]
131 ErrorDecodingBitstream(vpx_sys::vpx_codec_err_t, String),
132 /// We've encountered an invalid image format passed to us from libvpx.
133 #[error("Invalid image format ({0:?})")]
134 InvalidImageFormat(vpx_sys::vpx_img_fmt),
135 /// The raw image data buffer has the wrong length for the specified
136 /// image format, width and height (either too little or too much data
137 /// compared to what a well-formed data buffer should have).
138 #[error(
139 "Image data has bad length, expected: {expected}, received: {received}"
140 )]
141 ImageDataBadLength {
142 /// Expected data buffer length (in samples, **not** bytes).
143 expected: usize,
144 /// Actual data buffer length (in samples, **not** bytes).
145 received: usize,
146 },
147 /// The image width wasn't a multiple of 2, but the passed image format
148 /// requires it to be.
149 #[error("Image width isn't a multiple of 2")]
150 WidthNotMultipleOfTwo,
151 /// The image height wasn't a multiple of 2, but the passed image format
152 /// requires it to be.
153 #[error("Image height isn't a multiple of 2")]
154 HeightNotMultipleOfTwo,
155 /// Indicates that an attempt was made to set anything other than the
156 /// default profile for VP8 (which only supports that).
157 #[error("Invalid profile selected for codec")]
158 InvalidProfileSelected,
159}
160
161/// Result type for this crate.
162pub type Result<T> = ::core::result::Result<T, Error>;
163
164pub(crate) struct NoDebugWrapper<T: 'static>(T);
165
166impl<T: 'static> std::fmt::Debug for NoDebugWrapper<T> {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 std::any::TypeId::of::<T>().fmt(f)
169 }
170}