[Tutor] os.system vs subprocess.Popen args problems

Oscar Benjamin oscar.j.benjamin at gmail.com
Tue Sep 3 11:54:21 CEST 2013


On 3 September 2013 05:49, eryksun <eryksun at gmail.com> wrote:
> On Mon, Sep 2, 2013 at 10:19 AM, learner404 <learner404 at gmail.com> wrote:
>>
>> I can't understand why the command below works with os.system but not with
>> subprocess.Popen (on windows, recording video with FFMPEG.exe)
>>
>> cmd=('ffmpeg -f dshow -i video="%s" -f dshow -i audio="%s" -q 5 "%s"')%
>> (videoinputName, audioinputName, videoFileOutput)
>> os.system(cmd)
>> *works*
>>
>> subprocess.Popen(["ffmpeg","-f","dshow","-i",'video="%s"'%videoinputName,
>>   "-f","dshow","-i",'audio="%s"'%audioinputName,"-q","5",
>>   "%s"%videoFileOutput])
>> *don't work*
>>>> [dshow @ 025984a0] Could not find video device.
>>>> video="QuickCam Orbit/Sphere AF": Input/output error
>
> Popen joins the list into a string, as required by Windows
> CreateProcess(). It assumes the tokenizing rules used by Microsoft's C
> runtime. If that assumption is wrong, just switch to using a string
> instead of a list, with whatever custom quoting is required.

I've previously tried to find documentation that explains how MSVCRT
handles this. I didn't find anything as explicit as the explanation in
the subprocess docs. For example:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

> I'd first
> try it like this:
>
>     args = ['ffmpeg',
>             '-f', 'dshow', '-i', 'video=%s' % videoinputName,
>             '-f', 'dshow', '-i', 'audio=%s' % audioinputName,
>             '-q', '5', videoFileOutput]

By the way if you find this kind of thing a little less elegant than
the command line string for os.system you can always make a helper
function e.g.:

>>> import shlex
>>> def cmdsplit(cmdline, **kwargs):
...     return [a % kwargs for a in shlex.split(cmdline)]
...
>>> cmdline = 'ffmpeg -f dshow -i video=%(video)s -f dshow -i audio=%(audio)s -q 5 %(device)s'
>>> cmdsplit(cmdline, video="my video.mpg", audio="my audio.wav", device="my cam")
['ffmpeg', '-f', 'dshow', '-i', 'video=my video.mpg', '-f', 'dshow',
'-i', 'audio=my audio.wav', '-q', '5', 'my cam']

>
> Here's a simple script to print the raw command line, and also sys.argv.
>
> test.py
>
>     import sys
>     from ctypes import *
>
>     windll.kernel32.GetCommandLineW.restype = c_wchar_p
>
>     print(windll.kernel32.GetCommandLineW())

I'm pretty sure Python 2.x uses CreateProcessA and GetCommandLineA. No
idea about ffmpeg though (and probably makes no difference here)...

>     print(' '.join(sys.argv))

I'd expect 'print(sys.argv)' to be more informative here.

> system() vs Popen():
>
>     >>> exe = sys.executable
>
>     >>> cmdstr = '%s test.py video="QuickCam Orbit"' % exe
>     >>> os.system(cmdstr)
>     C:\Python27\python.exe  test.py video="QuickCam Orbit"
>     test.py video=QuickCam Orbit
>     0
>
>     >>> cmdlst = [exe, 'test.py', 'video="QuickCam Orbit"']
>     >>> subprocess.call(cmdlst)
>     C:\Python27\python.exe test.py "video=\"QuickCam Orbit\""
>     test.py video="QuickCam Orbit"
>     0

Ah, so subprocess does actually pass the quotes through. Okay that's
probably not what's wanted then.

It occurs to me that another possibility is if ffmpeg isn't really an
.exe on PATH but rather a .bat file or something. In that case
os.system or subprocess shell=True would pick it up but subprocess
shell=False might not. I say "might" because at least on some version
of Windows CreateProcess can run .bat files directly but I've never
seen this documented anywhere.

Apparently some newer versions of Windows have a "where" command that
could find ffmpeg for you. I don't have it on XP though...


Oscar


More information about the Tutor mailing list