El cluster C2 de fqmpeg agrupa siete verbos para todo lo que tenga que ver con "cambiar la forma" o "preparar para entrega": convert cambia el contenedor, gif y gif-to-video hacen el viaje de ida y vuelta entre GIF y MP4, hls y dash generan manifiestos para streaming adaptativo, segment parte un archivo largo en trozos de duración fija, y extract-stream saca una pista de vídeo / audio / subtítulo por índice. Ninguno decide el códec (eso es C1) — todos responden a la pregunta qué forma necesita el archivo a continuación.
Esta guía recorre cada comando — los flags FFmpeg que produce, sus valores por defecto, y la regla de nombres de salida — y luego encadena varios en flujos reales de entrega. Todo está verificado contra el código en src/commands/ de fqmpeg 3.0.1.
Lo que vas a sacar de esta guía
- Qué verbo elegir para cada caso (matriz de decisión)
- La invocación exacta de FFmpeg que cada verbo genera (salida
--dry-runverificada) - Valores por defecto, rangos permitidos y nombres de archivo para cada comando
- Tres recetas de extremo a extremo: HLS para hosting estático con CDN, vista previa GIF desde una edición larga, y cirugía multipista sobre un MKV
Formato y entrega: qué verbo para qué tarea
El atajo mental para este cluster va por dos ejes — un único archivo vs. salida fragmentada, y cambiar píxeles vs. cambiar solo el envoltorio.
| Objetivo | Verbo | Qué hace | Salida |
|---|---|---|---|
| Cambiar contenedor sin re-codificar | convert --copy | Remux con stream-copy | <nombre>.<ext> |
| Cambiar contenedor con re-codificación | convert | Decodifica + re-codifica | <nombre>.<ext> |
| Hacer un GIF de vista previa | gif | Recorte + paleta + escalado | <nombre>-gif.gif |
| Subir un GIF a MP4 | gif-to-video | Pad par + yuv420p | <nombre>.mp4 |
| Playlist HLS | hls | .m3u8 + segmentos .ts | <nombre>.m3u8 + _%03d.ts |
| Manifiesto MPEG-DASH | dash | .mpd + segmentos DASH | <nombre>.mpd |
| Cortar en trozos fijos | segment | Stream-copy -f segment | segment_%03d.<ext> |
| Sacar una pista por índice | extract-stream | -map 0:<spec> -c copy | <nombre>-stream-<spec>.<ext> |
Dos cosas que conviene interiorizar antes de seguir:
- Stream-copy vs. re-codificar.
convert --copy,segmentyextract-streamusan-c copy— no tocan los píxeles. Acaban en segundos porque solo reescriben el contenedor.convert(sin--copy),gif,gif-to-video,hlsydashre-codifican y van a la velocidad normal de codificación de FFmpeg. Cuando dudes, prueba primero la forma con stream-copy. - Archivo único vs. salida segmentada.
hls,dashysegmentgeneran muchos archivos en el directorio de trabajo: un manifiesto más N segmentos. Ejecútalos dentro de un directorio de salida dedicado, o vas a tener decenas de chunks.tsrevueltos junto a la fuente.
Para el lado más amplio de códec / calidad de estas decisiones, la guía de compresión de vídeo es el complemento natural. Para una tubería HLS de extremo a extremo desde fqmpeg hls hasta una CDN, mira la guía de streaming HLS con CDN.
Conversión de contenedor
convert — Cambia el contenedor (mp4 ↔ mov ↔ mkv ↔ webm ↔ mp3 ...)
Renombra el envoltorio. Por defecto FFmpeg elige los códecs que casan con el nuevo contenedor; con --copy hace stream-copy de las pistas tal cual.
- Código:
src/commands/convert.js - Por defecto: decodifica + re-codifica con los códecs por defecto del contenedor
--copy: añade-c copypara hacer remux sin tocar píxeles (rápido, sin pérdida — pero solo válido si el códec fuente es legal en el contenedor destino)
| Argumento / Opción | Por defecto | Notas |
|---|---|---|
<format> (posicional) | requerido | Extensión destino. El punto inicial se quita (.mov y mov valen igual) |
--copy | off | Modo stream-copy — sin re-codificar |
-o, --output <path> | <nombre-fuente>.<format> | Sobrescribe la ruta de salida |
$ npx fqmpeg convert input.mp4 mov --dry-run
ffmpeg -i input.mp4 input.mov
$ npx fqmpeg convert input.mp4 mov --copy --dry-run
ffmpeg -i input.mp4 -c copy input.mov
Cuando --copy funciona, termina en menos de un segundo en archivos de varios GB porque no hay decodificación. La trampa es la compatibilidad códec/contenedor:
- MP4 ↔ MOV: normalmente ambos copian bien (H.264 + AAC es legal en los dos)
- MP4 ↔ MKV: el copy funciona casi siempre (MKV es muy permisivo)
- WebM: requiere vídeo VP8/VP9/AV1 + audio Vorbis/Opus — copiar H.264 a
.webmfalla. Usaencode-vp9de C1
Si convert --copy da el error Could not find tag for codec ... in stream, el códec fuente no es legal en el contenedor destino. Quita --copy para volver a re-codificación.
Ida y vuelta GIF
gif — Hacer un GIF desde un clip de vídeo
Recorta un trozo de tiempo del vídeo y escribe un GIF de alta calidad. El predeterminado de 480 px × 15 fps × 5 s está calibrado para terreno README — pequeño para caber en el presupuesto de 4 MB de un README, pero suficientemente grande para leerse.
- Código:
src/commands/gif.js - Truco de calidad: usa la cadena de filtros de dos pasadas
palettegen/paletteuse. Esto genera una paleta óptima de 256 colores a partir del clip y la aplica en la segunda pasada. El resultado es muchísimo mejor que la codificación GIF ingenua (sin banding, sin ruido de dithering) - Escalador:
scale=<width>:-1:flags=lanczos— la altura es automática, lanczos es el remuestreador de alta calidad - Bucle:
-loop 0(infinito)
| Opción | Por defecto | Rango / Formato | Notas |
|---|---|---|---|
-s, --start <sec> | 0 | número no negativo | Desfase de inicio en segundos |
-d, --duration <sec> | 5 | número positivo | Duración del GIF |
--fps <n> | 15 | entero positivo | Más alto = más fluido pero archivo mayor |
--width <px> | 480 | entero positivo | La altura se deriva manteniendo aspecto |
Nombre por defecto: <nombre-fuente>-gif.gif.
$ npx fqmpeg gif input.mp4 --dry-run
ffmpeg -ss 0 -t 5 -i input.mp4 -vf fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -loop 0 input-gif.gif
# Personalizado: empieza a los 10 s, 3 segundos, 20 fps, 600 px de ancho
$ npx fqmpeg gif input.mp4 --start 10 --duration 3 --fps 20 --width 600 --dry-run
ffmpeg -ss 10 -t 3 -i input.mp4 -vf fps=20,scale=600:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse -loop 0 input-gif.gif
gif-to-video — Subir un GIF a MP4
La operación inversa. Convierte un GIF a un MP4 H.264 — mucho más pequeño, soporta sonido real (en este caso ninguno), funciona en tags <video> en todos lados.
- Código:
src/commands/gif-to-video.js - Formato de píxel:
-pix_fmt yuv420p(necesario para compatibilidad amplia con navegadores/códecs — la mayoría de decodificadores rechaza MP4 en RGB de 8 bits) - Arreglo de dimensiones pares:
-vf scale=trunc(iw/2)*2:trunc(ih/2)*2— H.264 requiere ancho/alto pares; esto los redondea hacia abajo al par más cercano cuando hace falta - Faststart:
-movflags faststartpara que el archivo empiece a reproducirse antes de descargarse entero - Bucle: usa
-stream_looppara repetir la fuente N veces (un MP4 estático se reproduce N+1 veces, ya que--loop 0significa una sola pasada)
| Opción | Por defecto | Rango | Notas |
|---|---|---|---|
--loop <n> | 0 | entero no negativo | 0 = una pasada. 3 = la fuente suena 4 veces |
Nombre por defecto: <nombre-fuente>.mp4.
$ npx fqmpeg gif-to-video input.gif --dry-run
ffmpeg -i input.gif -movflags faststart -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 input.mp4
# Repetir el GIF 4 veces en el MP4 resultante
$ npx fqmpeg gif-to-video input.gif --loop 3 --dry-run
ffmpeg -stream_loop 3 -i input.gif -movflags faststart -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 input.mp4
El uso más común es achicar un GIF que ha crecido demasiado — un GIF de tutorial de 12 MB suele convertirse en un MP4 de 600 KB sin pérdida perceptible.
Streaming adaptativo
Estos dos verbos producen el tipo de salida que servirías desde una CDN detrás de un tag <video> con hls.js o dash.js.
hls — Playlist HLS + segmentos
HTTP Live Streaming. El formato adaptativo de Apple, nativo en Safari y iOS, soportado vía hls.js en el resto de navegadores. La salida es una playlist .m3u8 y una secuencia de segmentos MPEG-TS (.ts).
- Código:
src/commands/hls.js - Códec de vídeo:
libx264(forzado — el contenedor.tsy los reproductores.m3u8tienen el soporte H.264 más robusto) - Códec de audio:
aac -hls_list_size 0: mantiene todos los segmentos en la playlist (modo VOD). Para una ventana móvil en directo, lo bajarías — pero VOD es el caso común- Patrón de nombres de segmento:
<nombre-playlist>_%03d.tsjunto a la playlist
| Opción | Por defecto | Rango | Notas |
|---|---|---|---|
--segment <sec> | 6 | número positivo | Duración del segmento. Apple recomienda 6 s para VOD; 2–4 s para baja latencia |
-o, --output <path> | <nombre-fuente>.m3u8 | ruta | Define la ruta de la playlist y el directorio de los segmentos |
$ npx fqmpeg hls input.mp4 --dry-run
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -hls_time 6 -hls_list_size 0 -hls_segment_filename input_%03d.ts input.m3u8
La salida es un solo peldaño de la escalera de bitrates — hls no genera la playlist maestra multi-bitrate que necesita el streaming adaptativo de verdad. Para eso, codificas la fuente a 3–5 bitrates distintos (usa bitrate de C1 para cada uno) y unes los .m3u8 resultantes en una playlist maestra a mano. La guía de streaming HLS con CDN recorre esa tubería entera incluyendo el despliegue en R2 / S3.
dash — Manifiesto MPEG-DASH
El formato adaptativo estándar W3C. La salida es un manifiesto .mpd y un conjunto de segmentos MP4 fragmentados. DASH se reproduce vía dash.js en la mayoría de navegadores; Safari tira hacia HLS pero acepta DASH a través del modo experimental DASH de hls.js o vía Media Source Extensions.
- Código:
src/commands/dash.js - Vídeo / audio:
libx264+aac(mismas defaults que HLS) -use_timeline 1 -use_template 1: genera un manifiesto basado en SegmentTemplate, que es el formato moderno y más pequeño preferido sobre SegmentList para VOD
| Opción | Por defecto | Notas |
|---|---|---|
--segment <sec> | 4 | DASH por defecto es más corto que HLS (4 s vs 6 s) — los reproductores DASH toleran mejor segmentos pequeños |
-o, --output <path> | <nombre-fuente>.mpd |
$ npx fqmpeg dash input.mp4 --dry-run
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f dash -seg_duration 4 -use_timeline 1 -use_template 1 input.mpd
Misma advertencia que con HLS — salida de una sola rendición. Para escaleras DASH multi-bitrate, lanza bitrate a varios objetivos y combina los manifiestos, o usa el argumento adaptation_sets de FFmpeg directamente vía --dry-run y edición manual.
Para decidir rápido entre los dos: usa HLS si tu audiencia es pesada en iOS o Safari; usa DASH si apuntas a dispositivos de salón, Android TV o cualquier cosa que siga el camino W3C. La mayoría de stacks de producción mandan ambos.
División y cirugía de pistas
segment — Cortar un archivo en trozos de duración fija
Divide la entrada en N piezas de duración fija cada una, con stream-copy para que sea casi instantáneo. Los nombres de archivo siguen un patrón numerado al estilo printf.
- Código:
src/commands/segment.js - Modo:
-f segment -c copy(sin re-codificación) -reset_timestamps 1: los PTS de cada segmento se resetean a 0 para que cada segmento se reproduzca independiente- Contenedor: preserva la extensión de entrada (los segmentos de
input.mp4son.mp4; los deinput.mkvson.mkv)
| Argumento / Opción | Por defecto | Notas |
|---|---|---|
<duration> (posicional) | requerido | Duración del segmento en segundos |
-o, --output <pattern> | segment_%03d.<ext-fuente> | Patrón printf — %03d se vuelve 001, 002, … |
$ npx fqmpeg segment input.mp4 10 --dry-run
ffmpeg -i input.mp4 -c copy -f segment -segment_time 10 -reset_timestamps 1 segment_%03d.mp4
Algunas notas prácticas:
- Corta en keyframes, no en segundos exactos. El modo stream-copy solo puede dividir en límites GOP existentes. Si tu fuente tiene un intervalo de keyframes de 5 segundos, un segmento de 10 segundos puede acabar a 9.7 s o 10.3 s. Para cortes precisos al frame, re-codifica (quita
-c copydel comando impreso) o acorta el GOP de la fuente primero - No es lo mismo que segmentos HLS. HLS produce una playlist junto a los chunks;
segmentsolo produce chunks. Para HLS, usahls - El patrón de salida por defecto vuelca archivos en CWD, no junto a la entrada. Ejecuta dentro de un directorio de salida o pasa
-o /ruta/a/dir/seg_%03d.mp4
extract-stream — Sacar una pista por índice
Extrae una sola pista de vídeo, audio o subtítulo de un archivo multi-pista. Solo stream-copy — rápido y sin pérdida. El formato del argumento sigue la sintaxis de stream specifier de FFmpeg: v:0 (primer vídeo), a:1 (segundo audio), s:0 (primer subtítulo).
- Código:
src/commands/extract-stream.js - Mapeo:
-map 0:<spec> -c copy - Extensión de salida: elegida por tipo de pista —
v:*→.mp4,a:*→.aac,s:*→.srt. Si el códec real no coincide (p. ej. el audio es Opus, no AAC), pasa--outputpara sobrescribir
| Argumento | Notas |
|---|---|
<input> | Archivo de entrada |
<stream> | Stream specifier: v:N, a:N o s:N |
Nombres por defecto:
v:0→<nombre-fuente>-stream-v0.mp4a:1→<nombre-fuente>-stream-a1.aacs:0→<nombre-fuente>-stream-s0.srt
$ npx fqmpeg extract-stream input.mkv v:0 --dry-run
ffmpeg -i input.mkv -map 0:v:0 -c copy input-stream-v0.mp4
$ npx fqmpeg extract-stream input.mkv a:1 --dry-run
ffmpeg -i input.mkv -map 0:a:1 -c copy input-stream-a1.aac
$ npx fqmpeg extract-stream input.mkv s:0 --dry-run
ffmpeg -i input.mkv -map 0:s:0 -c copy input-stream-s0.srt
Para saber qué pistas hay en un archivo, usa info (uno de los cuatro verbos de inspección del artículo hub) o ffprobe -v error -show_streams input.mkv directamente. La salida te da el mapa de índices: v:0, v:1, a:0, a:1, etc.
Recetas reales
Cada receta encadena varios verbos (a veces de varios clusters) en un flujo real.
Receta 1: Tubería HLS para hosting estático
Quieres entregar un vídeo de 30 minutos desde un host estático (Cloudflare R2, S3 + CloudFront, Vercel) y reproducirlo con hls.js dentro de un tag <video>. Una sola rendición sirve para la mayoría de casos.
# Paso 1: comprimir a un bitrate de entrega razonable
npx fqmpeg compress source.mov --crf 22 --preset slow
# → source-compressed.mp4
# Paso 2: empaquetar como HLS en una carpeta de salida limpia
mkdir hls-out
npx fqmpeg hls source-compressed.mp4 -o hls-out/stream.m3u8
# → hls-out/stream.m3u8 + hls-out/stream_001.ts ... stream_NNN.ts
Sube hls-out/ al host estático con lectura pública. En tu página:
<video controls></video>
<script type="module">
import Hls from "https://cdn.jsdelivr.net/npm/hls.js@latest/+esm";
const hls = new Hls();
hls.loadSource("https://cdn.example.com/hls-out/stream.m3u8");
hls.attachMedia(document.querySelector("video"));
</script>
Para una escalera multi-bitrate y los ajustes de caché del CDN, la guía de streaming HLS con CDN cubre la configuración de producción incluyendo peticiones byte-range y cabeceras de caché de segmento.
Receta 2: Vista previa GIF desde una edición larga
Has exportado un screencast de 4 minutos como MP4 y necesitas un GIF para el hero del README. Tiene que ser ~2 MB máximo y ~600 px de ancho.
# Paso 1: elige una ventana representativa de 5 segundos
# Visualmente busca un momento cerca del 1:30 de la edición
# Paso 2: extrae esa ventana como GIF
npx fqmpeg gif screencast.mp4 --start 90 --duration 5 --width 600 --fps 12
# → screencast-gif.gif
¿Por qué --fps 12 en lugar del 15 por defecto? Porque para screencasts de cabeza parlante o movimiento de cursor, la fluidez percibida con 12 fps es suficiente y el archivo pesa un 20 % menos. Si el GIF sigue siendo demasiado grande, baja --fps a 10 o --width a 480.
Si el .gif resultante se pasa de presupuesto, la respuesta rara vez es "ajustar más los settings de GIF". Convierte a MP4 con compress y sirve un <video autoplay loop muted playsinline> — mismo aspecto, ~10× más pequeño, más nítido.
Receta 3: Cirugía sobre un MKV multipista
Tienes un .mkv de un rip Blu-ray con tres pistas de audio (japonés, inglés, comentario en inglés) y dos pistas de subtítulos (inglés, inglés SDH). Quieres un MP4 limpio con solo el audio japonés y los subtítulos en inglés como .srt sidecar.
# Paso 1: inspecciona las pistas (con el verbo info del hub, o ffprobe directo)
ffprobe -v error -show_streams source.mkv | grep -E "index=|codec_type=|TAG:language"
# Supón: v:0 H.264, a:0 jpn, a:1 eng, a:2 eng-comm, s:0 eng, s:1 eng-sdh
# Paso 2: extraer el audio japonés
npx fqmpeg extract-stream source.mkv a:0 -o ja.aac
# Paso 3: extraer el subtítulo inglés
npx fqmpeg extract-stream source.mkv s:0 -o eng.srt
# Paso 4: extraer el vídeo
npx fqmpeg extract-stream source.mkv v:0 -o video.mp4
# Paso 5: unir vídeo + audio japonés en un MP4 final
# (esta parte queda fuera de C2 — usa ffmpeg directo)
ffmpeg -i video.mp4 -i ja.aac -c copy -map 0:v -map 1:a final.mp4
El patrón "MKV → vídeo + audio elegido + subtítulo sidecar" es el núcleo de "haz que este rip Blu-ray se vea en mi móvil". extract-stream desensambla sin re-codificar, así que un archivo de 4 GB se procesa en segundos. La unión final es una invocación normal de FFmpeg; puedes previsualizar la forma fusionada vía --dry-run con el verbo fqmpeg más cercano a lo que necesitas (p. ej. convert con flags personalizados) o escribir el FFmpeg a mano.
Preguntas Frecuentes
¿Por qué convert --copy a veces falla con "Could not find tag for codec"?
Porque el códec fuente no es legal en el contenedor destino. WebM solo acepta vídeo VP8/VP9/AV1 y audio Vorbis/Opus — copiar H.264 a .webm lo rechaza. MP4 acepta vídeo H.264/H.265/AV1 pero no VP9. Quita --copy para volver a re-codificación, o elige un contenedor más permisivo como .mkv.
¿hls produce una escalera adaptativa multi-bitrate?
No — produce una sola rendición (.m3u8 + chunks). El streaming adaptativo multi-bitrate requiere codificar la fuente a 2–5 bitrates distintos (usa bitrate del cluster de compresión para cada uno) y luego escribir una playlist maestra que referencie el .m3u8 de cada rendición. La guía de streaming HLS con CDN muestra el formato de la playlist maestra.
¿Debo entregar HLS o DASH?
HLS si tu audiencia tira a iOS / Safari / Apple TV — el ecosistema Apple trata HLS como nativo y DASH como ciudadano de segunda. DASH si apuntas a Android TV, smart TVs con reproductores W3C estándar, o tuberías estrictamente conformes a W3C. La mayoría de servicios grandes entregan ambos, multiplexando en tiempo de petición. Para proyectos pequeños, solo HLS cubre ~95 % de los espectadores gracias a hls.js.
¿Por qué segment corta en límites ligeramente desplazados del segundo exacto?
segment corre en modo stream-copy, que solo puede partir en keyframes existentes (límites GOP). Si tu fuente tiene un GOP de 5 segundos, un segmento de 10 segundos caerá entre 5 s y 15 s — lo más cerca posible de 10 s. Para cortes precisos al frame, re-codifica editando el comando impreso por --dry-run para quitar -c copy, o acorta el intervalo de keyframes de la fuente primero con -g 30 -keyint_min 30 en el codificador.
¿Por qué el GIF por defecto se ve mucho mejor que ffmpeg -i in.mp4 out.gif?
La línea ingenua usa la paleta nativa de GIF (256 colores fijos no derivados de tu clip), que produce banding y ruido de dithering. gif usa el filtro de dos pasadas palettegen / paletteuse de FFmpeg para calcular una paleta óptima a partir de los frames reales de tu clip. El mismo truco está enterrado en docenas de posts de Stack Overflow sobre "GIF de alta calidad en FFmpeg"; gif te ahorra teclearlo.
¿Puedo hacer que extract-stream escriba a una extensión personalizada?
Sí — pasa -o output.<ext>. La extensión por defecto asume AAC/SRT/MP4, lo cual es correcto para la mayoría de archivos pero incorrecto para, digamos, audio Opus en un MKV (extract-stream input.mkv a:0 -o audio.opus). El flag -c copy significa que los bytes que estaban dentro de la pista fuente se escriben tal cual al nuevo archivo, así que la extensión solo necesita coincidir con el códec real.
¿Puedo segmentar en lote una carpeta de archivos?
Sí — fqmpeg es shell-friendly. El patrón estándar:
for f in *.mp4; do
mkdir -p "segments/${f%.mp4}"
( cd "segments/${f%.mp4}" && npx fqmpeg segment "../../$f" 60 )
done
Cada invocación de segment corre en su propio subdirectorio para que los chunks no choquen. La subshell exterior ( ... ) evita que el cd se filtre a la siguiente iteración.
¿Hay soporte para HLS de Baja Latencia (LL-HLS)?
No vía un flag dedicado — hls produce HLS estándar. Para LL-HLS querrás --segment 1 o 2, más los flags de FFmpeg -hls_flags +program_date_time -hls_segment_type fmp4 y opciones de segmentos parciales. Lanza --dry-run, copia el comando impreso y añade los flags LL-HLS a mano. La especificación HTTP Live Streaming de Apple es la referencia autoritativa para los campos de segmento parcial y rendition report.
Conclusión
Los siete verbos de C2 cubren las decisiones de "forma del archivo" que vas a tomar una vez decidido el códec:
convertpara "mismo contenido, otro envoltorio" (con--copypara remux instantáneo)gif/gif-to-videopara el viaje de ida y vuelta del GIFhls/dashpara manifiestos de streaming adaptativosegmentpara trocear a duración fijaextract-streampara extraer pistas quirúrgicamente
Cada verbo imprime su invocación FFmpeg subyacente con --dry-run, así puedes copiarlo tal cual, adaptarlo (LL-HLS, patrones de segmento personalizados, swap a NVENC) o aprender la sintaxis detrás del verbo. Para el mapa más amplio de fqmpeg, vuelve a la guía completa de fqmpeg. Para decisiones del lado del códec, mira la inmersión profunda en compresión y codificación.