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

时间:2021-08-10 00:25:09

My work recently involves programmatically making videos. In python, the typical workflow looks something like this:

我最近的工作涉及以编程方式制作视频。在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"])

This workflow creates an image for each frame in the video and saves it to disk. After all images have been saved, ffmpeg is called to construct a video from all of the images.

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

Saving the images to disk (not the creation of the images in memory) consumes the majority of the cycles here, and does not appear to be necessary. Is there some way to perform the same function, but without saving the images to disk? So, ffmpeg would be called and the images would be constructed and fed to ffmpeg immediately after being constructed.

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

1 个解决方案

#1


49  

Ok I got it working. thanks to LordNeckbeard suggestion to use image2pipe. I had to use jpg encoding instead of png because image2pipe with png doesn't work on my verision of ffmpeg. The first script is essentially the same as your question's code except I implemented a simple image creation that just creates images going from black to red. I also added some code to time the execution.

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

serial execution

串行执行

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

parallel execution (with no images saved to disk)

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

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()

the results are interesting, I ran each script 3 times to compare performance: serial:

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

12.9062321186
12.8965060711
12.9360799789

parallel:

平行:

8.67797684669
8.57139396667
8.38926696777

So it seems the parallel version is faster about 1.5 times faster.

因此,似乎并行版本的速度提高了约1.5倍。

#1


49  

Ok I got it working. thanks to LordNeckbeard suggestion to use image2pipe. I had to use jpg encoding instead of png because image2pipe with png doesn't work on my verision of ffmpeg. The first script is essentially the same as your question's code except I implemented a simple image creation that just creates images going from black to red. I also added some code to time the execution.

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

serial execution

串行执行

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

parallel execution (with no images saved to disk)

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

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()

the results are interesting, I ran each script 3 times to compare performance: serial:

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

12.9062321186
12.8965060711
12.9360799789

parallel:

平行:

8.67797684669
8.57139396667
8.38926696777

So it seems the parallel version is faster about 1.5 times faster.

因此,似乎并行版本的速度提高了约1.5倍。