python FFMPEG 和 Pythons 子进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1455532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:17:51  来源:igfitidea点击:

FFMPEG and Pythons subprocess

pythonffmpegsubprocess

提问by

I'm trying to write a gui for FFMPEG. I'm using pythons subprocess to create a ffmpeg process for every conversion I want. This works fine, but I'd also like a way to get the progress of the conversion, whether it failed or not etc. I figured I could do this by accessing the process's stdout like so:

我正在尝试为FFMPEG. 我正在使用 pythons 子进程为我想要的每个转换创建一个 ffmpeg 进程。这很好用,但我也想要一种获取转换进度的方法,无论它是否失败等。我想我可以通过访问进程的标准输出来做到这一点,如下所示:

Calling subprocess.Popen()

打电话 subprocess.Popen()

# Convert - Calls FFMPEG with current settings. (in a seperate
# thread.)
def convert(self):
    # Check if options are valid
    if self.input == "" or self.output == "":
        return False

# Make the command string
ffmpegString = self.makeString()

# Try to open with these settings
try:
    self.ffmpeg = subprocess.Popen(ffmpegString, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
    self.error.append("OSError: ")
except ValueError:
    self.error.append("ValueError: Couldn't call FFMPEG with these parameters")

# Convert process should be running now.

And reading stdout:

并阅读stdout

convert = Convert()
convert.input = "test.ogv"
convert.output = "test.mp4"
convert.output_size = (0, 0)

convert.convert()

while 1:
    print convert.ffmpeg.stdout.readline()

This works but, ffmpeg's status doesn't show. I'm assuming it has something to do with way ffmpeg refreshes it. Is there a way to access it?

这有效,但是 ffmpeg 的状态没有显示。我假设它与 ffmpeg 刷新它的方式有关。有没有办法访问它?

采纳答案by Alex Martelli

I've often noticed problems reading standard output (or even standard error!) with subprocess, due to buffering issues that are hard to defeat. My favorite solution, when I do need to read such stdout/stderr from the subprocess, is to switch to using, instead of subprocess, pexpect(or, on Windows, wexpect).

由于难以解决的缓冲问题,我经常注意到使用子进程读取标准输出(甚至标准错误!)的问题。我最喜欢的解决方案是,当我确实需要从子进程中读取这样的 stdout/stderr 时,切换到 using,而不是subprocess, pexpect(或者,在 Windows 上,wexpect)。

回答by Arseniy Alexandrov

Simply add ,universal_newlines=True to your subprocess.Popen line.

只需将 ,universal_newlines=True 添加到您的 subprocess.Popen 行。

cmd="ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
    print(line)

For now you got line in cycle like:

现在你有一个循环的线路,如:

frame= 1900 fps=453 q=18.6 Lsize=    3473kB time=00:01:16.08 bitrate= 373.9kbits/s

Use the time= value to determine progress in percentage.

使用 time= 值来确定进度百分比。

回答by Linus Unneb?ck

I think you can't use readline because ffmpeg never prints one line, the status is updated by writing \r (carrige return) and then writing the line again.

我认为您不能使用 readline ,因为 ffmpeg 从不打印一行,状态通过写入 \r (回车)然后再次写入该行来更新。

size=      68kB time=0.39 bitrate=1412.1kbits/s    \rsize=    2786kB time=16.17 bitrate=1411.2kbits/s    \rsize=    5472kB time=31.76 bitrate=1411.2kbits/s    \r\n

If you examine the row above you'll notice that there is only one \n and that gets printed when the file is done converting.

如果您检查上面的行,您会注意到只有一个 \n 并且在文件完成转换后会打印出来。

回答by Derrick Petzold

Since ffmpeg writes the data unflushed to stderr you have to set the stderr file descriptor to non-blocking using fcntl.

由于 ffmpeg 将未刷新的数据写入 stderr,因此您必须使用 fcntl 将 stderr 文件描述符设置为非阻塞。

    fcntl.fcntl(
        pipe.stderr.fileno(),
        fcntl.F_SETFL,
        fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
    )

and then loop using select to read the data

然后循环使用select读取数据

    while True:
        readx = select.select([pipe.stderr.fileno()], [], [])[0]
        if readx:
            chunk = pipe.stderr.read()

for full example go here.

完整的例子去这里

回答by Bryan Rehbein

FFMPEG:

FFMPEG:

FFMPEG output all the status text (what you see when you run it manually on the command line) on the stderr interface. In order to capture output from ffmpeg, you need to be watching the stderr interface - or redirecting it like the example.

FFMPEG 在 stderr 界面上输出所有状态文本(您在命令行上手动运行时看到的内容)。为了从 ffmpeg 捕获输出,您需要观察 stderr 接口 - 或者像示例一样重定向它。

Check for output on stderr:

检查 stderr 上的输出:

Here is another way to try and read from stderr, instead of redirecting it when calling Popen

这是尝试从 stderr 读取的另一种方法,而不是在调用 Popen 时重定向它

The Popen classin Python has an file object called stderr, you would access it in the same way that you are accessing stdout. I'm thinking your loop would look something like this:

Python 中的Popen 类有一个名为 stderr 的文件对象,您可以像访问 stdout 一样访问它。我想你的循环看起来像这样:

while 1:
    print convert.ffmpeg.stdout.readline()
    print convert.ffmpeg.stderr.readline()

Disclaimer: I haven't tested this in Python, but I made a comparable application using Java.

免责声明:我没有在 Python 中测试过这个,但我使用 Java 制作了一个类似的应用程序。

回答by Petr J

ffmpegCommand='''
ffmpeg
-f lavfi
-i anullsrc=channel_layout=1c:sample_rate=11025
-rtsp_transport tcp
-rtsp_transport udp
-rtsp_transport http
-thread_queue_size 32000
-i rtsp://xxx.xxx.xxx.xxx:554/user=admin&password=xxx&channel=1&stream=1.sdp?real_stream
-reconnect 1
-reconnect_at_eof 1
-reconnect_streamed 1
-reconnect_delay_max 4294
-tune zerolatency
-c:v copy
-c:a aac
-bufsize 6000k
-f flv rtmp://a.rtmp.youtube.com/live2/xxx-xxx-xxx-xxx'''
cmd=ffmpegCommand.split()
# "universal newline support" This will cause to interpret \n, \r\n and \r     equally, each as a newline.

p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
while True:    
        print(p.stderr.readline().rstrip('\r\n'))