使用 Python 子进程冻结到 FFMPEG

Posted

技术标签:

【中文标题】使用 Python 子进程冻结到 FFMPEG【英文标题】:Piping to FFMPEG with Python subprocess freezes 【发布时间】:2017-04-19 05:52:50 【问题描述】:

通过以下代码,我可以使用 Python、Numpy 和 FFMPEG 二进制文件将视频帧传送到 FFMPEG:

from __future__ import print_function
import subprocess
import numpy as np
import sys

npshape = [480, 480]
cmd_out = ['ffmpeg',
           '-y', # (optional) overwrite output file if it exists
           '-f', 'rawvideo',
           '-vcodec','rawvideo',
           '-s', '%dx%d'%(npshape[1], npshape[0]), # size of one frame
           '-pix_fmt', 'rgb24',
           '-r', '24', # frames per second
           '-i', '-', # The input comes from a pipe
           '-an', # Tells FFMPEG not to expect any audio
           '-vcodec', 'mpeg4',
           'output.mp4']

fout = subprocess.Popen(cmd_out, stdin=subprocess.PIPE, stderr=subprocess.PIPE).stdin

for i in range(24*40):
    if i%(24)==0: 
        print('%d'%(i/24), end=' ')
        sys.stdout.flush()

    fout.write((np.random.random(npshape[0]*npshape[1]*3)*128).astype('uint8').tostring())

fout.close()

如果我写任何少于 37 秒的帧,这会正常工作,但如果我尝试写更多的内容,代码就会挂起。这种行为的根本原因是什么?我该如何解决?

【问题讨论】:

告诉:stderr=subprocess.PIPE,然后完全忽略它会导致灾难。 【参考方案1】:

一个极有可能的罪魁祸首是令人作呕的 subprocess.Popen 行。不仅您忽略了它的返回值——为了确保子进程在某个时间点完成和/或检查它的退出代码,你绝对不能这样做——你还使stderr成为一个管道但从不读取它——所以进程必须缓冲区填满时挂起。

这应该可以解决它:

p = subprocess.Popen(cmd_out, stdin=subprocess.PIPE)
fout = p.stdin

<...>

fout.close()
p.wait()
if p.returncode !=0: raise subprocess.CalledProcessError(p.returncode,cmd_out)

【讨论】:

感谢它的工作!从现在开始,这将成为我处理 Python 管道的标准方式。

以上是关于使用 Python 子进程冻结到 FFMPEG的主要内容,如果未能解决你的问题,请参考以下文章

Python 子进程中的 ffmpeg - 无法为“管道:”找到合适的输出格式

Python多进程(multiprocessing)

在 Windows 上的 Python Popen 子进程中暂停 FFmpeg 编码

如何将数据从 Python 异步套接字服务器发送到子进程?

python多进程和多线程

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