[video] ffmpeg를 사용하여 프레임을 추출하는 가장 빠른 방법은 무엇입니까?

안녕하세요, ffmpeg를 사용하여 동영상에서 프레임을 추출해야합니다. 이보다 빠른 방법이 있습니까?

ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg

?



답변

JPEG 인코딩 단계가 성능 집약적 인 경우 항상 압축되지 않은 프레임을 BMP 이미지로 저장할 수 있습니다.

ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp

이것은 또한 JPEG로 트랜스 코딩하여 양자화를 통해 더 많은 품질 손실을 일으키지 않는 장점이 있습니다. (PNG도 무손실이지만 인코딩하는 데 JPEG보다 훨씬 오래 걸리는 경향이 있습니다.)


답변

이 질문을 보았으므로 여기에 빠른 비교가 있습니다. 38m07s 길이의 비디오에서 분당 하나의 프레임을 추출하는 다음 두 가지 방법을 비교하십시오.

time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp

1 분 36.029s

ffmpeg가 원하는 프레임을 얻기 위해 전체 비디오 파일을 구문 분석하기 때문에 시간이 오래 걸립니다.

time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4   -frames:v 1 period_down_$i.bmp ; done

0m4.689s

이것은 약 20 배 더 빠릅니다. 빠른 검색을 사용하여 원하는 시간 인덱스로 이동하고 프레임을 추출한 다음 모든 시간 인덱스에 대해 ffmpeg를 여러 번 호출합니다. 참고 -accurate_seek 기본이고
, 지 확인하십시오 당신은 추가 -ss입력 비디오하기 전에 -i옵션을 선택합니다.

그것을 사용하는 것이 좋습니다 것을 참고 -filter:v -fps=fps=...대신 -r으로 , 후자는 정확하지 않을 수 있습니다. 티켓이 수정 된 것으로 표시되어 있지만 여전히 몇 가지 문제가 발생 했으므로 안전하게 플레이하는 것이 좋습니다.


답변

추출 할 프레임 (예 : 1, 200, 400, 600, 800, 1000)을 정확히 알고있는 경우 다음을 사용해보십시오.

select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
       -vsync vfr -q:v 2

나는 이것을 Imagemagick의 몽타주 파이프와 함께 사용하여 모든 비디오에서 10 프레임 미리보기를 얻습니다. 당연히 알아 내야 할 프레임 번호는ffprobe

ffmpeg -i myVideo.mov -vf \
    select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)',scale=320:-1 \
    -vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \
  | montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png

.

약간의 설명 :

  1. ffmpeg에서 표현식 +은 OR 및 *AND를 나타냅니다.
  2. \,단순히 ,캐릭터 를 탈출하는 것입니다.
  3. -vsync vfr -q:v 2그것 없이는 작동하지 않는 것 같지만 이유를 모르겠습니다-누구?

답변

나는 그것을 시도했다. 32 초에 3600 프레임. 당신의 방법은 정말 느립니다. 당신은 이것을 시도해야합니다.

ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg


답변

제 경우에는 적어도 1 초마다 프레임이 필요합니다. 위의 ‘탐색’접근 방식을 사용했지만 작업을 병렬화 할 수 있는지 궁금했습니다. FIFO 접근 방식으로 N 프로세스를 사용했습니다 .https :
//unix.stackexchange.com/questions/103920/parallelize-a-bash-for-loop/216475#216475

open_sem(){
  mkfifo /tmp/pipe-$$
  exec 3<>/tmp/pipe-$$
  rm /tmp/pipe-$$
  local i=$1
  for((;i>0;i--)); do
    printf %s 000 >&3
  done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
    "$@"
    printf '%.3d' $? >&3
    )&
}
N=16
open_sem $N
time for i in {0..39} ; do run_with_lock ffmpeg -ss `echo $i` -i /tmp/input/GOPR1456.MP4  -frames:v 1 /tmp/output/period_down_$i.jpg  & done

본질적으로 나는 &로 프로세스를 포크했지만 동시 스레드 수를 N으로 제한했습니다.

이로 인해 ‘탐색’접근 방식이 26 초에서 16 초로 향상되었습니다. 유일한 문제는 stdout이 넘쳐나 기 때문에 메인 스레드가 터미널로 완전히 빠져 나가지 않는다는 것입니다.


답변

이것은 나를 위해 일했습니다.

ffmpeg -i file.mp4 -vf fps=1 %d.jpg


답변