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}