How libvpx Handles Aspect Ratio and Pixel Geometry
This article explains how the libvpx library—the reference software encoder for the VP8 and VP9 video formats—manages aspect ratio and pixel geometry metadata. It explores the differences in how VP8 and VP9 handle Sample Aspect Ratio (SAR) and Display Aspect Ratio (DAR) within their respective bitstreams, how developers can configure these settings using the libvpx API, and the role of container formats in ensuring correct video playback.
The Difference Between VP8 and VP9 Bitstreams
The libvpx library handles pixel geometry differently depending on whether you are encoding to the older VP8 codec or the newer VP9 codec.
VP8: Container-Dependent Metadata
The VP8 bitstream format does not natively support pixel geometry or Sample Aspect Ratio (SAR) metadata within its raw frame headers. VP8 assumes a default pixel aspect ratio of 1:1 (square pixels). If a video encoded with VP8 requires a non-square aspect ratio (for example, anamorphic widescreen), this metadata cannot be stored in the raw VP8 video stream. Instead, libvpx relies entirely on the multiplexer (muxer) to write this geometry data into the container format, such as WebM or Matroska (MKV).
VP9: Native Bitstream Signaling
VP9 introduced native support for signaling pixel geometry directly within the frame header. The VP9 bitstream includes fields for “Render Width” and “Render Height” alongside the coded “Frame Width” and “Frame Height.”
If the render dimensions differ from the coded dimensions, the decoder calculates the Sample Aspect Ratio (SAR) to stretch or shrink the pixels accordingly during playback. This allows VP9 to support non-square pixels natively without relying solely on container-level metadata.
Using the libvpx API to Set Aspect Ratio
When programmatically encoding video using the libvpx
API, developers must pass the correct spatial dimensions to the
encoder.
- Setting Coded Dimensions: The actual encoded pixel
resolution is defined in the configuration structure
(
vpx_codec_enc_cfg_t) using theg_w(width) andg_h(height) parameters. - Setting Render Dimensions (VP9 Only): To define a
custom pixel aspect ratio in VP9, you must use the encoder control
VP9E_SET_RENDER_SIZE. This control takes a pointer to a two-integer array containing the desired display width and height.
int render_size[2] = { display_width, display_height };
vpx_codec_control(&codec_context, VP9E_SET_RENDER_SIZE, render_size);If this control is not set, libvpx defaults the render size to match the coded size, resulting in a 1:1 pixel aspect ratio.
The Role of Container Formats (WebM and MKV)
Because raw video bitstreams are rarely played back directly, the
container format plays a critical role in handling pixel geometry. When
encoding to WebM (the standard container for VP8 and VP9), libvpx works
in tandem with the muxer (such as libwebm or FFmpeg’s
muxer).
WebM and Matroska containers use specific Track elements to define display geometry: * PixelWidth / PixelHeight: The physical, coded dimensions of the video frames. * DisplayWidth / DisplayHeight: The dimensions at which the video should be rendered on screen.
When encoding VP8, the container’s DisplayWidth and
DisplayHeight are the only way to signal a non-square
aspect ratio to media players. For VP9, while the metadata exists in the
bitstream, muxers typically copy the VP9 render size values into the
container’s display headers to ensure maximum compatibility with
hardware decoders and media players.