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


118

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

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

?


1
^ 업데이트 URL : trac.ffmpeg.org/wiki/Seeking
Lambart

5
여유 CPU주기가있는 경우 여러 비디오에서 동시에 추출 할 수 있습니다.parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Ole Tange

답변:


156

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

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

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


9
이로 인해 내 컴퓨터에서 많은 프레임이 떨어집니다. ffmpeg에게 모든 것을 렌더링하도록 지시 할 수 있습니까?
Evi1M4chine

45
@ Evi1M4chine는이 모든 프레임을 추출 할 -r 매개 변수를 제거
studioj

14
JPEG는 CPU에서 실제로 어렵지 않지만 압축되지 않은 비트 맵은 스토리지에서 정말 어렵 기 때문에 JPEG에 비해 BMP에서 더 높은 처리량을 얻을 수 있을지 의심 스럽습니다.
Marcus Müller

4
모든 프레임을 추출하려면 :ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
fiatjaf

10
그러니까 ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png? (당신은 -i)
Joschua

68

이 질문을 보았으므로 여기에 빠른 비교가 있습니다. 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으로 , 후자는 정확하지 않을 수 있습니다. 티켓이 수정 된 것으로 표시되어 있지만 여전히 몇 가지 문제가 발생 했으므로 안전하게 플레이하는 것이 좋습니다.


6
2016 년 2 월 : ffmpeg 2.1부터 정확한 탐색 옵션이 이제 기본값입니다 -trac.ffmpeg.org/wiki/Seeking
mafrosis

1
bc기본 Ubuntu 패키지가 아니며 대신 bash :를 사용할 수 있습니다 let "i = $i * 60". BTW - 좋은 생각
길 라드의 mayani

3
-ss전에 추가하는 좋은 팁 -i. 그렇지 않으면, 전체 비디오 디코딩되고 필수가 프레임이 삭제됩니다
MoustafaAAtta

2
이것이 Google의 최고이기 때문에 2018 년에도 이것이 여전히 배당금을 창출하는 접근 방식이라는 점에 주목하고 싶습니다. 최상의 결과는 ffmpeg호스트의 코어 당 하나를 실행하는 것 같습니다. (bmp의 경우) 속도가 거의 선형으로 향상됩니다 (디스크와 같은 다른 병목 현상에 도달 할 때까지).
Knetic

질문이 '가장 빠른 방법'에 관한 것이기 때문에 이것은 받아 들여진 대답이어야합니다. 분명히 다른 방법에 비해 여전히 빠르다고 생각하는 ffprobe를 사용하여 'for 루프'에 대한 종료 변수를 알아야합니다.
iamprem

9

추출 할 프레임 (예 : 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그것 없이는 작동하지 않는 것 같지만 이유를 모르겠습니다-누구?

4

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

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

ffmpeg -i "input URL" -vf fps=1/5 out%d.png 입력 URL이 https 링크 여야하는 곳을 시도하고 있습니다.
x2212

ffmpeg -i file.mpg -vf fps=1 %d.jpg
Kishan Vaghela

1

제 경우에는 적어도 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이 넘쳐나 기 때문에 메인 스레드가 터미널로 완전히 빠져 나가지 않는다는 것입니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.