2014-05-13 87 views
1

我有一个python脚本通过子进程调用ffmpeg来做一些mp3操作。它在前台运行良好,但是如果我在后台运行它,它可以达到ffmpeg命令,它本身可以将其配置转储到stderr中。此时,一切都停止,并且父任务被报告为停止,而不会在任何地方引发异常。我已经在ffmpeg的地方尝试了一些其他简单的命令,它们通常在前景或背景中执行。在后台调用ffmpeg杀死脚本

这是问题的小例子:

import subprocess 

inf = "3HTOSD.mp3" 
outf = "out.mp3" 

args = [ "ffmpeg", 
      "-y", 
      "-i", inf, 
      "-ss", "0", 
      "-t", "20", 
      outf 
     ] 

print "About to do" 

result = subprocess.call(args) 

print "Done" 

我真的不能工作了,为什么还是包装过程中如何使家长没有至少提高一个错误终止,只有如何发生在一个很小的环境中。到底是怎么回事?另外,我知道ffmpeg不是最好的包,但我与使用ffmpeg编译到它的东西接口,所以再次使用它似乎是明智的。

回答

1

这可能与Linux process in background - “Stopped” in jobs?例如,使用parent.py

from subprocess import check_call 

check_call(["python", "-c", "import sys; sys.stdin.readline()"]) 

要重现该问题: “parent.py脚本显示为停止” 如果你在bash中运行它作为后台作业:

$ python parent.py & 
[1] 28052 
$ jobs 
[1]+ Stopped     python parent.py 

如果父母process is in an orphaned process group then it is killed on receiving SIGTTIN signal (a signal to stop)

解决办法是重新输入:

import os 
from subprocess import check_call 
try: 
    from subprocess import DEVNULL 
except ImportError: # Python 2 
    DEVNULL = open(os.devnull, 'r+b', 0) 

check_call(["python", "-c", "import sys; sys.stdin.readline()"], stdin=DEVNULL) 

如果你不需要看ffmpeg的标准输出/标准错误;你也可以重定向到/dev/null

check_call(ffmpeg_cmd, stdin=DEVNULL, stdout=DEVNULL, stderr=STDOUT) 
+0

这个。感谢你的解释,整个“等待stdin”的东西是我未知的未知之一。实现最简单的解决方案就是将一个subprocess.PIPE附加到调用的stdin。 – TimD

+0

@TimD:除非您在进程运行时读/写/关闭相应的管道,否则不要使用PIPE,即不要在subprocess.call()函数中使用它,即使它恰好与某些ffmpeg可执行文件的参数。 – jfs

-1

从Python /子/调用文档:

等待命令完成,然后返回返回码属性。

所以只要你调用的进程没有退出,你的程序就不会继续。

您应该设置一个Popen进程对象,将其标准输出和错误放入不同的缓冲区/流中,并且在出现错误时终止进程。

也许是这样工作的:

proc = subprocess.Popen(args, stderr = subprocess.PIPE) # puts stderr into a new stream 
while proc.poll() is None: 
    try: 
     err = proc.stderr.read() 
    except: continue 
    else: 
     if err: 
      proc.terminate() 
      break 
+0

你真的看过我的问题吗?你一直没有回答我问的问题。 – TimD

0

我喜欢用commands模块。在我看来,使用起来更简单。

import commands 
cmd = "ffmpeg -y -i %s -ss 0 -t 20 %s 2>&1" % (inf, outf) 
status, output = commands.getstatusoutput(cmd) 
if status != 0: 
    raise Exception(output) 

作为一个侧面说明,有时路径可以是一个问题,你可能想使用绝对路径FFmpeg的二进制文件。

[email protected]:~$ which ffmpeg 
/opt/local/bin/ffmpeg