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

?


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


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.


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ś?

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

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.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.