Film aus Python generieren, ohne einzelne Frames in Dateien zu speichern


Answers

Nach dem Patchen von ffmpeg (siehe Joe Kington Kommentare zu meiner Frage) konnte ich Piping-PNGs folgendermaßen in ffmpeg bringen:

import subprocess
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

outf = 'test.avi'
rate = 1

cmdstring = ('local/bin/ffmpeg',
             '-r', '%d' % rate,
             '-f','image2pipe',
             '-vcodec', 'png',
             '-i', 'pipe:', outf
             )
p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE)

plt.figure()
frames = 10
for i in range(frames):
    plt.imshow(np.random.randn(100,100))
    plt.savefig(p.stdin, format='png')

Ohne den Patch , der zwei Dateien trivial modifiziert und libavcodec/png_parser.c hinzufügt, würde es nicht funktionieren. Ich musste den Patch manuell auf libavcodec/Makefile anwenden. Zuletzt habe ich '-number' aus Makefile , um die man-Seiten zu erstellen. Mit Kompilierungsoptionen,

FFmpeg version 0.6.1, Copyright (c) 2000-2010 the FFmpeg developers
  built on Nov 30 2010 20:42:02 with gcc 4.2.1 (Apple Inc. build 5664)
  configuration: --prefix=/Users/paul/local_test --enable-gpl --enable-postproc --enable-swscale --enable-libxvid --enable-libx264 --enable-nonfree --mandir=/Users/paul/local_test/share/man --enable-shared --enable-pthreads --disable-indevs --cc=/usr/bin/gcc-4.2 --arch=x86_64 --extra-cflags=-I/opt/local/include --extra-ldflags=-L/opt/local/lib
  libavutil     50.15. 1 / 50.15. 1
  libavcodec    52.72. 2 / 52.72. 2
  libavformat   52.64. 2 / 52.64. 2
  libavdevice   52. 2. 0 / 52. 2. 0
  libswscale     0.11. 0 /  0.11. 0
  libpostproc   51. 2. 0 / 51. 2. 0
Question

Ich möchte einen h264- oder divx-Film aus Frames erstellen, die ich in einem Python-Skript in Matplotlib erzeuge. Es gibt ungefähr 100k Bilder in diesem Film.

In Beispielen im Internet [z. 1], ich habe nur die Methode gesehen, jeden Frame als PNG abzuspeichern und dann Mencoder oder ffmpeg auf diesen Dateien laufen zu lassen. In meinem Fall ist das Speichern jedes Frames unpraktisch. Gibt es eine Möglichkeit, ein aus matplotlib generiertes Plot zu verwenden und es direkt in ffmpeg zu pipen, sodass keine Zwischendateien erzeugt werden?

Programmieren mit ffmpegs C-api ist für mich zu schwierig [z. 2]. Außerdem benötige ich eine Kodierung mit einer guten Komprimierung wie x264, da die Filmdatei sonst für einen nachfolgenden Schritt zu groß ist. Es wäre also großartig, bei mencoder / ffmpeg / x264 zu bleiben.

Kann man mit Rohren [3] etwas machen?

[1] http://matplotlib.sourceforge.net/examples/animation/movie_demo.html

[2] Wie codiert man eine Reihe von Bildern in H264 mit Hilfe der x264 C API?

[3] http://www.ffmpeg.org/ffmpeg-doc.html#SEC41




Das ist toll! Ich wollte das Gleiche tun. Aber ich konnte die gepatchte ffmpeg-Quelle (0.6.1) in Vista mit MingW32 + MSYS + pr enviroment nicht kompilieren ... png_parser.c erzeugte Error1 während der Kompilierung.

Also habe ich eine JPEG-Lösung mit PIL entwickelt. Stellen Sie einfach Ihre ffmpeg.exe in den gleichen Ordner wie dieses Skript. Dies sollte mit ffmpeg ohne den Patch unter Windows funktionieren. Ich musste die stdin.write-Methode anstelle der Kommunikationsmethode verwenden, die in der offiziellen Dokumentation zum Subprozess empfohlen wird. Beachten Sie, dass die Option 2nd -vcodec den Codierungscodec angibt. Die Pipe wird von p.stdin.close () geschlossen.

import subprocess
import numpy as np
from PIL import Image

rate = 1
outf = 'test.avi'

cmdstring = ('ffmpeg.exe',
             '-y',
             '-r', '%d' % rate,
             '-f','image2pipe',
             '-vcodec', 'mjpeg',
             '-i', 'pipe:', 
             '-vcodec', 'libxvid',
             outf
             )
p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE, shell=False)

for i in range(10):
    im = Image.fromarray(np.uint8(np.random.randn(100,100)))
    p.stdin.write(im.tostring('jpeg','L'))
    #p.communicate(im.tostring('jpeg','L'))

p.stdin.close()