通过subprocess.PIPE接收ffmpeg的多个文件

3 投票
1 回答
1809 浏览
提问于 2025-04-18 17:49

我正在使用ffmpeg把视频转换成图片。这些图片接着会被我的Python程序处理。最开始,我是先用ffmpeg把图片保存到硬盘上,然后再用Python一个一个地读取它们。

这样做没问题,但为了加快程序的运行速度,我想跳过存储这一步,直接在内存中处理图片。

我用以下的ffmpeg和Python的子进程命令,把ffmpeg的输出直接传给Python:

command = "ffmpeg.exe -i ADD\\sg1-original.mp4 -r 1 -f image2pipe pipe:1"
pipe = subprocess.Popen(ffmpeg-command, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
image = Image.new(pipe.communicate()[0])

这样,图片变量就可以被我的程序使用了。问题是,如果我从ffmpeg发送超过一张图片,所有的数据都会存储在这个变量里。我需要一种方法来分开这些图片。我能想到的唯一方法是根据jpeg文件的结束标记(0xff, 0xd9)来分割。这种方法虽然可行,但不太可靠。

我在使用子进程传输文件时,遗漏了什么呢?有没有办法一次只从管道中读取一张图片?

1 个回答

1

一种解决方案是使用ppm格式,这种格式的大小是可以预测的:

ffmpeg -i movie.mp4 -r 1 -f image2pipe -vcodec ppm pipe:1

这个格式的具体说明可以在这里找到:http://netpbm.sourceforge.net/doc/ppm.html

它的样子大概是这样的:

P6      # magic number
640 480 # width height
255     # colors per channel
<data>

其中的大小会是640 * 480 * 3字节(假设每个颜色通道的颜色不超过255种)。

需要注意的是,这种格式是未压缩的,所以如果你一次性读取所有数据,可能会占用相当多的内存。你可以考虑将你的算法改成:

pipe = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=sys.stderr)
while True:
   chunk = pipe.stdout.read(4096)
   if not chunk:
       break
   # ... process chunk of data ...

请注意,子进程的stderr被设置为当前进程的stderr;这很重要,因为如果不这样做,stderr的缓冲区可能会被填满(因为没有人读取它),从而导致死锁。

撰写回答