2012-06-09 7 views
52

Hi Tôi cần phải trích xuất khung hình từ video sử dụng ffmpeg .. Có cách nào nhanh hơn để làm điều đó hơn thế này:Cách nhanh nhất để trích xuất khung bằng ffmpeg?

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

?

+1

http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg có thể hữu ích cho bạn – rogerdpack

+0

^url được cập nhật: https://trac.ffmpeg.org/wiki/Seeking – Lambart

+0

Nếu bạn có CPU các chu kỳ phụ tùng, bạn có thể trích xuất từ ​​nhiều video song song: 'song song -i {} -r 1/1 {.} -% 03d.bmp ::: * mpg' –

Trả lời

65

Nếu mã hóa bước JPEG là quá hiệu suất chuyên sâu, bạn luôn có thể lưu trữ các khung nén như hình ảnh BMP:

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

này cũng có lợi thế là không phải gánh chịu tổn thất chất lượng hơn thông qua lượng tử bằng cách chuyển mã để JPEG. (PNG cũng mất dữ liệu nhưng có xu hướng mất nhiều thời gian hơn JPEG để mã hóa.)

+0

cảm ơn! Sẽ thử rằng – Stpn

+0

điều này dường như sản xuất một khung hình nhiều hơn mà có trong video (số tôi có thể nhận được với bộ lọc showinfo hoặc ffprobe) – Guig

+5

Điều này dẫn đến * rất nhiều * khung rơi trên máy tính của tôi. Tôi có thể nói ffmpeg để render mọi thứ không? – Evi1M4chine

32

Đến với câu hỏi này, vì vậy đây là một so sánh nhanh. So sánh hai cách khác nhau để trích xuất một khung hình mỗi phút từ một đoạn video 38m07s dài:

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

1m36.029s

này có lâu vì ffmpeg phân tích toàn bộ file video để có được những khung hình mong muốn.

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

Đây là khoảng 20 lần nhanh hơn. Chúng tôi sử dụng tìm kiếm nhanh để đi đến chỉ mục thời gian mong muốn và trích xuất khung, sau đó gọi ffmpeg nhiều lần cho mọi chỉ mục thời gian. Lưu ý rằng -accurate_seekis the default và đảm bảo bạn thêm -ss trước tùy chọn video nhập -i.

Lưu ý rằng tốt hơn nên sử dụng -filter:v -fps=fps=... thay vì -r làm the latter may be inaccurate. Mặc dù the ticket is marked as fixed, tôi vẫn gặp phải một số sự cố, vì vậy hãy phát an toàn hơn.

+4

Tháng 2 năm 2016: tính đến ffmpeg 2.1, tùy chọn tìm kiếm chính xác bây giờ là mặc định - https: //trac.ffmpeg .org/wiki/Tìm kiếm – mafrosis

+0

'bc' không phải là gói Ubuntu gốc, thay vào đó người dùng có thể sử dụng bash:' let "i = $ i * 60" '. BTW - ý tưởng tuyệt vời –

+1

Mẹo hay khi thêm '-ss' trước' -i'. Nếu không, toàn bộ video sẽ được giải mã và các khung hình không được yêu cầu sẽ bị loại bỏ – MoustafaAAtta

6

Nếu bạn biết chính xác khung để trích xuất, ví dụ 1, 200, 400, 600, 800, 1000, hãy thử sử dụng:

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

Tôi đang sử dụng điều này với một ống để montage ImageMagick để nhận được 10 khung xem trước từ bất kỳ video nào. Rõ ràng là số khung bạn sẽ cần phải tìm ra bằng cách sử dụng ffprobe

ffmpeg -i myVideo.mov -vf \ 
    select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,100)',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 

.

bé giải thích:

  1. Trong biểu thức ffmpeg + là viết tắt của OR và * cho VÀ
  2. \, chỉ đơn giản là thoát khỏi , nhân vật
  3. Without -vsync vfr -q:v 2 nó dường như không làm việc nhưng tôi không biết tại sao - bất cứ ai?
+1

Một '" 'quá nhiều. Nên là: ' '' ffmpeg -i $ 1 -vf \ select = 'eq (n \, 1) + eq (n \, 200) + eq (n \, 400) + eq (n \, 600) + eq (n \, 800) + eq (n \, 100) ', tỷ lệ = 320: -1 \ - không đồng bộ vfr -q: v 2 -f image2pipe -vcodec ppm - \ | montage -tile x1 -geometry "1x1 + 0 + 0 <" -quality 100 -frame 1 - output.png''' – cauchy

0

Trong trường hợp của tôi, tôi cần khung ít nhất mỗi giây. Tôi đã sử dụng phương pháp 'tìm cách' ở trên nhưng tự hỏi liệu tôi có thể song song nhiệm vụ không.Tôi đã sử dụng các quá trình với FIFO cách tiếp cận ở đây N: https://unix.stackexchange.com/questions/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 
    (
    "[email protected]" 
    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 

Về cơ bản tôi chia hai quá trình này với & nhưng giới hạn số lượng bài đồng thời để N.

này cải thiện 'tìm cách' tiếp cận từ 26 từ giây đến 16 giây trong trường hợp của tôi. Vấn đề duy nhất là thread chính không thoát sạch trở lại terminal vì stdout bị ngập.