วิธีที่เร็วที่สุดในการแยกเฟรมโดยใช้ ffmpeg?


118

สวัสดีฉันต้องการแยกเฟรมจากวิดีโอโดยใช้ ffmpeg .. มีวิธีที่เร็วกว่านี้ไหม:

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

เหรอ?


1
^ ปรับปรุง url: trac.ffmpeg.org/wiki/Seeking
Lambart

5
หากคุณมีรอบ CPU เหลือคุณสามารถแยกจากวิดีโอหลายรายการพร้อมกันได้:parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Ole Tange

คำตอบ:


156

หากขั้นตอนการเข้ารหัส JPEG มีประสิทธิภาพมากเกินไปคุณสามารถจัดเก็บเฟรมที่ไม่มีการบีบอัดเป็นภาพ BMP ได้เสมอ:

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

นอกจากนี้ยังมีข้อดีคือไม่ต้องสูญเสียคุณภาพมากขึ้นผ่านการหาปริมาณโดยการแปลงรหัสเป็น JPEG (PNG ยังไม่มีการสูญเสีย แต่มักจะใช้เวลาเข้ารหัสนานกว่า JPEG)


9
ซึ่งส่งผลให้เครื่องของฉันมีเฟรมหล่นลงมามาก ฉันบอกให้ ffmpeg แสดงผลทุกอย่างได้ไหม
Evi1M4chine

45
@ Evi1M4chine เพียงแค่ลบพารามิเตอร์ -r สิ่งนี้จะแยกเฟรมทั้งหมด
studioj

14
ฉันต้องการเพิ่มว่าแม้ว่า JPEG จะไม่ได้ทำงานหนักกับ CPU แต่ Bitmaps ที่ไม่มีการบีบอัดนั้นยากมากในการจัดเก็บข้อมูลดังนั้นฉันสงสัยว่าคุณจะได้รับปริมาณงานที่สูงขึ้นเมื่อเทียบกับ BMP เมื่อเทียบกับ JPEG
Marcus Müller

4
ในการแยกเฟรมทั้งหมด:ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
fiatjaf

10
คุณหมายถึงffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.pngใช่ไหม? (คุณพลาด-i)
Joschua

68

เจอคำถามนี้จึงเป็นการเปรียบเทียบอย่างรวดเร็ว เปรียบเทียบสองวิธีที่แตกต่างกันนี้ในการแยกหนึ่งเฟรมต่อนาทีจากวิดีโอที่มีความยาว 38 นาที 7 วินาที:

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

1 นาที 36.029 วินาที

การดำเนินการนี้ใช้เวลานานเนื่องจาก ffmpeg จะแยกวิเคราะห์ไฟล์วิดีโอทั้งหมดเพื่อให้ได้เฟรมที่ต้องการ

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

เร็วกว่านี้ประมาณ 20 เท่า เราใช้การค้นหาอย่างรวดเร็วเพื่อไปยังดัชนีเวลาที่ต้องการและแยกเฟรมจากนั้นเรียก ffmpeg หลาย ๆ ครั้งสำหรับดัชนีทุกครั้ง โปรดทราบว่า-accurate_seek เป็นค่าเริ่มต้น และตรวจสอบให้แน่ใจว่าคุณได้เพิ่ม-ssก่อน-iตัวเลือกวิดีโออินพุต

โปรดทราบว่ามันจะดีกว่าที่จะใช้-filter:v -fps=fps=...แทน-rเป็นหลังอาจจะไม่ถูกต้อง แม้ว่าตั๋วจะถูกระบุว่าแก้ไขแล้ว แต่ฉันก็ยังพบปัญหาอยู่ดังนั้นควรเล่นอย่างปลอดภัย


6
ก.พ. 2559: ณ ffmpeg 2.1 ขณะนี้ตัวเลือกการค้นหาที่ถูกต้องเป็นค่าเริ่มต้น - trac.ffmpeg.org/wiki/Seeking
mafrosis

1
bcไม่ได้เป็นแพคเกจ Ubuntu let "i = $i * 60"พื้นเมืองแทนหนึ่งสามารถใช้ทุบตี: BTW - ความคิดที่ยอดเยี่ยม
Gilad Mayani

3
เคล็ดลับที่ดีเพิ่มก่อน-ss -iมิฉะนั้นวิดีโอทั้งหมดจะถูกถอดรหัสและเฟรมที่ไม่ต้องการจะถูกทิ้ง
MoustafaAtta

2
เนื่องจากนี่เป็นอันดับต้น ๆ ของ Google ฉันจึงอยากทราบว่าในปี 2018 นี้ยังคงเป็นแนวทางที่ให้ผลตอบแทนจากเงินปันผล ผลลัพธ์ที่ดีที่สุดดูเหมือนว่าจะทำงานหนึ่งffmpegต่อคอร์ของโฮสต์ของคุณซึ่ง (สำหรับ bmp) ให้การปรับปรุงความเร็วแบบใกล้เส้นตรง (จนกว่าคุณจะถึงคอขวดอื่น ๆ เช่นดิสก์)
Knetic

นี่ควรเป็นคำตอบที่ได้รับการยอมรับเนื่องจากคำถามเกี่ยวกับ 'วิธีที่เร็วที่สุด' เห็นได้ชัดว่าคุณต้องรู้ตัวแปร exit สำหรับ 'for loop' โดยใช้ ffprobe ซึ่งฉันคิดว่ายังเร็วกว่าเมื่อเทียบกับวิธีอื่น
iamprem

9

หากคุณทราบแน่ชัดว่าจะแยกเฟรมใดเช่น 1, 200, 400, 600, 800, 1000 ให้ลองใช้:

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

ฉันใช้สิ่งนี้กับท่อไปยังการตัดต่อของ Imagemagick เพื่อดูตัวอย่าง 10 เฟรมจากวิดีโอใด ๆ เห็นได้ชัดว่าหมายเลขเฟรมที่คุณต้องใช้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

.

คำอธิบายเล็กน้อย:

  1. ในนิพจน์ ffmpeg +ย่อมาจาก OR และ*for AND
  2. \,เป็นเพียงการหลีกหนีจาก,ตัวละคร
  3. ถ้าไม่มี-vsync vfr -q:v 2มันดูเหมือนจะไม่ได้ผล แต่ฉันไม่รู้ว่าทำไม - ใคร?

4

ฉันลองแล้ว 3600 เฟรมใน 32 วินาที วิธีการของคุณช้ามาก คุณควรลองสิ่งนี้

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

ฉันกำลังพยายาม ffmpeg -i "input URL" -vf fps=1/5 out%d.png ที่ URL อินพุตจะต้องเป็นลิงก์ https
x2212

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

1

ในกรณีของฉันฉันต้องการเฟรมอย่างน้อยทุกวินาที ฉันใช้วิธี 'ค้นหาเพื่อ' ข้างต้น แต่สงสัยว่าฉันจะขนานงานได้หรือไม่ ฉันใช้กระบวนการ N กับวิธี FIFO ที่นี่: /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

โดยพื้นฐานแล้วฉันแยกกระบวนการด้วย & แต่ จำกัด จำนวนเธรดพร้อมกันที่ N

สิ่งนี้ปรับปรุงวิธีการ 'ค้นหาเพื่อ' จาก 26 วินาทีเป็น 16 วินาทีในกรณีของฉัน ปัญหาเดียวคือเธรดหลักไม่ออกกลับไปที่เทอร์มินัลอย่างหมดจดเนื่องจาก stdout ถูกน้ำท่วม


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.