views:

851

answers:

4

I'm trying to use subprocess.Popen to construct a sequence to grab the duration of a video file. I've been searching for 3 days, and can't find any reason online as to why this code isn't working, but it keeps giving me a blank result:

import sys
import os
import subprocess

def main():
  the_file = "/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
  ffmpeg = subprocess.Popen(['/opt/local/bin/ffmpeg', '-i', the_file], stdout = subprocess.PIPE, )
  grep = subprocess.Popen(['grep', 'Duration'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )
  cut = subprocess.Popen(['cut', '-d', ' ', '-f', '4'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )
  sed = subprocess.Popen(['sed', 's/,//'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )

  duration = sed.communicate()
  print duration

if __name__ == '__main__':
  main()
+4  A: 

Using subprocess.PIPE will not magically wire the correct pipes for you.

You must pass the output pipe of the first process as the value for the parameter stdin of the second process. See the docs for an example.

Aaron Digulla
+2  A: 

Python can't "build a whole pipeline" in this way -- it could delegate the task to the shell, or glue it up more directly using the stdout attributes of previous subprocess objects in the line, but there's really no reason for that in this specific case, since you can code it directly in Python pretty easily. E.g.:

  ffmpeg = subprocess.Popen(['/opt/local/bin/ffmpeg', '-i', the_file],
                            stdout=subprocess.PIPE)
  for line in ffmpeg.stdout:
    if 'Duration' not in line: continue
    fields = line.split()
    duration = fields[4].replace(',', '')
    break
Alex Martelli
A: 

I would advise using something like this and avoiding opening other processes like you are doing.

If this as complicated as this script will become, I would just glue it together with bash.

prestomation
+1  A: 

stderr needs to be redirected to stdout. Also, there's no need to call other tools like cut/sed etc. do your string manipulation in Python

import subprocess
....
the_file = "/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
ffmpeg = subprocess.Popen(['/usr/bin/ffmpeg', '-i', the_file], stderr=subprocess.STDOUT,stdout = subprocess.PIPE )
out, err = ffmpeg.communicate()
if "Duration" in out:
    print out[out.index("Duration"):].split()[1]

If Python is not a must, you can use the shell directly.

the_file="/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
ffmpeg -i "$file" 2>&1 | awk '/Duration/{print $2}'
ghostdog74
Thank you. I didn't realize I had to redirect `stderr` as well.
Gordon Fontenot