32blogby Studio Mitsu

fqmpeg Overlays y Marcas de Agua: 13 Verbos

Trece verbos de fqmpeg para marcas de agua, texto, picture-in-picture, grids, blends y overlays analíticos — defaults y trampas verificados.

by omitsu25 min read
Contenido

El cluster C8 de fqmpeg es la caja de herramientas de composición: 13 verbos que ponen algo encima de (o al lado de) tu video. Cinco dibujan gráficos o texto estático (watermark, text, drawbox, timecode, border). Cuatro combinan varios videos en un solo lienzo (pip, pip-grid, blend, stack). Uno crea un video a partir de una imagen fija más audio (picture). Tres queman información analítica en el cuadro para revisión (video-info-overlay, histogram-overlay, progress).

Esta guía recorre cada verbo contra su fuente en src/commands/ de fqmpeg 3.0.3: el filtro FFmpeg subyacente, los defaults, el nombre del archivo de salida, y las trampas que --help por sí solo no muestra (text auto-escapa : y ' para que los pases literales; pip-grid auto-detecta 2x1/2x2/3x3 según la cantidad de inputs; progress necesita un argumento de duración porque FFmpeg no permite referenciar la duración de la fuente desde una expresión de filtro; la posición y el tamaño de histogram-overlay están hardcodeados).

Qué te llevas de esta guía

  • Una tabla de decisión para los 13 verbos por tarea (gráficos / multi-video / imagen-a-video / analítico)
  • La invocación FFmpeg exacta que genera cada verbo (verificada con --dry-run)
  • Defaults, rangos, palabras-clave de posición y nombres de salida para cada comando
  • Tres recetas de extremo a extremo — brandear un clip de YouTube, armar un reel de comparación, documentar una grabación de pantalla

Los 13 Verbos de un Vistazo

El cluster se divide en cuatro grupos de tarea. Elige el grupo, luego el verbo.

GrupoVerbosQué hacen
Gráficos y texto estáticowatermark, text, drawbox, timecode, borderQuemar logo, texto, rectángulo, timestamp en vivo o marco sólido alrededor del video
Composición multi-videopip, pip-grid, blend, stackPicture-in-picture, grids de 2-9 inputs, blends por opacidad o stacks lado-a-lado / arriba-abajo
Imagen a videopicturePromueve una imagen fija + audio a un MP4 reproducible (podcast, song-art video)
Overlays analíticosvideo-info-overlay, histogram-overlay, progressQuemar número de frame / PTS / picture-type, un histograma o waveform, o una barra de progreso ligada al tiempo

Tres cosas que vale saber antes de seguir:

  1. text auto-escapa : y '. El filtro drawtext trata : como separador de opciones y ' como delimitador de string, así que un Time: 12:34 literal normalmente requeriría escape manual. fqmpeg pre-escapa estos en el wrapper JS (''\\\\'', :\:), así que pasas el string tal cual. La contraparte: si intentaras inyectar opciones de drawtext a través del string, fqmpeg lo bloquea — por diseño.
  2. pip-grid auto-detecta el layout según la cantidad de inputs. Pasa 2 inputs y obtienes 2x1; con 3-4 sale 2x2; con 5-9 sale 3x3. Las ranuras vacías se rellenan repitiendo el último input — pasa 5 videos a un 3x3 y las ranuras 6-9 son clones del input 5. Forza con --layout 2x2 (etc.) cuando quieras una forma específica.
  3. progress necesita un argumento posicional <duration>. El drawbox de FFmpeg puede referenciar t (tiempo actual) dentro de una expresión, pero no la duración total de la fuente. fqmpeg lo resuelve tomando la duración como argumento explícito y horneándola en la fórmula iw*t/<duration>. Si no sabes la duración, corre npx fqmpeg duration input.mp4 antes.

Gráficos y Texto Estático

watermark — Overlay de imagen (logo PNG, etc.)

Superpone una imagen sobre un video en una de nueve posiciones predefinidas. El audio queda intacto.

  • Fuente: src/commands/watermark.js
  • Filtro: overlay=<x>:<y> donde <x>:<y> se calcula desde --pos y --margin
  • Audio: -c:a copy (sin tocar)
Argumento / OpciónDefaultOpciones / Notas
<input>requeridoVideo de entrada
<image>requeridoImagen de marca de agua (PNG con alfa recomendado)
--pos <position>bottom-righttop-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right
--margin <n>10Píxeles desde el borde elegido
-o, --output <path><input-stem>-watermarked.<ext>
bash
$ npx fqmpeg watermark input.mp4 logo.png --pos bottom-right --margin 10 --dry-run

  ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=W-w-10:H-h-10 -c:a copy input-watermarked.mp4

Se usa el tamaño nativo de la imagen — no hay --scale aquí. Si tu logo es muy grande, redimensiónalo antes con un editor o pre-procesa con ffmpeg -i logo.png -vf scale=120:-1 logo-small.png. Las posiciones centradas (top, bottom, center, left, right) calculan el offset desde el centro del cuadro, así que --margin solo afecta al eje perpendicular (ej. bottom usa el margen desde el borde inferior pero queda horizontalmente centrado independientemente del margen).

text — Dibujar texto / título sobre video

Quema un string de texto en una de siete posiciones predefinidas, con caja de fondo opcional y ventana de tiempo activable.

  • Fuente: src/commands/text.js
  • Filtro: drawtext=text='<escapado>':fontsize=N:fontcolor=C:<pos>[:box=1:boxcolor=...][:enable='...']
  • Auto-escape: ' y : del string de entrada se escapan antes de inlinear
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<string>requeridoTexto a dibujar (posicional, encierra los caracteres especiales del shell tú mismo)
--pos <position>centertop-left, top, top-right, center, bottom-left, bottom, bottom-right
--font-size <n>48Entero positivo
--color <name>whiteCualquier nombre de color FFmpeg o 0xRRGGBB
--bg <color>(ninguno)Color de la caja de fondo, ej. black@0.5 para opacidad 50%
--start <sec>(ninguno)Mostrar texto desde este tiempo
--end <sec>(ninguno)Ocultar texto después de este tiempo
-o, --output <path><input-stem>-text.<ext>
bash
$ npx fqmpeg text input.mp4 "Hola, Mundo" --pos top --font-size 64 --color yellow --bg black@0.5 --dry-run

  ffmpeg -i input.mp4 -vf "drawtext=text='Hola, Mundo':fontsize=64:fontcolor=yellow:x=(w-text_w)/2:y=20:box=1:boxcolor=black@0.5:boxborderw=8" -c:a copy input-text.mp4

Pasa strings con dos puntos y apóstrofes literales — --bg "black@0.5" y text "Time: 12:34" funcionan ambos sin escape manual. El boxborderw=8 (8 píxeles de padding dentro de la caja) está hardcodeado; si necesitas una caja más estrecha o más ancha, copia el --dry-run y edítalo. Para texto de varias líneas, drawtext de FFmpeg no envuelve — usa \n literal dentro del string y el filtro lo respetará en la mayoría de builds, pero el espaciado entre líneas puede requerir un line_spacing=N ajustado a mano (otra vez, copia el --dry-run).

--start y --end activan la visualización por ventana de tiempo vía la expresión enable de drawtext. Solo uno usa gte(t,N) o lte(t,N); ambos juntos producen between(t,A,B).

drawbox — Dibujar un rectángulo / borde sobre video

Dibuja un rectángulo (de contorno o relleno) en una posición fija. Útil para resaltar un área en un tutorial, censurar una región fija o marcar una grabación de pantalla.

  • Fuente: src/commands/drawbox.js
  • Filtro: drawbox=x=X:y=Y:w=W:h=H:color=C:t=T[:enable='...']
  • Formato de región: x:y:w:h regex estricto — cualquier otra cosa sale con Error: region must be x:y:w:h
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<region>requeridox:y:w:h en píxeles (origen arriba-izquierda)
--color <name>redNombre de color FFmpeg
--thickness <n>3Entero positivo, o el string literal fill para una caja sólida rellena
--start <sec>(ninguno)Mostrar desde este tiempo
--end <sec>(ninguno)Ocultar después de este tiempo
-o, --output <path><input-stem>-boxed.<ext>
bash
$ npx fqmpeg drawbox input.mp4 100:50:200:150 --color yellow --thickness fill --dry-run

  ffmpeg -i input.mp4 -vf drawbox=x=100:y=50:w=200:h=150:color=yellow:t=fill -c:a copy input-boxed.mp4

--thickness fill es el patrón de censura: caja de color sólido cubriendo la región. Para un highlight de solo contorno, usa un entero positivo (38 se lee bien en 1080p). Combina con --start/--end para resaltar solo los segundos donde algo importa en un tutorial. La región usa coordenadas absolutas en píxeles — si quieres un enfoque por porcentaje del cuadro, primero necesitas el tamaño del cuadro (npx fqmpeg info input.mp4).

timecode — Quemar código de tiempo / timestamp en vivo

Superpone la posición de reproducción actual como texto HH:MM:SS.mmm en una caja semitransparente negra en una esquina.

  • Fuente: src/commands/timecode.js
  • Filtro: drawtext=text='%{pts\\:hms}':fontsize=N:fontcolor=C:<pos>:box=1:boxcolor=black@0.5:boxborderw=4
  • Formato: %{pts:hms} — el formateador HMS built-in de FFmpeg (hardcodeado — no se exponen otros formatos)
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
--pos <position>top-lefttop-left, top-right, bottom-left, bottom-right (solo esquinas)
--font-size <n>24Entero positivo
--color <name>whiteColor FFmpeg
-o, --output <path><input-stem>-timecode.<ext>
bash
$ npx fqmpeg timecode input.mp4 --pos top-right --font-size 32 --dry-run

  ffmpeg -i input.mp4 -vf drawtext=text='%{pts\:hms}':fontsize=32:fontcolor=white:x=w-text_w-10:y=10:box=1:boxcolor=black@0.5:boxborderw=4 -c:a copy input-timecode.mp4

Útil para reels de revisión — los clientes citan tiempos del código quemado, así que feedback como "en 0:01:22.500 el corte queda duro" llega preciso. La caja negra está hardcodeada para legibilidad sobre fuentes brillantes. Si quieres un formato distinto (número de frame, código de tiempo de fuente, prefijo custom), usa text con las expresiones %{pts} / %{n} / %{localtime} de FFmpeg — mira video-info-overlay abajo para la variante multi-campo.

border — Marco decorativo alrededor del video

Aplica padding al cuadro por los cuatro lados con un color sólido, agrandando las dimensiones de salida en 2 * width por cada eje.

Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
--width <px>20Grosor del borde en píxeles (sumado a cada lado)
--color <name>whiteColor FFmpeg
-o, --output <path><input-stem>-bordered.<ext>
bash
$ npx fqmpeg border input.mp4 --width 30 --color black --dry-run

  ffmpeg -i input.mp4 -vf pad=iw+30*2:ih+30*2:30:30:color=black -c:a copy input-bordered.mp4

Las dimensiones de salida crecen — una fuente de 1920x1080 con --width 30 queda en 1980x1140. Algunas plataformas (posts cuadrados de Instagram, YouTube Shorts con aspect fijo) recortan tamaños no estándar, así que verifica el spec de destino antes de meter borde. Para un marco cuadrado alrededor de un clip vertical, calcula --width como la mitad de la diferencia entre el ancho de la fuente y el lado cuadrado deseado, y combina con crop antes para mejor control.

Composición Multi-Video

pip — Picture-in-picture

Escala un video "small" y lo superpone sobre un video "main" en una de cuatro esquinas.

  • Fuente: src/commands/pip.js
  • Filtro: [1]scale=iw*S:ih*S[pip];[0][pip]overlay=<xy>
  • Audio: Sin manejo explícito — el audio del video main pasa (comportamiento default de FFmpeg para el primer input)
Argumento / OpciónDefaultRangoNotas
<main>requeridoVideo de fondo
<small>requeridoVideo del overlay
--pos <position>bottom-righttop-left, top-right, bottom-left, bottom-right
--scale <n>0.250.11.0Tamaño del overlay relativo al main
--margin <n>10entero positivoPíxeles desde el borde
-o, --output <path><main-stem>-pip.<ext>
bash
$ npx fqmpeg pip main.mp4 webcam.mp4 --pos top-right --scale 0.3 --dry-run

  ffmpeg -i main.mp4 -i webcam.mp4 -filter_complex [1]scale=iw*0.3:ih*0.3[pip];[0][pip]overlay=main_w-overlay_w-10:10 main-pip.mp4

El uso clásico es una grabación de pantalla main con una face-cam small al 25% de escala en una esquina. La salida usa la duración del video main — si webcam.mp4 es más corto, se congela en su último frame; si es más largo, se corta. Para extender con el último frame del clip más corto, pre-procesa con tpad=stop_mode=clone o usa el verbo repeat-frame sobre el small input antes.

pip-grid — Layout en grid multi-input

Acomoda 2-9 videos en un grid (2x1, 1x2, 2x2, o 3x3). El layout se auto-detecta por la cantidad de inputs si --layout se omite.

  • Fuente: src/commands/pip-grid.js
  • Filtro: Por input scale=iw/cols:ih/rows, luego hstack por fila, después vstack de filas
  • Padding: Las ranuras vacías se rellenan repitiendo el último input
  • Audio: Copiado del input 0 (-c:a copy)
Argumento / OpciónDefaultNotas
<inputs...>requerido2-9 videos de entrada (posicional, variádico)
--layout <grid>auto2x1, 1x2, 2x2, 3x3. Auto: 2→2x1, 3-4→2x2, 5-9→3x3
-o, --output <path><input0-stem>-grid<layout>.<ext>
bash
$ npx fqmpeg pip-grid clip1.mp4 clip2.mp4 clip3.mp4 clip4.mp4 --layout 2x2 --dry-run

  ffmpeg -i clip1.mp4 -i clip2.mp4 -i clip3.mp4 -i clip4.mp4 \
    -filter_complex '[0:v]scale=iw/2:ih/2[v0];
                     [1:v]scale=iw/2:ih/2[v1];
                     [2:v]scale=iw/2:ih/2[v2];
                     [3:v]scale=iw/2:ih/2[v3];
                     [v0][v1]hstack=inputs=2[row0];
                     [v2][v3]hstack=inputs=2[row1];
                     [row0][row1]vstack=inputs=2[out]' \
    -map '[out]' -c:a copy clip1-grid2x2.mp4

Pasa 5 inputs a 3x3 y las ranuras 6-9 son clones del input 5 — útil para "5 tomas de una sola línea, grid de 9 para revisión", pero no esperado cuando pasas inputs de más / de menos accidentalmente. Usa --layout explícito si quieres 3x3 con esquinas vacías intencionales (tendrías que sumar videos de pantalla negra para llenarlos; fqmpeg no sintetiza espacios en blanco). Todos los inputs se escalan por iw/cols:ih/rows, así que aspect ratios distintos terminan estirados de forma no uniforme — pre-normaliza con resize o crop si te importa.

blend — Blend por opacidad de dos videos

Combina dos videos dibujando el segundo sobre el primero con un alfa configurable.

  • Fuente: src/commands/blend.js
  • Filtro: [1]format=yuva420p,colorchannelmixer=aa=O[over];[0][over]overlay
  • Audio: Re-encoded (sin -c:a copy explícito)
Argumento / OpciónDefaultRangoNotas
<input1>requeridoVideo base (debajo)
<input2>requeridoVideo overlay (arriba)
--opacity <n>0.501Alfa del input 2
-o, --output <path><input1-stem>-blend.<ext>
bash
$ npx fqmpeg blend input1.mp4 input2.mp4 --opacity 0.5 --dry-run

  ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex [1]format=yuva420p,colorchannelmixer=aa=0.5[over];[0][over]overlay input1-blend.mp4

Los dos videos tienen que coincidir espacialmente — blend superpone en 0:0, así que resoluciones distintas producen un compuesto desalineado. Redimensiona el overlay para que coincida con la base antes si hace falta. La duración de salida sigue el default de overlay de FFmpeg — generalmente la del más corto. Para efectos de "estela fantasma", --opacity 0.3-0.4. Por encima de 0.7 y el video base apenas se ve.

stack — Lado a lado o arriba/abajo

Une dos videos en un solo cuadro, horizontalmente (lado a lado) o verticalmente (arriba/abajo). Los dos videos tienen que coincidir en dimensiones del eje de unión (mismo alto para horizontal, mismo ancho para vertical).

  • Fuente: src/commands/stack.js
  • Filtro: [0:v][1:v]hstack=inputs=2 o vstack=inputs=2
  • Audio: -c:a copy (track del input 0)
Argumento / OpciónDefaultOpcionesNotas
<input1>requeridoVideo izquierdo/superior
<input2>requeridoVideo derecho/inferior
--direction <dir>horizontalhorizontal, vertical
-o, --output <path><input1-stem>-stacked.<ext>
bash
$ npx fqmpeg stack original.mp4 graded.mp4 --direction horizontal --dry-run

  ffmpeg -i original.mp4 -i graded.mp4 -filter_complex [0:v][1:v]hstack=inputs=2 -c:a copy original-stacked.mp4

El reel clásico de antes/después — color graded vs sin gradar, estabilizado vs fuente. Si los dos clips no coinciden en alto (para hstack), FFmpeg falla con Input 1 height 720 does not match input 0 height 1080. Pre-redimensiona el más chico con npx fqmpeg resize input.mp4 --height 1080. El audio viene solo del input1 — el del segundo video se descarta.

Imagen a Video

picture — Imagen fija + audio → video

Loopea una imagen fija por la duración de un archivo de audio y codifica el resultado como MP4. Uso común: convertir un episodio de podcast o una canción en un video subible a YouTube.

  • Fuente: src/commands/picture.js
  • Códec: libx264 + aac@192k + yuv420p + -tune stillimage + -shortest
  • Stem de salida: Derivado del nombre del audio (no de la imagen), como <audio-stem>-video.mp4
Argumento / OpciónDefaultNotas
<image>requeridoCover JPG / PNG
<audio>requeridoMP3 / WAV / etc.
-o, --output <path><audio-dir>/<audio-stem>-video.mp4Nota la fuente del stem
bash
$ npx fqmpeg picture cover.png episode.mp3 --dry-run

  ffmpeg -loop 1 -i cover.png -i episode.mp3 -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest episode-video.mp4

-tune stillimage le dice a x264 que optimice para contenido estático (calidad muy alta a bitrate muy bajo, ya que solo importa un frame). -shortest termina la salida cuando el input más corto termina — como la imagen looped es infinita, eso siempre es la duración del audio. El stem de salida espeja el nombre del audio, lo que matchea el flujo típico ("convertir este episodio en un video"). Si necesitas otro nombre, sobrescribe con -o.

Para un cover de podcast con marcadores de capítulos, corre picture primero y luego encadena embed-thumbnail y trabajos de metadata — fqmpeg los mantiene como verbos separados porque son decisiones independientes.

Overlays Analíticos

Estos verbos queman datos diagnósticos en el cuadro — útil para sesiones de QC, color correction, o para hacer un tutorial que muestre lo que está pasando frame a frame. No son para output de entrega final.

video-info-overlay — Número de frame, PTS, picture-type

Quema un overlay de texto por frame mostrando el índice (%{n}), el timestamp (%{pts:hms}) y el picture-type (%{pict_type} — I/P/B en H.264).

  • Fuente: src/commands/video-info-overlay.js
  • Filtro: drawtext=text='frame %{n} | pts %{pts\\:hms} | type %{pict_type}':x=10:y=10:fontsize=16:fontcolor=white:box=1:boxcolor=black@0.5
  • Posición, fuente, color: Todo hardcodeado (sin opciones)
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
-o, --output <path><input-stem>-info-overlay.<ext>
bash
$ npx fqmpeg video-info-overlay input.mp4 --dry-run

  ffmpeg -i input.mp4 -vf "drawtext=text='frame %{n} | pts %{pts\:hms} | type %{pict_type}':x=10:y=10:fontsize=16:fontcolor=white:box=1:boxcolor=black@0.5" -c:a copy input-info-overlay.mp4

Útil para QC ("este glitch está en el frame 4523, type P") y para mostrar la estructura del GOP visualmente en tutoriales. El overlay queda arriba-izquierda fijo a 16px — chico pero legible en 1080p. Para variantes con otro tamaño o reposicionadas, copia el --dry-run y edita, o arma una invocación custom con text y las mismas expresiones %{...}.

histogram-overlay — Overlay RGB / waveform / parade

Agrega un display de histograma 320x240 (o waveform/parade) en la esquina inferior derecha — útil para color correction donde quieres ver la distribución de niveles junto al cuadro.

  • Fuente: src/commands/histogram-overlay.js
  • Filtro (levels): split[main][hist];[hist]histogram,scale=320:240[h];[main][h]overlay=W-w-10:H-h-10
  • Filtro (waveform): split[main][wave];[wave]waveform=mode=column,scale=320:240[w];[main][w]overlay=W-w-10:H-h-10
  • Filtro (parade): split[main][par];[par]waveform=mode=column:display=parade,scale=320:240[p];[main][p]overlay=W-w-10:H-h-10
  • Posición y tamaño: Hardcodeados — abajo-derecha con margen de 10px, panel 320x240
Argumento / OpciónDefaultOpcionesNotas
<input>requeridoVideo de entrada
--mode <mode>levelslevels, waveform, parade
-o, --output <path><input-stem>-histogram.<ext>
bash
$ npx fqmpeg histogram-overlay input.mp4 --mode parade --dry-run

  ffmpeg -i input.mp4 -filter_complex split[main][par];[par]waveform=mode=column:display=parade,scale=320:240[p];[main][p]overlay=W-w-10:H-h-10 -c:a copy input-histogram.mp4

levels es el clásico histograma RGB de 256 bins. waveform muestra luma vs posición horizontal como un scope de columnas (estilo broadcast). parade es waveform separado por canal — tres columnas (R/G/B) lado a lado. Para revisión DIY de color grading donde quieres ver cómo cambia la distribución mientras hacés scrub, parade es lo más informativo.

progress — Barra de progreso ligada al tiempo

Quema una barra horizontal arriba o abajo del cuadro cuyo ancho crece linealmente de 0 al máximo conforme avanza el tiempo.

  • Fuente: src/commands/progress.js
  • Filtro: drawbox=x=0:y=<y>:w='iw*t/<duration>':h=H:color=C:t=fill
  • Por qué la duración es posicional: Las expresiones drawbox de FFmpeg pueden referenciar t (tiempo actual) pero no la duración total de la fuente — fqmpeg compensa horneando la duración en la fórmula
Argumento / OpciónDefaultNotas
<input>requeridoVideo de entrada
<duration>requeridoDuración total del video en segundos (mídela con npx fqmpeg duration input.mp4)
--pos <position>bottomtop, bottom
--color <name>redColor FFmpeg
--height <px>5Entero positivo
-o, --output <path><input-stem>-progress.<ext>
bash
$ npx fqmpeg progress input.mp4 90 --pos bottom --color cyan --height 8 --dry-run

  ffmpeg -i input.mp4 -vf drawbox=x=0:y=ih-8:w='iw*t/90':h=8:color=cyan:t=fill -c:a copy input-progress.mp4

Pasa la duración en segundos — 90 para 1m30s, 3600 para una hora. La barra llega al ancho completo exactamente en t = duration; si pasas una duración equivocada la barra se pasa o se queda corta. Wrapper típico de shell: dur=$(npx fqmpeg duration input.mp4) && npx fqmpeg progress input.mp4 $dur. Útil para tutoriales donde los espectadores quieren un indicador visual de cuánto queda.

Recetas del Mundo Real

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

Receta 1: Brandear un clip de YouTube

Tienes un video terminado y querés agregar marca de agua en una esquina, un título de apertura que se desvanezca después de 3 segundos y una barra de progreso fina abajo.

bash
# Step 1: marca de agua en esquina (PNG con alfa)
npx fqmpeg watermark final.mp4 logo.png --pos bottom-right --margin 20
# → final-watermarked.mp4

# Step 2: título de apertura mostrado los primeros 3 segundos
npx fqmpeg text final-watermarked.mp4 "Episodio 12 — Color Grading" \
  --pos top --font-size 56 --color white --bg "black@0.5" \
  --start 0 --end 3
# → final-watermarked-text.mp4

# Step 3: barra de progreso fina (asumiendo episodio de 8 minutos = 480s)
npx fqmpeg progress final-watermarked-text.mp4 480 --pos bottom --color "white@0.6" --height 4
# → final-watermarked-text-progress.mp4

Tres pasadas significan tres rondas de re-encoding H.264, lo cual es tolerable pero suma pérdida generacional. Si quieres una sola pasada, copia los tres strings de filtro de las salidas --dry-run y ensámblalos con ;/, en una sola invocación de FFmpeg. Para reruns frecuentes (un podcast semanal), el flujo de tres pasos está bien — la conveniencia le gana al drop de calidad despreciable.

Receta 2: Reel de comparación lado a lado con timecode

Querés mostrar un "antes/después" de un clip color graded, con un overlay de timecode para que los reviewers puedan referir momentos exactos.

bash
# Step 1: stack de los dos clips horizontalmente (deben coincidir en alto)
npx fqmpeg stack original.mp4 graded.mp4 --direction horizontal
# → original-stacked.mp4 (3840x1080 para dos fuentes 1920x1080)

# Step 2: quema timecode arriba a la izquierda como referencia
npx fqmpeg timecode original-stacked.mp4 --pos top-left --font-size 32
# → original-stacked-timecode.mp4

# Step 3 (opcional): etiquetar cada lado con un overlay de texto estático
npx fqmpeg text original-stacked-timecode.mp4 "ORIGINAL          GRADED" \
  --pos bottom --font-size 48 --color white --bg "black@0.5"

El truco de la etiqueta en el step 3 usa espacios para empujar "GRADED" al lado derecho — burdo pero efectivo. Para etiquetas pixel-perfect correrías dos invocaciones de text con posiciones custom (copia el --dry-run y reemplaza el x= derivado de --pos con coordenadas absolutas).

Receta 3: Documentar una grabación de pantalla con face-cam y progreso

Tienes una grabación de pantalla de 12 minutos (screen.mp4) y una webcam (webcam.mp4) y querés un deliverable de tutorial: face-cam en la esquina, barra de progreso ligada al tiempo y un título semi-transparente en los primeros 5 segundos.

bash
# Step 1: face-cam picture-in-picture
npx fqmpeg pip screen.mp4 webcam.mp4 --pos bottom-right --scale 0.2 --margin 20
# → screen-pip.mp4

# Step 2: barra de progreso (12 minutos = 720 segundos)
npx fqmpeg progress screen-pip.mp4 720 --pos top --color "red@0.7" --height 6
# → screen-pip-progress.mp4

# Step 3: título de apertura
npx fqmpeg text screen-pip-progress.mp4 "Configurando Vercel + Next.js" \
  --pos center --font-size 64 --color white --bg "black@0.7" \
  --start 0 --end 5
# → screen-pip-progress-text.mp4

Si la webcam tiene un aspect ratio distinto al screen capture (webcam cuadrada, pantalla 16:9), el overlay pip escala relativo a las dimensiones del video main — un 0.2 de escala en una pantalla de 1920 de ancho produce un overlay de 384 de ancho independientemente de las dimensiones de la fuente del webcam. Para preservar el aspecto propio de la webcam, pre-procésala con npx fqmpeg crop webcam.mp4 ... antes del paso pip.

Preguntas Frecuentes

¿Cómo paso dos puntos o apóstrofes dentro de un string de text?

Inclúyelos tal cual — npx fqmpeg text input.mp4 "Time: it's 12:34" funciona. El wrapper de fqmpeg escapa : y ' antes de inlinearlos en el filtro drawtext de FFmpeg (' queda como '\\\\'' y : como \:). No necesitas escapar nada tú salvo los caracteres especiales del shell (las comillas que rodean el string en tu shell ya lo manejan).

pip-grid aceptó mis 5 inputs y la fila de abajo está duplicada — ¿es lo previsto?

Sí — cuando la cantidad de inputs no llena el grid, fqmpeg rellena las ranuras vacías con el último input. Pasa 5 a un 3x3 (auto-detectado) y las ranuras 6-9 son clones del input 5. Para usar 2x2 con 4 inputs (saltando el padding), pasa 4 inputs (auto-detecta 2x2) o especifica --layout 2x2 explícito. Para dejar ranuras vacías a propósito, suministra un input de pantalla negra — fqmpeg no sintetiza uno por ti.

progress requiere una duración — ¿por qué no la auto-detecta?

La expresión del filtro drawbox de FFmpeg puede referenciar t (tiempo actual del frame en curso) pero no tiene expresión built-in para "duración total de la fuente". Las únicas formas de meter la duración total en el filtro son (1) hornearla como número literal, que es lo que hace fqmpeg; (2) sondear la fuente antes, lo que significaría correr ffprobe desde dentro del wrapper JS — fqmpeg mantiene los verbos single-purpose y no sondea de forma transparente. Usa dur=$(npx fqmpeg duration input.mp4) y luego pasa $dur como argumento.

¿Qué diferencia hay entre watermark y picture?

watermark superpone una imagen estática sobre un video existente — el input es un video y la marca de agua es una imagen pequeña. picture hace lo opuesto — crea un video a partir de una imagen fija y una pista de audio (loopeando la imagen por toda la duración del audio). Comparten plumbing interno de libavfilter pero resuelven problemas distintos: branding (watermark) vs creación de video desde una sola imagen (picture).

¿Puedo cambiar la posición o el tamaño del panel de histogram-overlay?

No vía las flags de fqmpeg — ambas están hardcodeadas (overlay=W-w-10:H-h-10 para abajo-derecha con margen de 10px, size=320x240). Para un layout custom, copia el string de filtro del --dry-run y edita los parámetros overlay=... y size=... antes de correr FFmpeg directamente. Edits comunes: overlay=10:H-h-10 para abajo-izquierda, size=480x270 para un panel más grande.

stack falló con "Input 1 height ... does not match" — ¿y ahora?

hstack requiere que todos los inputs compartan el mismo alto; vstack requiere el mismo ancho. Pre-redimensiona el input que no coincide: npx fqmpeg resize smaller.mp4 --height 1080 (igualando el alto del otro clip). Si los aspect ratios difieren y no querés cropear, paddea con pad primero para igualar dimensiones y luego apila — usar border es un workaround rápido ya que agrega un marco de ancho configurable a cada lado.

Agregar un border me deja un tamaño de salida no estándar — ¿importa?

Sí, en plataformas con requisitos estrictos de aspect ratio (posts cuadrados de Instagram a 1:1, YouTube Shorts a 9:16). Una fuente 1920x1080 con --width 30 queda en 1980x1140, que la mayoría de players letterboxean y algunas redes sociales recortan. Dos workarounds: (1) usa crop primero para encoger el video interno y luego border para volver al tamaño original; (2) dejá que la plataforma haga lo suyo y aceptá que el borde puede ser cropeado o letterboxed.

¿Puedo evitar la pérdida generacional de H.264 al encadenar varios verbos overlay?

Cada invocación de fqmpeg re-encodea — la pérdida se acumula. Dos formas de mitigarla: (1) sube la calidad intermedia a -crf 18 o lossless editando el output de --dry-run; (2) baipasea fqmpeg para la cadena combinando los strings de filtro de cada --dry-run en una sola invocación de FFmpeg con -vf "filter1,filter2,filter3" (o -filter_complex si algún verbo usa varios inputs). Para 2-3 pasadas la pérdida rara vez se nota en contenido real; para 5+ pasadas suma.

Conclusión

Los 13 verbos de C8 cubren las operaciones de composición que usás después de editar pero antes del output final:

  • Gráficos y texto estático (watermark, text, drawbox, timecode, border) — quemar logos, títulos, highlights, timestamps, marcos
  • Composición multi-video (pip, pip-grid, blend, stack) — picture-in-picture, grids de 2-9 inputs, blends por opacidad, stacks antes/después
  • Imagen a video (picture) — promover una imagen fija + audio a un MP4 reproducible
  • Overlays analíticos (video-info-overlay, histogram-overlay, progress) — quemar metadata de frame, scopes de color y progreso del tiempo para revisión

Cada verbo imprime su invocación FFmpeg subyacente bajo --dry-run, así que cuando los defaults de fqmpeg no encajan (una posición custom de histogram-overlay, un formato custom de drawtext, una cadena multi-filtro de una sola pasada para evitar pérdida generacional), copia el comando, persónalízalo y corre FFmpeg directo. Para el mapa más amplio de fqmpeg, ve la guía completa de fqmpeg.