If you're building applications on top of FFmpeg's C API, you'll encounter libavutil constantly. It's the foundational library that every other FFmpeg component depends on — providing memory management, math utilities, time calculations, pixel format helpers, and error handling.
This article explains what libavutil does, when to use it, and how to use its most important functions, with complete working code examples.
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
- 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
Where libavutil fits in the FFmpeg library stack
| Library | Primary role |
|---|---|
| libavcodec | Audio and video encoding/decoding |
| libavformat | Media container parsing and muxing |
| libavfilter | Video and audio filtering |
| libavutil | Utility functions: memory, math, logging, error handling |
| libswscale | Video rescaling and color space conversion |
| libswresample | Audio 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.
Memory Management
FFmpeg handles large amounts of data during media processing, making proper memory management critical.
Core functions
av_malloc(size_t size)— allocate memoryav_free(void *ptr)— free allocated memoryav_mallocz(size_t size)— allocate and zero-initialize memoryav_realloc(void *ptr, size_t size)— resize allocated memory
Basic usage
#include <libavutil/mem.h>
#include <stdio.h>
int main() {
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 (SSE, AVX). av_malloc ensures the correct alignment requirements are met. When passing buffers to FFmpeg's internal APIs, always use av_malloc to avoid alignment mismatches.
av_free must always be called on memory allocated with av_malloc. Mixing av_malloc with free, or malloc with av_free, is undefined behavior.
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.
Core functions
av_rescale(int64_t a, int64_t b, int64_t c)— computea * b / cwith overflow protectionav_rescale_q(int64_t a, AVRational bq, AVRational cq)— scale a timestamp between two timebasesav_log2(unsigned v)— log base 2
Timestamp conversion example
#include <libavutil/mathematics.h>
#include <libavutil/rational.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 = %ld ms\n", milliseconds); // 10000 ms = 10 seconds
return 0;
}
This is essential when mixing streams with different timebases — for example, combining video (typically 1/timebase) with audio (typically 1/sample_rate).
Simple scaling example
#include <libavutil/mathematics.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 = %ld\n", result); // 1500
return 0;
}
Image and Audio Format Utilities
Pixel format helpers
#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);
return 0;
}
Audio buffer size calculation
#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.
#include <libavutil/error.h>
#include <stdio.h>
int main() {
char errbuf[128];
// 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
#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_PANICAV_LOG_FATALAV_LOG_ERRORAV_LOG_WARNINGAV_LOG_INFOAV_LOG_VERBOSEAV_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.
Installation and Setup
Ubuntu / Debian
sudo apt update
sudo apt install ffmpeg libavutil-dev
For the latest version, build from source:
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
./configure
make -j$(nproc)
sudo make install
macOS
brew install ffmpeg
To set up pkg-config path for development:
export PKG_CONFIG_PATH=/usr/local/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
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
Common Errors and Solutions
undefined reference to 'av_malloc'
Cause: The library isn't being linked.
Fix: Add the library to your linker flags:
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:
# 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:
- Ensure every
av_mallocis paired withav_free - Never call
av_freeon a pointer you didn't get fromav_malloc - Use
gdbto identify the crash location:
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:
#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:
#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[128]; \
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);
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.
Summary
libavutil provides the low-level plumbing that makes FFmpeg development manageable:
- Memory: Use
av_malloc/av_freefor all FFmpeg-related allocations - Time: Use
av_rescale_qfor timestamp conversion between timebases - Errors: Use
av_strerrorto convert error codes to readable messages - Logging: Use
av_logwith 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.