2012-11-08 17 views
34

Son zamanlarda yaptığım çalışma programlı olarak video hazırlamayı içeriyor. piton, tipik iş akışı şöyle görünür:Görüntüleri diske kaydetmek yerine bir video oluşturmak için görüntüleri "akışa" aktarabilir misiniz?

import subprocess, Image, ImageDraw 

for i in range(frames_per_second * video_duration_seconds): 
    img = createFrame(i) 
    img.save("%07d.png" % i) 

subprocess.call(["ffmpeg","-y","-r",str(frames_per_second),"-i", "%07d.png","-vcodec","mpeg4", "-qscale","5", "-r", str(frames_per_second), "video.avi"]) 

Bu iş akışı videodaki her kare için bir resim oluşturur ve diske kaydeder. Tüm görüntüler kaydedildikten sonra, tüm görüntülerden bir video oluşturmak için ffmpeg çağrılır.

Görüntüleri diske kaydetme (bellekte görüntülerin oluşturulmasını değil), buradaki döngülerin çoğunu tüketir ve gerekli görünmez. Aynı işlevi yerine getirmenin, ancak görüntüleri diske kaydetmeden bir yolu var mı? Böylece, ffmpeg çağrılacak ve görüntüler inşa edildikten hemen sonra ffmpeg'e gönderilecek ve beslenecektir.

+8

Görüntüleri nasıl oluşturduğunuzu bilmiyorum, ancak ffmpeg de boru girişlerini kabul ediyor: 'ffmpeg -f image2pipe -c: v png -r 30000/1001 -i -'. – LordNeckbeard

+0

Basitlik için, sadece 'createFrame (i)' 'img'de sakladığımız bir Python Image Library resim nesnesini döndürdüğünü varsayalım. Cevabın doğru yönde atılmış bir adım olduğunu düşünüyorum, fakat zorluğun yarısı, python programında inşa edilmiş görüntüleri ffmpeg'ye aktarıyordu. – Brandon

+0

belki sıraya girebilir ve sonra görüntüleri ikinci bir iplikten geçirir mi? – lolopop

cevap

49

Tamam Çalışıyorum. image2pipe kullanmak için LordNeckbeard öneri teşekkürler. png because image2pipe with png doesn't work on my verision of ffmpeg yerine jpg kodlaması kullanmalıydım. İlk komut, aslında siyahın kırmızıdan kırmızıya dönüştüğü görüntüler yaratan basit bir resim oluşturma işlemi gerçekleştirmediğim sürece, sorununun koduyla aynıdır. Ayrıca, yürütmeyi zamanlamak için bazı kodları da ekledim.

seri yürütme

import subprocess, Image 

fps, duration = 24, 100 
for i in range(fps * duration): 
    im = Image.new("RGB", (300, 300), (i, 1, 1)) 
    im.save("%07d.jpg" % i) 
subprocess.call(["ffmpeg","-y","-r",str(fps),"-i", "%07d.jpg","-vcodec","mpeg4", "-qscale","5", "-r", str(fps), "video.avi"]) 

paralel yürütme

import Image 
from subprocess import Popen, PIPE 

fps, duration = 24, 100 
p = Popen(['ffmpeg', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', '24', '-i', '-', '-vcodec', 'mpeg4', '-qscale', '5', '-r', '24', 'video.avi'], stdin=PIPE) 
for i in range(fps * duration): 
    im = Image.new("RGB", (300, 300), (i, 1, 1)) 
    im.save(p.stdin, 'JPEG') 
p.stdin.close() 
p.wait() 

sonuç ilginçtir (diske kaydedilmiş resim olmadan), ben performans karşılaştırmak için 3 kez her senaryoyu ran: seri:

12.9062321186 
12.8965060711 
12.9360799789 

paralel:

8.67797684669 
8.57139396667 
8.38926696777 

yüzden paralel versiyonu daha hızlı yaklaşık 1,5 kat daha hızlı gibi görünüyor.

+0

Brilliant! Bunu test ettim ve harika çalışıyor. – Brandon

+16

Gelecekte bununla uğraşan herkes için 'mjpeg' 'png' ve 'JPEG' ile 'PNG' yerine png kullanmak benim için çalıştı. – Brandon

+0

En iyi kaliteyi -vcodec png ve 'im.save (p.stdin, 'PNG')' yi kullanarak elde edebildim, ancak dosya boyutu x4 – bluesummers