2009-09-21 3 views
8

Ich versuche, eine Gui für FFMPEG zu schreiben. Ich benutze Pythons Subprozess, um einen ffmpeg-Prozess für jede gewünschte Konvertierung zu erstellen. Dies funktioniert gut, aber ich möchte auch einen Weg, um den Fortschritt der Umwandlung zu bekommen, ob es versäumt oder nicht usw. Ich dachte, ich könnte dies tun durch den Zugriff auf die Standardausgabe der Prozess ist wie so:FFMPEG und Pythons Subprozess

subprocess.Popen() Aufruf

# Convert - Calls FFMPEG with current settings. (in a seperate 
# thread.) 
def convert(self): 
    # Check if options are valid 
    if self.input == "" or self.output == "": 
     return False 

# Make the command string 
ffmpegString = self.makeString() 

# Try to open with these settings 
try: 
    self.ffmpeg = subprocess.Popen(ffmpegString, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 
except OSError: 
    self.error.append("OSError: ") 
except ValueError: 
    self.error.append("ValueError: Couldn't call FFMPEG with these parameters") 

# Convert process should be running now. 

Und stdout Lesen:

convert = Convert() 
convert.input = "test.ogv" 
convert.output = "test.mp4" 
convert.output_size = (0, 0) 

convert.convert() 

while 1: 
    print convert.ffmpeg.stdout.readline() 

Dies aber, den Status des ffmpeg funktioniert nicht zeigen. Ich gehe davon aus, dass es etwas damit zu tun hat, wie ffmpeg es auffrischt. Gibt es eine Möglichkeit, darauf zuzugreifen?

Antwort

8

Ich habe oft Probleme beim Lesen der Standardausgabe (oder sogar Standardfehler!) Mit Subprozess bemerkt, aufgrund von Pufferproblemen, die schwer zu besiegen sind. Meine Lieblingslösung, wenn ich solche stdout/stderr aus dem Subprozess lesen muss, ist die Verwendung von anstelle von subprocess, pexpect (oder unter Windows wexpect).

+0

Beide Ihre Links sind tot, bitte beheben Sie sie. – slhck

-1

FFMPEG:

FFMPEG Ausgabe alle Statustext (was Sie sehen, wenn Sie es manuell auf der Kommandozeile ausgeführt werden) auf der stderr-Schnittstelle. Um die Ausgabe von ffmpeg zu erfassen, müssen Sie die stderr-Schnittstelle überwachen oder sie wie das Beispiel umleiten.

prüfen für die Ausgabe auf stderr:

Hier ist eine andere Art und Weise zu versuchen und von stderr zu lesen, anstatt sie zu Umleiten wenn Popen

Die Popen class in Python hat ein Dateiobjekt namens stderr Aufruf , würden Sie auf dieselbe Weise darauf zugreifen, wie Sie auf stdout zugreifen. Ich denke der Schleife wie folgt aussehen würde:

while 1: 
    print convert.ffmpeg.stdout.readline() 
    print convert.ffmpeg.stderr.readline() 

Haftungsausschluss: ich dies in Python nicht getestet, aber ich habe eine vergleichbare Anwendung mit Java.

+0

Er leitet stderr bereits auf stdout um. –

+0

Gorgapor, bist du sicher er ist? –

+0

Ja, das stderr wird im Code snippit in der Zeile mit subprocess.Popen umgeleitet - natürlich kann es abgeschnitten werden, wenn Sie die Bildlaufleiste nicht unter dem Code snippit verwenden ... –

3

Ich denke, dass Sie readline nicht verwenden können, weil ffmpeg nie eine Zeile druckt, der Status wird aktualisiert, indem \ r (carrige return) geschrieben wird und dann die Zeile erneut geschrieben wird.

size=  68kB time=0.39 bitrate=1412.1kbits/s \rsize= 2786kB time=16.17 bitrate=1411.2kbits/s \rsize= 5472kB time=31.76 bitrate=1411.2kbits/s \r\n 

Wenn Sie die Zeile untersuchen oben werden Sie feststellen, dass es nur eine \ n ist und dass gedruckt wird, wenn die Datei Konvertierung erfolgt.

+1

Sie können readline tun, aber Sie erhalten nur die endgültige Version der Zeile, sobald es fertig ist ... – Anentropic

2

Da ffmpeg die Daten unflushed in stderr schreibt, müssen Sie den stderr-Dateideskriptor mithilfe von fcntl auf nicht blockierend setzen.

 
    fcntl.fcntl(
     pipe.stderr.fileno(), 
     fcntl.F_SETFL, 
     fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK, 
    ) 

und dann Schleife wählt die Daten

 
    while True: 
     readx = select.select([pipe.stderr.fileno()], [], [])[0] 
     if readx: 
      chunk = pipe.stderr.read() 

für volles Beispiel geht here zu lesen.

+0

Ich bin mir nicht sicher, ob das immer noch wahr ist .. Ich bekomme progressive Ausgabe nur eine readline auf stderr in einem aktuellen Build von ffmpeg auf py2.7: 'für Zeile in proc.stderr: Druckzeile proc.stderr.flush()' – Anentropic

+0

ah nein, gut, sortieren Ich bekomme keine progressive Ausgabe der 'frame = xxx' - Statusausgabe während der Kodierung (da dies eine Zeile ist, die wiederholt aktualisiert wird), aber ich sehe die Metadaten l ines dann blockt es, bis die Kodierung beendet ist, nur die letzte Statusaktualisierung zeigend, dann zeigt es die restlichen Zusammenfassungslinien an. – Anentropic

5

Einfach hinzufügen, universal_newlines = True zu Ihrem subprocess.Popen Linie.

cmd="ffmpeg -i in.mp4 -y out.avi" 
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True) 
for line in process.stdout: 
    print(line) 

Für jetzt haben Sie Linie in Zyklus wie:

frame= 1900 fps=453 q=18.6 Lsize= 3473kB time=00:01:16.08 bitrate= 373.9kbits/s 

Verwenden Zeit = Wert Fortschritt in Prozent zu bestimmen.

+0

Interessante Lösung, aber fügen Sie einige Pufferprobleme mit Popen hinzu. Funktioniert nicht sofort, wenn Sie nach einer Live-Encoding-Überwachung suchen. – littlebridge

-2
ffmpegCommand=''' 
ffmpeg 
-f lavfi 
-i anullsrc=channel_layout=1c:sample_rate=11025 
-rtsp_transport tcp 
-rtsp_transport udp 
-rtsp_transport http 
-thread_queue_size 32000 
-i rtsp://xxx.xxx.xxx.xxx:554/user=admin&password=xxx&channel=1&stream=1.sdp?real_stream 
-reconnect 1 
-reconnect_at_eof 1 
-reconnect_streamed 1 
-reconnect_delay_max 4294 
-tune zerolatency 
-c:v copy 
-c:a aac 
-bufsize 6000k 
-f flv rtmp://a.rtmp.youtube.com/live2/xxx-xxx-xxx-xxx''' 
cmd=ffmpegCommand.split() 
# "universal newline support" This will cause to interpret \n, \r\n and \r  equally, each as a newline. 

p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True) 
while True:  
     print(p.stderr.readline().rstrip('\r\n'))