¿Cómo aparecer/desaparecer un clip de video/audio con una duración desconocida?

Estoy trabajando en un proyecto en el que estoy usando ffmpeg para convertir por lotes algunos archivos de video y agregar efectos de entrada/salida graduales al principio y al final de cada clip.

He estado usando este fragmento de código para agregar el efecto de desvanecimiento/desaparición en clips con duraciones conocidas:

ffmpeg -i clip.mp4 -filter:v 'fade=in:0:30,fade=out:9650:30' -c:v libx264 -crf 22 -preset veryfast -c:a copy fadeInOut.mp4

Mis dos preguntas son:

  1. ¿Cómo puedo hacer un fundido de entrada/salida de audio simultáneamente?
  2. ¿Puede ffmpeg calcular automáticamente la duración del clip y recibir el aviso de atenuación de los últimos 30 fotogramas?

¡Gracias!

Respuestas (3)

#1 Para atenuar simultáneamente la entrada/salida de audio:

ffmpeg -i clip.mp4 -vf 'fade=in:0:30,fade=out:960:30'
                   -af 'afade=in:st=0:d=1,afade=out:st=32:d=1'
       -c:v libx264 -crf 22 -preset veryfast fadeInOut.mp4

Los tiempos de afade son en segundos .

#2 ¿Automáticamente? No. Pero vea la solución a continuación

Primero puede ejecutar ffprobe para obtener la duración.

ffprobe -i clip.mp4 -show_entries stream=codec_type,duration -of compact=p=0:nk=1

Obtendrás algo como esto:

video|13.556000
audio|13.816000

Luego puede usar lo anterior para colocar sus fundidos. Estos tiempos son en segundos.

Solución alterna

ffmpeg -i clip.mp4 -sseof -1 -copyts -i clip.mp4 -filter_complex
       "[1]fade=out:0:30[t];[0][t]overlay,fade=in:0:30[v];
        anullsrc,atrim=0:2[at];[0][at]acrossfade=d=1,afade=d=1[a]"
       -map "[v]" -map "[a]" -c:v libx264 -crf 22 -preset veryfast -shortest fadeInOut.mp4

FFmpeg tiene una sseofopción que permite buscar una entrada desde el final. Podemos usar eso para lograr nuestro objetivo. Entonces alimentamos la entrada dos veces, y la segunda vez ingiere solo el último segundo. Le decimos a FFmpeg que conserve las marcas de tiempo, de modo que ffmpeg conserve la posición temporal de esta parte de la cola.

Aplicamos un desvanecimiento a esta cola y luego superponemos el resultado en la entrada completa. Dado que son el mismo archivo multimedia, el primer plano cubre completamente el fondo y, desde que copytsse aplicó, la superposición se produce en el marco idéntico correspondiente en la entrada de fondo.

Para el audio, creamos un audio ficticio en blanco de 2 segundos de duración y luego aplicamos un fundido cruzado de audio desde el audio principal a este audio ficticio. Dado que el segundo audio está en blanco, esto es, en efecto, un fundido de salida para la entrada principal. Se -shortestagrega para omitir partes del audio ficticio después de que se haya producido el fundido cruzado.

Esto da el error "¡no hay tal filtro!" para el filtro de audio.
Se utilizan 4 filtros de audio. ¿Cuál? Ejecute su comando con -reportagregado y comparta el informe.

Es un truco terrible, pero esto podría funcionar si todo lo que quieres hacer es el audio de entrada/salida gradual pero no sabes exactamente cuánto dura el clip:

ffmpeg -i input.mp4 -filter_complex "afade=d=0.5, areverse, afade=d=0.5, areverse" output.mp4

[editar 2019-07-24: tenga en cuenta que esta solución no es buena para las soluciones de transmisión, ya que requiere que se procese la pista completa antes de que se pueda transmitir el primer byte]

otra opción que es usar acrossfadecon una pista silenciosa:

ffmpeg -i input.mp4 -filter_complex "aevalsrc=0:d=0.6 [a_silence]; [0:a:0] [a_silence] acrossfade=d=0.6" output.mp4
Esto es realmente bastante elegante :-)
esto funciona muy bien podrias explicar como funciona tratando de dar sentido a la documentación ...
@oberhamsi: Opción 1: el primer filtro agrega un fundido al comienzo de la pista. Luego invierte el audio y agrega otro fundido de entrada al principio (que en realidad es el final). Finalmente la pista se invierte de nuevo. La opción 2 crea una pista silenciosa de 0,6 segundos y la fusiona durante la misma cantidad de tiempo con la pista original. Todos los filtros y su uso están documentados aquí: ffmpeg.org/ffmpeg-filters.html (aunque debo admitir que es un poco críptico)
¿Cuál sería la secuencia de comandos para fusionar Video + Audio (el audio es más largo) y tener un fundido de entrada y nuestro para el audio (digamos que el fundido de entrada termina después de 2 segundos, el fundido de salida comienza en 48 y termina en 51)?

La respuesta a la pregunta 2 es un rotundo ¡SÍ! Estaba buscando la misma funcionalidad y terminé escribiendo un script de bash que solicita la duración del desvanecimiento en segundos y calcula el cuadro inicial para el desvanecimiento:

#!/bin/bash

f="$*" # all args
p="${f##*/}" # file
fn="${p%.*}" # name only
e="${p##*.}" # extension

echo
echo $f
echo $p
echo $fn
echo $e
echo

read -e -p "Number of seconds of fade-out: " -i 1 sec # prompt for fade duration in seconds

r=$(ffprobe -show_streams "$f" 2> /dev/null | grep r_frame_rate | head -1 | cut -d \= -f 2) # frame rate
let "frames = $r * $sec" # duration of fade as number of frames
echo $r
echo $sec
echo $frames
lf=$(ffprobe -show_streams "$f" 2> /dev/null | grep nb_frames | head -1 | cut -d \= -f 2) # total number of frames
let "lf = $lf - $frames" # initial frame to start fade at

ffmpeg -loglevel quiet -i "$f" -vf fade=out:$lf:$frames -r $r -vcodec libx264 -preset slow -crf 12 -bf 2 -flags +cgop -pix_fmt yuv420p -acodec copy "$fn $sec sec fade-out.$e"
open "$fn $sec sec fade-out.$e"

Los fundidos requieren una nueva codificación, por lo que usar un crfvalor bajo para libx264da una nueva codificación de alta calidad. Los comentarios deben explicar todo lo demás.

La respuesta a la pregunta 2 es un rotundo ¡SÍ! --> sigue siendo No. La Q es ¿Puede ffmpeg calcular automáticamente la duración... pero ha escrito un script que ejecuta varios comandos ff* para hacerlo? Sin embargo, es útil para sistemas *nix.
Ya veo, ¿así que insistes en que TU respuesta AÚN es correcta? Si sigue mi secuencia de comandos, verá que efectivamente automatically figure out the durationusa ffprobe, que se instala con ffmpeg. ¿Quién dijo algo sobre alguna restricción en el número de comandos o *nix? Parece que el OP está usando una versión de UNIX. No .exeen el ffmpegcomando. Yo mismo estoy usando OS Xel cual está construido UNIXpero no lo está UNIX.
* Si sigue mi secuencia de comandos, verá que, de hecho, se da cuenta automáticamente * --> su secuencia de comandos sí, ffmpeg no.
Pero ffprobees una parte integral de la ffmpegdistribución. Estás picando liendres para salvar la cara, en mi opinión.
Tendría que estar de acuerdo en que algo que hace un script bash no es algo que hace automáticamente ffmpeg. Pero si esto funciona, esta es una forma de evitar ese problema. De ahí el término "solución alternativa". No puedo decir si funciona porque yo, como la mayoría de la gente, no tengo un sistema bash o unix. +1 por el esfuerzo de todos modos.