Does anyone know how to do run an OpenGL animation and then convert it into a mp4 movie? I've been trying with apitrace and ffmpeg but I get horrible quality output...
It's not too difficult to set up your app to stream frames directly to ffmpeg. This blog post by Miles Macklin shows how, and I've used this method in my own apps.
You spawn ffmpeg as a child process from your app, and at the end of each frame you just read back the GL framebuffer and write its contents to ffmpeg's stdin. The relevant code bits are excerpted here.
// start ffmpeg telling it to expect raw rgba 720p-60hz frames
// -i - tells it to read frames from stdin
const char* cmd = "ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s 1280x720 -i - "
"-threads 0 -preset fast -y -pix_fmt yuv420p -crf 21 -vf vflip output.mp4";
// open pipe to ffmpeg's stdin in binary write mode
FILE* ffmpeg = _popen(cmd, "wb");
Writing a frame:
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
fwrite(buffer, sizeof(int)*width*height, 1, ffmpeg);
You can adjust the quality by altering the
-crf option in the command line (lower numbers are better quality). Don't forget to change the resolution (
-s) and framerate (
-r) to match what you want, as well.
Depending on the quality, how fast your PC is, etc, it might not quite work in real-time. It's a good idea to set up your app to use a fixed per-frame timestep when you're in video capture mode, so the resulting animation doesn't depend on how much slowdown there was in the capture process.
That is not an easy question to answer. First of all you will have to understand the MP4 format. And secondly you will have to keep track of every frame being displayed by OpenGL. So my suggestion to maximize performance is to keep all of the frame data after every frame in a file on the hard drive and after the animation read all of the files and write to an MP4 file.