![FFmpeg를 사용하여 N초마다 프레임을 정확하게 추출합니다.](https://rvso.com/image/1672321/FFmpeg%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20N%EC%B4%88%EB%A7%88%EB%8B%A4%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9D%84%20%EC%A0%95%ED%99%95%ED%95%98%EA%B2%8C%20%EC%B6%94%EC%B6%9C%ED%95%A9%EB%8B%88%EB%8B%A4..png)
사용법
를 사용하여 비디오에서 이미지를 추출합니다 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
프레임이 "선택"되어 출력으로 전달됩니다.bitor
with는isnan(prev_selected_t)
첫 번째 프레임을 전달합니다. 여기서prev_selected_t
isNaN
(값이 없음)입니다.-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초마다 생성됩니다.