32blogby Studio Mitsu

fqmpeg Edición: Recortar, Velocidad, Concatenar, Frames

Quince verbos de fqmpeg para editar en el eje temporal: trim, concat, speed, fade, interpolate y más. Implementación verificada contra el código fuente.

by omitsu24 min read
Contenido

El cluster C4 de fqmpeg son quince verbos que operan sobre el eje temporal del video: cortarlo (trim, split), unirlo (concat, crossfade), repetirlo o invertirlo (loop, reverse, boomerang), cambiar su velocidad (speed, interpolate, fps), fundir los bordes (fade, fade-between), o congelar y estirar fotogramas individuales (freeze, repeat-frame, frame-step). Juntos cubren las operaciones de edición a las que recurres entre "tengo el material en bruto" y "esto está listo para publicar".

Esta guía recorre cada verbo — los flags FFmpeg que genera, sus valores por defecto, las reglas de nombrado de salida y los gotchas que vienen del filtro subyacente (el rango 0.5–2.0 de atempo, la semántica del offset de xfade, la aritmética de timestamps de tpad). Todo se ha verificado contra el código fuente en src/commands/ de fqmpeg 3.0.1.

Lo que te llevarás de esta guía

  • Una matriz de decisión para los 15 verbos por tarea (cortar / unir / tiempo / transición / frame)
  • La invocación FFmpeg exacta que genera cada verbo (salida --dry-run verificada)
  • Defaults, valores permitidos y nombres de salida para cada comando
  • Tres recetas de extremo a extremo, incluyendo una pipeline de cámara lenta suave

Vista General de los 15 Verbos

El cluster se divide limpiamente en cuatro grupos de tareas. Eliges el grupo y luego el verbo.

GrupoVerbosQué hacen
Cortes y unionestrim, split, concatCortar una sección, dividir en segmentos iguales, o unir varios archivos
Reproducción temporalloop, reverse, speed, boomerangReproducir N veces, hacia atrás, más rápido/lento, o adelante-y-atrás
Transicionescrossfade, fade, fade-betweenMezclar dos clips, fundir los bordes, o pasar a negro entre clips
A nivel de fotogramafreeze, repeat-frame, frame-step, interpolate, fpsCongelar un frame, mantener el último, decimar, interpolar, o cambiar la tasa

Tres cosas que conviene saber antes de seguir:

  1. trim es rápido por keyframe, no preciso al frame. Usa -c copy así que el corte se ajusta al keyframe inmediatamente anterior al tiempo solicitado. Para cortes precisos al frame hay que reencodear — la guía de corte sin pérdida con FFmpeg cubre el trade-off en detalle.
  2. speed encadena atempo para grandes cambios de velocidad. El filtro de audio atempo de FFmpeg sólo acepta 0.5–2.0 por instancia; fqmpeg construye la cadena automáticamente (p. ej. 4x se convierte en atempo=2.0,atempo=2).
  3. interpolate consume mucha CPU. La interpolación con compensación de movimiento corre a ~5–20× tiempo real en una laptop típica. Úsalo sólo cuando el resultado visible de verdad necesita movimiento suave (slow-mo, conversión a una tasa más alta); para simplemente encajar a una tasa objetivo, fps es suficiente.

Cortes y Uniones

trim — Cortar una sección (stream-copy)

Corta una sección entre --start y --duration o --to. Usa -c copy así que es rápido (sin reencode), pero el corte se ajusta al keyframe anterior más cercano. Para cortes precisos al frame, reencodea las costuras.

  • Fuente: src/commands/trim.js
  • Códec: -c copy -map 0 (passthrough, todos los streams)
  • Formato de tiempo: segundos (30) o HH:MM:SS (00:01:30) en cualquier argumento de tiempo
  • Se requiere uno de --duration o --to — si no, el comando termina con Error: specify --duration (-d) or --to (-t).
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
-s, --start <time>0Tiempo de inicio
-d, --duration <time>Longitud del corte desde --start
-t, --to <time>Tiempo de fin (mutuamente excluyente con --duration)
-o, --output <path><nombre-entrada>-trimmed.<ext>Sobrescribir salida
bash
$ npx fqmpeg trim input.mp4 --start 00:00:10 --duration 00:00:30 --dry-run

  ffmpeg -i input.mp4 -ss 00:00:10 -t 00:00:30 -c copy -map 0 input-trimmed.mp4

Si el corte arranca en un frame que no es keyframe, FFmpeg busca hacia atrás al keyframe anterior y el archivo resultante puede ser un poco más largo que lo pedido o tener un primer frame congelado durante unos cientos de milisegundos. Es el costo de -c copy. La guía de corte sin pérdida cubre enfoques de dos pasadas que sólo reencodean los GOPs en las costuras.

split — Dividir en segmentos iguales

Divide la entrada en segmentos de N segundos usando el muxer segment de FFmpeg. Stream-copy, así que es instantáneo. El patrón de salida por defecto usa %03d (tres dígitos con cero a la izquierda): input-part000.mp4, input-part001.mp4, etc.

  • Fuente: src/commands/split.js
  • Muxer: -f segment -segment_time <s> -reset_timestamps 1
  • Códec: -c copy -map 0
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<seconds>requeridoDuración del segmento en segundos
-o, --output <pattern><nombre-entrada>-part%03d.<ext>Patrón con placeholder estilo printf
bash
$ npx fqmpeg split input.mp4 60 --dry-run

  ffmpeg -i input.mp4 -c copy -map 0 -f segment -segment_time 60 -reset_timestamps 1 input-part%03d.mp4

Como con trim, los límites de segmento se ajustan a keyframes — así que un "segmento de 60 segundos" puede durar 58–62 segundos según dónde caigan los GOPs. -reset_timestamps 1 reinicia el PTS de cada segmento a 0, que es lo que esperan las herramientas downstream (HLS, DASH, reproductores).

concat — Unir archivos

Concatena dos o más archivos de video. Dos modos:

  • Modo demuxer (default, stream-copy): construye un filelist.txt temporal con rutas absolutas, ejecuta -f concat -safe 0 y limpia el archivo al salir. Rápido, pero requiere que los inputs compartan códec/contenedor/resolución.

  • Modo reencode (--re-encode): usa filter_complex concat para unir entradas que difieren en códec o resolución. Más lento pero tolerante.

  • Fuente: src/commands/concat.js

  • Sufijo por defecto: -joined

Argumento / OpciónDefaultNotas
<inputs...>requerido2 o más archivos de video
--re-encodeoffCambia a concat basado en filtro (cuando los códecs difieren)
-o, --output <path><primer-nombre>-joined.<ext>Sobrescribir salida
bash
$ npx fqmpeg concat clip1.mp4 clip2.mp4 clip3.mp4 --dry-run

  # File list (auto-generated):
  # file '/abs/path/clip1.mp4'
  # file '/abs/path/clip2.mp4'
  # file '/abs/path/clip3.mp4'

  ffmpeg -f concat -safe 0 -i filelist.txt -c copy clip1-joined.mp4

$ npx fqmpeg concat clip1.mp4 clip2.mp4 --re-encode --dry-run

  ffmpeg -i clip1.mp4 -i clip2.mp4 -filter_complex [0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa] -map [outv] -map [outa] clip1-joined.mp4

La salida --dry-run del modo demuxer incluye la lista de archivos auto-generada como bloque de comentario — útil para depurar problemas de rutas absolutas. El filelist.txt real se escribe en el directorio del input con un nombre con hash tipo .fqmpeg-concat-1715450000000.txt y se borra cuando el proceso termina, así que no lo verás en el sistema de archivos después de una ejecución real.

Si el concat en modo demuxer falla con Non-monotonous DTS in output stream o Could not write header, los inputs probablemente tienen distintos timestamps, códecs o resoluciones. Añade --re-encode y reintenta.

Reproducción Temporal

loop — Reproducir N veces

Repite el video N veces usando -stream_loop. Stream-copy, así que es instantáneo.

  • Fuente: src/commands/loop.js
  • Filtro: -stream_loop <N-1> (el stream_loop de FFmpeg cuenta loops adicionales, así que loop 3 = reproducir 3 veces = stream_loop 2)
  • Sufijo por defecto: -loop<N>
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<count>requeridoNúmero de reproducciones (ej. 3 = reproducir 3 veces)
-o, --output <path><nombre>-loop<N>.<ext>Sobrescribir salida
bash
$ npx fqmpeg loop input.mp4 3 --dry-run

  ffmpeg -stream_loop 2 -i input.mp4 -c copy input-loop3.mp4

El count se valida como número positivo pero sólo la parte entera llega a FFmpeg (Math.floor(n) - 1). Pasar 0 o un número negativo dispara un error del validador antes de que FFmpeg arranque.

reverse — Reproducir hacia atrás

Aplica el filtro de video reverse y el de audio areverse, así que video y audio van hacia atrás. Usa --no-audio para descartar audio (mucho más rápido en clips largos, ya que areverse bufferea todo el stream de audio en memoria).

Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
--no-audio(audio se mantiene)Descartar audio (más rápido en clips largos)
-o, --output <path><nombre>-reversed.<ext>Sobrescribir salida
bash
$ npx fqmpeg reverse input.mp4 --dry-run

  ffmpeg -i input.mp4 -vf reverse -af areverse input-reversed.mp4

speed — Cambiar la velocidad de reproducción

Re-tempa el video con setpts y el audio con uno o más filtros atempo encadenados. fqmpeg gestiona el encadenamiento por ti, así que puedes pasar cualquier multiplicador positivo.

  • Fuente: src/commands/speed.js
  • Filtro de video: setpts=(1/speed)*PTS
  • Filtro de audio: atempo encadenado (el atempo de FFmpeg sólo acepta 0.5–2.0 por instancia, así que 4× se convierte en atempo=2.0,atempo=2 y 0.25× en atempo=0.5,atempo=0.5)
  • Sufijo por defecto: <N>x para acelerar, slow<N>x para ralentizar
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<factor>requeridoMultiplicador de velocidad (ej. 2 = 2× más rápido, 0.5 = mitad)
--no-audio(audio se mantiene)Descartar audio (útil en time-lapse)
-o, --output <path><nombre>-<sufijo>.<ext>Sobrescribir salida
bash
$ npx fqmpeg speed input.mp4 2 --dry-run

  ffmpeg -i input.mp4 -filter:v setpts=0.500000*PTS -filter:a atempo=2 input-2x.mp4

$ npx fqmpeg speed input.mp4 4 --dry-run

  ffmpeg -i input.mp4 -filter:v setpts=0.250000*PTS -filter:a atempo=2.0,atempo=2 input-4x.mp4

$ npx fqmpeg speed input.mp4 0.5 --dry-run

  ffmpeg -i input.mp4 -filter:v setpts=2.000000*PTS -filter:a atempo=0.5 input-slow0.5x.mp4

Para time-lapse (mucha aceleración, audio inservible) siempre pasa --no-audio — encadenar cuatro o cinco atempo funciona pero produce artefactos imposibles de escuchar. Para cámara lenta suave (factores menores a 1.0), speed 0.5 simplemente duplica frames. Para sintetizar frames intermedios, encadena interpolate (Receta 2 abajo).

boomerang — Adelante y luego atrás

Splittea el stream de video, invierte una copia y concatena adelante + atrás para un loop ping-pong sin costuras. La parte de video se reencodea; el audio se stream-copy (o se descarta con --no-audio).

bash
$ npx fqmpeg boomerang input.mp4 --dry-run

  ffmpeg -i input.mp4 -filter_complex [0:v]split[fwd][rev];[rev]reverse[reversed];[fwd][reversed]concat=n=2:v=1:a=0 -c:a copy input-boomerang.mp4

El manejo de audio es intencionalmente simple: el filtro sólo concatena video, así que el audio copiado (-c:a copy) suena durante la parte hacia adelante y se corta en medio del boomerang. Para clips estilo Instagram normalmente da igual (el formato va silenciado en autoplay). Si el audio es parte del efecto, pasa --no-audio para que el silencio sea intencional, o postprocesa con verbos audio para crear una pista propia.

Transiciones

crossfade — Mezclar dos clips con xfade

Aplica una de las transiciones xfade integradas de FFmpeg entre dos videos. Por defecto, ffprobe se ejecuta sobre clip1 para detectar su duración y la transición se temporiza para arrancar cerca del final de clip1 — es decir, clip1 se reproduce completo y luego hace crossfade suave hacia clip2. El audio también se mezcla en paralelo con acrossfade.

  • Fuente: src/commands/crossfade.js
  • Filtro (default): [0:v][1:v]xfade=transition=<tipo>:duration=<seg>:offset=<auto>[v];[0:a][1:a]acrossfade=d=<seg>[a]
  • Offset automático: offset = ffprobe(clip1).duration - <duración del crossfade>. Sobrescríbelo con --offset <n>
  • Transiciones (21): fade, wipeleft, wiperight, wipeup, wipedown, slideleft, slideright, slideup, slidedown, circlecrop, rectcrop, distance, fadeblack, fadewhite, radial, smoothleft, smoothright, smoothup, smoothdown, squeezev, squeezeh
Argumento / OpciónDefaultNotas
<input1>requeridoPrimer video
<input2>requeridoSegundo video
<duration>requeridoDuración de la transición en segundos
--transition <type>fadeUna de las 21 transiciones de arriba
--offset <seconds>auto-detectadoCuándo arranca la transición (en la timeline de clip1)
--no-audio-fadeoffStream-copy de audio en lugar de acrossfade (úsalo cuando los clips no tienen audio)
-o, --output <path><nombre1>-crossfade.<ext>Sobrescribir salida
bash
# Default: detección automática de la duración de clip1 vía ffprobe (aquí clip1 es 8.5s)
$ npx fqmpeg crossfade clip1.mp4 clip2.mp4 1.5 --transition wipeleft --dry-run

  ffmpeg -i clip1.mp4 -i clip2.mp4 -filter_complex [0:v][1:v]xfade=transition=wipeleft:duration=1.5:offset=7[v];[0:a][1:a]acrossfade=d=1.5[a] -map [v] -map [a] clip1-crossfade.mp4

# Offset manual y sin crossfade de audio (cuando un clip no tiene pista de audio)
$ npx fqmpeg crossfade clip1.mp4 clip2.mp4 1.5 --offset 5 --no-audio-fade --dry-run

  ffmpeg -i clip1.mp4 -i clip2.mp4 -filter_complex xfade=transition=fade:duration=1.5:offset=5 -c:a copy clip1-crossfade.mp4

El offset automático coincide con la expectativa más común — "reproducir clip1 completo y luego pasar a clip2 con un fundido". Pasa --offset <n> para empezar la transición antes (efecto de solapamiento) y --no-audio-fade si alguna entrada no tiene audio (acrossfade da error cuando falta una pista).

fade — Fundir entrada y/o salida

Añade fade-in al inicio, fade-out al final, o ambos. Los filtros de video (fade) y audio (afade) se emiten en paralelo, así que el nivel de audio sigue al fade visual.

  • Fuente: src/commands/fade.js
  • Se requiere al menos uno de --in o --out
  • --out requiere --duration (la longitud total del video, para saber cuándo arrancar el fade)
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
--in <seconds>0Duración del fade-in
--out <seconds>0Duración del fade-out
--duration <seconds>Longitud total del video (requerida si --out > 0)
-o, --output <path><nombre>-fade.<ext>Sobrescribir salida
bash
$ npx fqmpeg fade input.mp4 --in 2 --dry-run

  ffmpeg -i input.mp4 -vf fade=t=in:st=0:d=2 -af afade=t=in:st=0:d=2 input-fade.mp4

$ npx fqmpeg fade input.mp4 --in 2 --out 2 --duration 30 --dry-run

  ffmpeg -i input.mp4 -vf fade=t=in:st=0:d=2,fade=t=out:st=28:d=2 -af afade=t=in:st=0:d=2,afade=t=out:st=28:d=2 input-fade.mp4

Obtén la duración total primero con npx fqmpeg duration input.mp4. El tiempo de inicio del fade-out se calcula automáticamente como duration - fadeOut. Si la entrada no tiene pista de audio, la cadena -af fallará — quita el audio antes con strip-audio, o ejecuta FFmpeg directamente sin -af.

fade-between — Pasar a negro entre dos clips

Funde clip1 a negro, después funde de negro a clip2 y los concatena. Distinto de crossfade — hay un frame negro en medio, no una mezcla directa. El audio se concatena de extremo a extremo (sin crossfade de audio).

Argumento / OpciónDefaultNotas
<input1>requeridoPrimer video
<input2>requeridoSegundo video
--duration <n>1Duración del fade en segundos (aplicada a ambos clips)
-o, --output <path><nombre1>-faded.<ext>Sobrescribir salida
bash
$ npx fqmpeg fade-between clip1.mp4 clip2.mp4 --duration 1.5 --dry-run

  ffmpeg -i clip1.mp4 -i clip2.mp4 -filter_complex [0]fade=t=out:st=0:d=1.5[v0];[1]fade=t=in:st=0:d=1.5[v1];[v0][v1]concat=n=2:v=1:a=0[v];[0:a][1:a]concat=n=2:v=0:a=1[a] -map [v] -map [a] clip1-faded.mp4

Nota que el st=0 (start = 0) del fade aplica a la propia timeline de cada clip — así que clip1 empieza a fundirse desde el principio, no al final. Para el habitual "fundir los últimos 1.5s de clip1 y luego los primeros 1.5s de clip2" haría falta otra cadena de filtros; este verbo encaja en casos donde los clips ya son ediciones cortas y todo el clip puede subir o bajar.

Operaciones a Nivel de Frame

freeze — Congelar un solo frame

Congela el video en un tiempo dado durante una duración dada usando un truco con tpad + setpts. El audio se stream-copy (es decir, sigue sonando durante el congelamiento).

  • Fuente: src/commands/freeze.js
  • Filtro: tpad=stop_mode=clone:stop_duration=0,setpts='if(gte(T,<at>),if(lte(T,<at>+<hold>),<at>/TB,PTS-<hold>/TB),PTS)'
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<at>requeridoPosición temporal a congelar (segundos o HH:MM:SS)
<hold>requeridoCuánto mantener el congelamiento (segundos)
-o, --output <path><nombre>-freeze.<ext>Sobrescribir salida
bash
$ npx fqmpeg freeze input.mp4 5 2 --dry-run

  ffmpeg -i input.mp4 -vf tpad=stop_mode=clone:stop_duration=0,setpts='if(gte(T,5),if(lte(T,5+2),5/TB,PTS-2/TB),PTS)' -c:a copy input-freeze.mp4

La expresión setpts congela el tiempo en <at> durante <hold> segundos y luego sigue, desplazado por <hold>. Como el audio se copia, suena de forma continua durante el congelamiento (sin padding de audio). Para un congelamiento totalmente sincronizado (audio también pausado), entra a FFmpeg directamente con -af "asetpts=..." o pausa-y-resume con el demuxer concat sobre tres partes recortadas.

repeat-frame — Mantener el último frame

Rellena el final del video repitiendo el último frame durante N segundos. Útil para añadir una tarjeta de título estática o estirar un clip corto a una duración objetivo. El audio se copia (termina en su largo original y el frame extendido es silencioso).

Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<seconds>requeridoTiempo a mantener el último frame
-o, --output <path><nombre>-hold.<ext>Sobrescribir salida
bash
$ npx fqmpeg repeat-frame input.mp4 3 --dry-run

  ffmpeg -i input.mp4 -vf tpad=stop_mode=clone:stop_duration=3 -c:a copy input-hold.mp4

frame-step — Conservar 1 de cada N frames

Decima el video conservando 1 de cada N frames y reflujea los timestamps. Siempre quita el audio (-an) — la temporización original ya no aplica. La frecuencia de salida coincide con la entrada pero el contenido es esencialmente un time-lapse N× sin suavizado.

Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<n>requeridoConservar 1 de cada N frames (entero positivo)
-o, --output <path><nombre>-step.<ext>Sobrescribir salida
bash
$ npx fqmpeg frame-step input.mp4 5 --dry-run

  ffmpeg -i input.mp4 -vf select='not(mod(n\,5))',setpts=N/FRAME_RATE/TB -an input-step.mp4

Para un time-lapse más suave (en lugar de una decimación dura) usa speed --no-audiospeed reescala los timestamps de forma continua, mientras que frame-step es esencialmente vecino-más-cercano en el eje temporal.

interpolate — Cámara lenta suave por compensación de movimiento

Genera frames sintéticos intermedios usando el minterpolate de FFmpeg con interpolación compensada por movimiento. Este es el verbo de "slow-mo suave" — bajar un material a 30 fps a la mitad de velocidad e interpolar a 60 fps da un resultado fluido (a diferencia de los frames duplicados que produce speed 0.5).

  • Fuente: src/commands/interpolate.js
  • Filtro: minterpolate=fps=<objetivo>:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1
  • Lento. La interpolación con compensación de movimiento es CPU-intensiva — espera 5–20× tiempo real en una laptop típica.
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<target-fps>requeridoTasa de frames objetivo (ej. 60, 120)
-o, --output <path><nombre>-<N>fps-interp.<ext>Sobrescribir salida
bash
$ npx fqmpeg interpolate input.mp4 60 --dry-run

  ffmpeg -i input.mp4 -vf minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1 -c:a copy input-60fps-interp.mp4

mi_mode=mci es interpolación compensada por movimiento (la mejor calidad y la más lenta). mc_mode=aobmc es matching por bloques superpuestos adaptativos, me_mode=bidir es estimación bidireccional, vsbmc=1 activa compensación con bloques de tamaño variable. Estos defaults priorizan calidad sobre velocidad; si el resultado tiene shimmering o ghosting en escenas con mucho movimiento, baja a mi_mode=blend o mi_mode=dup editando la salida --dry-run y ejecutando FFmpeg directamente.

fps — Cambiar tasa de frames (sin interpolación)

La versión simple: fija la tasa de frames de salida tirando o duplicando frames. Sin compensación de movimiento, así que las aceleraciones se ven choppy y las ralentizaciones titubeantes — pero es instantáneo donde interpolate es lento.

Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<rate>requeridoTasa objetivo (ej. 24, 30, 60)
-o, --output <path><nombre>-<N>fps.<ext>Sobrescribir salida
bash
$ npx fqmpeg fps input.mp4 24 --dry-run

  ffmpeg -i input.mp4 -vf fps=24 -c:a copy input-24fps.mp4

Cuándo usar fps vs interpolate: fps para encajar a una tasa objetivo (ej. convertir captura de gameplay a 60 fps en un tutorial a 30 fps), interpolate cuando realmente quieres movimiento suave a una tasa más alta (slow-mo, panorámicas suaves).

Recetas Reales

Cada receta encadena varios verbos en un workflow que de hecho usarías.

Receta 1: Encadenar 3 clips con crossfades y un fade-out final

Patrón de edición habitual: encadenar tres clips con crossfades suaves entre cada par y luego un fundido a negro de 1 segundo al final. Cada llamada a crossfade autodetecta la duración del clip anterior y temporiza la transición correctamente.

bash
# Step 1: crossfade entre clip1 y clip2 (1s de transición)
npx fqmpeg crossfade clip1.mp4 clip2.mp4 1 -o c12.mp4

# Step 2: crossfade de c12 con clip3
npx fqmpeg crossfade c12.mp4 clip3.mp4 1 -o c123.mp4

# Step 3: largo total y fade-out de 1s
total=$(npx fqmpeg duration c123.mp4 | awk -F: '{print ($1*3600)+($2*60)+$3}')
npx fqmpeg fade c123.mp4 --out 1 --duration "$total" -o final.mp4

Cada archivo intermedio se reencodea (xfade es una cadena de filtros, no admite stream-copy), así que los costos se acumulan en cadenas largas. Para clips largos, conviene editar la salida --dry-run del paso 2 para incluir el tercer input en una sola cadena de filtros. Pasa --no-audio-fade si alguno de los tres clips no tiene pista de audio — acrossfade falla cuando falta audio en una entrada.

Receta 2: Cámara lenta suave desde un material a 30 fps

Toma un clip, bájalo a media velocidad e interpólalo a 60 fps para que no titubee. La pipeline de dos pasos produce algo parecido a lo que daría un material grabado a 120 fps reproducido a la mitad.

bash
# Step 1: bajar a 0.5x (sin audio - el audio en cámara lenta rara vez suena bien)
npx fqmpeg speed source.mp4 0.5 --no-audio
# → source-slow0.5x.mp4

# Step 2: interpolar a 60 fps para suavizar
npx fqmpeg interpolate source-slow0.5x.mp4 60
# → source-slow0.5x-60fps-interp.mp4

El paso 2 es el lento — la interpolación compensada va a ~5–20× tiempo real. Para batches, hazlo de noche o en una máquina más fuerte. Si la fuente ya está a 60 fps, salta el paso 2 — speed 0.5 te deja en un equivalente a 30 fps que ya se ve suave en una pantalla a 60 fps.

Receta 3: Reel de momentos destacados desde un stream de 1 hora

Saca tres highlights de un stream largo, pásales fade-to-black entre medias y añade un fundido de entrada de un segundo al inicio.

bash
# Step 1: cortar tres highlights con trim
npx fqmpeg trim stream.mp4 --start 00:12:30 --duration 00:00:20 -o h1.mp4
npx fqmpeg trim stream.mp4 --start 00:34:15 --duration 00:00:25 -o h2.mp4
npx fqmpeg trim stream.mp4 --start 00:51:00 --duration 00:00:15 -o h3.mp4

# Step 2: fade-between entre h1 y h2
npx fqmpeg fade-between h1.mp4 h2.mp4 --duration 0.8 -o h12.mp4

# Step 3: fade-between entre (h1+h2) y h3
npx fqmpeg fade-between h12.mp4 h3.mp4 --duration 0.8 -o h123.mp4

# Step 4: largo total y fade-in de 1s
total=$(npx fqmpeg duration h123.mp4)
# → 0:00:60.xxxxxx (alrededor de 60s después de que los fades quitan algo en cada borde)
npx fqmpeg fade h123.mp4 --in 1 --duration 60 -o reel.mp4

Cada trim se ajusta a keyframe — para cortes que tengan que caer en un frame específico (ej. en mitad de una acción) revisa la guía de corte sin pérdida enlazada en el paso 1 de la tabla del inicio. Los fades de los pasos 2–4 reencodean, así que el ajuste a keyframe del trim no se compone en cascada.

Preguntas Frecuentes

¿Por qué loop 3 produce -stream_loop 2?

Porque el -stream_loop de FFmpeg cuenta loops adicionales, no reproducciones totales. -stream_loop 0 significa "reproducir una vez", -stream_loop 2 significa "reproducir una vez y luego repetir dos veces más = 3 reproducciones totales". fqmpeg le resta 1 al conteo del usuario para igualar la intención ("reproducir 3 veces").

trim es rápido pero el corte no está donde pedí. ¿Qué pasa?

trim usa -c copy, lo que significa que la salida arranca en el keyframe inmediatamente anterior al --start que pediste. Si el GOP es de 250 frames y pides empezar en 5 segundos, podrías arrancar de hecho en 4.0 segundos. El trade-off es la velocidad: stream-copy es esencialmente I/O-bound (instantáneo en SSD), mientras que los cortes precisos al frame reencodean los GOPs en las costuras. La guía de corte sin pérdida con FFmpeg recorre el enfoque de "reencodear sólo los bordes".

concat falla con "Non-monotonous DTS" — ¿qué hago?

Las entradas tienen distintos timestamps, códecs o resoluciones, y el concat por stream-copy no puede unirlas. Reintenta con --re-encode. Eso cambia a filter_complex concat, que decodifica y reencodea todo (más lento, pero tolera mismatches). Si tienes muchos clips y sólo uno es el raro, reencodea ese primero con compress y luego corre el concat demuxer sobre el conjunto homogeneizado.

speed encadena atempo para grandes aceleraciones — ¿afecta la calidad del audio?

Sí, de forma audible. Cada instancia de atempo aplica un estiramiento por phase-vocoder; encadenar dos o tres está bien para contenido casual pero produce artefactos notables (warbling en contenido tonal como música). Para time-lapse (mucha aceleración), pasa --no-audio y mete una pista musical después. Para aceleraciones moderadas (1.0–2.0×) sólo se aplica un atempo y la calidad está fina.

¿frame-step da el mismo resultado que speed?

No. frame-step N conserva 1 de cada N frames y reflujea los timestamps para que la salida vaya a la misma tasa de la entrada — una decimación dura sin suavizado. speed N reescala los timestamps de forma continua, así que la salida va a la misma tasa pero con todos los frames preservados (en una secuencia más rápida). Para time-lapse: usa speed --no-audio para movimiento más suave, frame-step cuando específicamente quieres ese look "stuttery" decimado.

¿Puedo usar freeze y mantener el audio también pausado?

No con el verbo tal cual — el audio se stream-copy, así que sigue sonando durante el congelamiento. Para una pausa sincronizada, lo más limpio es dividir la entrada en tres pedazos con trim (antes del congelamiento, el frame congelado como clip de 1 frame, después del congelamiento), aplicar repeat-frame al frame para sostener la duración, y volver a unir los tres con concat --re-encode.

interpolate es lento — ¿cuándo realmente vale la pena?

Cuando el resultado visible necesita movimiento suave: reproducción en cámara lenta de acción rápida, conversión de tasa de frames de un clip animado para una pantalla de alto refresh, o salvar material a 24 fps para una plataforma a 60 fps. No vale la pena para reencodear un screencast tutorial (no hay movimiento rápido que suavizar), para salidas time-lapse (los artefactos van en dirección equivocada) o para subir a una plataforma que reencodea (YouTube, Instagram) — el reencodeo destruye la mayor parte de la suavidad ganada.

¿Cómo recorto en lote una carpeta de videos a un largo fijo?

Loop de shell estándar:

bash
for v in raw/*.mp4; do
  npx fqmpeg trim "$v" --start 0 --duration 60 -o "trimmed/$(basename "$v")"
done

Cada salida cae en trimmed/ con el mismo nombre de archivo. Para cortes batch precisos al frame, reemplaza trim por el patrón de reencode de la guía de corte sin pérdida.

Conclusión

Los quince verbos de C4 cubren las operaciones de edición sobre el eje temporal a las que recurres en una pasada típica:

  • trim, split, concat para cortes y uniones (stream-copy cuando los códecs coinciden, --re-encode cuando no)
  • loop, reverse, speed, boomerang para reproducción temporal (atento al encadenado de atempo en speed y al costo de buffer de audio en reverse)
  • crossfade, fade, fade-between para transiciones (crossfade autodetecta la duración de clip1 y mezcla audio en paralelo; usa --offset o --no-audio-fade para sobrescribir)
  • freeze, repeat-frame, frame-step, interpolate, fps para trabajo a nivel de frame (usa interpolate sólo cuando la suavidad realmente importa; es lento)

Cada verbo imprime su invocación FFmpeg subyacente con --dry-run, así que cuando los defaults no encajan (el manejo de audio de freeze, un crossfade --offset específico) puedes copiar el comando, customizarlo y ejecutar FFmpeg directo. Para corte preciso al frame o el mapa completo de fqmpeg, mira la guía de corte sin pérdida y la fqmpeg complete guide.