How to Allocate and Populate an AVFrame in FFmpeg
In FFmpeg, the AVFrame structure is the primary
container used to hold uncompressed audio or video data, such as raw
YUV/RGB video frames or PCM audio samples. Programmatically working with
an AVFrame requires allocating the structure, defining
frame properties such as dimensions and pixel format, allocating data
buffers, and safely populating those buffers with raw data. This guide
provides a step-by-step walkthrough and a clean C code example
demonstrating how to allocate, configure, fill, and free an
AVFrame using the modern FFmpeg API.
1. Allocate the AVFrame Structure
The first step is allocating memory for the AVFrame
struct itself using av_frame_alloc(). This allocates the
wrapper but does not allocate any memory for the underlying image or
audio payload.
AVFrame *frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate AVFrame\n");
return -1;
}2. Configure Frame Properties
Before allocating memory for the underlying image data, define the frame's basic metadata:
format: Pixel format (e.g.,AV_PIX_FMT_YUV420P,AV_PIX_FMT_RGB24).width: Image width in pixels.height: Image height in pixels.
frame->format = AV_PIX_FMT_YUV420P;
frame->width = 1920;
frame->height = 1080;3. Allocate Data Buffers
Call av_frame_get_buffer() to allocate internal memory
buffers according to the configured resolution and pixel format. The
second parameter specifies alignment, where 0 lets FFmpeg
select optimal alignment (often 32 or 64 bytes for SIMD operations).
int ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate frame data buffers\n");
av_frame_free(&frame);
return ret;
}4. Ensure Buffer Writability
If an AVFrame is shared or reference-counted, verify
that its buffers are writable prior to modifying the data by calling
av_frame_make_writable():
ret = av_frame_make_writable(frame);
if (ret < 0) {
fprintf(stderr, "Frame is not writable\n");
av_frame_free(&frame);
return ret;
}5. Populate Data Planes
Once memory is allocated, populate the frame by accessing its data
pointers (frame->data) and stride values
(frame->linesize).
For planar formats like AV_PIX_FMT_YUV420P:
frame->data[0]: Y (Luminance) planeframe->data[1]: U (Chrominance) planeframe->data[2]: V (Chrominance) plane
Always respect frame->linesize[n] when moving across
rows to account for row padding:
/* Fill Y plane */
for (int y = 0; y < frame->height; y++) {
for (int x = 0; x < frame->width; x++) {
frame->data[0][y * frame->linesize[0] + x] = x + y;
}
}
/* Fill Cb and Cr planes (half resolution for YUV420P) */
for (int y = 0; y < frame->height / 2; y++) {
for (int x = 0; x < frame->width / 2; x++) {
frame->data[1][y * frame->linesize[1] + x] = 128;
frame->data[2][y * frame->linesize[2] + x] = 64;
}
}For packed formats (such as AV_PIX_FMT_RGB24), all color
components reside consecutively within frame->data[0],
where each pixel occupies multiple bytes across row strides defined by
frame->linesize[0].
6. Set Timestamps (Optional)
If passing the frame to an encoder or multiplexer, assign the
presentation timestamp (pts):
frame->pts = 0; // Increment this monotonically for subsequent frames7. Free the Frame
When processing is complete, release the data buffers and the frame
struct using av_frame_free(). Passing a double pointer
resets your frame pointer to NULL.
av_frame_free(&frame);