【问题标题】:Killing python ffmpeg subprocess breaks cli output杀死 python ffmpeg 子进程会破坏 cli 输出
【发布时间】:2012-05-22 01:26:39
【问题描述】:

我正在尝试使用子进程执行系统命令并读取输出。

但是如果命令花费超过 10 秒,我想杀死子进程。

我尝试了多种方法。

我最后一次尝试的灵感来自这篇文章:https://stackoverflow.com/a/3326559/969208

例子:

import os
import signal
from subprocess import Popen, PIPE

class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm

def pexec(args):

    p = Popen(args, stdout=PIPE, stderr=PIPE)

    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(10)

    stdout = stderr = ''
    try:
        stdout, stderr = p.communicate()
        signal.alarm(0)
    except Alarm:
        try:
            os.kill(p.pid, signal.SIGKILL)
        except:
            pass

    return (stdout, stderr)

问题是:程序退出后,cli 中不会显示任何字符,直到我点击返回。并且点击返回不会给我一个新的线路。

我想这与 stdout 和 stderr 管道有关。

我已经尝试从管道中冲洗和读取 (p.stdout.flush())

我也尝试过使用不同的 Popen 参数,但可能遗漏了一些东西。只是想我会在这里保持简单。

我在 Debian 服务器上运行它。

我错过了什么吗?

编辑:

似乎只有在终止正在进行的 ffmpeg 进程时才会出现这种情况。如果ffmpeg进程在10秒前正常退出,完全没有问题。

我尝试执行几个不同的命令,这些命令需要超过 10 秒,一个打印输出,一个不打印输出,还有一个 ffmpeg 命令来检查文件的完整性。

args = ['sleep', '12s'] # Works fine
args = ['ls', '-R', '/var'] # Works fine, prints lots for a long time
args = ['ffmpeg', '-v', '1', '-i', 'large_file.mov','-f', 'null', '-'] # Breaks cli output

我相信 ffmpeg 使用 \r 打印并在 strerr 管道上打印所有内容。这可能是原因吗?任何想法如何解决它?

【问题讨论】:

    标签: python ffmpeg subprocess


    【解决方案1】:

    嗯。你的代码在我的 Ubuntu 服务器上运行良好。

    (我想这是 Debian 的近亲或兄弟)

    我又添加了几行代码,以便测试您的代码。

    import os
    import signal
    from subprocess import Popen, PIPE
    
    class Alarm(Exception):
        pass
    
    def alarm_handler(signum, frame):
        raise Alarm
    def pexec(args):
        p = Popen(args, stdout=PIPE, stderr=PIPE)
    
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.alarm(1)
    
        stderr = ''
        try:
            stdout, stderr = p.communicate()
            signal.alarm(0)
        except Alarm:
        print "Done!"
            try:
                os.kill(p.pid, signal.SIGKILL)
            except:
                pass
    
        return (stdout, stderr)
    
    args = ('find', '/', '-name','*')
    stdout = pexec(args)
    print "----------------------result--------------------------"
    print stdout
    print "----------------------result--------------------------"
    

    像魅力一样工作。

    如果这段代码在你的服务器上运行,我想问题实际上出在

    您尝试检索数据的命令行应用程序。

    【讨论】:

    • 谢谢瑞恩,你是对的,它工作正常。似乎只有在杀死正在进行的 ffmpeg 进程时才会出现这种情况。请查看我的编辑。
    【解决方案2】:

    我也有同样的问题。我无法让正在运行的 FFmpeg 从 python 子进程正常终止,所以我使用<process>.kill()。但是我认为这意味着 FFmpeg 无法正确恢复 tty 的模式(如此处所述:https://askubuntu.com/a/172747

    您可以通过在 bash 提示符下运行 reset 来恢复您的 shell,但这会清除屏幕,因此您在继续工作时看不到脚本的输出。

    最好运行stty echo,它会为您的 shell 会话重新打开回显。

    你甚至可以在你 nuked FFmpeg 之后在你的脚本中运行它。我在做:

    ffmpeg_popen.kill()
    ffmpeg_popen.wait()
    subprocess.call(["stty", "echo"])
    

    这适用于我在 Ubuntu 上使用 bash 作为我的 shell。 YMMV,但我希望它有所帮助。它闻起来很老套,但这是我找到的最佳解决方案。

    【讨论】:

      【解决方案3】:

      我在使用 ffmpeg 时遇到了类似的问题。似乎如果使用 Popen.kill() 杀死 ffmpeg,它不会正确关闭并且不会在您的终端上恢复回显。

      我们可以使用到标准输入的管道来解决这个问题,并像在 cli 会话中一样编写 q 来关闭 ffmpeg:

      p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
      p.stdin.write(b"q")
      

      为了避免死锁,最好使用 Popen.communicate。以下也将起作用:

      p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
      p.communicate(b'q')
      

      但似乎甚至以下工作:

      p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
      p.kill()
      

      如果它有输入管道,我不确定是什么导致这个 ffmpeg 干净地关闭。也许它首先与导致此错误的原因有关?

      【讨论】:

        猜你喜欢
        • 2017-01-27
        • 2010-12-08
        • 1970-01-01
        • 2016-01-24
        • 1970-01-01
        • 1970-01-01
        • 2017-08-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多