ffmpeg extrae imágenes de varios puntos de tiempo seleccionados

ffmpeg extrae imágenes de varios puntos de tiempo seleccionados

Tengo un archivo de video y me gusta extraer una sola imagen de (aproximadamente 1500) puntos de tiempo específicos (expl. -ss 00:50, ss 00:67, ss: 01:70...)

¿Hay alguna forma de hacer esto? Intenté usar este comando:

ffmpeg.exe -ss 00:50 -i all.avi -t 00:00:01 -vframes 1 images-filename_%03d.png

Esto funciona muy bien para una sola imagen, pero ¿hay alguna manera de hacerlo para tantos puntos de tiempo específicos?

¿Alguien tiene un consejo?

Respuesta1

Esta respuesta mejora@slhck'srespuesta, que puede no funcionar en algunas situaciones.

Una sutileza al seleccionar cuadros por marca de tiempo (aproximada) es que la marca de tiempo real del cuadro puede no ser exactamente igual a la marca de tiempo deseada. Por ejemplo, en un vídeo con una velocidad de fotogramas de 23,98 (24000/1001) no hay ningún fotograma con marca de tiempo 1,0; el fotograma más cercano tiene un valor de marca de tiempo de 1,001.

La expresión eq(t, specific_timepoint)se evalúa como verdadera sólo si tes exactamente igual a specific_timepoint. Por lo tanto, no podrá seleccionar un marco en la situación descrita anteriormente. Como solución alternativa, podemos seleccionar el primer cuadro inmediatamente después de la marca de tiempo deseada, es decir, el cuadro cuyo valor de marca de tiempo es mayor o igual al punto de tiempo especificado, mientras que la marca de tiempo del cuadro anterior era menor que el punto de tiempo especificado. La expresión de selección para un único punto de tiempo será

lt(prev_pts * TB,timepoint) * gte(pts * TB,timepoint)

Tenga en cuenta que deliberadamente no utilicé una variante más corta.

between(timepoint, prev_pts*TB, pts*TB)

que es equivalente a

lte(prev_pts * TB,timepoint) * gte(pts * TB,timepoint)

ya que seleccionaría dos fotogramas consecutivos cuando el valor de marca de tiempo de (el primero) uno de elloscoincide exactamenteel valor del punto de tiempo especificado.

Ejemplo de selección de los cuadros correspondientes o inmediatamente posteriores a los puntos de tiempo 1.5, 10 y 20:

ffmpeg -i input.mp4 -filter:v \
    "select='lt(prev_pts*TB\,1.5)*gte(pts*TB\,1.5) \
            +lt(prev_pts*TB\,10)*gte(pts*TB\,10)   \
            +lt(prev_pts*TB\,20)*gte(pts*TB\,20)'" \
    -vsync drop images-filename_%03d.png

Respuesta2

Agregue varias marcas de tiempo como opciones para el selectfiltro.

ffmpeg -i input.mp4 -filter:v \
"select='eq(t\,1.5)+eq(t\,10)+eq(t\,20)'" \
-vsync drop images-filename_%03d.png

Si el filtro se evalúa como verdadero, generará un fotograma, por lo que agregar comprobaciones que comparen la marca de tiempo del fotograma tcon una marca de tiempo particular en segundos (por ejemplo, 1.5) le dará todos los fotogramas en esas marcas de tiempo.

Respuesta3

El OP solicita extraer imágenes para "muchos puntos de tiempo específicos" y da 3 ejemplos. Para mí, 3 no es mucho, así que amplié la respuesta publicada por @Leon para permitir la entrada de archivos demuchopuntos de tiempo. El código Python construye y luego ejecuta un ffmpegcomando largo. Se supone que los puntos de tiempo son el segundo y tercer elemento en una línea de texto separada por comas que comienza con 'Dialogue:', como en elTipos de archivos .ssa y .assusado porAegisub. Dado que los puntos de tiempo de los subtítulos son un rango, el programa pregunta en qué fracción de ese rango desea capturar la imagen. Descubrí que normalmente obtengo las imágenes que quiero usando valores de 0,5 y 0,9.

'''
Splits a video into images at timepoints defined in a subtitle file
supply: .mp4 video and .ass subtitle file into the program directory
output: .png files within an img directory (which program makes if you don't)
to run: enter the .mp4 & .ass filename (same) and the timepoint fraction
timepoint fraction=0.5 means midway between each subtitle start & end point

code constructs and then executes a long ffmpeg command based on this post:
https://superuser.com/a/1330042/752104
'''
import datetime as dt
import os
os.system("mkdir img")


def get_sec(stringHMS):
    timedeltaObj = dt.datetime.strptime(
        stringHMS, "%H:%M:%S.%f") - dt.datetime(1900, 1, 1)
    return timedeltaObj.total_seconds()


defName = 'm'
defFrac = '0.5'
prompt1 = 'Enter file name for both .mp4 and .ass file [' + defName + ']:'
prompt2 = 'Fraction between subtitle start & end points (0-1)[' + \
    defFrac + ']:'
fname = input(prompt1)
if fname == '':
    fname = defName
fh = open(fname + ".ass")
frac = input(prompt2)
if frac == '':
    frac = defFrac
cmd = "ffmpeg -i " + fname + ".mp4 -filter:v \"select='"  # construct ffmpeg cmd
plus = ""
for line in fh:
    if not line.startswith('Dialogue:'):
        continue
    timePt = line.split(",")
    t1 = get_sec(timePt[1])
    t2 = get_sec(timePt[2])
    t = str(t1 + float(frac) * (t2 - t1))
    cmd = cmd + plus + "lt(prev_pts*TB\," + t + ")*gte(pts*TB\," + t + ")"
    plus = " +"  # plus is added only after the first lt()
cmd = cmd + "'\" -vsync drop img/img%03d.png"
os.system(cmd)  # execute the ffmpeg command

información relacionada