FFmpeg를 사용하여 N초마다 프레임을 정확하게 추출합니다.

FFmpeg를 사용하여 N초마다 프레임을 정확하게 추출합니다.

사용법

를 사용하여 비디오에서 이미지를 추출합니다 ffmpeg.

나는 10초마다 하나의 축소된 이미지를 덤프하여 imagemagick. 이러한 몽타주는 웹 기반 비디오 플레이어에서 스크러버를 마우스로 가리키면 비디오의 미리보기를 표시하는 데 다시 사용됩니다. (몽타주에서 어떤 이미지를 표시할지 계산)

명령

이리저리 놀다가 품질보다 속도라는 아이디어를 바탕으로 다음 명령을 실행하게 되었습니다.

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

이것은 잘 작동하는 것 같았습니다. 여기저기서 샷이 약 ± 0.5~1초 정도씩 어긋나지만 그 정도는 괜찮습니다.

문제

문제는 ffmpeg비디오 시작 시 하나의 추가 이미지를 생성한다는 것입니다. 예를 들어 파일은 다음과 같습니다.

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
...

때로는 첫 번째와 두 번째가 몇 밀리초씩 차이가 나는 경우도 있습니다.

내가 아는 한 (지금은) 첫 번째 이미지를 삭제하고 나머지를 계속 진행할 수 있지만 왜 이런 일이 발생하는지, 버그인지 아니면 다른 것인지 잘 모르겠습니다.

다르게 말하면: 첫 번째 두 프레임의 "효과"가 다음과 같은지 알아야 합니다.믿을 수 있는다른 버전에서도 삭제할 수 있습니다 ffmpeg.

이미지를 사용하여 10초를 표시합니다. 지정된 시간에 비디오의 스냅샷10초 뒤에 꺼져생성된 첫 번째 이미지를 삭제하지 않으면 어떤 이유로든 그렇게 해야 한다면~ 아니다시작할 때 속이는 버전을 만들거나, 다른 버전을 만들거나, 첫 번째 이미지를 삭제하면 동일한 문제가 발생합니다.

몽타주

(관심이 있다면 몽타주는 다음과 같이 생성됩니다):

montage -tile 5x -geometry +0+0 -background none [file1  - file50 ]  montage01.jpg
montage -tile 5x -geometry +0+0 -background none [file51 - file100]  montage02.jpg
...

답변(셸)을 기반으로 현재 사용하는 명령은 다음과 같습니다.

# 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"

답변1

을 사용하면 -r 0.1출력 프레임 속도가 0.1Hz로 설정되지만 정확히 10초마다 입력 비디오에서 프레임을 얻는다는 보장은 없습니다(이유는 잘 모르겠습니다).

이를 해결하는 한 가지 방법은 다음을 사용하는 것입니다.필터 선택.

예(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)1"통과된" 타임스탬프 간의 차이가 10초 이상인 경우 입니다 .
    표현식이 로 평가되면 1프레임이 "선택"되어 출력으로 전달됩니다.
  • bitorwith는 isnan(prev_selected_t)첫 번째 프레임을 전달합니다. 여기서 prev_selected_tis NaN(값이 없음)입니다.
  • -vsync 0"통과" 적용 - 각 프레임은 타임스탬프와 함께 디먹서에서 먹서로 전달됩니다.

scale_cuda다음은 및 를 사용한 예입니다 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   
  • 필터 사용으로 인해 필터를 맨 마지막에 thumbnail_cuda배치해야 합니다 .select

테스트:
10fps의 프레임 카운터를 사용하여 합성 비디오 구축:

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

위 명령을 실행한 후 출력 프레임은 다음과 같습니다.

여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요
여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요여기에 이미지 설명을 입력하세요

보시다시피 선택한 프레임은 정확히 10초마다 생성됩니다.

관련 정보