Concatenar vídeos con ffmpeg no da siempre los resultados esperados, depende de la versión, de los codecs instalados y varios factores que pueden hacer que el script que en un equipo funciona perfectamente, en otro ordenador no funcione tan bien.
Lo que nunca falla es ImageMagick -sic-. Así pues, voy a comentar un script que funcionaría, o debería funcionar, en todos los sistemas:
El objetivo es el mismo que el del artículo sobre cómo componer vídeos con fotografías y sonido:
Un script que reciba un fichero de audio como parámetro, por ejemplo un podcast, aunque podría ser cualqueir otro fichero de audio, con una duración variable y que se genere un vídeo con unos elementos básicos para un vídeo de YouTube:
- Entradilla
- Una imagen principal que se intercale con una cartela con las redes sociales o cualquier otra imagen, por ejemplo, una llamada a la acción de suscribirse al canal o cualquier otra imagen.
- Pantalla final
La imagen de la llamada a la acción o las redes sociales podría ser también una animación o una secuencia de vídeo. Su adaptación simplemente sería cambiar la imagen fija por un vídeo y copiar la parte de la entradilla. De hecho, si he combinado vídeo con imagen fija ha sido precisamente para que este script pueda ser germen para otras adaptaciones.
Y, de paso, ver en acción el contenido explicado en otros artículos:
- Recorrer un directorio con head y tail
- Saber la duración de un vídeo o audio y usarlo en un shell script
- Componer un vídeo con ffmpeg a partir de fotogramas generados con ImageMagick
- Trabajar con funciones y parámetros en shell script
- Que ImageMagick sirve para multitud de propósitos, no únicamente escalar imágenes o ponerles una marca de agua
La explicación del código está en estos artículos. El resto, en los comentarios del script:
#!/bin/bash
function numerodesegundos()
{
let horasdeaudio=${1:0:2}
let minutosdeaudio=${1:3:2}
let segundosdeaudio=${1:6:2}
echo $[ ($horasdeaudio*60*60) + ($minutosdeaudio*60) + $segundosdeaudio ]
}
function compruebaentradilla()
{
# Comprueba si la entradilla tiene su directorio
# y están los fotogramas desmontados ahí.
#
# Si no lo está, crea el directorio y
# desmonta los fotogramas de la entradilla
if [ ! -d $directorioentradilla ]
then
mkdir $directorioentradilla
ffmpeg -i $entradilla $directorioentradilla/fotograma%04d.png
else
let contenido=$(ls $directorioentradilla | wc -l)
if [ $contenido -eq 0 ]
then
ffmpeg -i $entradilla $directorioentradilla/fotograma%04d.png
fi
fi
fotogramasentradilla=$(ls $directorioentradilla | wc -l)
echo $fotogramasentradilla
}
# Extrae el nombre del fichero de audio pasado como parámetro quitando la extensión
sinextension=${1%.*}
# Calcula la duración del audio del fichero pasado como argumento
duracion=$(./vinfo.sh duration $1)
# Ficheros auxiliares
entradilla="entradilla.mp4"
directorioentradilla="entradilla"
imagenprincipal="fondopodcast.png"
redessociales="redessociales.png"
pantallafinal="pantallafinal.png"
# Calcula la duración en segundos del audio y el número de fotogramas necesarios para el vídeo
segundosdeaudio=$(numerodesegundos $duracion)
let totalfotogramas=$segundosdeaudio*24
fotogramasentradilla=$(compruebaentradilla)
# Calcula la duración de la entradilla
duracionentradilla=$(./vinfo.sh duration $entradilla)
segundosentradilla=${duracionentradilla:6:2}
# Calcula cuánto duran los contenidos extras con dos cortes para la cartela de redes sociales
let duracionextras=$segundosentradilla+5+5+20
# Calcula la diferencia entre los segundos de audio del fichero parámetro y los extras
let tiempototalarellenar=$segundosdeaudio-$duracionextras
# Como vamos a hacer dos cortes para la cartela de redes sociales, divide el tiempo entre 3
let tercio=$tiempototalarellenar/3
let fotogramastercio=$tercio*24
##############################################################################
#
# Los bloques de imágenes quedarán así:
# Entradilla -> del fotograma 1 hasta que se acaben los fotogramas de la entradilla
# Imagen Principal -> desde último fotograma entradilla + 1 hasta un tercio de los fotogramas restantes más
# Cartela Redes Sociales: 5 segundos x 24 fotogramas = 120 fotogramas
#
# Nuevo bloque de: Imagen principal + cartela redes sociales + imagen principal
# Este bloque hay que repetirlo a mano, con un while que compruebe los bloques
# no funciona el convert imagen.png png:- para pasárselo a ffmpeg
#
# Pantalla final: 20 segundos x 24 fotogramas = 480 fotogramas
#
##############################################################################
contador=1
let fotogramasredessociales=120
let fotogramaspantallafinal=480
# Calcula los finales de los bloques:
let finprimerbloque=$fotogramasentradilla+1+$fotogramastercio
let finsegundobloque=$finprimerbloque+1+$fotogramastercio
let fintercerbloque=$finsegundobloque+1+$fotogramasredessociales
let fincuartobloque=$fintercerbloque+1+$fotogramastercio
let finquintobloque=$fincuartobloque+1+$fotogramasredessociales
let finsextobloque=$finquintobloque+1+$fotogramastercio
let finseptimobloque=$finsextobloque+1+$fotogramaspantallafinal
for i in $(seq 1 $totalfotogramas)
do
if [ $contador -le $fotogramasentradilla ]
then
imagen=$(ls $directorioentradilla | head -n $contador | tail -n 1)
let contador++
elif [ $contador -gt $fotogramasentradilla ] && [ $contador -le $finprimerbloque ]
then
imagen=$imagenprincipal
let contador++
elif [ $contador -gt $finprimerbloque ] && [ $contador -le $finsegundobloque ]
then
imagen=$redessociales
let contador++
elif [ $contador -gt $finsegundobloque ] && [ $contador -le $fintercerbloque ]
then
imagen=$imagenprincipal
let contador++
elif [ $contador -gt $fintercerbloque ] && [ $contador -le $fincuartobloque ]
then
imagen=$redessociales
let contador++
elif [ $contador -gt $fincuartobloque ] && [ $contador -le $finquintobloque ]
then
imagen=$imagenprincipal
let contador++
elif [ $contador -gt $finquintobloque ] && [ $contador -le $finsextobloque ]
then
imagen=$imagenprincipal
let contador++
elif [ $contador -gt $finsextobloque ] && [ $contador -le $finseptimobloque ]
then
imagen=$pantallafinal
let contador++
fi
convert $imagen png:-
done | ffmpeg -f image2pipe -i - pistadevideo.mp4
ffmpeg -i pistadevideo.mp4 -i $1 -c:v copy -c:a copy $sinextension.mp4
rm pistadevideo.mp4