Najszybszy sposób na wyodrębnienie ramek za pomocą ffmpeg?

118

Cześć, muszę wyodrębnić klatki z filmów za pomocą ffmpeg .. Czy istnieje szybszy sposób na zrobienie tego niż ten:

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

?

Stpn
źródło
1
^ zaktualizowany adres URL: trac.ffmpeg.org/wiki/Seeking
Lambart
5
Jeśli masz wolne cykle procesora, możesz wyodrębnić wiele filmów równolegle:parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Ole Tange

Odpowiedzi:

156

Jeśli krok kodowania JPEG wymaga zbyt dużej wydajności, zawsze możesz zapisać nieskompresowane klatki jako obrazy BMP:

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

Ma to również tę zaletę, że nie powoduje większej utraty jakości w wyniku kwantyzacji przez transkodowanie do formatu JPEG. (PNG jest również bezstratny, ale zwykle trwa znacznie dłużej niż kodowanie JPEG).

Multimedia Mike
źródło
9
Powoduje to wiele zrzucania klatek na moim komputerze. Czy mogę powiedzieć ffmpeg, aby wyrenderował wszystko?
Evi1M4chine
45
@ Evi1M4chine po prostu usuń parametr -r, co spowoduje wyodrębnienie wszystkich ramek
studioj
14
Chciałbym dodać, że chociaż JPEG nie jest naprawdę trudne dla procesora, nieskompresowane mapy bitowe są naprawdę bardzo trudne w pamięci, więc wątpię, abyś uzyskał wyższą przepustowość z BMP w porównaniu z JPEG.
Marcus Müller
4
Aby wyodrębnić wszystkie klatki:ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
fiatjaf
10
Masz na myśli ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png, prawda? (brakowało ci -i)
Joschua
68

Przeszedłem przez to pytanie, więc oto szybkie porównanie. Porównaj te dwa różne sposoby wyodrębniania jednej klatki na minutę z filmu o długości 38 min:

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

1m36,029s

Trwa to długo, ponieważ ffmpeg analizuje cały plik wideo, aby uzyskać żądane klatki.

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

To około 20 razy szybciej. Używamy szybkiego wyszukiwania, aby przejść do żądanego indeksu czasu i wyodrębnić klatkę, a następnie kilkakrotnie wywołać ffmpeg dla każdego indeksu czasu. Zauważ, że -accurate_seek jest to ustawienie domyślne i upewnij się, że dodajesz -ssprzed -iopcją wejścia wideo .

Zauważ, że lepiej jest użyć -filter:v -fps=fps=...zamiast, -rponieważ ta ostatnia może być niedokładna. Chociaż bilet jest oznaczony jako naprawiony , nadal miałem pewne problemy, więc lepiej zagraj w to bezpiecznie.

blutorange
źródło
6
Luty 2016: od ffmpeg 2.1, opcja dokładnego wyszukiwania jest teraz domyślna - trac.ffmpeg.org/wiki/Seeking
mafrosis
1
bcnie jest rodowitym pakiet Ubuntu zamiast można użyć bash: let "i = $i * 60". BTW - doskonały pomysł
gilad mayani
3
Dobra wskazówka dodana -sswcześniej -i. W przeciwnym razie całe wideo zostanie zdekodowane, a niepotrzebne klatki zostaną odrzucone
MoustafaAAtta
2
Ponieważ jest to najlepsze w Google, chciałbym zauważyć, że w 2018 roku jest to nadal podejście, które przynosi dywidendy. Najlepszy wynik wydaje się działać po jednym ffmpegna rdzeń twojego hosta - co (dla bmp) daje prawie liniową poprawę szybkości (dopóki nie trafisz na inne wąskie gardło, takie jak dysk).
Knetic
To powinna być akceptowana odpowiedź, ponieważ pytanie dotyczy „najszybszej drogi”. Oczywiście musisz znać zmienną wyjściową dla pętli for przy użyciu ffprobe, która moim zdaniem jest nadal szybsza w porównaniu z innymi metodami.
iamprem
9

Jeśli wiesz dokładnie, które ramki wyodrębnić, np. 1, 200, 400, 600, 800, 1000, spróbuj użyć:

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

Używam tego z rurką do montażu Imagemagick, aby uzyskać podgląd 10 klatek z dowolnego filmu. Oczywiście numery ramek, które musisz obliczyć, używającffprobe

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

.

Małe wyjaśnienie:

  1. W ffmpeg wyrażenia +oznaczają OR i *AND
  2. \,po prostu wymyka się ,postaci
  3. Bez -vsync vfr -q:v 2tego nie wydaje się działać, ale nie wiem dlaczego - ktoś?
Voy
źródło
4

Próbowałem tego. 3600 klatek w 32 sekundy. twoja metoda jest naprawdę powolna. Powinieneś tego spróbować.

ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
Kübra
źródło
Próbuję, ffmpeg -i "input URL" -vf fps=1/5 out%d.png gdzie wejściowy adres URL musi być łączem https.
x2212
ffmpeg -i file.mpg -vf fps=1 %d.jpg
Kishan Vaghela
1

W moim przypadku potrzebuję ramek przynajmniej co sekundę. Użyłem powyższego podejścia „szukaj”, ale zastanawiałem się, czy mógłbym zrównoleglać to zadanie. Użyłem procesów N z podejściem FIFO tutaj: /unix/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

Zasadniczo rozwidliłem proces z & ale ograniczyłem liczbę współbieżnych wątków do N.

Poprawiło to podejście „szukania” z 26 do 16 sekund w moim przypadku. Jedynym problemem jest to, że główny wątek nie wychodzi czysto z powrotem do terminala, ponieważ stdout zostaje zalane.

Tycon
źródło
0

To zadziałało dla mnie

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

Kishan Vaghela
źródło