2009-09-21 5 views
8

J'essaye d'écrire un GUI pour FFMPEG. J'utilise le sous-processus pythons pour créer un processus ffmpeg pour chaque conversion que je veux. Cela fonctionne très bien, mais je voudrais aussi comme un moyen d'obtenir les progrès de la conversion, si elle a échoué ou non, etc. Je me suis dit que je pouvais le faire en accédant à stdout du processus comme ceci:Sous-processus FFMPEG et Pythons

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

Et la lecture 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() 

Cela fonctionne, mais le statut de ffmpeg ne montre pas. Je suppose que cela a quelque chose à voir avec la façon dont ffmpeg le rafraîchit. Y a-t-il un moyen d'y accéder?

Répondre

8

J'ai souvent remarqué des problèmes de lecture de sortie standard (ou même d'erreur standard!) Avec un sous-processus, en raison de problèmes de mise en mémoire tampon difficiles à résoudre. Ma solution préférée, quand j'ai besoin de lire un tel stdout/stderr du sous-processus, est de passer à l'utilisation, au lieu de subprocess, pexpect (ou, sur Windows, wexpect).

+0

vos deux liens sont morts, s'il vous plaît les corriger – slhck

-1

FFMPEG:

sortie FFMPEG tout le texte d'état (ce que vous voyez lorsque vous exécutez manuellement sur la ligne de commande) sur l'interface stderr. Afin de capturer la sortie de ffmpeg, vous devez regarder l'interface stderr - ou la rediriger comme l'exemple.

Vérifier la sortie sur stderr:

Voici une autre façon d'essayer de lire stderr, au lieu de rediriger lorsque vous appelez Popen

Le Popen class en Python a un objet fichier appelé stderr , vous y accèderiez de la même manière que vous accédez à stdout. Je pense votre boucle ressemblerait à quelque chose comme ceci:

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

Disclaimer: Je ne l'ai pas testé ce en Python, mais je fait une application comparable en utilisant Java.

+0

Il redirige déjà stderr vers stdout. –

+0

Gorgapor, tu es sûr qu'il l'est? –

+0

Oui, le stderr est redirigé dans le code snippit sur la ligne avec subprocess.Popen - bien sûr il peut être coupé si vous n'utilisez pas la barre de défilement sous le code snippit ... –

3

Je pense que vous ne pouvez pas utiliser readline car ffmpeg n'imprime jamais une ligne, le statut est mis à jour en écrivant \ r (carrige return), puis en réécrivant la ligne.

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 

Si vous examinez la ligne ci-dessus, vous remarquerez qu'il n'y a qu'un seul \ n et qui est imprimé lorsque le fichier est fait la conversion.

+1

vous pouvez faire readline, mais vous obtenez seulement la version finale de cette ligne une fois qu'il est fini ... – Anentropic

2

Comme ffmpeg écrit les données non-purgées dans stderr, vous devez définir le descripteur de fichier stderr sur non-bloquant en utilisant fcntl.

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

et boucle à l'aide de sélection pour lire les données

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

par exemple complet aller here.

+0

Je ne suis pas sûr si cela est toujours vrai .. Je reçois une sortie progressive juste en faisant une readline sur stderr dans une version actuelle de ffmpeg sur py2.7: 'pour ligne dans proc.stderr: ligne d'impression proc.stderr.flush()' – Anentropic

+0

ah non, bien, sort Je ne reçois pas de sortie progressive de la sortie de statut 'frame = xxx' pendant le codage (puisque c'est une ligne qui est mise à jour à plusieurs reprises) mais je vois les métadonnées l ines alors il bloque jusqu'à ce que l'encodage soit terminé, ne montre que la dernière mise à jour du statut, puis affiche les lignes de résumé restantes. – Anentropic

5

Ajoutez simplement universal_newlines = True à votre ligne subprocess.Popen.

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) 

Pour l'instant vous avez obtenu la ligne dans le cycle comme:

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

Utilisez le temps = valeur pour déterminer les progrès en pourcentage.

+0

Solution intéressante, mais ajoutez quelques problèmes de mise en mémoire tampon avec Popen. Ne fonctionnera pas dès la sortie de la boîte si vous recherchez une surveillance de codage en direct. – 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')) 
Questions connexes