Можете ли вы "потопить" изображения в ffmpeg, чтобы создать видео, а не сохранять их на диск?

Моя работа в последнее время связана с программным составлением видео. В 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"])

Этот рабочий процесс создает изображение для каждого кадра в видео и сохраняет его на диск. После сохранения всех изображений ffmpeg вызывается для создания видео со всех изображений.

Сохранение изображений на диск (а не создание изображений в памяти) потребляет большую часть циклов здесь и не кажется необходимым. Есть ли способ выполнить одну и ту же функцию, но без сохранения изображений на диск? Таким образом, будет вызываться ffmpeg, и изображения будут построены и переданы в ffmpeg сразу после его создания.

Ответ 1

Хорошо, я начал работать. благодаря предложению LordNeckbeard использовать image2pipe. Мне пришлось использовать jpg-кодировку вместо png, потому что image2pipe с png не работает в моей версии ffmpeg. Первый script по существу совпадает с вашим кодом вопроса, за исключением того, что я реализовал простое создание образа, которое просто создает образы, идущие от черного к красному. Я также добавил код во время выполнения.

серийное исполнение

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

параллельное выполнение (без изображений, сохраненных на диске)

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

результаты интересны, я провел каждый script 3 раза, чтобы сравнить производительность: серийный номер:

12.9062321186
12.8965060711
12.9360799789

:

8.67797684669
8.57139396667
8.38926696777

Итак, параллельная версия быстрее примерно в 1,5 раза быстрее.