2009-09-21 27 views
8

Estoy intentando escribir una interfaz gráfica de usuario para FFMPEG. Estoy usando el subproceso de pitones para crear un proceso ffmpeg para cada conversión que deseo. Esto funciona bien, pero también me gustaría una manera de conseguir el progreso de la conversión, si no lo hizo o no, etc. pensé que podría hacerlo accediendo a la salida estándar del proceso de esta manera:Subproceso FFMPEG y Python

Calling 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, estado de ffmpeg no muestra. Supongo que tiene algo que ver con la forma en que ffmpeg lo actualiza. ¿Hay alguna forma de acceder a ella?

Respuesta

8

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 memoria intermedia que son difíciles de superar. Mi solución favorita, cuando necesito leer stdout/stderr del subproceso, es cambiar a usar, en lugar de subprocess, pexpect (o, en Windows, wexpect).

+0

Ambos enlaces están muertos, por favor, corríjalos. – slhck

-1

FFMPEG:

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

Comprobar para la salida de stderr:

Aquí hay otra manera de tratar de leer de stderr, en lugar de redirigirla al llamar Popen

El Popen class en Python tiene un objeto archivo llamado stderr , tendría acceso a él de la misma manera que está accediendo a stdout. Estoy pensando en su bucle sería algo como esto:

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

de responsabilidad: No he probado esto en Python, pero hice una aplicación comparables utilizando Java.

+0

Él ya está redirigiendo stderr a stdout. –

+0

Gorgapor, ¿estás seguro de que lo es? –

+0

Sí, stderr se redirige en el snippit de código en la línea con subproceso.Popen - por supuesto, se puede cortar si no usa la barra de desplazamiento debajo del snippit de código ... –

3

Creo que no puede usar readline porque ffmpeg nunca imprime una línea, el estado se actualiza escribiendo \ r (retorno de carro) 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 anterior se dará cuenta de que sólo hay un \ n y que se imprime cuando el archivo se realiza la conversión.

+1

puedes leer, pero solo obtienes la versión final de esa línea una vez que ha terminado ... – Anentropic

2

Dado que ffmpeg escribe los datos no borrados en stderr, debe configurar el descriptor del archivo stderr como no bloqueante con fcntl.

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

y luego seleccione bucle que utiliza para leer los datos

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

para la plena ejemplo ir here.

+0

No estoy seguro de si esto sigue siendo cierto ... . Obtengo salida progresiva simplemente haciendo una línea de lectura en stderr en una compilación actual de ffmpeg en py2.7: 'para la línea en proc.stderr: línea de impresión proc.stderr.flush()' – Anentropic

+0

ah no, bueno, clasificación de. No recibo salida progresiva de la salida de estado 'frame = xxx' durante la codificación (ya que esta es una línea que se actualiza repetidamente) pero veo los metadatos l Luego, se bloquea hasta que la codificación finaliza, mostrando solo la última actualización de estado, y luego muestra las líneas de resumen restantes. – Anentropic

5

Simplemente agregue, universal_newlines = Verdadero en su subproceso. Línea de acceso libre.

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 se tiene la línea en el ciclo como:

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

Uso del tiempo = valor para determinar el progreso en porcentaje.

+0

Solución interesante, pero agregue algunos problemas de almacenamiento en búfer con Popen. No funcionará directamente si está buscando monitoreo de codificación en vivo. – 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')) 
Cuestiones relacionadas