--- title: "Servidor de transcodificación FFmpeg en Ubuntu 24.04" description: "Instala FFmpeg en Ubuntu 24.04, transcodifica a H.264, HEVC y HLS, usa aceleración VAAPI o NVENC y automatiza la conversión por lotes con un timer de systemd." category: "Servidores de Medios y Streaming" language: es source: https://cubepath.com/es/docs/servidores-de-medios-y-streaming/configuracion-de-servidor-de-transcodificacion-ffmpeg updated: 2026-09-25 --- # Servidor de transcodificación FFmpeg en Ubuntu 24.04 FFmpeg es la herramienta de referencia para convertir, recortar y empaquetar vídeo y audio desde la línea de comandos. En este tutorial convertirás un servidor Ubuntu 24.04 en un nodo de transcodificación: instalarás FFmpeg, elegirás los parámetros de calidad adecuados para H.264 y HEVC, generarás un paquete HLS con varias calidades y, si el servidor tiene GPU, usarás aceleración por hardware con VAAPI (Intel/AMD) o NVENC (NVIDIA). Al final dejarás un proceso por lotes que convierte automáticamente los vídeos que aparecen en una carpeta. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS o un servidor dedicado de CubePath. - Un usuario no root con privilegios `sudo`. - CPU con 4 núcleos o más: la codificación por software con `libx264` y `libx265` escala casi linealmente con los núcleos. - Espacio en disco rápido (SSD o NVMe) para los originales y los ficheros generados. - Opcional: una GPU Intel, AMD o NVIDIA en un servidor dedicado para los pasos de aceleración por hardware. Un VPS normal no tiene GPU, así que en ese caso puedes saltarte los pasos 4 y 5. ## Paso 1: Instalar FFmpeg Ubuntu 24.04 incluye FFmpeg 6.1 en sus repositorios, compilado con `libx264`, `libx265`, `libvpx`, `libopus`, `libmp3lame` y soporte para VAAPI y NVENC. Para un servidor de transcodificación es suficiente y se actualiza con el resto del sistema: ```bash sudo apt update sudo apt install ffmpeg ``` Comprueba la versión instalada: ```bash ffmpeg -hide_banner -version | head -n 1 ``` ```output ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers ``` Verifica también qué codificadores de vídeo tienes disponibles: ```bash ffmpeg -hide_banner -encoders | grep -E "libx264|libx265|libvpx-vp9|nvenc|vaapi" ``` Deberías ver al menos `libx264`, `libx265` y `libvpx-vp9`, además de los codificadores `h264_nvenc`, `hevc_nvenc`, `h264_vaapi` y `hevc_vaapi`. Que aparezcan en la lista solo significa que FFmpeg sabe usarlos; para que funcionen hace falta el hardware y el controlador correspondientes. Crea una estructura de carpetas para trabajar: ```bash sudo mkdir -p /srv/transcode/{entrada,salida,hls} sudo chown -R $USER:$USER /srv/transcode ``` Copia en `/srv/transcode/entrada` un vídeo de prueba con el nombre `muestra.mp4` para seguir los ejemplos. ## Paso 2: Transcodificar a H.264 y HEVC con calidad constante Para archivos que se van a almacenar o descargar, el modo recomendado es CRF (Constant Rate Factor): fijas un nivel de calidad y el codificador usa los bits que necesite en cada escena. En `libx264` el rango útil es de 18 (casi sin pérdida visual) a 28, con 23 como valor por defecto. El `preset` decide cuánto tiempo de CPU se invierte: `slow` comprime mejor que `medium`, `veryfast` es mucho más rápido pero genera ficheros más grandes. ```bash ffmpeg -hide_banner -i /srv/transcode/entrada/muestra.mp4 \ -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p \ -c:a aac -b:a 160k \ -movflags +faststart \ /srv/transcode/salida/muestra-h264.mp4 ``` `-pix_fmt yuv420p` garantiza compatibilidad con navegadores y móviles, y `-movflags +faststart` mueve el índice al principio del fichero para que la reproducción web empiece antes de descargarlo entero. HEVC (H.265) consigue una calidad similar con un 30 a 50 % menos de bitrate, a cambio de mucha más CPU. Su escala CRF es distinta: 28 en `libx265` equivale aproximadamente a 23 en `libx264`: ```bash ffmpeg -hide_banner -i /srv/transcode/entrada/muestra.mp4 \ -c:v libx265 -crf 28 -preset medium -tag:v hvc1 \ -c:a aac -b:a 160k \ -movflags +faststart \ /srv/transcode/salida/muestra-hevc.mp4 ``` La etiqueta `-tag:v hvc1` es necesaria para que Safari y los dispositivos Apple reproduzcan el fichero. Comprueba el resultado con `ffprobe`, que se instala junto con FFmpeg: ```bash ffprobe -v error -select_streams v:0 \ -show_entries stream=codec_name,width,height,bit_rate \ -of default=noprint_wrappers=1 /srv/transcode/salida/muestra-h264.mp4 ``` ```output codec_name=h264 width=1920 height=1080 bit_rate=4213760 ``` Si necesitas un bitrate fijo (por ejemplo, para un destino con ancho de banda limitado), usa `-b:v 3000k -maxrate 3000k -bufsize 6000k` en lugar de `-crf`. ## Paso 3: Generar HLS con varias calidades HLS (HTTP Live Streaming) divide el vídeo en segmentos cortos y ofrece varias calidades para que el reproductor cambie de una a otra según la conexión. Un único comando de FFmpeg puede escalar el vídeo a tres resoluciones, codificar cada una y escribir la lista maestra: ```bash cd /srv/transcode/hls ffmpeg -hide_banner -i /srv/transcode/entrada/muestra.mp4 \ -filter_complex "[0:v]split=3[v1][v2][v3];[v1]scale=-2:1080[v1out];[v2]scale=-2:720[v2out];[v3]scale=-2:480[v3out]" \ -map "[v1out]" -c:v:0 libx264 -b:v:0 5000k -maxrate:v:0 5350k -bufsize:v:0 7500k \ -map "[v2out]" -c:v:1 libx264 -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k \ -map "[v3out]" -c:v:2 libx264 -b:v:2 1400k -maxrate:v:2 1498k -bufsize:v:2 2100k \ -map a:0 -map a:0 -map a:0 -c:a aac -b:a 128k -ac 2 \ -preset veryfast -g 48 -keyint_min 48 -sc_threshold 0 \ -f hls -hls_time 6 -hls_playlist_type vod -hls_flags independent_segments \ -hls_segment_filename "stream_%v/segmento_%03d.ts" \ -master_pl_name master.m3u8 \ -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \ "stream_%v/playlist.m3u8" ``` Los puntos importantes son: - `scale=-2:720` ajusta la altura y calcula un ancho par que mantiene la proporción. - `-g 48 -keyint_min 48 -sc_threshold 0` fuerza fotogramas clave a intervalos fijos para que los segmentos de todas las calidades estén alineados. - `-var_stream_map` agrupa cada pista de vídeo con su pista de audio; `%v` se sustituye por 0, 1 y 2. Comprueba que se han creado la lista maestra y las tres variantes: ```bash cat /srv/transcode/hls/master.m3u8 ``` ```output #EXTM3U #EXT-X-VERSION:6 #EXT-X-STREAM-INF:BANDWIDTH=5640800,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" stream_0/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=3220800,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2" stream_1/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1680800,RESOLUTION=854x480,CODECS="avc1.64001e,mp4a.40.2" stream_2/playlist.m3u8 ``` El directorio `/srv/transcode/hls` se puede servir tal cual con cualquier servidor web (Nginx, Caddy) o subir a un almacenamiento de objetos detrás de una CDN. ## Paso 4: Aceleración por hardware con VAAPI (Intel y AMD) VAAPI permite usar el bloque de codificación de las GPU Intel (integradas o Arc) y AMD. Instala la utilidad de diagnóstico y el controlador correspondiente. En Intel, el paquete `intel-media-va-driver-non-free` está en el repositorio `multiverse` e incluye todas las funciones de codificación: ```bash sudo apt install vainfo intel-media-va-driver-non-free ``` En AMD, el controlador está en Mesa: ```bash sudo apt install vainfo mesa-va-drivers ``` El dispositivo de la GPU aparece en `/dev/dri/renderD128` y solo pueden usarlo los miembros del grupo `render`. Añade tu usuario al grupo y vuelve a iniciar sesión para que se aplique: ```bash sudo usermod -aG render $USER ``` Comprueba que el controlador carga y qué perfiles admite codificar (las líneas con `VAEntrypointEncSlice`): ```bash vainfo --display drm --device /dev/dri/renderD128 | grep -E "Driver version|EncSlice" ``` ```output vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.1.0 () VAProfileH264Main : VAEntrypointEncSlice VAProfileH264High : VAEntrypointEncSlice VAProfileHEVCMain : VAEntrypointEncSlice ``` Con el dispositivo operativo, este comando decodifica y codifica en la GPU sin pasar los fotogramas por la memoria del sistema, y reescala a 720p con el filtro `scale_vaapi`: ```bash ffmpeg -hide_banner \ -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi \ -i /srv/transcode/entrada/muestra.mp4 \ -vf "scale_vaapi=w=1280:h=720" \ -c:v h264_vaapi -qp 23 \ -c:a aac -b:a 160k -movflags +faststart \ /srv/transcode/salida/muestra-vaapi.mp4 ``` Para HEVC, cambia `h264_vaapi` por `hevc_vaapi`. Si el códec de origen no se puede decodificar en la GPU, FFmpeg mostrará un error de formato; en ese caso decodifica por software y sube los fotogramas a la GPU: ```bash ffmpeg -hide_banner -vaapi_device /dev/dri/renderD128 \ -i /srv/transcode/entrada/muestra.mp4 \ -vf "format=nv12,hwupload" \ -c:v h264_vaapi -qp 23 \ -c:a aac -b:a 160k \ /srv/transcode/salida/muestra-vaapi-sw.mp4 ``` ## Paso 5: Aceleración por hardware con NVENC (NVIDIA) NVENC es el codificador dedicado de las GPU NVIDIA. FFmpeg lo carga en tiempo de ejecución a través del controlador propietario, así que lo único que necesitas es instalar el controlador recomendado por Ubuntu: ```bash sudo apt install ubuntu-drivers-common sudo ubuntu-drivers install sudo reboot ``` Tras reiniciar, comprueba que el controlador reconoce la GPU: ```bash nvidia-smi --query-gpu=name,driver_version --format=csv,noheader ``` ```output NVIDIA L4, 550.120 ``` Este comando decodifica con la GPU (`-hwaccel cuda`), reescala en la GPU con `scale_cuda` y codifica con `h264_nvenc` usando control de bitrate variable. Los presets de NVENC van de `p1` (más rápido) a `p7` (mejor calidad): ```bash ffmpeg -hide_banner \ -hwaccel cuda -hwaccel_output_format cuda \ -i /srv/transcode/entrada/muestra.mp4 \ -vf "scale_cuda=1280:720" \ -c:v h264_nvenc -preset p5 -rc vbr -cq 23 -b:v 0 \ -c:a aac -b:a 160k -movflags +faststart \ /srv/transcode/salida/muestra-nvenc.mp4 ``` Para HEVC, usa `hevc_nvenc` y añade `-tag:v hvc1`. Mientras el comando se ejecuta, en otra terminal puedes confirmar que la GPU está trabajando: ```bash nvidia-smi dmon -s u -c 5 ``` Las columnas `enc` y `dec` deberían mostrar porcentajes de uso mayores que cero. ## Paso 6: Automatizar la transcodificación por lotes Para procesar todo lo que llegue a `/srv/transcode/entrada`, crea un script que convierta cada vídeo nuevo a H.264, se salte los que ya estén convertidos y no se ejecute dos veces a la vez: ```bash sudo nano /usr/local/bin/transcode-batch.sh ``` ```bash #!/usr/bin/env bash set -euo pipefail ENTRADA="/srv/transcode/entrada" SALIDA="/srv/transcode/salida" # Evita dos ejecuciones simultáneas exec 9>/run/lock/transcode-batch.lock flock -n 9 || { echo "Ya hay una ejecución en curso"; exit 0; } find "$ENTRADA" -maxdepth 1 -type f \( -iname '*.mp4' -o -iname '*.mkv' -o -iname '*.mov' -o -iname '*.avi' \) -print0 | while IFS= read -r -d '' origen; do nombre="$(basename "${origen%.*}")" destino="$SALIDA/${nombre}.mp4" temporal="$SALIDA/.${nombre}.part.mp4" if [[ -f "$destino" ]]; then continue fi echo "Transcodificando: $origen" if nice -n 10 ffmpeg -hide_banner -nostdin -loglevel error -y -i "$origen" \ -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p \ -c:a aac -b:a 160k -movflags +faststart \ "$temporal"; then mv "$temporal" "$destino" echo "Completado: $destino" else rm -f "$temporal" echo "ERROR al transcodificar: $origen" >&2 fi done ``` El fichero se escribe primero con un nombre temporal y solo se renombra cuando FFmpeg termina bien, así nunca queda un vídeo a medias con el nombre final. `-nostdin` evita que FFmpeg consuma la entrada del bucle. Si tienes GPU, sustituye las opciones de vídeo por las de los pasos 4 o 5. Hazlo ejecutable y pruébalo a mano: ```bash sudo chmod 755 /usr/local/bin/transcode-batch.sh /usr/local/bin/transcode-batch.sh ``` ```output Transcodificando: /srv/transcode/entrada/muestra.mp4 Completado: /srv/transcode/salida/muestra.mp4 ``` Ahora crea un servicio de systemd que ejecute el script con tu usuario. Sustituye `tu_usuario` por el nombre de tu usuario: ```bash sudo nano /etc/systemd/system/transcode-batch.service ``` ```ini [Unit] Description=Transcodificación por lotes con FFmpeg [Service] Type=oneshot User=tu_usuario ExecStart=/usr/local/bin/transcode-batch.sh IOSchedulingClass=idle ``` Y un timer que lo lance cada 10 minutos: ```bash sudo nano /etc/systemd/system/transcode-batch.timer ``` ```ini [Unit] Description=Ejecuta la transcodificación por lotes cada 10 minutos [Timer] OnBootSec=2min OnUnitActiveSec=10min [Install] WantedBy=timers.target ``` Activa el timer y comprueba cuándo se ejecutará: ```bash sudo systemctl daemon-reload sudo systemctl enable --now transcode-batch.timer systemctl list-timers transcode-batch.timer ``` Si quieres usar VAAPI desde el servicio, añade `SupplementaryGroups=render` en la sección `[Service]`. La salida de cada ejecución queda en el journal: ```bash journalctl -u transcode-batch.service -n 20 ``` ## Solución de problemas **`Unknown encoder 'libfdk_aac'` u otro codificador que no existe.** El FFmpeg de Ubuntu no incluye códecs con licencia no libre como `libfdk_aac`. Usa el codificador AAC nativo (`-c:a aac`), cuya calidad es buena a partir de 128 kbps. **`Failed to initialise VAAPI connection` o `No VA display found`.** Comprueba que existe `/dev/dri/renderD128`, que el paquete del controlador está instalado y que tu usuario pertenece al grupo `render` (`id` debe mostrarlo; si no, cierra la sesión y vuelve a entrar). **`Cannot load libcuda.so.1` o `No capable devices found` con NVENC.** El controlador de NVIDIA no está cargado. Revisa `nvidia-smi`; si falla, reinstala con `sudo ubuntu-drivers install` y reinicia. Las GPU de consumo tienen además un límite de sesiones NVENC simultáneas. **La transcodificación es muy lenta.** Revisa con `htop` si la CPU está al 100 %. Un preset más rápido (`-preset veryfast`) reduce mucho el tiempo a costa de ficheros algo mayores. Si esperabas usar la GPU y la CPU está saturada, comprueba en la salida de FFmpeg que el codificador es `h264_vaapi` o `h264_nvenc` y no `libx264`. ## Conclusión Ya tienes un servidor que transcodifica a H.264 y HEVC con calidad controlada, genera paquetes HLS multicalidad y procesa automáticamente los vídeos nuevos con un timer de systemd, con aceleración por GPU cuando el hardware lo permite. Como siguientes pasos puedes servir el directorio HLS con Nginx y HTTPS, subir la salida a un almacenamiento de objetos compatible con S3 o añadir la generación de miniaturas con el filtro `thumbnail` de FFmpeg al script de lotes.