Si estás construyendo aplicaciones sobre la API en C de FFmpeg, te encontrarás con libavutil constantemente. Es la biblioteca base de la que depende cada otro componente de FFmpeg — proporcionando gestión de memoria, utilidades matemáticas, cálculos de tiempo, helpers de formato de píxel y manejo de errores.
Este artículo explica qué hace libavutil, cuándo usarla y cómo usar sus funciones más importantes, con ejemplos completos de código funcional.
Lo que aprenderás
- El rol de libavutil en el ecosistema FFmpeg
- Gestión de memoria con av_malloc y av_free
- Conversión de marcas de tiempo con av_rescale_q
- Manejo de errores con av_strerror
- Registro con av_log
- 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
- Registro estructurado con control de nivel
- Funciones de hash criptográfico (MD5, SHA1, HMAC)
- Aritmética de números racionales
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, registro, 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.
Funciones principales
av_malloc(size_t size)— asignar memoriaav_free(void *ptr)— liberar memoria asignadaav_mallocz(size_t size)— asignar e inicializar a cero la memoriaav_realloc(void *ptr, size_t size)— redimensionar memoria asignada
Uso básico
#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;
}
¿Por qué usar av_malloc en lugar de malloc?
FFmpeg internamente usa asignación de memoria alineada para optimizar operaciones SIMD (SSE, AVX). av_malloc asegura que se cumplan los requisitos de alineación correctos. Cuando pasas buffers a las APIs internas de FFmpeg, siempre usa av_malloc para evitar desajustes de alineación.
av_free siempre debe llamarse sobre memoria asignada con av_malloc.
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.
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() {
// 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 = 10 seconds
return 0;
}
Esto es esencial cuando mezclas streams con diferentes timebases — por ejemplo, combinando video (típicamente 1/timebase) con audio (típicamente 1/sample_rate).
Ejemplo de escalado simple
#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;
}
Utilidades de formato de imagen y audio
Helpers de formato de píxel
#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;
}
Cálculo de tamaño de buffer de audio
#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;
}
Manejo de errores y registro
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[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;
}
Registro estructurado
#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;
}
Niveles de registro 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.
Instalación y configuración
Ubuntu / Debian
sudo apt update
sudo apt install ffmpeg libavutil-dev
Para la última versión, compila desde el código fuente:
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
./configure
make -j$(nproc)
sudo make install
macOS
brew install ffmpeg
Para configurar la ruta de pkg-config para desarrollo:
export PKG_CONFIG_PATH=/usr/local/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)
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)
# or manually:
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:
# 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
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
gdbpara 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 of \"%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í hay un patrón robusto de manejo de errores para aplicaciones FFmpeg:
#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]);
}
Este patrón facilita identificar exactamente qué paso falló y por qué.
Artículos relacionados
Si quieres automatizar FFmpeg sin adentrarte en la API de C, Python ofrece una alternativa práctica:
- Automatización de FFmpeg con Python: Scripts de procesamiento por lotes — Usa
subprocessde Python para controlar FFmpeg y construye pipelines de automatización para procesamiento masivo de video — sin necesidad de C.
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 - Tiempo: Usa
av_rescale_qpara conversión de marcas de tiempo entre timebases - Errores: Usa
av_strerrorpara convertir códigos de error a mensajes legibles - Registro: 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.