Cara tercepat untuk mengekstrak frame menggunakan ffmpeg?

118

Hai, saya perlu mengekstrak bingkai dari video menggunakan ffmpeg .. Apakah ada cara yang lebih cepat untuk melakukannya daripada ini:

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

?

Stpn
sumber
1
^ Diperbarui url: trac.ffmpeg.org/wiki/Seeking
Lambart
5
Jika Anda memiliki siklus CPU yang tersisa, Anda dapat mengekstrak dari beberapa video secara paralel:parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Ole Tange

Jawaban:

156

Jika langkah pengkodean JPEG terlalu intensif kinerja, Anda selalu dapat menyimpan bingkai yang tidak dikompresi sebagai gambar BMP:

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

Ini juga memiliki keuntungan karena tidak menimbulkan lebih banyak kehilangan kualitas melalui kuantisasi dengan melakukan transcoding ke JPEG. (PNG juga lossless tetapi cenderung membutuhkan waktu lebih lama daripada JPEG untuk dienkode.)

Multimedia Mike
sumber
9
Ini menghasilkan banyak frame yang jatuh di mesin saya. Bisakah saya memberi tahu ffmpeg untuk merender semuanya?
Evi1M4chine
45
@ Evi1M4chine hapus saja parameter -r ini akan mengekstrak semua frame
studioj
14
Saya ingin menambahkan bahwa meskipun JPEG tidak terlalu keras pada CPU, Bitmaps yang tidak dikompresi sangat sulit pada penyimpanan, jadi saya ragu Anda akan mendapatkan hasil yang lebih tinggi dengan BMP dibandingkan dengan JPEG.
Marcus Müller
4
Untuk mengekstrak semua frame:ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
fiatjaf
10
Maksudmu ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png, kan? (Anda kehilangan -i)
Joschua
68

Menemukan pertanyaan ini, jadi inilah perbandingan singkatnya. Bandingkan dua cara berbeda ini untuk mengekstrak satu frame per menit dari video berdurasi 38m07s:

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

1m36.029s

Ini membutuhkan waktu lama karena ffmpeg mem-parsing seluruh file video untuk mendapatkan frame yang diinginkan.

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

Ini sekitar 20 kali lebih cepat. Kami menggunakan pencarian cepat untuk membuka indeks waktu yang diinginkan dan mengekstrak bingkai, lalu memanggil ffmpeg beberapa kali untuk setiap indeks waktu. Perhatikan bahwa -accurate_seek ini adalah default , dan pastikan Anda menambahkan -sssebelum opsi input video -i.

Perhatikan bahwa lebih baik menggunakan -filter:v -fps=fps=...daripada -rkarena yang terakhir mungkin tidak akurat. Meskipun tiket ditandai sebagai sudah diperbaiki , saya masih mengalami beberapa masalah, jadi lebih baik bermain aman.

blutorange
sumber
6
Feb 2016: mulai ffmpeg 2.1, opsi pencarian yang akurat sekarang default - trac.ffmpeg.org/wiki/Seeking
mafrosis
1
bcbukan paket Ubuntu asli, bukan satu dapat menggunakan bash: let "i = $i * 60". BTW - ide bagus
gilad mayani
3
Tip bagus menambahkan -sssebelumnya -i. Jika tidak, seluruh video akan didekodekan dan bingkai yang tidak diperlukan akan dibuang
MoustafaAAtta
2
Karena ini adalah yang teratas dari google, saya ingin mencatat bahwa pada tahun 2018 ini masih merupakan pendekatan yang menghasilkan dividen. Hasil terbaik tampaknya menjalankan satu ffmpegper inti host Anda - yang (untuk bmp) menghasilkan peningkatan kecepatan yang hampir linier (sampai Anda mencapai beberapa hambatan lain, seperti disk).
Knetic
Ini harus menjadi jawaban yang diterima, karena pertanyaannya adalah tentang 'cara tercepat'. Tentunya Anda perlu mengetahui variabel keluar untuk 'for loop' menggunakan ffprobe yang menurut saya masih lebih cepat dibandingkan dengan metode lain.
iamprem
9

Jika Anda tahu persis frame mana yang akan diekstrak, misalnya 1, 200, 400, 600, 800, 1000, coba gunakan:

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

Saya menggunakan ini dengan pipa ke montase Imagemagick untuk mendapatkan pratinjau 10 bingkai dari video mana pun. Jelas nomor bingkai yang perlu Anda ketahui menggunakanffprobe

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

.

Sedikit penjelasan:

  1. Dalam ekspresi ffmpeg +singkatan dari OR dan* AND
  2. \, hanya keluar dari , karakter
  3. Tanpa -vsync vfr -q:v 2itu sepertinya tidak berhasil tetapi saya tidak tahu mengapa - siapa?
Voy
sumber
4

Saya mencobanya. 3600 bingkai dalam 32 detik. metode Anda sangat lambat. Anda harus mencobanya.

ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
Kübra
sumber
Saya mencoba di ffmpeg -i "input URL" -vf fps=1/5 out%d.png mana URL masukan harus berupa tautan https.
x2212
ffmpeg -i file.mpg -vf fps=1 %d.jpg
Kishan Vaghela
1

Dalam kasus saya, saya membutuhkan bingkai setidaknya setiap detik. Saya menggunakan pendekatan 'mencari' di atas tetapi bertanya-tanya apakah saya bisa memparalelkan tugas tersebut. Saya menggunakan proses N dengan pendekatan FIFO di sini: /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

Pada dasarnya saya membagi proses dengan & tetapi membatasi jumlah utas bersamaan ke N.

Ini meningkatkan pendekatan 'seek to' dari 26 detik menjadi 16 detik dalam kasus saya. Satu-satunya masalah adalah utas utama tidak keluar dengan bersih kembali ke terminal karena stdout dibanjiri.

Tycon
sumber
0

Ini berhasil untuk saya

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

Kishan Vaghela
sumber