杀死python ffmpeg子进程会破坏cli输出

时间:2012-05-14 14:32:55

标签: python ffmpeg subprocess

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

但如果命令超过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 args,但可能会错过一些东西。我以为我会在这里保持简单。

我在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管道上打印所有内容。这可能是原因吗?任何想法如何解决它?

3 个答案:

答案 0 :(得分: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--------------------------"

像魅力一样。

如果此代码适用于您的服务器,我猜问题实际上就在于

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

答案 1 :(得分:0)

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

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

最好是运行stty echo,这会为你的shell会话重新开启回声。

您甚至可以在使用FFmpeg后在脚本中运行此功能。我在做:

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

这适用于Ubuntu,bash作为我的shell。 YMMV,但我希望它有所帮助。它闻起来很丑,但它是我发现的最佳解决方案。

答案 2 :(得分:0)

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

我们可以使用管道到stdin来解决这个问题,并像在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干净地关闭它,如果它有一个输入管道。也许它首先与导致这个错误的原因有关?