ffmpeg extrai imagens de vários pontos no tempo selecionados

ffmpeg extrai imagens de vários pontos no tempo selecionados

Eu tenho um arquivo de vídeo e gosto de extrair uma única imagem de (cerca de 1.500) pontos de tempo específicos. (expl. -ss 00:50, ss 00:67, ss: 01:70 ...)

Existe uma maneira de fazer isso? Eu tentei usar este comando:

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

Isso funciona muito bem para uma única imagem, mas existe uma maneira de fazer isso para tantos pontos de tempo específicos?

Alguém tem um conselho?

Responder1

Esta resposta melhora@slhckderesponder, que pode não funcionar em algumas situações.

Uma sutileza na seleção de quadros por carimbo de data/hora (aproximado) é que o carimbo de data/hora real do quadro pode não ser exatamente igual ao carimbo de data/hora desejado. Por exemplo, em um vídeo com taxa de quadros 23,98 (24000/1001) não há quadro com carimbo de data/hora 1,0 - o quadro mais próximo tem valor de carimbo de data/hora de 1,001.

A expressão eq(t, specific_timepoint)será avaliada como verdadeira somente se tfor exatamente igual a specific_timepoint. Portanto, não será possível selecionar um quadro na situação descrita acima. Como solução alternativa, podemos selecionar o primeiro quadro imediatamente após o carimbo de data/hora desejado, ou seja, o quadro cujo valor do carimbo de data/hora é maior ou igual ao ponto de tempo especificado, enquanto o carimbo de data/hora do quadro anterior foi menor que o ponto de tempo especificado. A expressão de seleção para um único ponto no tempo será

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

Observe que eu deliberadamente não usei uma variante mais curta

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

o que equivale a

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

pois selecionaria dois quadros consecutivos quando o valor do carimbo de data/hora do (primeiro) um delescorresponde exatamenteo valor do ponto de tempo especificado.

Exemplo de seleção dos frames correspondentes ou imediatamente seguintes aos pontos de tempo 1.5, 10 e 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

Responder2

Adicione vários carimbos de data/hora como opções para o selectfiltro.

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

Se o filtro for avaliado como verdadeiro, ele produzirá um quadro, portanto, a adição de verificações comparando o carimbo de data/hora do quadro tcom um carimbo de data/hora específico em segundos (por exemplo, 1.5) fornecerá todos os quadros nesses carimbos de data/hora.

Responder3

O OP pede para extrair imagens para "muitos momentos específicos" e dá 3 exemplos. Para mim, 3 não é muito, então estendi a resposta postada por @Leon para permitir a entrada de arquivos deum monte dePontos de tempo. O código python constrói e executa um ffmpegcomando longo. Ele assume que os pontos de tempo são o segundo e o terceiro itens em uma linha de texto separada por vírgula começando com 'Dialogue:', como noTipos de arquivo .ssa e .assusado porAegisub. Como os pontos de tempo das legendas são um intervalo, o programa pergunta em qual fração desse intervalo você deseja capturar a imagem. Descobri que normalmente consigo as imagens que desejo usando valores de 0,5 e 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

informação relacionada