Reputation: 1380
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()
Upvotes: 14
Views: 44930
Reputation: 251
As others have pointed out, you need to pass the PIPE from one process to the next. The stdout (PIPE) from one process becomes the stdin for the following task.
Something like this (starting from your example):
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 = ffmpeg.stdout, stdout = subprocess.PIPE)
cut = subprocess.Popen(['cut', '-d', ' ', '-f', '4'],
stdin = grep.stdout, stdout = subprocess.PIPE)
sed = subprocess.Popen(['sed', 's/,//'],
stdin = cut.stdout, stdout = subprocess.PIPE)
duration = sed.communicate()[0]
print duration
if __name__ == '__main__':
main()
Upvotes: 25
Reputation: 342263
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}'
Upvotes: 15
Reputation: 881497
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
Upvotes: 4
Reputation: 328556
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.
Upvotes: 14