Ffmpeg kullanarak kareleri ayıklamanın en hızlı yolu?


118

Merhaba ffmpeg kullanarak videolardan kareler çıkarmam gerekiyor .. Bunu yapmanın bundan daha hızlı bir yolu var mı:

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

?


1
^ güncellenmiş url: trac.ffmpeg.org/wiki/Seeking
Lambart

5
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Ole Tange

Yanıtlar:


156

JPEG kodlama adımı çok yüksek performans gerektiriyorsa, sıkıştırılmamış kareleri her zaman BMP görüntüleri olarak saklayabilirsiniz:

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

Bu aynı zamanda, JPEG'ye kod dönüştürme yoluyla niceleme yoluyla daha fazla kalite kaybına uğramama avantajına sahiptir. (PNG ayrıca kayıpsızdır ancak kodlanması JPEG'den çok daha uzun sürer.)


9
Bu , makinemde çok fazla kare düşmesine neden oluyor. Ffmpeg'e her şeyi oluşturmasını söyleyebilir miyim?
Evi1M4chine

45
@ Evi1M4chine sadece -r parametresini kaldırın, bu tüm kareleri çıkaracaktır
studioj

14
JPEG CPU için gerçekten zor olmasa da, sıkıştırılmamış Bitmap'lerin depolama için gerçekten zor olduğunu eklemek isterim, bu yüzden JPEG ile karşılaştırıldığında BMP ile daha yüksek verim elde edeceğinizden şüpheliyim.
Marcus Müller

4
Tüm kareleri çıkarmak için:ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
fiatjaf

10
Yani ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.pngdeğil mi? (kaçırıyordunuz -i)
Joschua

68

Bu soruyla karşılaştık, işte hızlı bir karşılaştırma. 38m07s uzunluğundaki bir videodan dakikada bir kare çıkarmak için bu iki farklı yolu karşılaştırın:

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

1m36.029s

Bu uzun sürer çünkü ffmpeg istenen kareleri elde etmek için tüm video dosyasını ayrıştırır.

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

Bu yaklaşık 20 kat daha hızlı. İstenilen zaman indeksine gitmek ve bir çerçeve çıkarmak için hızlı aramayı kullanırız, ardından her zaman indeksi için birkaç kez ffmpeg çağırırız. Bunun -accurate_seek varsayılan olduğunu ve -ssvideo giriş -iseçeneğinden önce eklediğinizden emin olun .

Kullanımı daha iyi olduğunu Not -filter:v -fps=fps=...yerine -rolarak ikincisi hatalı olabilir. Bilet düzeltildi olarak işaretlenmiş olsa da , yine de bazı sorunlar yaşadım, bu yüzden güvenli oynamalıyım.


6
Şubat 2016: ffmpeg 2.1 itibariyle, doğru arama seçeneği artık varsayılandır - trac.ffmpeg.org/wiki/Seeking
mafrosis

1
bcyerel bir Ubuntu paketi değildir, bunun yerine bash: kullanılabilir let "i = $i * 60". BTW - excellent idea
gilad mayani

3
-ssÖnceden iyi bir ipucu eklemek -i. Aksi takdirde, tüm videonun kodu çözülecek ve gerekli olmayan kareler atılacak
MoustafaAAtta

2
Bu Google'ın zirvesi olduğundan, 2018'de bunun hala temettü getiren bir yaklaşım olduğunu belirtmek isterim. En iyi sonuç ffmpeg, ana makinenizin çekirdeği başına bir tane çalışıyor gibi görünüyor - bu (bmp için) hızda neredeyse doğrusal iyileştirmeler sağlıyor (disk gibi başka bir darboğazla karşılaşana kadar).
Knetic

Soru 'en hızlı yol' ile ilgili olduğu için bu kabul edilen cevap olmalıdır. Açıkçası, diğer yöntemlere göre daha hızlı olduğunu düşündüğüm ffprobe kullanan 'for döngüsü' için çıkış değişkenini bilmeniz gerekiyor.
iamprem

9

Tam olarak hangi karelerin çıkarılacağını biliyorsanız, örneğin 1, 200, 400, 600, 800, 1000, kullanmayı deneyin:

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

Bunu, herhangi bir videodan 10 kare önizleme almak için Imagemagick'in montajına giden bir boru ile kullanıyorum. Açıkçası kullanarak çözmeniz gereken çerçeve numaraları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

.

Küçük açıklama:

  1. Ffmpeg'de ifadeler +OR ve *AND anlamına gelir
  2. \,sadece ,karakterden kaçıyor
  3. Olmadan -vsync vfr -q:v 2işe yaramıyor gibi görünüyor ama nedenini bilmiyorum - kimse?

4

Denedim. 32 saniyede 3600 kare. yönteminiz gerçekten yavaş. Bunu denemelisin.

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

ffmpeg -i "input URL" -vf fps=1/5 out%d.png Giriş URL'sinin bir https bağlantısı olması gereken yerde deniyorum .
x2212

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

1

Benim durumumda en azından her saniye çerçevelere ihtiyacım var. Yukarıdaki 'aramak' yaklaşımını kullandım ama görevi paralelleştirip paralelleştiremeyeceğimi merak ettim. Burada FIFO yaklaşımıyla N işlemlerini kullandım: /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

Esasen süreci çatalladım ve eşzamanlı iş parçacığı sayısını N ile sınırladım.

Bu, benim durumumda 'arama' yaklaşımını 26 saniyeden 16 saniyeye çıkardı. Tek sorun, stdout taşındığı için ana iş parçacığının terminale temiz bir şekilde geri çıkmamasıdır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.