How to Use AVBufferRef in FFmpeg C API

FFmpeg utilizes AVBufferRef as the core of its reference-counting mechanism to manage heap memory safely and efficiently across audio and video processing pipelines. This article explains how AVBufferRef works, detailing how to allocate reference-counted buffers, duplicate references without copying data, handle copy-on-write semantics, and properly release references to prevent memory leaks.

Understanding AVBuffer and AVBufferRef

Memory management in FFmpeg distinguishes between the underlying data and the reference pointing to it:

  • AVBuffer: An opaque structure holding the actual allocated memory, its size, the current reference count, and a free callback. You generally do not interact with AVBuffer directly.
  • AVBufferRef: A lightweight wrapper structure that references an AVBuffer. It exposes a pointer to the memory (data) and the buffer size. Multiple AVBufferRef instances can point to the same underlying AVBuffer.

When an AVBuffer's reference count drops to zero, FFmpeg executes the associated cleanup function and frees the memory automatically.

Allocating a Reference-Counted Buffer

To allocate a new buffer, use av_buffer_alloc(). This creates the underlying AVBuffer and returns a pointer to an AVBufferRef with an initial reference count of 1.

#include <libavutil/buffer.h>

size_t size = 1024;
AVBufferRef *buf = av_buffer_alloc(size);
if (!buf) {
    // Handle allocation failure
}

// Access data and size
memset(buf->data, 0, buf->size);

If you need to manage custom memory or bind external buffers, use av_buffer_create() to supply a custom deallocator callback:

void custom_free(void *opaque, uint8_t *data) {
    free(data);
}

uint8_t *external_memory = malloc(size);
AVBufferRef *buf = av_buffer_create(external_memory, size, custom_free, NULL, 0);

Duplicating References

To share memory between different structures (such as AVFrame or AVPacket) without duplicating the payload, create a new reference using av_buffer_ref().

AVBufferRef *buf_copy = av_buffer_ref(buf);
if (!buf_copy) {
    // Handle error (allocation of descriptor failed)
}
// Both `buf` and `buf_copy` point to the same data.
// The internal reference count is now 2.

Releasing References

To drop a reference, use av_buffer_unref(). This function decrements the internal reference count and sets the target pointer to NULL. When the reference count reaches zero, the underlying memory is freed.

av_buffer_unref(&buf);
// `buf` is now NULL. The underlying data remains allocated because `buf_copy` still exists.

av_buffer_unref(&buf_copy);
// `buf_copy` is now NULL. The reference count hits 0; the data is freed.

Always pass the address of the AVBufferRef pointer (&buf) to ensure dangling pointers are cleared.

Modifying Shared Buffers (Copy-on-Write)

If multiple references point to the same buffer, modifying the contents directly can lead to unintended side effects. FFmpeg provides copy-on-write functionality through av_buffer_is_writable() and av_buffer_make_writable().

  • av_buffer_is_writable(buf) returns 1 if the reference count is strictly 1, meaning the buffer is safe to modify without affecting other references.
  • av_buffer_make_writable(&buf) checks if the buffer is writable. If the reference count is greater than 1, it allocates a new buffer, copies the data over, decrements the reference on the original buffer, and replaces your pointer with the new, exclusive copy.
// Ensure buf can be safely written to
int ret = av_buffer_make_writable(&buf);
if (ret < 0) {
    // Allocation failure during copy
}

// Safe to modify buf->data
buf->data[0] = 0xFF;

Integration with AVFrame and AVPacket

Higher-level structures like AVFrame and AVPacket rely on AVBufferRef:

  • AVPacket stores its compressed data reference in packet->buf.
  • AVFrame stores uncompressed plane references in an array: frame->buf[0], frame->buf[1], etc.

When cloning frames or packets via functions like av_frame_ref() or av_packet_ref(), FFmpeg internally calls av_buffer_ref() on these pointers, avoiding expensive memory copies. Calling av_frame_unref() or av_packet_unref() releases the respective references automatically.