ffmpeg는 선택한 여러 시점에서 사진을 추출합니다.

ffmpeg는 선택한 여러 시점에서 사진을 추출합니다.

나는 비디오 파일을 가지고 있으며 특정 시점(약 1500)에서 단일 이미지를 추출하고 싶습니다.(expl. -ss 00:50, ss 00:67, ss: 01:70 ...)

이를 수행할 수 있는 방법이 있습니까? 나는 다음 명령을 사용해 보았습니다.

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

이는 단일 사진에 적합하지만 그렇게 많은 특정 시점에 대해 이를 수행할 수 있는 방법이 있습니까?

누구든지 조언이 있나요?

답변1

이 답변은 다음과 같이 개선됩니다.@slhck'에스답변, 일부 상황에서는 작동하지 않을 수 있습니다.

(대략적인) 타임스탬프를 기준으로 프레임을 선택할 때 한 가지 미묘한 점은 프레임의 실제 타임스탬프가 원하는 타임스탬프와 정확히 동일하지 않을 수 있다는 것입니다. 예를 들어, 프레임 속도가 23.98(24000/1001)인 비디오에는 타임스탬프가 1.0인 프레임이 없습니다. 가장 가까운 프레임의 타임스탬프 값은 1.001입니다.

표현식은 가 와 정확히 같은 eq(t, specific_timepoint)경우에만 true로 평가됩니다 . 따라서 위에서 설명한 상황에서는 프레임 선택에 실패하게 됩니다. 해결 방법으로 원하는 타임스탬프 바로 다음의 첫 번째 프레임, 즉 타임스탬프 값이 지정된 시점보다 크거나 같고 이전 프레임의 타임스탬프가 지정된 시점보다 작은 프레임을 선택할 수 있습니다. 단일 시점에 대한 선택 표현식은 다음과 같습니다.tspecific_timepoint

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

의도적으로 더 짧은 변형을 사용하지 않았습니다.

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

이는 다음과 같습니다.

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

두 개의 연속 프레임 중 (첫 번째) 프레임의 타임스탬프 값이 선택되면정확하게 일치함지정된 시점 값.

타임포인트 1.5, 10 및 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

답변2

필터 옵션으로 여러 타임스탬프를 추가합니다 select.

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

필터가 true로 평가되면 프레임이 출력되므로 프레임 타임스탬프를 t초 단위의 특정 타임스탬프(예: 1.5)와 비교하는 검사를 추가하면 해당 타임스탬프의 모든 프레임을 얻을 수 있습니다.

답변3

OP는 "많은 특정 시점"에 대한 이미지 추출을 요청하고 3가지 예를 제공합니다. 나에게 3은 많지 않기 때문에 @Leon이 게시한 답변을 확장하여 다음의 파일 입력을 허용했습니다.많은시점. Python 코드는 긴 명령을 구성한 다음 실행합니다 ffmpeg. 여기서는 시점이 'Dialogue:'에서와 같이 쉼표로 구분된 텍스트 줄의 두 번째 및 세 번째 항목이라고 가정합니다..ssa 및 .ass 파일 형식에 의해 사용됨애기섭. 자막 시점은 범위이므로 프로그램은 해당 범위의 어느 부분에서 이미지를 캡처할지 묻습니다. 나는 일반적으로 0.5와 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

관련 정보