How to check if a video has sound in Python? - python
I would just like a True if a video has audio or False if it does not have audio.
I feel like I'm almost there using subprocess.
I get info about the video file running ffprobe and splitting the results into a list.
I've tried matching a string that does or does not have audio in the list but this is not giving me consistant results.
from subprocess import Popen, PIPE
import subprocess
b = '/path/to/mp4'
'0:1' in str(subprocess.run(['ffprobe', b], stdout=PIPE, stderr=PIPE).stderr.split()[-20])
The line above checks if there is a second stream in the video file in the 20th from the last line. Like I said, not always consistent.
I'm just having trouble requesting or parsing what I'm getting from ffmprobe.
Here is everything returned from ffprobe instead of just the 20th from the last item.
b = '/path/to/mp4'
subprocess.run(['ffprobe', b], stdout=PIPE, stderr=PIPE).stderr.split()
returns...
[b'ffprobe',
b'version',
b'4.2.4-1ubuntu0.1',
b'Copyright',
b'(c)',
b'2007-2020',
b'the',
b'FFmpeg',
b'developers',
b'built',
b'with',
b'gcc',
b'9',
b'(Ubuntu',
b'9.3.0-10ubuntu2)',
b'configuration:',
b'--prefix=/usr',
b'--extra-version=1ubuntu0.1',
b'--toolchain=hardened',
b'--libdir=/usr/lib/x86_64-linux-gnu',
b'--incdir=/usr/include/x86_64-linux-gnu',
b'--arch=amd64',
b'--enable-gpl',
b'--disable-stripping',
b'--enable-avresample',
b'--disable-filter=resample',
b'--enable-avisynth',
b'--enable-gnutls',
b'--enable-ladspa',
b'--enable-libaom',
b'--enable-libass',
b'--enable-libbluray',
b'--enable-libbs2b',
b'--enable-libcaca',
b'--enable-libcdio',
b'--enable-libcodec2',
b'--enable-libflite',
b'--enable-libfontconfig',
b'--enable-libfreetype',
b'--enable-libfribidi',
b'--enable-libgme',
b'--enable-libgsm',
b'--enable-libjack',
b'--enable-libmp3lame',
b'--enable-libmysofa',
b'--enable-libopenjpeg',
b'--enable-libopenmpt',
b'--enable-libopus',
b'--enable-libpulse',
b'--enable-librsvg',
b'--enable-librubberband',
b'--enable-libshine',
b'--enable-libsnappy',
b'--enable-libsoxr',
b'--enable-libspeex',
b'--enable-libssh',
b'--enable-libtheora',
b'--enable-libtwolame',
b'--enable-libvidstab',
b'--enable-libvorbis',
b'--enable-libvpx',
b'--enable-libwavpack',
b'--enable-libwebp',
b'--enable-libx265',
b'--enable-libxml2',
b'--enable-libxvid',
b'--enable-libzmq',
b'--enable-libzvbi',
b'--enable-lv2',
b'--enable-omx',
b'--enable-openal',
b'--enable-opencl',
b'--enable-opengl',
b'--enable-sdl2',
b'--enable-libdc1394',
b'--enable-libdrm',
b'--enable-libiec61883',
b'--enable-nvenc',
b'--enable-chromaprint',
b'--enable-frei0r',
b'--enable-libx264',
b'--enable-shared',
b'libavutil',
b'56.',
b'31.100',
b'/',
b'56.',
b'31.100',
b'libavcodec',
b'58.',
b'54.100',
b'/',
b'58.',
b'54.100',
b'libavformat',
b'58.',
b'29.100',
b'/',
b'58.',
b'29.100',
b'libavdevice',
b'58.',
b'8.100',
b'/',
b'58.',
b'8.100',
b'libavfilter',
b'7.',
b'57.100',
b'/',
b'7.',
b'57.100',
b'libavresample',
b'4.',
b'0.',
b'0',
b'/',
b'4.',
b'0.',
b'0',
b'libswscale',
b'5.',
b'5.100',
b'/',
b'5.',
b'5.100',
b'libswresample',
b'3.',
b'5.100',
b'/',
b'3.',
b'5.100',
b'libpostproc',
b'55.',
b'5.100',
b'/',
b'55.',
b'5.100',
b'Input',
b'#0,',
b'mov,mp4,m4a,3gp,3g2,mj2,',
b'from',
b"'/media/iii/Q2/tor/Reddit/Subs/unexpected/l2aifial2ir51.mp4':",
b'Metadata:',
b'major_brand',
b':',
b'isom',
b'minor_version',
b':',
b'512',
b'compatible_brands:',
b'isomiso2avc1mp41',
b'encoder',
b':',
b'Lavf58.29.100',
b'Duration:',
b'00:00:16.27,',
b'start:',
b'0.000000,',
b'bitrate:',
b'1341',
b'kb/s',
b'Stream',
b'#0:0(und):',
b'Video:',
b'h264',
b'(Main)',
b'(avc1',
b'/',
b'0x31637661),',
b'yuv420p,',
b'384x480',
b'[SAR',
b'1:1',
b'DAR',
b'4:5],',
b'1205',
b'kb/s,',
b'30',
b'fps,',
b'30',
b'tbr,',
b'12k',
b'tbn,',
b'60',
b'tbc',
b'(default)',
b'Metadata:',
b'handler_name',
b':',
b'Bento4',
b'Video',
b'Handler',
b'Stream',
b'#0:1(und):',
b'Audio:',
b'aac',
b'(LC)',
b'(mp4a',
b'/',
b'0x6134706D),',
b'48000',
b'Hz,',
b'stereo,',
b'fltp,',
b'128',
b'kb/s',
b'(default)',
b'Metadata:',
b'handler_name',
b':',
b'Bento4',
b'Sound',
b'Handler']
I have also tried modifying this function from one that returns the duration of video files to one that returns True or False for audio because this is probably a less hacky way of getting the bool. I'm a bit out of my depth trying to use these different options.
def get_length(filename):
result = subprocess.run(["ffprobe", "-v", "error", "-show_entries",
"format=duration", "-of",
"default=noprint_wrappers=1:nokey=1", filename],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
return float(result.stdout)
I believe I found the option to sort any video file with an output of 1 (for True, has sound), or 0 (for False, does not have sound) by passing nb_streams in the format option below.
Used a combination of this answer and the docs for ffmpeg to figure this out.
def has_audio(filename):
result = subprocess.run(["ffprobe", "-v", "error", "-show_entries",
"format=nb_streams", "-of",
"default=noprint_wrappers=1:nokey=1", filename],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
return (int(result.stdout) -1)
The code actually returns the number of streams. 2 for two streams, video and audio, or 1 for just video. I subtracted a one because I want the bool answer.
This should probably not be used to sort audio only files. Though I wonder if 1 for just video and 2 for audio and video is always the case for known video files. Can a video file have 3 or more streams?
Building on previous answers, this will check each stream to see if at least one has an "audio" type codec. Please note that an audio stream may be present but silent, in which case this will still return True.
from subprocess import check_output
import json
def has_audio_streams(file_path):
command = ['ffprobe', '-show_streams',
'-print_format', 'json', file_path]
output = check_output(command)
parsed = json.loads(output)
streams = parsed['streams']
audio_streams = list(filter((lambda x: x['codec_type'] == 'audio'), streams))
return len(audio_streams) > 0
The answer isn't too hard.
MAC
pip3 install ffprobe
WINDOWS
pip install ffprobe
LINUX
pip install ffprobe
USAGE
ffprobe -show_streams -print_format json input.mov should work.
One can use pymediainfo module for this.
def has_audio(p):
from pymediainfo import MediaInfo
fileInfo = MediaInfo.parse(p)
return any([track.track_type == 'Audio' for track in fileInfo.tracks])
Related
FFMPEG Frame-exact Video Cropping
Goal: To crop a video at a specific frame using FFMPEG Problem: Video freezes at the end for ~1s I'm new to FFMPEG, so not sure if any other details are needed to debug this. import subprocess import datetime # Calculate start and end times in hh:mm:ss.ms start_frame, end_frame = (9553, 10181) start_time = str(datetime.timedelta(seconds=start_frame/fps)) end_time = str(datetime.timedelta(seconds=end_frame/fps)) cmd = ['ffmpeg', '-y', '-ss', start_time, '-to', end_time, '-i', input_path, '-c', 'copy', clip_path] subprocess.call(cmd) Values: Start Frame: 9553 End Frame: 10181 Start Time: 0:06:22.120000 End Time: 0:06:47.240000
You will have to cut on key frames only or remove -c copy and re-encode.
Python,Shell: How to extract data and store in a iterable varible(specifically in list)?
I am working on my own project. In which these steps have to be performed: Connect to remote server. Get pid, process name, cpu usage, swap memory usage by each running process on remote server daily on some specific time(say at 4'0 clock). I have to compare every day's result with previous day's result (e.g. day1-pid with day2 pid and day1 process name with day2 process name etc.) So far I have done up to step-2. Now I want to know that how to extract the pid, process name, cpu usage, swap memory usage from remote server and store it in some iterable variable. So that I can compare it for checking memory spike? Any other way apart from my idea will be appreciable. My code sample is like this: import paramiko import re import psutil class ShellHandler: def __init__(self, host, user, psw): self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.ssh.connect(host, username=user, password=psw, port=22) channel = self.ssh.invoke_shell() self.stdin = channel.makefile('wb') self.stdout = channel.makefile('r') def __del__(self): self.ssh.close() #staticmethod def _print_exec_out(cmd, out_buf, err_buf, exit_status): print('command executed: {}'.format(cmd)) print('STDOUT:') for line in out_buf: print(line, end="") print('end of STDOUT') print('STDERR:') for line in err_buf: print(line, end="") print('end of STDERR') print('finished with exit status: {}'.format(exit_status)) print('------------------------------------') #print(psutil.pids()) pass def execute(self, cmd): """ :param cmd: the command to be executed on the remote computer :examples: execute('ls') execute('finger') execute('cd folder_name') """ cmd = cmd.strip('\n') self.stdin.write(cmd + '\n') finish = 'end of stdOUT buffer. finished with exit status' echo_cmd = 'echo {} $?'.format(finish) self.stdin.write(echo_cmd + '\n') shin = self.stdin self.stdin.flush() shout = [] sherr = [] exit_status = 0 for line in self.stdout: if str(line).startswith(cmd) or str(line).startswith(echo_cmd): # up for now filled with shell junk from stdin shout = [] elif str(line).startswith(finish): # our finish command ends with the exit status exit_status = int(str(line).rsplit(maxsplit=1)[1]) if exit_status: # stderr is combined with stdout. # thus, swap sherr with shout in a case of failure. sherr = shout shout = [] break else: # get rid of 'coloring and formatting' special characters shout.append(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[#-~]').sub('', line).replace('\b', '').replace('\r', '')) # first and last lines of shout/sherr contain a prompt if shout and echo_cmd in shout[-1]: shout.pop() if shout and cmd in shout[0]: shout.pop(0) if sherr and echo_cmd in sherr[-1]: sherr.pop() if sherr and cmd in sherr[0]: sherr.pop(0) self._print_exec_out(cmd=cmd, out_buf=shout, err_buf=sherr, exit_status=exit_status) return shin, shout, sherr obj=ShellHandler('Servername','username','password') pID=[] ## I want this(pid, cmd, swap memory) to store in a varible which would be iterable. pID=ShellHandler.execute(obj,"ps -eo pid,cmd,lstart,%mem,%cpu|awk '{print $1}'") print(pID[0])##---------------------------------Problem not giving any output.
Your ShellHandler's execute method returns three items, the first of which is the input you sent to it. You should probably call it directly like this, anyway: obj = ShellHandler('Servername','username','password') in, out, err = obj.execute("ps -eo pid,lstart,%mem,%cpu,cmd") for line in out.split('\n'): pid, lstartwd, lstartmo, lstartdd, lstartm, lstartyy, mem, cpu, cmd = line.split(None, 8) I moved cmd last because it might contain spaces. The lstart value also contains multiple space-separated fields. Here's what the output looks like in Debian: 19626 Tue Jan 15 15:03:57 2019 0.0 0.0 less filename There are many questions about how to parse ps output in more detail; I'll refer you to them for figuring out how to handle the results from split exactly. Splitting out the output of ps using Python Is there any way to get ps output programmatically?
ps aux command should have all the info you need (pid, process name, cpu, memory)
Python video editing -- How to trim videos
Is there an easy way to trim a video file in python. If I know the start time and end time, I want to save the new file as multiple shorter files based on input. example pseudo code: function cut_video(original_vid, start, stop): original_vid.start_time(start) original_vid.end_time(stop) original_vid.trim() #based on times new_vid = original_vid return new_vid
Found a solution: def get_ffmpeg_bin(): ffmpeg_dir = helper_functions.get_ffmpeg_dir_path() FFMPEG_BIN = os.path.join(ffmpeg_dir, "ffmpeg.exe") return FFMPEG_BIN def split_vid_from_path(video_file_path, start_time, durration): ffmpeg_binary = get_ffmpeg_bin() output_file_name = get_next_file_name(video_file_path) pipe = sp.Popen([ffmpeg_binary,"-v", "quiet", "-y", "-i", video_file_path, "-vcodec", "copy", "-acodec", "copy", "-ss", start_time, "-t", durration, "-sn", output_file_name ]) pipe.wait() return True sample_vid = os.path.join(get_sample_vid_dir_path(), "Superman-01-The_Mad_Scientist.mp4") split_vid_from_path(sample_vid, "00:00:00", "00:00:17") https://www.ffmpeg.org/ffmpeg.html -> this documentation allows you to add your own custom flags to your ffmpeg wrapper. Something to note, you may want to verify the user is giving you valid data.
A nice module to do these kids of things is moviepy. Example Code: from moviepy.editor import * video = VideoFileClip("myHolidays.mp4").subclip(50,60) # Make the text. Many more options are available. txt_clip = ( TextClip("My Holidays 2013",fontsize=70,color='white') .set_position('center') .set_duration(10) ) result = CompositeVideoClip([video, txt_clip]) # Overlay text on video result.write_videofile("myHolidays_edited.webm",fps=25) # Many options... The documentation of this module can be found at https://pypi.org/project/moviepy/
avconv with subprocess
It's seems like I never really manage to wrap my head around subprocess. This commandline works in bash avconv -i "concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts" -vcodec copy -acodec copy /tmp/test1.ts Bu if I try this: cmdline = ['avconv', '-i "concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts"', '-vcodec copy', '-acodec copy', '/tmp/test1.ts'] subprocess.call(cmdline) It exit avconv with the following error: avconv version 0.8.3-4:0.8.3-0ubuntu0.12.04.1, Copyright (c) 2000-2012 the Libav developers built on Jun 12 2012 16:52:09 with gcc 4.6.3 Unrecognized option 'i "concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts"' Failed to set value '-vcodec copy' for option 'i "concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts"' 1 I've tried some variants (including shell=True) but I can't figure out the problem. Update Cjb made an answer that really worked. But my real code is more complicated. I believe it's hard to get something out of it. But I throw it in here just in case there is an obvoius problem that I missed. def run_avconv(output_dir, fnames): full_fnames = [os.path.join(output_dir, fname.replace('\n', '')) for fname in fnames] concatted_files = '|'.join(full_fnames) cmd_line = [AVCONV_CMD, '-i', '"concat:' + concatted_files + '"', '-vcodec', 'copy', '-acodec', 'copy', os.path.join(output_dir, 'out.ts')] subprocess.Popen(cmd_line) the full_fnames variable is: ['/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment2.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment3.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment4.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment5.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment6.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment7.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment8.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment9.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment10.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment11.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment12.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment13.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment14.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment15.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment16.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment17.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment18.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment19.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment20.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment21.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment22.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment23.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment24.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment25.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment26.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment27.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment28.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment29.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment30.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment31.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment32.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment33.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment34.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment35.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment36.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment37.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment38.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment39.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment40.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment41.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment42.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment43.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment44.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment45.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment46.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment47.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment48.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment49.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment50.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment51.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment52.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment53.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment54.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment55.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment56.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment57.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment58.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment59.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment60.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment61.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment62.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment63.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment64.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment65.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment66.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment67.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment68.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment69.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment70.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment71.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment72.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment73.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment74.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment75.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment76.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment77.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment78.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment79.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment80.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment81.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment82.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment83.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment84.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment85.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment86.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment87.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment88.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment89.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment90.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment91.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment92.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment93.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment94.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment95.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment96.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment97.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment98.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment99.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment100.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment101.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment102.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment103.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment104.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment105.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment106.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment107.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment108.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment109.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment110.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment111.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment112.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment113.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment114.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment115.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment116.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment117.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment118.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment119.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment120.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment121.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment122.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment123.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment124.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment125.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment126.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment127.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment128.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment129.ts', '/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment130.ts']
Try it with this: cmdline = [ 'avconv', '-i', 'concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts', '-vcodec', 'copy', '-acodec', 'copy', '/tmp/test1.ts', ] subprocess.call(cmdline) You really want to pass each separate part as a different item in the list.
The answer by #djc is correct, however if you wanted to work by copying and pasting a string, you can do something like this: import shlex from pprint import pprint cmd = """avconv -i "concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts" -vcodec copy -acodec copy /tmp/test1.ts""" for_subprocess = shlex.split(cmd) pprint(for_subprocess) ['avconv', '-i', 'concat:/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment0.ts|/tmp/BABAR_AND_THE_A-011A-hts-a-v1-cc3651d01841d748_Layer6/6148_Period1/segment1.ts', '-vcodec', 'copy', '-acodec', 'copy', '/tmp/test1.ts']
Python on Windows - how to wait for multiple child processes?
How to wait for multiple child processes in Python on Windows, without active wait (polling)? Something like this almost works for me: proc1 = subprocess.Popen(['python','mytest.py']) proc2 = subprocess.Popen(['python','mytest.py']) proc1.wait() print "1 finished" proc2.wait() print "2 finished" The problem is that when proc2 finishes before proc1, the parent process will still wait for proc1. On Unix one would use waitpid(0) in a loop to get the child processes' return codes as they finish - how to achieve something like this in Python on Windows?
It might seem overkill, but, here it goes: import Queue, thread, subprocess results= Queue.Queue() def process_waiter(popen, description, que): try: popen.wait() finally: que.put( (description, popen.returncode) ) process_count= 0 proc1= subprocess.Popen( ['python', 'mytest.py'] ) thread.start_new_thread(process_waiter, (proc1, "1 finished", results)) process_count+= 1 proc2= subprocess.Popen( ['python', 'mytest.py'] ) thread.start_new_thread(process_waiter, (proc2, "2 finished", results)) process_count+= 1 # etc while process_count > 0: description, rc= results.get() print "job", description, "ended with rc =", rc process_count-= 1
Building on zseil's answer, you can do this with a mix of subprocess and win32 API calls. I used straight ctypes, because my Python doesn't happen to have win32api installed. I'm just spawning sleep.exe from MSYS here as an example, but clearly you could spawn any process you like. I use OpenProcess() to get a HANDLE from the process' PID, and then WaitForMultipleObjects to wait for any process to finish. import ctypes, subprocess from random import randint SYNCHRONIZE=0x00100000 INFINITE = -1 numprocs = 5 handles = {} for i in xrange(numprocs): sleeptime = randint(5,10) p = subprocess.Popen([r"c:\msys\1.0\bin\sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, p.pid) handles[h] = p.pid print "Spawned Process %d" % p.pid while len(handles) > 0: print "Waiting for %d children..." % len(handles) arrtype = ctypes.c_long * len(handles) handle_array = arrtype(*handles.keys()) ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE) h = handle_array[ret] ctypes.windll.kernel32.CloseHandle(h) print "Process %d done" % handles[h] del handles[h] print "All done!"
Twisted has an asynchronous process-spawning API which works on Windows. There are actually several different implementations, many of which are not so great, but you can switch between them without changing your code.
Twisted on Windows will perform an active wait under the covers. If you don't want to use threads, you will have to use the win32 API to avoid polling. Something like this: import win32process import win32event # Note: CreateProcess() args are somewhat cryptic, look them up on MSDN proc1, thread1, pid1, tid1 = win32process.CreateProcess(...) proc2, thread2, pid2, tid2 = win32process.CreateProcess(...) thread1.close() thread2.close() processes = {proc1: "proc1", proc2: "proc2"} while processes: handles = processes.keys() # Note: WaitForMultipleObjects() supports at most 64 processes at a time index = win32event.WaitForMultipleObjects(handles, False, win32event.INFINITE) finished = handles[index] exitcode = win32process.GetExitCodeProcess(finished) procname = processes.pop(finished) finished.close() print "Subprocess %s finished with exit code %d" % (procname, exitcode)
You can use psutil: >>> import subprocess >>> import psutil >>> >>> proc1 = subprocess.Popen(['python','mytest.py']) >>> proc2 = subprocess.Popen(['python','mytest.py']) >>> ls = [psutil.Process(proc1.pid), psutil.Process(proc2.pid)] >>> >>> gone, alive = psutil.wait_procs(ls, timeout=3) 'gone' and 'alive' are lists indicating which processes are gone and which ones are still alive. Optionally you can specify a callback which gets invoked every time one of the watched processes terminates: >>> def on_terminate(proc): ... print "%s terminated" % proc ... >>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)
you can use psutil import psutil with psutil.Popen(["python", "mytest.py"]) as proc1, psutil.Popen( ["python", "mytest.py"] ) as proc2: gone, alive = psutil.wait_procs([proc1, proc2], timeout=3) 'gone' and 'alive' are lists indicating which processes are gone and which ones are still alive. Optionally you can specify a callback which gets invoked every time one of the watched processes terminates: def on_terminate(proc): print "%s terminated" % proc gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)