Hola, necesito extraer fotogramas de videos usando ffmpeg. ¿Hay una forma más rápida de hacerlo que esta?
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Hola, necesito extraer fotogramas de videos usando ffmpeg. ¿Hay una forma más rápida de hacerlo que esta?
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Respuestas:
Si el paso de codificación JPEG requiere demasiado rendimiento, siempre puede almacenar los fotogramas sin comprimir como imágenes BMP:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
Esto también tiene la ventaja de no incurrir en una mayor pérdida de calidad a través de la cuantificación mediante la transcodificación a JPEG. (PNG tampoco tiene pérdida, pero tiende a tardar mucho más en codificarse que JPEG)
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
, verdad? (te faltaba el -i
)
Encontré esta pregunta, así que aquí hay una comparación rápida. Compare estas dos formas diferentes de extraer un fotograma por minuto de un video de 38 min 07 s de duración:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1 min 36,029 s
Esto lleva mucho tiempo porque ffmpeg analiza todo el archivo de vídeo para obtener los fotogramas deseados.
time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4 -frames:v 1 period_down_$i.bmp ; done
0 min 4.689 s
Esto es aproximadamente 20 veces más rápido. Usamos la búsqueda rápida para ir al índice de tiempo deseado y extraer un marco, luego llamamos a ffmpeg varias veces para cada índice de tiempo. Tenga en cuenta que -accurate_seek
es el predeterminado
y asegúrese de agregar -ss
antes de la -i
opción de video de entrada .
Tenga en cuenta que es mejor usarlo en -filter:v -fps=fps=...
lugar de -r
ya que este último puede ser inexacto. Aunque el boleto está marcado como fijo , todavía experimenté algunos problemas, así que es mejor ir a lo seguro.
bc
no es un paquete de Ubuntu nativo, en lugar uno puede usar bash: let "i = $i * 60"
. Por cierto - excelente idea
-ss
antes -i
. De lo contrario, se decodificará todo el video y se descartarán los fotogramas no necesarios
ffmpeg
por núcleo de su host, lo que (para bmp) produce mejoras casi lineales en la velocidad (hasta que llega a algún otro cuello de botella, como el disco).
Si sabe exactamente qué fotogramas extraer, por ejemplo, 1, 200, 400, 600, 800, 1000, intente usar:
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
-vsync vfr -q:v 2
Estoy usando esto con una tubería para el montaje de Imagemagick para obtener una vista previa de 10 cuadros de cualquier video. Obviamente, los números de fotogramas que necesitará averiguar usandoffprobe
ffmpeg -i myVideo.mov -vf \
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)',scale=320:-1 \
-vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \
| montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png
.
Pequeña explicación:
+
representan OR y *
AND\,
es simplemente escapar del ,
personaje-vsync vfr -q:v 2
él no parece funcionar, pero no sé por qué, ¿alguien?Lo intenté. 3600 fotogramas en 32 segundos. tu método es realmente lento. Deberías probar esto.
ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
ffmpeg -i "input URL" -vf fps=1/5 out%d.png
que la URL de entrada sea un enlace https.
ffmpeg -i file.mpg -vf fps=1 %d.jpg
En mi caso, necesito fotogramas al menos cada segundo. Usé el enfoque de 'buscar' anterior, pero me pregunté si podría paralelizar la tarea. Utilicé los procesos N con enfoque FIFO aquí: /unix/103920/parallelize-a-bash-for-loop/216475#216475
open_sem(){
mkfifo /tmp/pipe-$$
exec 3<>/tmp/pipe-$$
rm /tmp/pipe-$$
local i=$1
for((;i>0;i--)); do
printf %s 000 >&3
done
}
run_with_lock(){
local x
read -u 3 -n 3 x && ((0==x)) || exit $x
(
"$@"
printf '%.3d' $? >&3
)&
}
N=16
open_sem $N
time for i in {0..39} ; do run_with_lock ffmpeg -ss `echo $i` -i /tmp/input/GOPR1456.MP4 -frames:v 1 /tmp/output/period_down_$i.jpg & done
Esencialmente bifurqué el proceso con & pero limité el número de subprocesos concurrentes a N.
Esto mejoró el enfoque de 'buscar' de 26 segundos a 16 segundos en mi caso. El único problema es que el hilo principal no sale limpiamente de regreso a la terminal ya que stdout se inunda.
Esto funcionó para mi
ffmpeg -i file.mp4 -vf fps=1 %d.jpg