libavutil es la biblioteca base de FFmpeg — proporciona gestión de memoria, matemáticas de marcas de tiempo, manejo de errores, logging y helpers de formato de píxel/muestra de los que dependen todas las demás bibliotecas de FFmpeg. Si escribes código C contra la API de FFmpeg, incluirás headers de libavutil en prácticamente cada archivo.
Este artículo cubre las funciones que más usarás al construir aplicaciones de procesamiento de medios con la API en C de FFmpeg, con ejemplos de código completos que puedes compilar y ejecutar.
Lo que aprenderás
- El rol de libavutil en el ecosistema FFmpeg
- Gestión de memoria con
av_mallocyav_free - Conversión de marcas de tiempo con
av_rescale_q - Manejo de errores con
av_strerror - Logging con
av_log - Trabajo con AVFrame y AVDictionary
- Cálculo de hash para verificación de integridad de archivos
- Instalación y configuración de compilación
¿Qué es libavutil?
Resumen
libavutil es la biblioteca de utilidades central de FFmpeg. Proporciona los bloques de construcción de bajo nivel de los que dependen todas las demás bibliotecas de FFmpeg (libavcodec, libavformat, libavfilter y otras).
Capacidades clave:
- Asignación de memoria y gestión de buffers
- Operaciones matemáticas y escalado
- Utilidades de formato de píxel y formato de muestra
- Conversión de código de error a cadena de texto
- Logging estructurado con control de nivel
- Funciones de hash criptográfico (MD5, SHA1, HMAC)
- Aritmética de números racionales
- Frames con conteo de referencias (
AVFrame) - Diccionarios de metadatos clave-valor (
AVDictionary)
A partir de FFmpeg 8.1 (lanzado en marzo de 2026), la API central de libavutil permanece estable. La documentación oficial de Doxygen enumera 10 categorías de módulos que abarcan 148 archivos de cabecera.
Dónde encaja libavutil en la pila de bibliotecas de FFmpeg
| Biblioteca | Rol principal |
|---|---|
| libavcodec | Codificación y decodificación de audio y video |
| libavformat | Parsing y muxing de contenedores de medios |
| libavfilter | Filtrado de video y audio |
| libavutil | Funciones de utilidad: memoria, matemáticas, logging, manejo de errores |
| libswscale | Reescalado de video y conversión de espacio de color |
| libswresample | Remuestreo de audio y conversión de formato |
libavutil es la capa de cimientos. Rara vez la usas de forma aislada, pero siempre está presente cuando trabajas con la API en C de FFmpeg.
Gestión de memoria
FFmpeg maneja grandes cantidades de datos durante el procesamiento de medios, haciendo que la gestión adecuada de memoria sea crítica. Los segfaults por mezclar llamadas av_malloc/free son uno de los problemas más comunes en el desarrollo con FFmpeg.
Funciones principales
av_malloc(size_t size)— asignar memoriaav_free(void *ptr)— liberar memoria asignadaav_mallocz(size_t size)— asignar e inicializar a ceroav_realloc(void *ptr, size_t size)— redimensionar memoriaav_freep(void **ptr)— liberar y establecer puntero a NULL (más seguro)
Uso básico
#include <libavutil/mem.h>
#include <stdio.h>
int main() {
// Asignar un array de 10 enteros
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;
}
¿Por qué usar av_malloc en lugar de malloc?
FFmpeg internamente usa asignación de memoria alineada para optimizar operaciones SIMD. El tamaño de alineación depende de las capacidades de tu CPU:
| Característica CPU | Alineación |
|---|---|
| AVX-512 | 64 bytes |
| AVX / AVX2 | 32 bytes |
| SSE / NEON | 16 bytes |
En un build típico x86_64 con AVX2, av_malloc devuelve memoria alineada a 32 bytes. Esto importa porque las rutinas DSP internas de FFmpeg usan instrucciones SIMD que crashean con datos no alineados. El malloc estándar solo garantiza alineación de 16 bytes en la mayoría de plataformas.
Usar malloc regular para los buffers de frames puede causar segfaults aleatorios que solo aparecen con ciertas resoluciones de video. Cambiar a av_malloc los resuelve — las rutas de código AVX2 necesitan alineación de 32 bytes, y malloc no la proporciona.
av_freep: La alternativa más segura
av_freep libera memoria y establece el puntero a NULL en un solo paso, previniendo bugs de use-after-free:
#include <libavutil/mem.h>
#include <stdio.h>
int main() {
uint8_t *buffer = (uint8_t *) av_malloc(1024);
if (!buffer) return 1;
// ... usar buffer ...
av_freep(&buffer);
// buffer ahora es NULL — seguro verificar antes de usar
printf("buffer after freep: %p\n", (void *)buffer); // (nil)
return 0;
}
Operaciones matemáticas y cálculo de tiempo
El manejo de tiempo en FFmpeg está basado en timebase — un número racional que define lo que un "tick" representa. Por ejemplo, un timebase de 1/90000 significa que cada unidad PTS (Presentation Timestamp) es 1/90000 de segundo.
Diferentes streams pueden tener diferentes timebases, así que la conversión entre ellos es una operación común. Si estás trabajando con streaming HLS o muxing de múltiples streams, usarás av_rescale_q constantemente.
Funciones principales
av_rescale(int64_t a, int64_t b, int64_t c)— calculara * b / ccon protección contra desbordamientoav_rescale_q(int64_t a, AVRational bq, AVRational cq)— escalar una marca de tiempo entre dos timebasesav_log2(unsigned v)— logaritmo base 2
Ejemplo de conversión de marca de tiempo
#include <libavutil/mathematics.h>
#include <libavutil/rational.h>
#include <inttypes.h>
#include <stdio.h>
int main() {
// Convertir número de frame en timebase de 30fps a milisegundos
AVRational src_timebase = {1, 30}; // 30 fps (una unidad = 1/30 segundo)
AVRational dst_timebase = {1, 1000}; // milisegundos (una unidad = 1ms)
int64_t frame_number = 300; // frame 300 a 30fps = 10 segundos
int64_t milliseconds = av_rescale_q(frame_number, src_timebase, dst_timebase);
printf("Frame 300 a 30fps = %" PRId64 " ms\n", milliseconds); // 10000 ms
return 0;
}
Esto es esencial cuando mezclas streams con diferentes timebases — por ejemplo, combinando video (típicamente {1, 90000}) con audio (típicamente {1, 48000} para 48kHz).
¿Por qué av_rescale en lugar de multiplicación simple?
Un a * b / c ingenuo puede desbordar int64_t con marcas de tiempo grandes. av_rescale usa aritmética intermedia de 128 bits para evitar esto. Por ejemplo, al procesar una grabación de varias horas de livestream, las marcas de tiempo pueden desbordar y producir posiciones de seek completamente incorrectas en la salida.
Ejemplo de escalado simple
#include <libavutil/mathematics.h>
#include <inttypes.h>
#include <stdio.h>
int main() {
// av_rescale: calcula a * b / c con redondeo correcto
int64_t result = av_rescale(1000, 3, 2);
printf("1000 * 3 / 2 = %" PRId64 "\n", result); // 1500
return 0;
}
AVFrame y AVDictionary
Estas dos estructuras aparecen en todas partes del código FFmpeg, y ambas pertenecen a libavutil.
AVFrame — datos de medios decodificados
AVFrame contiene datos crudos de video o audio decodificados. Está gestionado por conteo de referencias a través del sistema AVBuffer de libavutil, así que copiar un frame es barato (incrementa un refcount, no duplica datos de píxeles).
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
#include <stdio.h>
int main() {
AVFrame *frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "No se pudo asignar el frame\n");
return 1;
}
frame->format = AV_PIX_FMT_YUV420P;
frame->width = 1920;
frame->height = 1080;
// Asignar el buffer de píxeles real
int ret = av_frame_get_buffer(frame, 0); // 0 = alineación por defecto
if (ret < 0) {
fprintf(stderr, "No se pudo asignar el buffer del frame\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;
}
Puntos clave:
- Siempre usa
av_frame_alloc()/av_frame_free()— nunca pongas un AVFrame en el stack av_frame_get_buffer()asigna datos de píxeles/muestras con alineación correctaav_frame_ref()crea una nueva referencia a los mismos datos (copia barata)av_frame_unref()libera una referencia
AVDictionary — metadatos clave-valor
AVDictionary es el almacén clave-valor de propósito general de FFmpeg. Se usa para metadatos de contenedores, opciones de códec y opciones de formato.
#include <libavutil/dict.h>
#include <stdio.h>
int main() {
AVDictionary *dict = NULL;
// Agregar entradas
av_dict_set(&dict, "title", "My Video", 0);
av_dict_set(&dict, "artist", "32blog", 0);
av_dict_set_int(&dict, "track", 1, 0);
// Buscar una entrada
const AVDictionaryEntry *entry = av_dict_get(dict, "title", NULL, 0);
if (entry) {
printf("Title: %s\n", entry->value); // "My Video"
}
// Iterar todas las entradas
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;
}
Encontrarás AVDictionary al leer metadatos de archivos, pasar opciones a códecs (avcodec_open2) y configurar contextos de formato.
Utilidades de formato de imagen y audio
Helpers de formato de píxel
#include <libavutil/pixdesc.h>
#include <stdio.h>
int main() {
// Obtener el nombre de un formato de píxel
enum AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
const char *name = av_get_pix_fmt_name(pix_fmt);
printf("Formato de píxel: %s\n", name); // yuv420p
// Buscar un formato de píxel por nombre
enum AVPixelFormat found = av_get_pix_fmt("yuv420p");
printf("Enum de formato encontrado: %d\n", found);
// Obtener descripción detallada del formato
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
printf("Componentes: %d, bits por píxel: %d\n",
desc->nb_components,
av_get_bits_per_pixel(desc));
return 0;
}
La referencia de formatos de píxel lista todos los formatos disponibles. Los usarás al configurar la codificación o al trabajar con codificación acelerada por GPU donde se necesita conversión de formato.
Cálculo de tamaño de buffer de audio
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <stdio.h>
int main() {
// Calcular el tamaño de buffer necesario para 1024 muestras,
// 2 canales (estéreo), formato entero con signo de 16 bits
int buffer_size = av_samples_get_buffer_size(
NULL, // salida de linesize (NULL = no lo necesitamos)
2, // canales
1024, // muestras por canal
AV_SAMPLE_FMT_S16, // formato de muestra (entero con signo de 16 bits)
0 // alineación (0 = por defecto)
);
printf("Tamaño del buffer: %d bytes\n", buffer_size); // 4096 bytes
return 0;
}
Manejo de errores y logging
Conversión de código de error a cadena de texto
Las funciones de FFmpeg devuelven enteros negativos para errores. av_strerror los convierte a mensajes legibles.
#include <libavutil/error.h>
#include <stdio.h>
int main() {
char errbuf[AV_ERROR_MAX_STRING_SIZE];
// AVERROR(EINVAL) = -22 (Argumento inválido)
int errnum = AVERROR(EINVAL);
av_strerror(errnum, errbuf, sizeof(errbuf));
printf("Error: %s\n", errbuf); // "Invalid argument"
// AVERROR_EOF = fin de archivo
av_strerror(AVERROR_EOF, errbuf, sizeof(errbuf));
printf("Error: %s\n", errbuf); // "End of file"
return 0;
}
Logging estructurado
#include <libavutil/log.h>
int main() {
// Establecer nivel mínimo de log (mensajes por debajo se suprimen)
av_log_set_level(AV_LOG_DEBUG);
// Registrar en diferentes niveles de severidad
av_log(NULL, AV_LOG_ERROR, "Esto es un error\n");
av_log(NULL, AV_LOG_WARNING, "Esto es una advertencia\n");
av_log(NULL, AV_LOG_INFO, "Esto es info\n");
av_log(NULL, AV_LOG_DEBUG, "Esto es salida de depuración\n");
return 0;
}
Niveles de log de mayor a menor severidad:
AV_LOG_QUIET(suprime toda la salida)AV_LOG_PANICAV_LOG_FATALAV_LOG_ERRORAV_LOG_WARNINGAV_LOG_INFOAV_LOG_VERBOSEAV_LOG_DEBUG
Durante el desarrollo, establece AV_LOG_DEBUG para ver los registros internos detallados de FFmpeg. Para producción, AV_LOG_WARNING o AV_LOG_ERROR mantiene la salida manejable.
Callback de log personalizado
Puedes redirigir la salida de log de FFmpeg a tu propio sistema de logging:
#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);
// Redirigir a tu sistema de logging
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, "Esto pasa por nuestro callback personalizado\n");
return 0;
}
Instalación y configuración
Si aún no tienes FFmpeg instalado, consulta la guía completa de instalación de FFmpeg para instrucciones específicas por plataforma. Aquí va la versión rápida para desarrollo con la API en C.
Ubuntu / Debian
sudo apt update
sudo apt install ffmpeg libavutil-dev
Para la última versión (FFmpeg 8.1 a marzo de 2026), compila desde el código fuente:
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
git checkout release/8.1
./configure
make -j$(nproc)
sudo make install
macOS
brew install ffmpeg
Para configurar la ruta de pkg-config para desarrollo:
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig"
Windows
Descarga las bibliotecas de desarrollo (incluye headers y archivos .lib) desde ffmpeg.org/download.html y configura tu IDE para enlazar contra ellas. Para una cadena de herramientas de compilación adecuada, se recomienda MSYS2 con MinGW.
Compilando un programa con libavutil
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
Si también necesitas soporte de formato/códec (la mayoría de proyectos reales lo necesitan):
gcc -o my_program my_program.c \
$(pkg-config --cflags --libs libavutil libavformat libavcodec)
Errores comunes y soluciones
undefined reference to 'av_malloc'
Causa: La biblioteca no se está enlazando.
Solución: Agrega la biblioteca a tus flags del enlazador:
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
# o manualmente:
gcc -o my_program my_program.c -lavutil
libavutil.so.XX: cannot open shared object file
Causa: La ruta de la biblioteca compartida no está en LD_LIBRARY_PATH.
Solución:
# Verificar qué biblioteca falta
ldd $(which ffmpeg) | grep libavutil
# Agregar la ruta de la biblioteca
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
# Registrar la biblioteca con el enlazador del sistema
sudo ldconfig
Fallo de segmentación (Segmentation fault)
Causa: Corrupción de memoria — usualmente por acceder a memoria liberada, usar punteros no inicializados o mezclar llamadas av_malloc/free.
Solución:
- Asegúrate de que cada
av_mallocesté emparejado conav_free - Nunca llames
av_freesobre un puntero que no obtuviste deav_malloc - Usa
av_freeppara auto-nullificar punteros después de liberar - Usa AddressSanitizer para detección rápida:
gcc -fsanitize=address -g -o my_program my_program.c \
$(pkg-config --cflags --libs libavutil)
./my_program
O usa GDB para identificar la ubicación del crash:
gdb --args ./my_program
run
bt
Ejemplo práctico: Verificación de integridad de archivo con MD5
libavutil incluye funciones de hash criptográfico. Aquí hay un ejemplo completo calculando un hash MD5:
#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 de \"%s\": ", data);
for (int i = 0; i < 16; i++) {
printf("%02x", digest[i]);
}
printf("\n");
av_free(md5);
return 0;
}
Ejemplo práctico: Patrón seguro de manejo de errores
Aquí está un patrón robusto de manejo de errores para aplicaciones FFmpeg:
#include <libavutil/error.h>
#include <libavformat/avformat.h>
#include <stdio.h>
// Macro para verificación de errores consistente
#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, "No se pudo abrir el archivo");
ret = avformat_find_stream_info(fmt_ctx, NULL);
CHECK(ret, "No se pudo encontrar info de streams");
printf("Formato: %s\n", fmt_ctx->iformat->name);
printf("Duración: %ld segundos\n", fmt_ctx->duration / AV_TIME_BASE);
printf("Número de streams: %u\n", fmt_ctx->nb_streams);
// Imprimir metadatos usando iteración de AVDictionary
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("Uso: %s <archivo_entrada>\n", argv[0]);
return 1;
}
return inspect_media_file(argv[1]);
}
Este patrón facilita identificar exactamente qué paso falló y por qué. Compílalo con:
gcc -o inspect inspect.c $(pkg-config --cflags --libs libavutil libavformat)
Artículos relacionados
- Guía de instalación de FFmpeg — Instala FFmpeg en cualquier plataforma
- Guía de comandos FFmpeg — Usar FFmpeg desde la línea de comandos en lugar de la API en C
- Codificación GPU con NVENC y QSV — Codificación acelerada por hardware que se beneficia de la API
hwcontextde libavutil - Guía de compresión de video FFmpeg — Técnicas prácticas de compresión usando los códecs que libavutil soporta
- Automatización de FFmpeg con Python — Usa
subprocessde Python para controlar FFmpeg sin tocar la API en C - FFmpeg.wasm: Procesamiento de video en el navegador — libavutil compilado a WebAssembly para procesamiento del lado del cliente
- Guía de licencia comercial de FFmpeg — Implicaciones LGPL vs GPL al enlazar libavutil en productos comerciales
FAQ
¿Cuál es la diferencia entre libavutil y libavcodec?
libavutil proporciona funciones de utilidad de bajo nivel (gestión de memoria, matemáticas, logging, manejo de errores) de las que dependen todas las demás bibliotecas de FFmpeg. libavcodec se encarga específicamente de la codificación y decodificación de códecs de audio y video. No puedes usar libavcodec sin libavutil, pero sí puedes usar libavutil por sí solo.
¿Puedo usar libavutil sin el resto de FFmpeg?
Sí. libavutil no tiene dependencias de otras bibliotecas de FFmpeg. Puedes enlazar solo -lavutil y usar sus funciones de memoria, utilidades matemáticas, funciones de hash y logging. Esto es útil para herramientas pequeñas que necesitan asignación de memoria alineada o aritmética de marcas de tiempo sin procesamiento completo de medios.
¿Es libavutil thread-safe?
La mayoría de las funciones de libavutil son thread-safe. La asignación de memoria (av_malloc, av_free), las funciones matemáticas (av_rescale_q) y el manejo de errores (av_strerror) se pueden llamar desde múltiples hilos sin sincronización. Sin embargo, av_log_set_level y av_log_set_callback modifican estado global y solo deberían llamarse durante la inicialización.
¿Qué alineación usa av_malloc?
Depende del soporte SIMD de tu build: 64 bytes para AVX-512, 32 bytes para AVX/AVX2 y 16 bytes para SSE/NEON. En un build estándar de Linux x86_64, típicamente son 32 bytes. Esta alineación asegura que las rutinas optimizadas con SIMD de FFmpeg no crasheen por acceso no alineado.
¿Cómo verifico qué versión de libavutil tengo instalada?
Usa pkg-config o verifica programáticamente:
pkg-config --modversion libavutil
O en código C:
#include <libavutil/version.h>
printf("libavutil %d.%d.%d\n",
LIBAVUTIL_VERSION_MAJOR,
LIBAVUTIL_VERSION_MINOR,
LIBAVUTIL_VERSION_MICRO);
¿Debo usar av_frame_clone o av_frame_ref?
Usa av_frame_ref() cuando quieras una nueva referencia a los mismos datos subyacentes (barato, solo incrementa el refcount). Usa av_frame_clone() cuando necesites una copia completamente independiente. En la mayoría de los casos, av_frame_ref es lo que quieres — evita copias de datos innecesarias.
¿Qué es AV_TIME_BASE y cuándo lo uso?
AV_TIME_BASE es la unidad de tiempo interna de FFmpeg, definida como 1,000,000 (microsegundos). Las marcas de tiempo a nivel de contenedor como AVFormatContext.duration usan esta base. Para convertir a segundos, divide por AV_TIME_BASE. Para marcas de tiempo a nivel de stream, usa el time_base propio del stream con av_rescale_q.
¿Cómo manejo funciones deprecadas de libavutil?
FFmpeg marca las funciones deprecadas con attribute_deprecated y las elimina en la siguiente versión mayor. Consulta la documentación de cambios de API para rutas de migración. Compila con -Wdeprecated-declarations para detectar el uso de APIs deprecadas tempranamente.
Conclusión
libavutil proporciona la fontanería de bajo nivel que hace manejable el desarrollo con FFmpeg:
- Memoria: Usa
av_malloc/av_freepara todas las asignaciones relacionadas con FFmpeg — la alineación importa para SIMD - Tiempo: Usa
av_rescale_qpara conversión de marcas de tiempo entre timebases — nunca hagas multiplicación manual - Frames: Usa
AVFrameconav_frame_alloc/av_frame_freepara todos los datos de medios decodificados - Metadatos: Usa
AVDictionarypara pares clave-valor (opciones, metadatos, configuración de códec) - Errores: Usa
av_strerrorpara convertir códigos de error a mensajes legibles - Logging: Usa
av_logcon niveles apropiados para depuración y producción - Hashing: Usa las funciones
av_md5_*para verificación de integridad de archivos
Entender libavutil es la base para trabajar efectivamente con la API en C de FFmpeg. Cada operación de nivel superior — decodificación de fotogramas, aplicación de filtros, escritura de salida — depende de las utilidades que esta biblioteca proporciona.