你可以"流"图像到ffmpeg构建一个视频,而不是将它们保存到磁盘?

Bra*_*don 42 python ffmpeg image stream python-imaging-library

我最近的工作涉及以编程方式制作视频.在python中,典型的工作流程看起来像这样:

import subprocess, Image, ImageDraw

for i in range(frames_per_second * video_duration_seconds):
    img = createFrame(i)
    img.save("%07d.png" % i)

subprocess.call(["ffmpeg","-y","-r",str(frames_per_second),"-i", "%07d.png","-vcodec","mpeg4", "-qscale","5", "-r", str(frames_per_second), "video.avi"])
Run Code Online (Sandbox Code Playgroud)

此工作流程为视频中的每个帧创建一个图像并将其保存到磁盘.保存所有图像后,调用ffmpeg以构建来自所有图像的视频.

将图像保存到磁盘(而不是在内存中创建图像)会占用此处的大部分周期,并且似乎不需要.有没有办法执行相同的功能,但没有将图像保存到磁盘?因此,将调用ffmpeg并构建图像并在构造后立即将其提供给ffmpeg.

Mar*_*agh 56

好的,我得到了它的工作.感谢LordNeckbeard建议使用image2pipe.我不得不使用jpg编码而不是png,因为带有png的image2pipe对我的ffmpeg的验证不起作用.第一个脚本与你的问题代码基本相同,只是我实现了一个简单的图像创建,只创建从黑色到红色的图像.我还添加了一些代码来计算执行时间.

串行执行

import subprocess, Image

fps, duration = 24, 100
for i in range(fps * duration):
    im = Image.new("RGB", (300, 300), (i, 1, 1))
    im.save("%07d.jpg" % i)
subprocess.call(["ffmpeg","-y","-r",str(fps),"-i", "%07d.jpg","-vcodec","mpeg4", "-qscale","5", "-r", str(fps), "video.avi"])
Run Code Online (Sandbox Code Playgroud)

并行执行(没有图像保存到磁盘)

import Image
from subprocess import Popen, PIPE

fps, duration = 24, 100
p = Popen(['ffmpeg', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', '24', '-i', '-', '-vcodec', 'mpeg4', '-qscale', '5', '-r', '24', 'video.avi'], stdin=PIPE)
for i in range(fps * duration):
    im = Image.new("RGB", (300, 300), (i, 1, 1))
    im.save(p.stdin, 'JPEG')
p.stdin.close()
p.wait()
Run Code Online (Sandbox Code Playgroud)

结果很有意思,我运行每个脚本3次以比较性能: serial:

12.9062321186
12.8965060711
12.9360799789
Run Code Online (Sandbox Code Playgroud)

平行:

8.67797684669
8.57139396667
8.38926696777
Run Code Online (Sandbox Code Playgroud)

所以似乎并行版本的速度提高了约1.5倍.

  • 对于将来偶然发现这种情况的人来说,用'png'替换'mjpeg'和用'PNG'替换'JPEG'对我来说使用png. (17认同)
  • @einstein FFmpeg 正在对视频进行编码,同时生成图像。 (3认同)
  • 尽管文件大小为 x4,但我设法使用“-vcodec png”和“im.save(p.stdin, 'PNG')”获得最佳质量 (2认同)
  • 它应该流式传输而不是并行传输。 (2认同)

Jor*_*ren 5

imageio直接支持这一点。它使用 FFMPEG 和Video Acceleration API,速度非常快:

import imageio

writer = imageio.get_writer('video.avi', fps=fps)
for i in range(frames_per_second * video_duration_seconds):
    img = createFrame(i)
    writer.append_data(img)
writer.close()
Run Code Online (Sandbox Code Playgroud)