![Extraiga fotogramas con precisión cada N segundos usando FFmpeg](https://rvso.com/image/1672321/Extraiga%20fotogramas%20con%20precisi%C3%B3n%20cada%20N%20segundos%20usando%20FFmpeg.png)
El uso
Extraigo imágenes de vídeos usando ffmpeg
.
Descargo una imagen reducida cada 10 segundos, inclusive, que combino en montajes con imagemagick
. Estos montajes nuevamente se utilizan para mostrar una vista previa del video cuando se coloca el cursor sobre un reproductor de video basado en la web. (Calculando qué imagen del montaje mostrar).
El comando
Después de jugar, terminé con el siguiente comando donde la idea es velocidad sobre calidad:
ffmpeg \
-loglevel error \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$video_file" \
-r 0.1 \
-filter:v "scale_cuda=w=-1:h=100,thumbnail_cuda=2,hwdownload,format=nv12" \
-color_range 2 \
f%09d.jpg
Esto pareció funcionar bien. Los disparos están desviados entre ± 0,5 y 1 segundo aquí y allá, pero eso es soportable.
El problema
El problema es que ffmpeg
produce una imagen adicional al inicio de los videos. Por ejemplo, los archivos son:
file time
f000000001.jpg 00:00:00
f000000002.jpg 00:00:00
f000000003.jpg 00:00:10
f000000004.jpg 00:00:20
f000000005.jpg 00:00:30
...
A veces, el primero y el segundo tienen una diferencia de unos pocos milisegundos.
Tal como lo sé (ahora), puedo simplemente eliminar la primera imagen y continuar con el resto, pero no estoy seguro de por qué sucede esto y si se trata de un error o algo más.
Dicho de otra manera: necesito saber si el "efecto" de los dos primeros fotogramas esconfiablepara poder eliminarlo ffmpeg
también en otras versiones.
Como uso las imágenes para mostrar 10 seg. instantánea del vídeo en un momento específicoestá apagado por 10 segundossi no elimino la primera imagen generada. Si por alguna razón debería entoncesnocree una copia al inicio, otra versión o lo que sea, eliminar la primera imagen crearía el mismo problema.
Montaje
(Si es de interés los montajes se crean algo así como):
montage -tile 5x -geometry +0+0 -background none [file1 - file50 ] montage01.jpg
montage -tile 5x -geometry +0+0 -background none [file51 - file100] montage02.jpg
...
Comando que uso ahora según la respuesta (shell):
# Set on call or global:
file_in=sample.mp4
pix_fmt=yuvj420p
sec_snap_interval=10
nr_start=1
pfx_out=snap
ffmpeg \
-loglevel warning \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$file_in" \
-pix_fmt "$pix_fmt" \
-filter:v "
scale_cuda=
w = -1 :
h = 100,
thumbnail_cuda = 2,
hwdownload,
format = nv12,
select = 'bitor(
gte(t - prev_selected_t, $sec_snap_interval),
isnan(prev_selected_t)
)'
" \
-vsync passthrough \
-color_range 2 \
-start_number "$nr_start" \
"$pfx_out%09d.jpg"
Respuesta1
El uso -r 0.1
establece la velocidad de fotogramas de salida en 0,1 Hz, pero no se garantiza que se obtengan fotogramas del vídeo de entrada exactamente cada 10 segundos (no estoy seguro de por qué).
Una forma de resolverlo es usandoseleccionar filtro.
Ejemplo (sin aceleración de GPU):
ffmpeg -i input.mp4 -vf "select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" -vsync 0 f%09d.jpg
bitor(gte(t-prev_selected_t\,10)
es1
cuando la diferencia entre las marcas de tiempo "aprobadas" es mayor que 10 segundos.
Cuando la expresión se evalúa como1
, el marco se "selecciona" y se pasa a la salida.bitor
withisnan(prev_selected_t)
pasa el primer fotograma, dondeprev_selected_t
estáNaN
(no tiene valor).-vsync 0
aplica "paso a través": cada cuadro se pasa con su marca de tiempo del demuxer al muxer.
Aquí hay un ejemplo con scale_cuda
y thumbnail_cuda
:
ffmpeg \
-loglevel error \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$video_file" \
-filter:v "scale_cuda=w=-1:h=100,thumbnail_cuda=2,hwdownload,format=nv12,select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" \
-vsync 0 \
-color_range 2 \
f%09d.jpg
- Debido al uso de
thumbnail_cuda
filtro, tenemos que colocar elselect
filtro al final.
Pruebas:
cree vídeo sintético con contador de fotogramas a 10 fps:
ffmpeg -y -f lavfi -r 10 -i testsrc=size=128x72:rate=1:duration=1000 -vf setpts=N/10/TB -vcodec libx264 -pix_fmt yuv420p input.mp4
Marcos de salida después de ejecutar el comando anterior:
Como puede ver, los cuadros seleccionados son exactamente cada 10 segundos.