【问题标题】:Calling ffmpeg kills script in background only调用 ffmpeg 仅在后台杀死脚本
【发布时间】:2014-07-01 19:09:09
【问题描述】:

我有一个 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 编译到其中的东西进行交互,因此再次使用它似乎是明智的。

【问题讨论】:

    标签: python ffmpeg subprocess


    【解决方案1】:

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

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

    如果您在 bash 中将其作为后台作业运行,则应该重现该问题:“parent.py 脚本显示为已停止”:

    $ 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)
    

    【讨论】:

    • 这个。感谢您的解释,整个“等待标准输入”的事情对我来说是那些未知的未知数之一。实现的最简单解决方案就是将 subprocess.PIPE 附加到调用的标准输入。
    • @TimD:除非您在进程运行时读/写/关闭相应的管道,否则不要使用 PIPE,即不要将其与 subprocess.call() 函数一起使用,即使它恰好可以使用ffmpeg 可执行文件的一些参数集。
    【解决方案2】:

    我喜欢使用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
    

    【讨论】:

      【解决方案3】:

      来自 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
      

      【讨论】:

      • 您真的阅读了我的问题吗?你根本没有回答我的问题。
      猜你喜欢
      • 2012-09-30
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多