Allocate and Populate an AVFrame in FFmpeg

This article explains how to programmatically allocate, configure, and populate an AVFrame structure using the FFmpeg libraries (libavutil and libavcodec). You will learn how to initialize the frame, allocate the underlying data buffers based on specific dimensions and pixel formats, write custom raw pixel data to the buffers, and properly free the memory when finished.

1. Frame Allocation

To begin, allocate the core AVFrame structure. This function sets up the structure wrapper but does not allocate any buffer memory for the actual video or audio data.

#include <libavutil/frame.h>
#include <libavutil/imgutils.h>

AVFrame *frame = av_frame_alloc();
if (!frame) {
    fprintf(stderr, "Could not allocate video frame\n");
    exit(1);
}

2. Configure Frame Properties

Before allocating data buffers, specify the properties of the frame. For a video frame, you must define the pixel format, width, and height.

frame->format = AV_PIX_FMT_YUV420P;
frame->width  = 640;
frame->height = 480;

3. Allocate Data Buffers

Once the properties are defined, call av_frame_get_buffer() to allocate the physical buffers for the image data. The second argument specifies the buffer alignment (using 0 lets FFmpeg select the optimal alignment for the CPU architecture).

int ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
    fprintf(stderr, "Could not allocate the video frame data buffers\n");
    av_frame_free(&frame);
    exit(1);
}

4. Populate the Frame with Data

Before writing data to the allocated buffers, call av_frame_make_writable() to ensure the frame is not shared and can be safely modified.

You can then access the pixel planes using the frame->data pointers. The frame->linesize array defines the byte-stride for each horizontal line of data, which may include padding bytes for alignment.

Below is an example of populating a planar YUV420P frame with a custom color pattern:

ret = av_frame_make_writable(frame);
if (ret < 0) {
    av_frame_free(&frame);
    exit(1);
}

// Populate the Y (Luminance) 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; 
    }
}

// Populate the U and V (Chrominance) planes (subsampled by 2 in 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 + y;
        frame->data[2][y * frame->linesize[2] + x] = 64 + x;
    }
}

5. Memory Cleanup

To avoid memory leaks, free the underlying data buffers and the frame structure itself using av_frame_free() when you are finished using the frame.

av_frame_free(&frame);