pub struct VideoFrame { /* private fields */ }Expand description
A decoded video frame.
This structure holds the pixel data and metadata for a single video frame. It supports both packed formats (like RGBA) where all data is in a single plane, and planar formats (like YUV420P) where each color component is stored in a separate plane.
§Memory Layout
For packed formats (RGB, RGBA, BGR, BGRA):
- Single plane containing all pixel data
- Stride equals width ×
bytes_per_pixel(plus optional padding)
For planar YUV formats (YUV420P, YUV422P, YUV444P):
- Plane 0: Y (luma) - full resolution
- Plane 1: U (Cb) - may be subsampled
- Plane 2: V (Cr) - may be subsampled
For semi-planar formats (NV12, NV21):
- Plane 0: Y (luma) - full resolution
- Plane 1: UV interleaved - half height
§Strides
Each plane has an associated stride (also called line size or pitch), which is the number of bytes from the start of one row to the start of the next. This may be larger than the actual data width due to alignment requirements.
Implementations§
Source§impl VideoFrame
impl VideoFrame
Sourcepub fn new(
planes: Vec<PooledBuffer>,
strides: Vec<usize>,
width: u32,
height: u32,
format: PixelFormat,
timestamp: Timestamp,
key_frame: bool,
) -> Result<Self, FrameError>
pub fn new( planes: Vec<PooledBuffer>, strides: Vec<usize>, width: u32, height: u32, format: PixelFormat, timestamp: Timestamp, key_frame: bool, ) -> Result<Self, FrameError>
Creates a new video frame with the specified parameters.
§Arguments
planes- Pixel data for each planestrides- Stride (bytes per row) for each planewidth- Frame width in pixelsheight- Frame height in pixelsformat- Pixel formattimestamp- Presentation timestampkey_frame- Whether this is a key frame
§Errors
Returns FrameError::MismatchedPlaneStride if planes.len() != strides.len().
§Examples
use ff_format::{PixelFormat, PooledBuffer, Rational, Timestamp, VideoFrame};
// Create a 640x480 YUV420P frame
let width = 640u32;
let height = 480u32;
// Y plane: full resolution
let y_stride = width as usize;
let y_data = vec![128u8; y_stride * height as usize];
// U/V planes: half resolution in both dimensions
let uv_stride = (width / 2) as usize;
let uv_height = (height / 2) as usize;
let u_data = vec![128u8; uv_stride * uv_height];
let v_data = vec![128u8; uv_stride * uv_height];
let frame = VideoFrame::new(
vec![
PooledBuffer::standalone(y_data),
PooledBuffer::standalone(u_data),
PooledBuffer::standalone(v_data),
],
vec![y_stride, uv_stride, uv_stride],
width,
height,
PixelFormat::Yuv420p,
Timestamp::default(),
true,
).unwrap();
assert_eq!(frame.num_planes(), 3);Sourcepub fn empty(
width: u32,
height: u32,
format: PixelFormat,
) -> Result<Self, FrameError>
pub fn empty( width: u32, height: u32, format: PixelFormat, ) -> Result<Self, FrameError>
Creates an empty video frame with the specified dimensions and format.
The frame will have properly sized planes filled with zeros based on the pixel format.
§Arguments
width- Frame width in pixelsheight- Frame height in pixelsformat- Pixel format
§Errors
Returns FrameError::UnsupportedPixelFormat if the format is
PixelFormat::Other, as the memory layout cannot be determined.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert_eq!(frame.width(), 1920);
assert_eq!(frame.height(), 1080);
assert_eq!(frame.num_planes(), 1);Sourcepub const fn width(&self) -> u32
pub const fn width(&self) -> u32
Returns the frame width in pixels.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert_eq!(frame.width(), 1920);Sourcepub const fn height(&self) -> u32
pub const fn height(&self) -> u32
Returns the frame height in pixels.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert_eq!(frame.height(), 1080);Sourcepub const fn format(&self) -> PixelFormat
pub const fn format(&self) -> PixelFormat
Returns the pixel format of this frame.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Yuv420p).unwrap();
assert_eq!(frame.format(), PixelFormat::Yuv420p);Sourcepub const fn timestamp(&self) -> Timestamp
pub const fn timestamp(&self) -> Timestamp
Returns the presentation timestamp of this frame.
§Examples
use ff_format::{PixelFormat, PooledBuffer, Rational, Timestamp, VideoFrame};
let ts = Timestamp::new(90000, Rational::new(1, 90000));
let frame = VideoFrame::new(
vec![PooledBuffer::standalone(vec![0u8; 1920 * 1080 * 4])],
vec![1920 * 4],
1920,
1080,
PixelFormat::Rgba,
ts,
true,
).unwrap();
assert_eq!(frame.timestamp(), ts);Sourcepub const fn is_key_frame(&self) -> bool
pub const fn is_key_frame(&self) -> bool
Returns whether this frame is a key frame (I-frame).
Key frames are complete frames that don’t depend on any other frames for decoding. They are used as reference points for seeking.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let mut frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert!(!frame.is_key_frame());
frame.set_key_frame(true);
assert!(frame.is_key_frame());Sourcepub fn set_key_frame(&mut self, key_frame: bool)
pub fn set_key_frame(&mut self, key_frame: bool)
Sets whether this frame is a key frame.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let mut frame = VideoFrame::empty(640, 480, PixelFormat::Rgba).unwrap();
frame.set_key_frame(true);
assert!(frame.is_key_frame());Sourcepub fn set_timestamp(&mut self, timestamp: Timestamp)
pub fn set_timestamp(&mut self, timestamp: Timestamp)
Sets the timestamp of this frame.
§Examples
use ff_format::{PixelFormat, Rational, Timestamp, VideoFrame};
let mut frame = VideoFrame::empty(640, 480, PixelFormat::Rgba).unwrap();
let ts = Timestamp::new(3000, Rational::new(1, 90000));
frame.set_timestamp(ts);
assert_eq!(frame.timestamp(), ts);Sourcepub fn num_planes(&self) -> usize
pub fn num_planes(&self) -> usize
Returns the number of planes in this frame.
- Packed formats (RGBA, RGB24, etc.): 1 plane
- Planar YUV (YUV420P, YUV422P, YUV444P): 3 planes
- Semi-planar (NV12, NV21): 2 planes
§Examples
use ff_format::{PixelFormat, VideoFrame};
let rgba = VideoFrame::empty(640, 480, PixelFormat::Rgba).unwrap();
assert_eq!(rgba.num_planes(), 1);
let yuv = VideoFrame::empty(640, 480, PixelFormat::Yuv420p).unwrap();
assert_eq!(yuv.num_planes(), 3);
let nv12 = VideoFrame::empty(640, 480, PixelFormat::Nv12).unwrap();
assert_eq!(nv12.num_planes(), 2);Sourcepub fn planes(&self) -> &[PooledBuffer]
pub fn planes(&self) -> &[PooledBuffer]
Returns a slice of all plane buffers.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(640, 480, PixelFormat::Yuv420p).unwrap();
let planes = frame.planes();
assert_eq!(planes.len(), 3);Sourcepub fn plane(&self, index: usize) -> Option<&[u8]>
pub fn plane(&self, index: usize) -> Option<&[u8]>
Returns the data for a specific plane, or None if the index is out of bounds.
§Arguments
index- The plane index (0 for Y/RGB, 1 for U/UV, 2 for V)
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(640, 480, PixelFormat::Yuv420p).unwrap();
// Y plane exists
assert!(frame.plane(0).is_some());
// U and V planes exist
assert!(frame.plane(1).is_some());
assert!(frame.plane(2).is_some());
// No fourth plane
assert!(frame.plane(3).is_none());Sourcepub fn plane_mut(&mut self, index: usize) -> Option<&mut [u8]>
pub fn plane_mut(&mut self, index: usize) -> Option<&mut [u8]>
Returns mutable access to a specific plane’s data.
§Arguments
index- The plane index
§Examples
use ff_format::{PixelFormat, VideoFrame};
let mut frame = VideoFrame::empty(640, 480, PixelFormat::Rgba).unwrap();
if let Some(data) = frame.plane_mut(0) {
// Fill with red (RGBA)
for chunk in data.chunks_exact_mut(4) {
chunk[0] = 255; // R
chunk[1] = 0; // G
chunk[2] = 0; // B
chunk[3] = 255; // A
}
}Sourcepub fn strides(&self) -> &[usize]
pub fn strides(&self) -> &[usize]
Returns a slice of all stride values.
Strides indicate the number of bytes between the start of consecutive rows in each plane.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
let strides = frame.strides();
assert_eq!(strides[0], 1920 * 4); // RGBA = 4 bytes per pixelSourcepub fn stride(&self, plane: usize) -> Option<usize>
pub fn stride(&self, plane: usize) -> Option<usize>
Returns the stride for a specific plane, or None if the index is out of bounds.
§Arguments
plane- The plane index
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(640, 480, PixelFormat::Yuv420p).unwrap();
// Y plane stride = width
assert_eq!(frame.stride(0), Some(640));
// U/V plane stride = width / 2
assert_eq!(frame.stride(1), Some(320));
assert_eq!(frame.stride(2), Some(320));Sourcepub fn data(&self) -> Vec<u8> ⓘ
pub fn data(&self) -> Vec<u8> ⓘ
Returns the frame data as a contiguous byte vector.
For packed formats with a single plane, this returns a copy of the plane data. For planar formats, this concatenates all planes into a single buffer.
§Note
This method allocates a new vector and copies the data. For zero-copy
access, use plane() or planes() instead.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(4, 4, PixelFormat::Rgba).unwrap();
let data = frame.data();
assert_eq!(data.len(), 4 * 4 * 4); // 4x4 pixels, 4 bytes eachSourcepub fn data_ref(&self) -> Option<&[u8]>
pub fn data_ref(&self) -> Option<&[u8]>
Returns a reference to the first plane’s data as a contiguous slice.
This is only meaningful for packed formats (RGBA, RGB24, etc.) where
all data is in a single plane. Returns None if the format is planar
or if no planes exist.
§Examples
use ff_format::{PixelFormat, VideoFrame};
// Packed format - returns data
let rgba = VideoFrame::empty(640, 480, PixelFormat::Rgba).unwrap();
assert!(rgba.data_ref().is_some());
// Planar format - returns None
let yuv = VideoFrame::empty(640, 480, PixelFormat::Yuv420p).unwrap();
assert!(yuv.data_ref().is_none());Sourcepub fn data_mut(&mut self) -> Option<&mut [u8]>
pub fn data_mut(&mut self) -> Option<&mut [u8]>
Returns a mutable reference to the first plane’s data.
This is only meaningful for packed formats where all data is in a
single plane. Returns None if the format is planar.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let mut frame = VideoFrame::empty(4, 4, PixelFormat::Rgba).unwrap();
if let Some(data) = frame.data_mut() {
data[0] = 255; // Modify first byte
}Sourcepub fn total_size(&self) -> usize
pub fn total_size(&self) -> usize
Returns the total size in bytes of all plane data.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert_eq!(frame.total_size(), 1920 * 1080 * 4);Sourcepub const fn resolution(&self) -> (u32, u32)
pub const fn resolution(&self) -> (u32, u32)
Returns the resolution as a (width, height) tuple.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
assert_eq!(frame.resolution(), (1920, 1080));Sourcepub fn aspect_ratio(&self) -> f64
pub fn aspect_ratio(&self) -> f64
Returns the aspect ratio as a floating-point value.
§Examples
use ff_format::{PixelFormat, VideoFrame};
let frame = VideoFrame::empty(1920, 1080, PixelFormat::Rgba).unwrap();
let aspect = frame.aspect_ratio();
assert!((aspect - 16.0 / 9.0).abs() < 0.01);Trait Implementations§
Source§impl Clone for VideoFrame
impl Clone for VideoFrame
Source§fn clone(&self) -> VideoFrame
fn clone(&self) -> VideoFrame
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more