I would like to create an h264 or divx movie from frames that I generate in a python script in matplotlib. There are about 100k frames in this movie.
In examples on the web [eg. 1], I have only seen the method of saving each frame as a png and then running mencoder or ffmpeg on these files. In my case, saving each frame is impractical. Is there a way to take a plot generated from matplotlib and pipe it directly to ffmpeg, generating no intermediate files?
Programming with ffmpeg's C-api is too difficult for me [eg. 2]. Also, I need an encoding that has good compression such as x264 as the movie file will otherwise be too large for a subsequent step. So it would be great to stick with mencoder/ffmpeg/x264.
Is there something that can be done with pipes [3]?
[1] http://matplotlib.sourceforge.net/examples/animation/movie_demo.html
[2] How does one encode a series of images into H264 using the x264 C API?
Converting to image formats is quite slow and adds dependencies. After looking at these page and other I got it working using raw uncoded buffers using mencoder (ffmpeg solution still wanted).
Details at: http://vokicodder.blogspot.com/2011/02/numpy-arrays-to-video.html
I got some nice speedups.
This is great! I wanted to do the same. But, I could never compile the patched ffmpeg source (0.6.1) in Vista with MingW32+MSYS+pr enviroment... png_parser.c produced Error1 during compilation.
So, I came up with a jpeg solution to this using PIL. Just put your ffmpeg.exe in the same folder as this script. This should work with ffmpeg without the patch under Windows. I had to use stdin.write method rather than the communicate method which is recommended in the official documentation about subprocess. Note that the 2nd -vcodec option specifies the encoding codec. The pipe is closed by p.stdin.close().
These are all really great answers. Here's another suggestion. @user621442 is correct that the bottleneck is typically the writing of the image, so if you are writing png files to your video compressor, it will be pretty slow (even if you are sending them through a pipe instead of writing to disk). I found a solution using pure ffmpeg, which I personally find easier to use than matplotlib.animation or mencoder.
Also, in my case, I wanted to just save the image in an axis, instead of saving all of the tick labels, figure title, figure background, etc. Basically I wanted to make a movie/animation using matplotlib code, but not have it "look like a graph". I've included that code here, but you can make standard graphs and pipe them to ffmpeg instead if you want.
After patching ffmpeg (see Joe Kington comments to my question), I was able to get piping png's to ffmpeg as follows:
It would not work without the patch, which trivially modifies two files and adds
libavcodec/png_parser.c
. I had to manually apply the patch tolibavcodec/Makefile
. Lastly, I removed '-number' fromMakefile
to get the man pages to build. With compile options,This functionality is now (at least as of 1.2.0, maybe 1.1) baked into matplotlib via the
MovieWriter
class and it's sub-classes in theanimation
module. You also need to installffmpeg
in advance.Documentation for
animation