简体   繁体   English

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

[英]Killing python ffmpeg subprocess breaks cli output

I'm trying to execute a system command with subprocess and reading the output. 我正在尝试使用子进程执行系统命令并读取输出。

But if the command takes more than 10 seconds I want to kill the subprocess. 但是,如果命令花费了10秒钟以上,我想杀死该子进程。

I've tried doing this in several ways. 我尝试了几种方法。

My last try was inspired by this post: https://stackoverflow.com/a/3326559/969208 我的最后一次尝试是受此帖子启发的: https : //stackoverflow.com/a/3326559/969208

Example: 例:

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)

The problem is: After the program exits no chars are shown in the cli until I hit return. 问题是:程序退出后,cli中不会显示任何字符,直到我按回车键为止。 And hitting return will not give me a new line. 争取回报不会给我新的界限。

I suppose this has something to do with the stdout and stderr pipe. 我想这与stdout和stderr管道有关。

I've tried flushing and reading from the pipe (p.stdout.flush()) 我试过冲洗并从管道读取(p.stdout.flush())

I've also tried with different Popen args, but might've missed something. 我也尝试过使用不同的Popen参数,但可能会错过一些东西。 Just thought I'd keep it simple here. 只是以为我会在这里保持简单。

I'm running this on a Debian server. 我正在Debian服务器上运行它。

Am I missing something here? 我在这里想念什么吗?

EDIT: 编辑:

It seems this is only the case when killing an ongoing ffmpeg process. 似乎只有在终止正在进行的ffmpeg进程时才如此。 If the ffmpeg process exits normally before 10 seconds, there is no problem at all. 如果ffmpeg进程在10秒之前正常退出,则完全没有问题。

I've tried executing a couple of different command that take longer than 10 seconds, one who prints output, one who doesn't and a ffmpeg command to check the integrity of a file. 我尝试执行几个不同的命令,这些命令花费的时间超过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

I believe ffmpeg prints using \\r and prints everything on the strerr pipe. 我相信ffmpeg使用\\ r打印并在strerr管道上打印所有内容。 Can this be the cause? 这可能是原因吗? Any ideas how to fix it? 任何想法如何解决?

Well. 好。 your code surely works fine on my Ubuntu server. 您的代码在我的Ubuntu服务器上肯定可以正常工作。

(which is close cousin or brother of Debian I suppose) (我想这是Debian的近亲或兄弟)

I added few more lines, so that I can test your code. 我增加了几行,以便我可以测试您的代码。

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--------------------------"

Works like a charm. 奇迹般有效。

If this code works on your server, I guess problem actually lies on 如果此代码在您的服务器上有效,我想问题实际上就在于

command line application that you trying to retrieve data. 您尝试检索数据的命令行应用程序。

I have the same problem. 我也有同样的问题。 I can't get a running FFmpeg to terminate gracefully from a python subprocess, so I am using <process>.kill() . 我无法获得运行中的FFmpeg来从python子<process>.kill()正常终止,因此我正在使用<process>.kill() However I think this means FFmpeg does not restore the mode of the tty properly (as described here: https://askubuntu.com/a/172747 ) 但是我认为这意味着FFmpeg无法正确还原tty的模式(如此处所述: https : //askubuntu.com/a/172747

You can get your shell back by running reset at the bash prompt, but that clears the screen so you can't see your script's output as you continue to work. 您可以通过在bash提示符处运行reset恢复外壳,但这会清除屏幕,因此在继续工作时看不到脚本的输出。

Better is to run stty echo which turns echoing back on for your shell session. 更好的方法是运行stty echo ,以便在您的Shell会话中重新打开stty echo

You can even run this in your script after you've nuked FFmpeg. 对FFmpeg进行核对后,甚至可以在脚本中运行它。 I am doing: 我在做:

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

This works for me on Ubuntu with bash as my shell. 这在bash作为shell的Ubuntu上对我有效。 YMMV, but I hope it helps. YMMV,但希望对您有所帮助。 It smells hacky but it's the best solution I've found. 它闻起来很黑,但这是我找到的最好的解决方案。

I ran into a similar issue with ffmpeg. 我遇到了ffmpeg的类似问题。 It seems that if ffmpeg is killed using Popen.kill() it does not properly close and does not reinstate echoing on your terminal. 看来,如果使用Popen.kill()将ffmpeg杀死,则无法正确关闭ffmpeg,也不会恢复终端上的回显。

We can solve this using a pipe to stdin, and writing q to close ffmpeg as we would in a cli session: 我们可以使用管道连接到stdin,然后像在cli会话中那样写q来关闭ffmpeg来解决此问题:

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

It's probably preferable to use Popen.communicate in order to avoid a deadlock. 最好使用Popen.communicate以避免死锁。 The following will also work: 以下内容也将起作用:

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

But it seems like even the following works: 但似乎甚至以下作品:

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

I'm not sure what causes this ffmpeg to close cleanly if it has an input pipe. 我不确定是什么原因导致该ffmpeg干净关闭,如果它具有输入管道。 Perhaps it has something to do with what causes this bug in the first place? 也许与最初导致此错误的原因有关?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM