views:

867

answers:

4

I'm trying to write a gui for FFMPEG. I'm using pythons subprocess to create a ffmpeg process for every conversion I want. This works fine, but I'd also like a way to get the progress of the conversion, whether it failed or not etc. I figured I could do this by accessing the process's stdout like so:

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.

And reading 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()

This works but, ffmpeg's status doesn't show. I'm assuming it has something to do with way ffmpeg refreshes it. Is there a way to access it?

A: 

FFMPEG:

FFMPEG output all the status text (what you see when you run it manually on the command line) on the stderr interface. In order to capture output from ffmpeg, you need to be watching the stderr interface - or redirecting it like the example.

Check for output on stderr:

Here is another way to try and read from stderr, instead of redirecting it when calling Popen

The Popen class in Python has an file object called stderr, you would access it in the same way that you are accessing stdout. I'm thinking your loop would look something like this:

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

Disclaimer: I haven't tested this in Python, but I made a comparable application using Java.

Redbeard 0x0A
He is already redirecting stderr to stdout.
Christian Oudard
Gorgapor, are you sure he is?
Matthew Talbert
Yes, the stderr is redirected in the code snippit on the line with subprocess.Popen -- of course it can be cut off if you don't use the scroll bar under the code snippit...
Redbeard 0x0A
Yes, I'm already redirecting it =(
bombpersons
+4  A: 

I've often noticed problems reading standard output (or even standard error!) with subprocess, due to buffering issues that are hard to defeat. My favorite solution, when I do need to read such stdout/stderr from the subprocess, is to switch to using, instead of subprocess, pexpect (or, on Windows, wexpect).

Alex Martelli
A: 

I think you can't use readline because ffmpeg never prints one line, the status is updated by writing \r (carrige return) and then writing the line again.

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

If you examine the row above you'll notice that there is only one \n and that gets printed when the file is done converting.

Linus Unnebäck
A: 

Since ffmpeg writes the data unflushed to stderr you have to set the stderr file descriptor to non-blocking using fcntl.

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

and then loop using select to read the data

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

for full example go here.

Derrick Petzold