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
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
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
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Odpowiedzi:
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).
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
, prawda? (brakowało ci -i
)
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 -ss
przed -i
opcją wejścia wideo .
Zauważ, że lepiej jest użyć -filter:v -fps=fps=...
zamiast, -r
ponieważ 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.
bc
nie jest rodowitym pakiet Ubuntu zamiast można użyć bash: let "i = $i * 60"
. BTW - doskonały pomysł
-ss
wcześniej -i
. W przeciwnym razie całe wideo zostanie zdekodowane, a niepotrzebne klatki zostaną odrzucone
ffmpeg
na 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).
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:
+
oznaczają OR i *
AND\,
po prostu wymyka się ,
postaci-vsync vfr -q:v 2
tego nie wydaje się działać, ale nie wiem dlaczego - ktoś?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
ffmpeg -i "input URL" -vf fps=1/5 out%d.png
gdzie wejściowy adres URL musi być łączem https.
ffmpeg -i file.mpg -vf fps=1 %d.jpg
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.
To zadziałało dla mnie
ffmpeg -i file.mp4 -vf fps=1 %d.jpg