Configuración de Servidor de Transcodificación FFmpeg

FFmpeg es la herramienta estándar en la industria para procesamiento de vídeo y audio, capaz de transcodificar prácticamente cualquier formato multimedia. Configurado correctamente en un servidor Linux, FFmpeg puede procesar múltiples streams en paralelo con aceleración hardware VAAPI (Intel/AMD) o NVENC (NVIDIA), construir pipelines de streaming en vivo y ejecutar tareas de procesamiento por lotes de forma eficiente. Esta guía cubre la configuración de FFmpeg como servidor de transcodificación en producción.

Requisitos Previos

  • Ubuntu 20.04+, Debian 11+, CentOS 8+ o Rocky Linux 8+
  • Mínimo 4 GB de RAM para transcodificación múltiple
  • CPU multi-núcleo (8+ recomendados) o GPU NVIDIA/Intel con soporte NVENC/VAAPI
  • Almacenamiento rápido (SSD o NVMe) para archivos temporales
  • Para NVENC: NVIDIA con drivers 418.30+ y GPU con soporte NVENC

Instalación de FFmpeg

Ubuntu/Debian

# Instalar FFmpeg desde los repositorios oficiales (versión estable)
sudo apt update
sudo apt install -y ffmpeg

# Verificar la instalación y códecs disponibles
ffmpeg -version
ffmpeg -codecs | grep -E "h264|h265|hevc|vp9|av1"

# Verificar los encoders disponibles
ffmpeg -encoders | grep -E "264|265|nvenc|vaapi|qsv"

CentOS/Rocky Linux

# Instalar repositorios necesarios
sudo dnf install -y epel-release
sudo dnf install -y https://download1.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm
sudo dnf install -y https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm

# Instalar FFmpeg
sudo dnf install -y ffmpeg ffmpeg-devel

# Verificar
ffmpeg -version

Compilación desde Código Fuente

Para obtener soporte completo de códecs y aceleración hardware, compilar FFmpeg desde el código fuente:

# Instalar dependencias de compilación
sudo apt install -y \
  build-essential git cmake pkg-config \
  libx264-dev libx265-dev libvpx-dev libopus-dev \
  libfdk-aac-dev libmp3lame-dev libvorbis-dev \
  libva-dev libdrm-dev

# Clonar el código fuente de FFmpeg
git clone https://git.ffmpeg.org/ffmpeg.git /opt/ffmpeg-src
cd /opt/ffmpeg-src

# Configurar con todas las características necesarias
./configure \
  --prefix=/usr/local \
  --enable-gpl \
  --enable-nonfree \
  --enable-libx264 \
  --enable-libx265 \
  --enable-libvpx \
  --enable-libopus \
  --enable-libfdk-aac \
  --enable-libmp3lame \
  --enable-libvorbis \
  --enable-vaapi \
  --enable-libdrm

# Compilar usando todos los núcleos disponibles
make -j$(nproc)

# Instalar
sudo make install
sudo ldconfig

# Verificar la instalación compilada
ffmpeg -version

Selección de Códecs y Formatos

Codificación H.264 (AVC)

# Transcodificación básica H.264 con calidad constante (CRF)
# CRF: 18 (alta calidad) a 28 (baja calidad), 23 es el valor por defecto
ffmpeg -i entrada.mkv \
  -c:v libx264 \
  -crf 23 \
  -preset medium \
  -c:a aac -b:a 192k \
  salida.mp4

# Para streaming (dos pasadas para bitrate constante)
# Primera pasada - análisis
ffmpeg -i entrada.mkv -c:v libx264 -b:v 3000k -pass 1 -an -f null /dev/null

# Segunda pasada - codificación final
ffmpeg -i entrada.mkv \
  -c:v libx264 -b:v 3000k -pass 2 \
  -c:a aac -b:a 192k \
  salida-streaming.mp4

Codificación H.265 (HEVC)

# HEVC ofrece mejor compresión que H.264 al mismo nivel de calidad
ffmpeg -i entrada.mkv \
  -c:v libx265 \
  -crf 28 \
  -preset medium \
  -c:a aac -b:a 192k \
  salida-hevc.mp4

# HEVC con metadata de nivel/perfil específico
ffmpeg -i entrada.mkv \
  -c:v libx265 \
  -crf 28 \
  -x265-params "level-idc=41:profile=main" \
  -c:a copy \
  salida-hevc-compat.mp4

VP9 para Web

# VP9 con calidad variable (CRF) para web
ffmpeg -i entrada.mkv \
  -c:v libvpx-vp9 \
  -crf 30 -b:v 0 \
  -deadline good -cpu-used 2 \
  -c:a libopus -b:a 128k \
  salida.webm

Aceleración Hardware VAAPI

VAAPI (Video Acceleration API) soporta Intel y AMD:

# Verificar el soporte VAAPI
vainfo

# Ver los dispositivos disponibles
ls /dev/dri/

# Transcodificación H.264 con VAAPI
ffmpeg -vaapi_device /dev/dri/renderD128 \
  -i entrada.mkv \
  -vf 'format=nv12,hwupload' \
  -c:v h264_vaapi \
  -qp 23 \
  -c:a aac -b:a 192k \
  salida-vaapi.mp4

# Transcodificación HEVC con VAAPI
ffmpeg -vaapi_device /dev/dri/renderD128 \
  -i entrada.mkv \
  -vf 'format=nv12,hwupload' \
  -c:v hevc_vaapi \
  -qp 28 \
  -c:a aac -b:a 192k \
  salida-hevc-vaapi.mp4

# Escalar resolución con VAAPI (1080p a 720p)
ffmpeg -vaapi_device /dev/dri/renderD128 \
  -i entrada.mkv \
  -vf 'format=nv12,hwupload,scale_vaapi=1280:720' \
  -c:v h264_vaapi \
  -b:v 2500k \
  -c:a aac -b:a 128k \
  salida-720p.mp4

Aceleración Hardware NVENC

NVENC usa el encoder de hardware de NVIDIA:

# Verificar soporte NVENC
nvidia-smi
ffmpeg -encoders | grep nvenc

# H.264 con NVENC
ffmpeg -i entrada.mkv \
  -c:v h264_nvenc \
  -preset p5 \
  -rc vbr \
  -b:v 4000k \
  -maxrate 6000k \
  -bufsize 8000k \
  -c:a aac -b:a 192k \
  salida-nvenc.mp4

# HEVC con NVENC (más eficiente en GPUs modernas)
ffmpeg -i entrada.mkv \
  -c:v hevc_nvenc \
  -preset p5 \
  -rc vbr \
  -b:v 3000k \
  -tag:v hvc1 \
  -c:a aac -b:a 192k \
  salida-hevc-nvenc.mp4

# Decodificación hardware con NVIDIA (reduce carga de CPU)
ffmpeg \
  -hwaccel cuda \
  -hwaccel_output_format cuda \
  -i entrada.mkv \
  -c:v h264_nvenc \
  -preset p4 \
  -b:v 3000k \
  -c:a copy \
  salida-gpu.mp4

Procesamiento por Lotes

#!/bin/bash
# Script de transcodificación por lotes para convertir una carpeta entera

ENTRADA_DIR="/mnt/videos/originales"
SALIDA_DIR="/mnt/videos/transcodificados"
LOG_FILE="/var/log/ffmpeg-batch.log"

# Crear directorio de salida si no existe
mkdir -p "$SALIDA_DIR"

# Contar el total de archivos para mostrar progreso
TOTAL=$(find "$ENTRADA_DIR" -name "*.mkv" -o -name "*.avi" -o -name "*.mp4" | wc -l)
ACTUAL=0

# Procesar cada archivo de vídeo
find "$ENTRADA_DIR" -type f \( -name "*.mkv" -o -name "*.avi" -o -name "*.mp4" \) | while read -r archivo; do
  ACTUAL=$((ACTUAL + 1))
  NOMBRE=$(basename "$archivo" | sed 's/\.[^.]*$//')
  SALIDA="${SALIDA_DIR}/${NOMBRE}.mp4"

  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Procesando ($ACTUAL/$TOTAL): $archivo" | tee -a "$LOG_FILE"

  # Saltar si el archivo de salida ya existe
  if [ -f "$SALIDA" ]; then
    echo "  -> Ya existe, omitiendo" | tee -a "$LOG_FILE"
    continue
  fi

  # Transcodificar con VAAPI (o cambiar a libx264 si no hay GPU)
  ffmpeg -vaapi_device /dev/dri/renderD128 \
    -i "$archivo" \
    -vf 'format=nv12,hwupload' \
    -c:v h264_vaapi -qp 23 \
    -c:a aac -b:a 192k \
    -y "$SALIDA" \
    >> "$LOG_FILE" 2>&1

  if [ $? -eq 0 ]; then
    echo "  -> Completado: $SALIDA" | tee -a "$LOG_FILE"
  else
    echo "  -> ERROR al procesar: $archivo" | tee -a "$LOG_FILE"
  fi
done

echo "Procesamiento por lotes completado." | tee -a "$LOG_FILE"
# Ejecutar el script
chmod +x /opt/scripts/transcoding-batch.sh
/opt/scripts/transcoding-batch.sh

# O como tarea en segundo plano con nohup
nohup /opt/scripts/transcoding-batch.sh &
tail -f /var/log/ffmpeg-batch.log

Pipelines de Streaming

Streaming HLS (para reproductores web)

# Generar stream HLS desde un archivo (múltiples calidades)
ffmpeg -i entrada.mkv \
  -filter_complex \
  "[v:0]split=3[v1][v2][v3]; \
   [v1]scale=1920:1080[1080p]; \
   [v2]scale=1280:720[720p]; \
   [v3]scale=854:480[480p]" \
  -map "[1080p]" -c:v:0 libx264 -b:v:0 5000k \
  -map "[720p]"  -c:v:1 libx264 -b:v:1 2500k \
  -map "[480p]"  -c:v:2 libx264 -b:v:2 1000k \
  -map 0:a -c:a aac -b:a 128k \
  -f hls \
  -hls_time 6 \
  -hls_list_size 0 \
  -hls_segment_filename "/var/www/hls/segment_%v_%03d.ts" \
  -master_pl_name master.m3u8 \
  /var/www/hls/stream_%v.m3u8

Restreaming RTMP

# Recibir stream RTMP y re-emitir a múltiples destinos
ffmpeg -i rtmp://localhost:1935/live/stream \
  -c:v copy -c:a copy \
  -f flv rtmp://destino1.ejemplo.com/live/clave1 \
  -c:v copy -c:a copy \
  -f flv rtmp://destino2.ejemplo.com/live/clave2

Optimización de Calidad

# Análisis de la calidad con VMAF (requiere compilación con libvmaf)
ffmpeg -i original.mkv -i transcodificado.mp4 \
  -lavfi "[0:v][1:v]libvmaf" \
  -f null -

# Verificar metadatos de un vídeo transcodificado
ffprobe -v quiet -print_format json -show_format -show_streams salida.mp4 | \
  python3 -m json.tool | grep -E "codec_name|bit_rate|width|height"

# Ajustar el preset según la prioridad:
# ultrafast > superfast > veryfast > faster > fast > medium > slow > slower > veryslow
# Más rápido = menos CPU, menor compresión
# Más lento = más CPU, mejor compresión
ffmpeg -i entrada.mkv -c:v libx264 -crf 23 -preset veryfast salida-rapida.mp4
ffmpeg -i entrada.mkv -c:v libx264 -crf 23 -preset slow salida-calidad.mp4

Solución de Problemas

Error de VAAPI "No such file or directory" para /dev/dri/renderD128:

# Verificar disponibilidad del dispositivo
ls -la /dev/dri/
# Instalar los drivers de VA-API
sudo apt install -y vainfo libva-intel-driver intel-media-va-driver  # Intel
# sudo apt install -y mesa-va-drivers  # AMD

# Verificar acceso del usuario actual
groups $(whoami) | grep -E "video|render"
sudo usermod -aG render,video $(whoami)

Error "Cannot load nvcuda.dll" con NVENC:

# Verificar que los drivers NVIDIA están instalados
nvidia-smi
# Verificar la versión del driver (debe ser 418.30+)
nvidia-smi --query-gpu=driver_version --format=csv,noheader

Proceso de transcodificación muy lento:

# Monitorear el uso de CPU/GPU
htop
nvidia-smi dmon  # Para NVIDIA
intel_gpu_top    # Para Intel (requiere intel-gpu-tools)

# Verificar si se usa aceleración hardware real
ffmpeg -i entrada.mkv -c:v h264_nvenc -b:v 3000k -c:a copy salida.mp4 -v verbose 2>&1 | grep "nvenc"

Conclusión

FFmpeg configurado con aceleración hardware permite procesar vídeo de alta calidad con una fracción del coste computacional de la transcodificación por software. Dominar VAAPI y NVENC, junto con los parámetros de calidad como CRF y los presets, te permite construir pipelines de transcodificación eficientes que pueden escalar desde un único servidor hasta clusters de procesamiento distribuido.