Subproceso FFMPEG y Pythons

Estoy tratando de escribir una interfaz FFMPEG de FFMPEG para FFMPEG . Estoy usando el subproceso pythons para crear un proceso ffmpeg para cada conversión que deseo. Esto funciona bien, pero también me gustaría una forma de obtener el progreso de la conversión, ya sea que haya fallado o no, etc. Me imaginé que podría hacer esto accediendo a la salida estándar del proceso de esta manera:

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

Y leyendo 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() 

Esto funciona pero, el estado de ffmpeg no se muestra. Supongo que tiene algo que ver con la manera en que ffmpeg lo actualiza. ¿Hay alguna forma de acceder a ella?

A menudo he notado problemas al leer la salida estándar (o incluso el error estándar) con el subproceso, debido a problemas de almacenamiento en búfer que son difíciles de vencer. Mi solución favorita, cuando necesito leer dicho stdout / stderr del subproceso, es cambiar a usar, en lugar de subprocess , pexpect (o, en Windows, wexpect ).

Simplemente agregue, universal_newlines = Verdadero a su subproceso. Línea abierta.

 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) 

Por ahora tienes linea en ciclo como:

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

Usa el tiempo = valor para determinar el progreso en porcentaje.

Creo que no puedes usar readline porque ffmpeg nunca imprime una línea, el estado se actualiza escribiendo \ r (retorno de carrige) y luego escribiendo la línea nuevamente.

 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 examina la fila de arriba, notará que solo hay un \ n y que se imprime cuando el archivo termina de convertirse.

Dado que ffmpeg escribe los datos sin fluir en stderr, debe configurar el descriptor de archivo stderr para que no se bloquee mediante fcntl.

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

y luego bucle utilizando seleccionar para leer los datos

     mientras que True
         readx = select.select ([pipe.stderr.fileno ()], [], []) [0]
         si readx:
             chunk = pipe.stderr.read ()

para el ejemplo completo vaya aquí .

FFMPEG:

FFMPEG genera todo el texto de estado (lo que ve cuando lo ejecuta manualmente en la línea de comandos) en la interfaz stderr. Para capturar la salida de ffmpeg, debe estar viendo la interfaz stderr, o redirigirla como en el ejemplo.

Compruebe la salida en stderr:

Esta es otra manera de intentar leer desde stderr, en lugar de redirigirlo al llamar a Popen

La clase Popen en Python tiene un objeto de archivo llamado stderr, al que accederías de la misma manera que accedes a stdout. Estoy pensando que su bucle se vería así:

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

Descargo de responsabilidad: no he probado esto en Python, pero hice una aplicación similar utilizando Java.

 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'))