Trying to chain processes together on a pipeline
Peter Otten
__peter__ at web.de
Tue Jun 28 02:32:35 EDT 2011
Andrew Berg wrote:
> I'm working on an audio/video converter script (moving from bash to
> Python for some extra functionality), and part of it is chaining the
> audio decoder (FFmpeg) either into SoX to change the volume and then to
> the Nero AAC encoder or directly into the Nero encoder. This is the
> chunk of code from my working bash script to give an idea of what I'm
> trying to accomplish (it's indented because it's nested inside a while
> loop and an if statement):
>> if [ "$process_audio" = "true" ]
>> then
>> if [ $vol == 1.0 ]
>> then
>> ffmpeg -i "${ifile_a}" -f wav - 2>$nul | neroaacenc
>> -ignorelength -q 0.4 -if - -of ${prefix}${zero}${ep}.m4a
>> else
>> # the pipeline-as-file option of sox fails on Windows
>> 7, so I use the safe method since there's only one pipeline going into
>> sox
>> ffmpeg -i "${ifile_a}" -f sox - 2>$nul | sox -t sox -
>> -t wav - vol $vol 2>$nul | neroaacenc -ignorelength -q 0.4 -if - -of
>> ${prefix}${zero}${ep}.m4a
>> fi
>> else
>> echo "Audio skipped."
>> fi
> This is pretty easy and straightforward in bash, but not so in Python.
> This is what I have in Python (queue[position] points to an object I
> create earlier that holds a bunch of info on what needs to be encoded -
> input and output file names, command line options for the various
> encoders used, and so forth), but clearly it has some problems:
>> try:
>> ffmpeg_proc = subprocess.Popen(queue[position].ffmpeg_cmd,
>> stdout=subprocess.PIPE, stderr=os.devnull)
>> except WindowsError:
>> error_info = str(sys.exc_info()[1])
>> last_win_error_num = find_win_error_no(error_msg=error_info)
>> if last_win_error_num == '2': # Error 2 = 'The system cannot
>> find the file specified'
>> logger.critical('Could not execute ' +
>> queue[position].ffmpeg_exe + ': File not found.')
>> elif last_win_error_num == '193': # Error 193 = '%1 is not a
>> valid Win32 application'
>> logger.critical('Could not execute ' +
>> queue[position].ffmpeg_exe + ': It\'s not a valid Win32 application.')
>> break
>> if queue[position].vol != 1:
>> try:
>> sox_proc = subprocess.Popen(queue[position].sox_cmd,
>> stdin=ffmpeg_proc.stdout, stdout=subprocess.PIPE, stderr=os.devnull)
>> except WindowsError:
>> error_info = str(sys.exc_info()[1])
>> last_win_error_num = find_win_error_no(error_msg=error_info)
>> if last_win_error_num == '2': # Error 2 = 'The system
>> cannot find the file specified'
>> logger.critical('Could not execute ' +
>> queue[position].sox_exe + ': File not found.')
>> elif last_win_error_num == '193': # Error 193 = '%1 is not
>> a valid Win32 application'
>> logger.critical('Could not execute ' +
>> queue[position].sox_exe + ': It\'s not a valid Win32 application.')
>> break
>> wav_pipe = sox_proc.stdout
>> else:
>> wav_pipe = ffmpeg_proc.stdout
>> try:
>> nero_aac_proc = subprocess.Popen(queue[position].nero_aac_cmd,
>> stdin=wav_pipe)
>> except WindowsError:
>> error_info = str(sys.exc_info()[1])
>> last_win_error_num = find_win_error_no(error_msg=error_info)
>> if last_win_error_num == '2': # Error 2 = 'The system cannot
>> find the file specified'
>> logger.critical('Could not execute ' +
>> queue[position].sox_exe + ': File not found.')
>> elif last_win_error_num == '193': # Error 193 = '%1 is not a
>> valid Win32 application'
>> logger.critical('Could not execute ' +
>> queue[position].sox_exe + ': It\'s not a valid Win32 application.')
>> break
>>
>> ffmpeg_proc.wait()
>> if queue[position].vol != 1:
>> sox_proc.wait()
>> nero_aac_proc.wait()
>> break
> Note: those break statements are there to break out of the while loop
> this is in.
> Firstly, that first assignment to ffmpeg_proc raises an exception:
>> Traceback (most recent call last):
>> File "C:\Users\Bahamut\workspace\Disillusion\disillusion.py", line
>> 288, in <module>
>> ffmpeg_proc = subprocess.Popen(queue[position].ffmpeg_cmd,
>> stdout=subprocess.PIPE, stderr=os.devnull)
>> File "C:\Python32\lib\subprocess.py", line 700, in __init__
>> errread, errwrite) = self._get_handles(stdin, stdout, stderr)
>> File "C:\Python32\lib\subprocess.py", line 861, in _get_handles
>> errwrite = msvcrt.get_osfhandle(stderr.fileno())
>> AttributeError: 'str' object has no attribute 'fileno'
> I'm not really sure what it's complaining about since the exception
> propagates from the msvcrt module through the subprocess module into my
> program. I'm thinking it has to do my stderr assignment, but if that's
> not right, I don't know what is.
os.devnull is a string, but you need a writable file:
>>> subprocess.call(["ls"], stdout=os.devnull)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/subprocess.py", line 470, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.6/subprocess.py", line 614, in __init__
errread, errwrite) = self._get_handles(stdin, stdout, stderr)
File "/usr/lib/python2.6/subprocess.py", line 971, in _get_handles
c2pwrite = stdout.fileno()
AttributeError: 'str' object has no attribute 'fileno'
>>> subprocess.call(["ls"], stdout=open(os.devnull, "w"))
0
> Secondly, there are no Popen.stdout.close() calls because I'm not sure
> where to put them.
> Thirdly, I have nearly identical except WindowsError: blocks repeated -
> I'm sure I can avoid this with decorators as suggested in a recent
> thread, but I haven't learned decorators yet. This code isn't very
> complete; I'm trying to get it to work in ideal conditions first, then
> worry about how to handle failure.
Start with factoring out common code into a good old function.
> Using Python 3 on Windows 7.
More information about the Python-list
mailing list