FFmpeg Memory Management: av_packet_free and av_frame_free
In FFmpeg C API development, improper management of
AVPacket and AVFrame lifecycles is a leading
cause of memory leaks and application crashes. This guide explains how
to properly allocate, reference, and release memory using
av_packet_free and av_frame_free, ensuring
your multimedia applications remain stable and leak-free.
Understanding the Allocation Model
To prevent leaks, you must understand that both AVPacket
(which holds compressed encoded data) and AVFrame (which
holds uncompressed raw data) consist of two parts: 1. The
Wrapper (Struct): The metadata container (e.g., width, height,
pts, dts). 2. The Payload (Data Buffer): The actual
pixel data or audio samples.
Both must be freed correctly. Doing this manually by freeing struct members is highly discouraged. Instead, you must use FFmpeg’s dedicated lifecycle APIs.
Proper Allocation and Deallocation
Always allocate packets and frames on the heap using their respective
allocation functions. Never allocate them on the stack (e.g.,
AVPacket pkt;), as this bypasses FFmpeg’s internal
initialization and reference-counting mechanisms.
Recommended Allocation Pattern
AVFrame *frame = av_frame_alloc();
AVPacket *pkt = av_packet_alloc();
if (!frame || !pkt) {
// Handle memory allocation failure
}Recommended Deallocation Pattern
To free both the underlying data buffers and the container structs,
pass the address of your pointer to av_frame_free and
av_packet_free.
av_frame_free(&frame);
av_packet_free(&pkt);Why pass a double pointer (&frame)?
Passing a double pointer allows FFmpeg to do two things: 1. Internally
call unref functions to free the underlying data buffers.
2. Free the container struct itself and automatically set your pointer
(frame or pkt) to NULL. This
prevents accidental double-free errors and dangling pointer bugs.
Managing Loops and Reference Counting
When processing video or audio in a loop (such as decoding or demuxing), allocating and freeing a new packet/frame on every iteration is highly inefficient. Instead, allocate once outside the loop, reuse the container inside the loop, and free it once at the end.
To do this safely without leaking memory, you must use reference
counting via av_packet_unref and
av_frame_unref.
The Loop Reuse Pattern
AVPacket *pkt = av_packet_alloc();
if (!pkt) return;
while (av_read_frame(format_context, pkt) >= 0) {
// Process the packet (e.g., send to decoder)
// Wipe the packet data and decrement the reference count,
// preparing the struct to be reused in the next iteration.
av_packet_unref(pkt);
}
// Clean up the container when the loop finishes
av_packet_free(&pkt);Note: Functions like av_read_frame and
avcodec_receive_frame will automatically call
unref on the destination object before writing new data.
However, explicitly calling unref in your cleanup paths or
when skipping packets prevents leaks in error-handling
branches.
Best Practices to Prevent Memory Leaks
- Avoid Stack Allocation: Never use
AVPacket pkt;orAVFrame frame;. Stack-allocated structs do not utilize modern FFmpeg reference counting and will cause undefined behavior or memory leaks when passed to APIs. - Use the
gotoCleanup Pattern: In C, handle errors by jumping to a cleanup label at the end of your function. Ensure your cleanup block safely callsav_packet_free(&pkt)andav_frame_free(&frame). Because these functions acceptNULLpointers safely, you do not need to check if the pointer is valid before calling them. - Handle Ownership Transfers: Be aware of functions
that take ownership of data. For example,
av_packet_move_ref(dst, src)moves the reference fromsrctodstand blankssrc. If you manually freesrcafterward, it is safe, but you must ensuredstis eventually freed.