调用ffmpeg只会在后台杀死脚本

时间:2014-05-13 22:23:36

标签: python ffmpeg subprocess

我有一个python脚本通过子进程调用ffmpeg进行一些mp3操作。它在前台工作正常,但是如果我在后台运行它,它会获得ffmpeg命令,它本身就可以将其配置转储到stderr中。此时,一切都停止,父任务报告为已停止,而不会在任何地方引发异常。我在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编译到其中的东西接口,所以再次使用它似乎是明智的。

3 个答案:

答案 0 :(得分:2)

可能与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 stdout / stderr;您也可以将它们重定向到/dev/null

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

答案 1 :(得分: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)

作为旁注,有时PATH可能是个问题,您可能希望使用ffmpeg二进制文件的绝对路径。

matt@goliath:~$ which ffmpeg
/opt/local/bin/ffmpeg

答案 2 :(得分:-1)

来自python / subprocess / call文档:

  

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

因此,只要您调用的进程没有退出,您的程序就不会继续。

您应该设置一个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