32blogby Studio Mitsu

FFmpeg libavutil Guide: Functions, Usage, and Code Examples

A deep dive into FFmpeg's libavutil library. Covers memory management, timestamp conversion, error handling, and pixel format utilities with complete C code examples.

by omitsu15 min read
FFmpeglibavutilClibraryerror-handlingmemory management
On this page

libavutil is FFmpeg's foundational utility library — it provides memory allocation, timestamp math, error handling, logging, and pixel/sample format helpers that every other FFmpeg library depends on. If you're writing C code against FFmpeg's API, you'll include libavutil headers in virtually every file.

This article covers the functions you'll use most when building media applications with FFmpeg's C API, with complete code examples you can compile and run.

What you'll learn

  • The role of libavutil in the FFmpeg ecosystem
  • Memory management with av_malloc and av_free
  • Timestamp conversion with av_rescale_q
  • Error handling with av_strerror
  • Logging with av_log
  • Working with AVFrame and AVDictionary
  • Hash computation for file integrity checks
  • Installation and build setup

What is libavutil?

Overview

libavutil is FFmpeg's core utility library. It provides the low-level building blocks that all other FFmpeg libraries (libavcodec, libavformat, libavfilter, and others) depend on.

Key capabilities:

  • Memory allocation and buffer management
  • Mathematical operations and scaling
  • Pixel format and sample format utilities
  • Error code to string conversion
  • Structured logging with level control
  • Cryptographic hash functions (MD5, SHA1, HMAC)
  • Rational number arithmetic
  • Reference-counted frames (AVFrame)
  • Key-value metadata dictionaries (AVDictionary)

As of FFmpeg 8.1 (released March 2026), libavutil remains stable with the same core API surface. The official Doxygen documentation lists 10 module categories spanning 148 header files.

Where libavutil fits in the FFmpeg library stack

LibraryPrimary role
libavcodecAudio and video encoding/decoding
libavformatMedia container parsing and muxing
libavfilterVideo and audio filtering
libavutilUtility functions: memory, math, logging, error handling
libswscaleVideo rescaling and color space conversion
libswresampleAudio resampling and format conversion

libavutil is the foundation layer. You rarely use it in isolation, but it's always present when working with FFmpeg's C API.

libavutilMemory / Math / ErrorFoundationlibavcodecEncode / DecodeDepends onlibavformatContainer I/OCallsApplicationYour code

Memory Management

FFmpeg handles large amounts of data during media processing, making proper memory management critical. Segfaults from mismatched av_malloc/free calls are one of the most common pitfalls in FFmpeg development.

Core functions

  • av_malloc(size_t size) — allocate memory
  • av_free(void *ptr) — free allocated memory
  • av_mallocz(size_t size) — allocate and zero-initialize memory
  • av_realloc(void *ptr, size_t size) — resize allocated memory
  • av_freep(void **ptr) — free and set pointer to NULL (safer)

Basic usage

c
#include <libavutil/mem.h>
#include <stdio.h>

int main() {
    // Allocate an array of 10 integers
    int *data = (int *) av_malloc(sizeof(int) * 10);
    if (!data) {
        fprintf(stderr, "Memory allocation failed\n");
        return 1;
    }

    for (int i = 0; i < 10; i++) {
        data[i] = i * i;
    }

    printf("data[5] = %d\n", data[5]); // 25

    av_free(data);
    return 0;
}

Why use av_malloc instead of malloc?

FFmpeg internally uses aligned memory allocation to optimize SIMD operations. The alignment size depends on your CPU's capabilities:

CPU FeatureAlignment
AVX-51264 bytes
AVX / AVX232 bytes
SSE / NEON16 bytes

On a typical x86_64 build with AVX2, av_malloc returns 32-byte aligned memory. This matters because FFmpeg's internal DSP routines use SIMD instructions that crash on unaligned data. Standard malloc only guarantees 16-byte alignment on most platforms.

Using regular malloc for frame buffers can cause random segfaults that only show up with certain video resolutions. Switching to av_malloc fixes them — the AVX2 code paths need 32-byte alignment, and malloc doesn't provide it.

av_freep: The safer alternative

av_freep frees memory and sets the pointer to NULL in one step, preventing use-after-free bugs:

c
#include <libavutil/mem.h>
#include <stdio.h>

int main() {
    uint8_t *buffer = (uint8_t *) av_malloc(1024);
    if (!buffer) return 1;

    // ... use buffer ...

    av_freep(&buffer);
    // buffer is now NULL — safe to check before use
    printf("buffer after freep: %p\n", (void *)buffer); // (nil)

    return 0;
}

Mathematical Operations and Time Calculation

Time handling in FFmpeg is based on timebase — a rational number that defines what one "tick" represents. For example, a timebase of 1/90000 means each PTS (Presentation Timestamp) unit is 1/90000 of a second.

Different streams can have different timebases, so converting between them is a common operation. If you're working with HLS streaming or muxing multiple streams, you'll use av_rescale_q constantly.

Core functions

  • av_rescale(int64_t a, int64_t b, int64_t c) — compute a * b / c with overflow protection
  • av_rescale_q(int64_t a, AVRational bq, AVRational cq) — scale a timestamp between two timebases
  • av_log2(unsigned v) — log base 2

Timestamp conversion example

c
#include <libavutil/mathematics.h>
#include <libavutil/rational.h>
#include <inttypes.h>
#include <stdio.h>

int main() {
    // Convert frame number in 30fps timebase to milliseconds
    AVRational src_timebase = {1, 30};    // 30 fps (one unit = 1/30 second)
    AVRational dst_timebase = {1, 1000};  // milliseconds (one unit = 1ms)

    int64_t frame_number = 300; // frame 300 at 30fps = 10 seconds

    int64_t milliseconds = av_rescale_q(frame_number, src_timebase, dst_timebase);
    printf("Frame 300 at 30fps = %" PRId64 " ms\n", milliseconds); // 10000 ms

    return 0;
}

This is essential when mixing streams with different timebases — for example, combining video (typically {1, 90000}) with audio (typically {1, 48000} for 48kHz).

Why av_rescale instead of plain multiplication?

A naive a * b / c can overflow int64_t with large timestamps. av_rescale uses 128-bit intermediate arithmetic to avoid this. For example, when processing a multi-hour livestream recording, timestamps can overflow and produce completely wrong seek positions in the output.

Simple scaling example

c
#include <libavutil/mathematics.h>
#include <inttypes.h>
#include <stdio.h>

int main() {
    // av_rescale: computes a * b / c with correct rounding
    int64_t result = av_rescale(1000, 3, 2);
    printf("1000 * 3 / 2 = %" PRId64 "\n", result); // 1500

    return 0;
}

AVFrame and AVDictionary

These two structures show up everywhere in FFmpeg code, and both rely on libavutil.

AVFrame — decoded media data

AVFrame holds raw decoded video or audio data. It's reference-counted via libavutil's AVBuffer system, so copying a frame is cheap (it increments a refcount, not duplicating pixel data).

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

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

    frame->format = AV_PIX_FMT_YUV420P;
    frame->width  = 1920;
    frame->height = 1080;

    // Allocate the actual pixel buffer
    int ret = av_frame_get_buffer(frame, 0); // 0 = default alignment
    if (ret < 0) {
        fprintf(stderr, "Could not allocate frame buffer\n");
        av_frame_free(&frame);
        return 1;
    }

    printf("Frame: %dx%d, format=%d, linesize[0]=%d\n",
           frame->width, frame->height, frame->format, frame->linesize[0]);

    av_frame_free(&frame);
    return 0;
}

Key points:

  • Always use av_frame_alloc() / av_frame_free() — never stack-allocate an AVFrame
  • av_frame_get_buffer() allocates pixel/sample data with proper alignment
  • av_frame_ref() creates a new reference to the same data (cheap copy)
  • av_frame_unref() releases a reference

AVDictionary — key-value metadata

AVDictionary is FFmpeg's general-purpose key-value store. It's used for container metadata, codec options, and format options.

c
#include <libavutil/dict.h>
#include <stdio.h>

int main() {
    AVDictionary *dict = NULL;

    // Add entries
    av_dict_set(&dict, "title", "My Video", 0);
    av_dict_set(&dict, "artist", "32blog", 0);
    av_dict_set_int(&dict, "track", 1, 0);

    // Look up an entry
    const AVDictionaryEntry *entry = av_dict_get(dict, "title", NULL, 0);
    if (entry) {
        printf("Title: %s\n", entry->value); // "My Video"
    }

    // Iterate all entries
    const AVDictionaryEntry *e = NULL;
    while ((e = av_dict_iterate(dict, e))) {
        printf("%s = %s\n", e->key, e->value);
    }

    av_dict_free(&dict);
    return 0;
}

You'll encounter AVDictionary when reading file metadata, passing options to codecs (avcodec_open2), and configuring format contexts.


Image and Audio Format Utilities

Pixel format helpers

c
#include <libavutil/pixdesc.h>
#include <stdio.h>

int main() {
    // Get the name of a pixel format
    enum AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
    const char *name = av_get_pix_fmt_name(pix_fmt);
    printf("Pixel format: %s\n", name); // yuv420p

    // Look up a pixel format by name
    enum AVPixelFormat found = av_get_pix_fmt("yuv420p");
    printf("Found format enum: %d\n", found);

    // Get detailed format description
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
    printf("Components: %d, bits per pixel: %d\n",
           desc->nb_components,
           av_get_bits_per_pixel(desc));

    return 0;
}

The pixel format reference lists all available formats. You'll use these when setting up encoding or working with GPU-accelerated encoding where format conversion is needed.

Audio buffer size calculation

c
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <stdio.h>

int main() {
    // Calculate buffer size needed for 1024 samples,
    // 2 channels (stereo), 16-bit signed integer format
    int buffer_size = av_samples_get_buffer_size(
        NULL,               // linesize output (NULL = don't need it)
        2,                  // channels
        1024,               // samples per channel
        AV_SAMPLE_FMT_S16,  // sample format (16-bit signed integer)
        0                   // alignment (0 = default)
    );
    printf("Buffer size: %d bytes\n", buffer_size); // 4096 bytes
    return 0;
}

Error Handling and Logging

Error code to string conversion

FFmpeg functions return negative integers for errors. av_strerror converts these to human-readable messages.

c
#include <libavutil/error.h>
#include <stdio.h>

int main() {
    char errbuf[AV_ERROR_MAX_STRING_SIZE];

    // AVERROR(EINVAL) = -22 (Invalid argument)
    int errnum = AVERROR(EINVAL);
    av_strerror(errnum, errbuf, sizeof(errbuf));
    printf("Error: %s\n", errbuf); // "Invalid argument"

    // AVERROR_EOF = end of file
    av_strerror(AVERROR_EOF, errbuf, sizeof(errbuf));
    printf("Error: %s\n", errbuf); // "End of file"

    return 0;
}

Structured logging

c
#include <libavutil/log.h>

int main() {
    // Set minimum log level (messages below this level are suppressed)
    av_log_set_level(AV_LOG_DEBUG);

    // Log at different severity levels
    av_log(NULL, AV_LOG_ERROR,   "This is an error\n");
    av_log(NULL, AV_LOG_WARNING, "This is a warning\n");
    av_log(NULL, AV_LOG_INFO,    "This is info\n");
    av_log(NULL, AV_LOG_DEBUG,   "This is debug output\n");

    return 0;
}

Log levels from most to least severe:

  • AV_LOG_QUIET (suppresses all output)
  • AV_LOG_PANIC
  • AV_LOG_FATAL
  • AV_LOG_ERROR
  • AV_LOG_WARNING
  • AV_LOG_INFO
  • AV_LOG_VERBOSE
  • AV_LOG_DEBUG

During development, set AV_LOG_DEBUG to see detailed internal FFmpeg logs. For production, AV_LOG_WARNING or AV_LOG_ERROR keeps output manageable.

Custom log callback

You can redirect FFmpeg's log output to your own logging system:

c
#include <libavutil/log.h>
#include <stdio.h>
#include <stdarg.h>

static void custom_log_callback(void *ptr, int level, const char *fmt, va_list vl) {
    if (level > av_log_get_level()) return;

    char line[1024];
    vsnprintf(line, sizeof(line), fmt, vl);

    // Route to your logging system
    fprintf(stderr, "[FFmpeg][%d] %s", level, line);
}

int main() {
    av_log_set_callback(custom_log_callback);
    av_log_set_level(AV_LOG_INFO);

    av_log(NULL, AV_LOG_INFO, "This goes through our custom callback\n");
    return 0;
}

Installation and Setup

If you haven't installed FFmpeg yet, see the complete FFmpeg installation guide for platform-specific instructions. Below is the quick version for C API development.

Ubuntu / Debian

bash
sudo apt update
sudo apt install ffmpeg libavutil-dev

For the latest version (FFmpeg 8.1 as of March 2026), build from source:

bash
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
git checkout release/8.1
./configure
make -j$(nproc)
sudo make install

macOS

bash
brew install ffmpeg

To set up pkg-config path for development:

bash
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig"

Windows

Download the development libraries (includes headers and .lib files) from ffmpeg.org/download.html and configure your IDE to link against them. For a proper build toolchain, MSYS2 with MinGW is recommended.

Compiling a program with libavutil

bash
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)

If you also need format/codec support (most real projects do):

bash
gcc -o my_program my_program.c \
    $(pkg-config --cflags --libs libavutil libavformat libavcodec)

Common Errors and Solutions

undefined reference to 'av_malloc'

Cause: The library isn't being linked.

Fix: Add the library to your linker flags:

bash
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
# or manually:
gcc -o my_program my_program.c -lavutil

libavutil.so.XX: cannot open shared object file

Cause: The shared library path isn't in LD_LIBRARY_PATH.

Fix:

bash
# Check which library is missing
ldd $(which ffmpeg) | grep libavutil

# Add the library path
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

# Register the library with the system linker
sudo ldconfig

Segmentation fault

Cause: Memory corruption — usually from accessing freed memory, using uninitialized pointers, or mismatched av_malloc/free calls.

Fix:

  1. Ensure every av_malloc is paired with av_free
  2. Never call av_free on a pointer you didn't get from av_malloc
  3. Use av_freep to auto-null pointers after freeing
  4. Use AddressSanitizer for quick detection:
bash
gcc -fsanitize=address -g -o my_program my_program.c \
    $(pkg-config --cflags --libs libavutil)
./my_program

Or use GDB to identify the crash location:

bash
gdb --args ./my_program
run
bt

Practical Example: File Integrity Check with MD5

libavutil includes cryptographic hash functions. Here's a complete example computing an MD5 hash:

c
#include <libavutil/md5.h>
#include <stdio.h>
#include <string.h>

int main() {
    AVMD5 *md5 = av_md5_alloc();
    if (!md5) {
        fprintf(stderr, "Failed to allocate MD5 context\n");
        return 1;
    }

    const char *data = "Hello, FFmpeg!";
    unsigned char digest[16];

    av_md5_init(md5);
    av_md5_update(md5, (const uint8_t*)data, strlen(data));
    av_md5_final(md5, digest);

    printf("MD5 of \"%s\": ", data);
    for (int i = 0; i < 16; i++) {
        printf("%02x", digest[i]);
    }
    printf("\n");

    av_free(md5);
    return 0;
}

Practical Example: Safe Error Handling Pattern

Here's a robust error-handling pattern for FFmpeg applications:

c
#include <libavutil/error.h>
#include <libavformat/avformat.h>
#include <stdio.h>

// Macro for consistent error checking
#define CHECK(ret, msg) \
    do { \
        if ((ret) < 0) { \
            char errbuf[AV_ERROR_MAX_STRING_SIZE]; \
            av_strerror(ret, errbuf, sizeof(errbuf)); \
            fprintf(stderr, "%s: %s\n", msg, errbuf); \
            return (ret); \
        } \
    } while (0)

int inspect_media_file(const char *filename) {
    AVFormatContext *fmt_ctx = NULL;
    int ret;

    ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
    CHECK(ret, "Could not open file");

    ret = avformat_find_stream_info(fmt_ctx, NULL);
    CHECK(ret, "Could not find stream info");

    printf("Format: %s\n", fmt_ctx->iformat->name);
    printf("Duration: %ld seconds\n", fmt_ctx->duration / AV_TIME_BASE);
    printf("Number of streams: %u\n", fmt_ctx->nb_streams);

    // Print metadata using AVDictionary iteration
    const AVDictionaryEntry *tag = NULL;
    while ((tag = av_dict_iterate(fmt_ctx->metadata, tag))) {
        printf("  %s: %s\n", tag->key, tag->value);
    }

    avformat_close_input(&fmt_ctx);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <input_file>\n", argv[0]);
        return 1;
    }
    return inspect_media_file(argv[1]);
}

This pattern makes it easy to pinpoint exactly which step failed and why. Compile it with:

bash
gcc -o inspect inspect.c $(pkg-config --cflags --libs libavutil libavformat)


FAQ

What is the difference between libavutil and libavcodec?

libavutil provides low-level utility functions (memory management, math, logging, error handling) that all other FFmpeg libraries depend on. libavcodec specifically handles encoding and decoding of audio and video codecs. You cannot use libavcodec without libavutil, but you can use libavutil on its own.

Can I use libavutil without the rest of FFmpeg?

Yes. libavutil has no dependencies on other FFmpeg libraries. You can link just -lavutil and use its memory functions, math utilities, hash functions, and logging. This is useful for small tools that need aligned memory allocation or timestamp arithmetic without full media processing.

Is libavutil thread-safe?

Most libavutil functions are thread-safe. Memory allocation (av_malloc, av_free), math functions (av_rescale_q), and error handling (av_strerror) can be called from multiple threads without synchronization. However, av_log_set_level and av_log_set_callback modify global state and should only be called during initialization.

What alignment does av_malloc use?

It depends on your build's SIMD support: 64 bytes for AVX-512, 32 bytes for AVX/AVX2, and 16 bytes for SSE/NEON. On a standard x86_64 Linux build, it's typically 32 bytes. This alignment ensures FFmpeg's SIMD-optimized routines don't crash on unaligned access.

How do I check which version of libavutil I have installed?

Use pkg-config or check programmatically:

bash
pkg-config --modversion libavutil

Or in C code:

c
#include <libavutil/version.h>
printf("libavutil %d.%d.%d\n",
       LIBAVUTIL_VERSION_MAJOR,
       LIBAVUTIL_VERSION_MINOR,
       LIBAVUTIL_VERSION_MICRO);

Should I use av_frame_clone or av_frame_ref?

Use av_frame_ref() when you want a new reference to the same underlying data (cheap, just increments refcount). Use av_frame_clone() when you need a completely independent copy. In most cases, av_frame_ref is what you want — it avoids unnecessary data copying.

What is AV_TIME_BASE and when do I use it?

AV_TIME_BASE is FFmpeg's internal time unit, defined as 1,000,000 (microseconds). Container-level timestamps like AVFormatContext.duration use this base. To convert to seconds, divide by AV_TIME_BASE. For stream-level timestamps, use the stream's own time_base with av_rescale_q.

How do I handle deprecated libavutil functions?

FFmpeg marks deprecated functions with attribute_deprecated and removes them in the next major version. Check the API changes documentation for migration paths. Compile with -Wdeprecated-declarations to catch usage of deprecated APIs early.


Wrapping Up

libavutil provides the low-level plumbing that makes FFmpeg development manageable:

  • Memory: Use av_malloc/av_free for all FFmpeg-related allocations — alignment matters for SIMD
  • Time: Use av_rescale_q for timestamp conversion between timebases — never do manual multiplication
  • Frames: Use AVFrame with av_frame_alloc/av_frame_free for all decoded media data
  • Metadata: Use AVDictionary for key-value pairs (options, metadata, codec settings)
  • Errors: Use av_strerror to convert error codes to readable messages
  • Logging: Use av_log with appropriate levels for debugging and production
  • Hashing: Use av_md5_* functions for file integrity verification

Understanding libavutil is the foundation for working effectively with FFmpeg's C API. Every higher-level operation — decoding frames, applying filters, writing output — relies on the utilities this library provides.