我试图熟悉python子进程,这是我的小代码:
import subprocess
import os
import re
import subprocess as sp
import logging
the_file = "/home/vagrant/test/out.pkg"
out_file = "/home/vagrant/test/result.mp4"
ffmpeg = sp.Popen(['/usr/bin/ffmpeg', '-i', the_file, out_file], stdout = sp.PIPE, stderr = sp.STDOUT)
process_output = ffmpeg.communicate()
print "communicate:", process_output
结果:
communicate: ("ffmpeg version N-75410-g58fe57d Copyright (c) 2000-2015 the FFmpeg developers\n built with gcc 4.4.7 (GCC) 20120313 (Red Hat 4.4.7-16)\n configuration: --prefix=/home/vagrant/ffmpeg_build --extra-cflags=-I/home/vagrant/ffmpeg_build/include --extra-ldflags=-L/home/vagrant/ffmpeg_build/lib --bindir=/usr/local/bin --enable-gpl --enable-nonfree --enable-libfdk_aac --enable-libmp3lame --enable-libvorbis --enable-libopus --enable-libvpx --enable-libx264 --enable-libfreetype\n libavutil 55. 2.100 / 55. 2.100\n libavcodec 57. 3.100 / 57. 3.100\n libavformat 57. 2.100 / 57. 2.100\n libavdevice 57. 0.100 / 57. 0.100\n libavfilter 6. 5.100 / 6. 5.100\n libswscale 4. 0.100 / 4. 0.100\n libswresample 2. 0.100 / 2. 0.100\n libpostproc 54. 0.100 / 54. 0.100\nInput #0, tty, from '/home/vagrant/test/out.txt':\n Duration: 00:00:00.04, bitrate: 1 kb/s\n Stream #0:0: Video: ansi, pal8, 640x400, 25 fps, 25 tbr, 25 tbn, 25 tbc\nNo pixel format specified, yuv444p for H.264 encoding chosen.\nUse -pix_fmt yuv420p for compatibility with outdated media players.\n[libx264 @ 0x379f300] using cpu capabilities: MMX2 SSE2Fast SSSE3 Cache64\n[libx264 @ 0x379f300] profile High 4:4:4 Predictive, level 3.0, 4:4:4 8-bit\n[libx264 @ 0x379f300] 264 - core 148 r2597 e86f3a1 - H.264/MPEG-4 AVC codec - Copyleft 2003-2015 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=1 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00\nOutput #0, mp4, to '/home/vagrant/test/result.mp4':\n Metadata:\n encoder : Lavf57.2.100\n Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv444p, 640x400, q=-1--1, 25 fps, 12800 tbn, 25 tbc\n Metadata:\n encoder : Lavc57.3.100 libx264\nStream mapping:\n Stream #0:0 -> #0:0 (ansi (native) -> h264 (libx264))\nPress [q] to stop, [?] for help\nframe= 1 fps=0.0 q=28.0 Lsize= 2kB time=00:00:00.04 bitrate= 362.4kbits/s \nvideo:1kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 78.698227%\n[libx264 @ 0x379f300] frame I:1 Avg QP:13.08 size: 326\n[libx264 @ 0x379f300] mb I I16..4: 0.4% 99.1% 0.5%\n[libx264 @ 0x379f300] 8x8 transform intra:99.1%\n[libx264 @ 0x379f300] coded y,u,v intra: 0.4% 0.0% 0.0%\n[libx264 @ 0x379f300] i16 v,h,dc,p: 0% 75% 25% 0%\n[libx264 @ 0x379f300] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 92% 8% 0% 0% 0% 0% 0% 0%\n[libx264 @ 0x379f300] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 35% 35% 2% 1% 0% 2% 0% 0%\n[libx264 @ 0x379f300] kb/s:65.20\n", None)
正如预期的那样,给我发回一个元组(stdout,stderr)。但问题是,ffmpeg会转换任何文件(如上所示,甚至是pkg文件)而不会让我返回错误或退出状态1. stderr = None
任何人都能解释一下这个错误吗?非常感谢。
答案 0 :(得分:1)
检查ffmpeg.returncode
,查看退出状态。
设置stderr=sp.PIPE
以从communicate()
获取相应的非None值。
答案 1 :(得分:1)
在这种情况下,您最好使用subprocess.check_output()
。
from subprocess import check_output, STDOUT, CalledProcessError
args = ['/usr/bin/ffmpeg', '-i', the_file, out_file]
try:
txt = check_output(args, stderr=STDOUT)
except CalledProcessError as e:
print "conversion failed", e
else:
print the_file, 'converted to', out_file
以上代码捕获ffmpeg
中txt
的标准输出和标准错误流。并且它通过捕获异常来处理非零返回值。
如果要运行多个程序,使用Popen
是很好的。下面给出的程序并行运行多个ffmpeg
实例,以将大量视频(例如从相机或手机)转换为MP4格式。
#!/usr/bin/env python3
# vim:fileencoding=utf-8:ft=python
#
# Author: R.F. Smith <rsmith@xs4all.nl>
# Last modified: 2015-09-22 21:41:17 +0200
#
# To the extent possible under law, Roland Smith has waived all copyright and
# related or neighboring rights to vid2mp4.py. This work is published from the
# Netherlands. See http://creativecommons.org/publicdomain/zero/1.0/
"""Convert all video files given on the command line to H.264/AAC streams in
an MP4 container."""
__version__ = '1.1.1'
from multiprocessing import cpu_count
from time import sleep
import logging
import os
import subprocess
import sys
def main(argv):
"""
Entry point for vid2mp4.
Arguments:
argv: All command line arguments.
"""
if len(argv) == 1:
binary = os.path.basename(argv[0])
print("{} version {}".format(binary, __version__), file=sys.stderr)
print("Usage: {} [file ...]".format(binary), file=sys.stderr)
sys.exit(0)
logging.basicConfig(level="INFO", format='%(levelname)s: %(message)s')
checkfor(['ffmpeg', '-version'])
vids = argv[1:]
procs = []
maxprocs = cpu_count()
for ifile in vids:
while len(procs) == maxprocs:
manageprocs(procs)
procs.append(startencoder(ifile))
while len(procs) > 0:
manageprocs(procs)
def checkfor(args, rv=0):
"""
Make sure that a program necessary for using this script is available.
Arguments:
args: String or list of strings of commands. A single string may
not contain spaces.
rv: Expected return value from evoking the command.
"""
if isinstance(args, str):
if ' ' in args:
raise ValueError('no spaces in single command allowed')
args = [args]
try:
rc = subprocess.call(args, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
if rc != rv:
raise OSError
except OSError as oops:
outs = "required program '{}' not found: {}."
logging.error(outs.format(args[0], oops.strerror))
sys.exit(1)
def startencoder(fname):
"""
Use ffmpeg to convert a video file to H.264/AAC streams in an MP4
container.
Arguments:
fname: Name of the file to convert.
Returns:
A 3-tuple of a Process, input path and output path.
"""
basename, ext = os.path.splitext(fname)
known = ['.mp4', '.avi', '.wmv', '.flv', '.mpg', '.mpeg', '.mov', '.ogv']
if ext.lower() not in known:
ls = "File {} has unknown extension, ignoring it.".format(fname)
logging.warning(ls)
return (None, fname, None)
ofn = basename + '.mp4'
args = ['ffmpeg', '-i', fname, '-c:v', 'libx264', '-crf', '29', '-flags',
'+aic+mv4', '-c:a', 'libfaac', '-sn', ofn]
with open(os.devnull, 'w') as bitbucket:
try:
p = subprocess.Popen(args, stdout=bitbucket, stderr=bitbucket)
logging.info("Conversion of {} to {} started.".format(fname, ofn))
except:
logging.error("Starting conversion of {} failed.".format(fname))
return (p, fname, ofn)
def manageprocs(proclist):
"""
Check a list of subprocesses tuples for processes that have ended and
remove them from the list.
Arguments:
proclist: a list of (process, input filename, output filename)
tuples.
"""
nr = '# of conversions running: {}\r'.format(len(proclist))
logging.info(nr, end='')
sys.stdout.flush()
for p in proclist:
pr, ifn, ofn = p
if pr is None:
proclist.remove(p)
elif pr.poll() is not None:
logging.info('Conversion of {} to {} finished.'.format(ifn, ofn))
proclist.remove(p)
sleep(0.5)
if __name__ == '__main__':
main(sys.argv)