2009-09-21 7 views
8

Próbuję napisać gui dla FFMPEG. Używam podprocesów pythonów do utworzenia procesu ffmpeg dla każdej wybranej konwersji. Działa to dobrze, ale ja też lubię sposób, aby uzyskać postęp konwersji, czy to nie udało, czy nie itd. Pomyślałem, co mogłem zrobić to poprzez dostęp do stdout procesu jest tak:Podproces FFMPEG i Pythons

Wywołanie subprocess.Popen()

# 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. 

i czytanie stdout:

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

convert.convert() 

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

działa to jednak, status FFmpeg nie pokazuje. Zakładam, że ma to coś wspólnego z tym, co ffmpeg odświeża. Czy jest jakiś sposób, aby uzyskać do niego dostęp?

Odpowiedz

8

Często zauważyłem problemy z odczytywaniem standardowego wyjścia (lub nawet błędu standardowego!) Z podprocesu, z powodu problemów z buforowaniem, które są trudne do pokonania. Moim ulubionym rozwiązaniem, gdy potrzebuję odczytać stdout/stderr z podprocesu, jest przełączenie na używanie, zamiast subprocess, pexpect (lub, w systemie Windows, wexpect).

+0

Oba twoje łącza są martwe, napraw je. – slhck

-1

FFMPEG:

wyjście FFMPEG cały tekst status (co widać po uruchomieniu go ręcznie w linii poleceń) na interfejsie stderr. Aby przechwytywać dane wyjściowe z ffmpeg, musisz obserwować interfejs stderr - lub przekierowywać go jak przykład.

Sprawdź wyjście na stderr:

Oto kolejny sposób, aby spróbować odczytać z stderr zamiast przekierowanie go podczas wywoływania POPEN

Popen class w Pythonie ma obiekt pliku o nazwie stderr , będziesz miał do niego dostęp w taki sam sposób, w jaki uzyskujesz dostęp do standardowego. Myślę, że pętla będzie wyglądać mniej więcej tak:

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

Oświadczenie: Nie testowałem tego w Pythonie, ale zrobiłem porównywalny aplikacji przy użyciu Java.

+0

Już przekierowuje stderr na stdout. –

+0

Gorgapor, czy na pewno jest? –

+0

Tak, stderr jest przekierowywany w skrypcie kodu na linii z podprocesorem.Popen - oczywiście można go wyłączyć, jeśli nie używasz paska przewijania pod kodem kodu ... –

3

Myślę, że nie można użyć readline, ponieważ ffmpeg nigdy nie drukuje jednej linii, status jest aktualizowany przez zapisanie \ r (powrót carrige), a następnie ponowne wpisanie wiersza.

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 

Jeśli przyjrzysz wiersz powyżej można zauważyć, że istnieje tylko jeden \ n oraz że zostanie wydrukowany kiedy plik jest wykonywana konwersja.

+1

możesz zrobić readline, ale ostatnią wersję tej linii otrzymasz dopiero po jej zakończeniu ... – Anentropic

2

Ponieważ ffmpeg zapisuje dane odseparowane na stderr, należy ustawić deskryptor pliku stderr na nieblokujący, używając fcntl.

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

a następnie wybierz za pomocą pętli do odczytania danych

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

pełnego przykład pójść here.

+0

Nie jestem pewien, czy to nadal prawda. Otrzymuję wyjście progresywne po prostu robiąc readlinę na stderr w bieżącej kompilacji ffmpeg na py2.7: 'dla linii w proc.stderr: linia drukowania proc.stderr.flush()' – Anentropic

+0

ah nie, dobrze, sortuj z. Nie otrzymuję progresywnego wyjścia wyjścia statusu 'frame = xxx' podczas kodowania (ponieważ jest to jedna linia, która jest aktualizowana wielokrotnie), ale widzę metadane Ines następnie blokuje do zakończenia kodowania, wyświetlając tylko ostatnią aktualizację statusu, a następnie wyświetla pozostałe wiersze podsumowania. – Anentropic

5

Po prostu dodaj, universal_newlines = Prawda do twojego podprocesu.Popen linii.

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) 

Teraz masz linię w cyklu jak:

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

wykorzystać czas = wartość w celu określenia postępów w procentach.

+0

Ciekawe rozwiązanie, ale dodaj trochę problemów z buforowaniem z Popenem. Nie będzie działać od razu po wyjęciu z pudełka, jeśli szukasz monitorowania na żywo. – 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'))