How to create and play IVF / VP8 / WebM / libvpx video in OpenGL
Thursday, February 2nd, 2012Disclaimer: this tutorial covers how to render IVF / VP8 / libvpx video in an OpenGL libSDL / SDL window. IVF video only includes video, not audio. For game developers, it’s trivial to play audio via their own audio system. So you’ll have two files per movie “movie.ivf” and “movie.ogg” or whatever. As an exercise to the reader, you could easily jam both into a single file if you really wanted to.
The Problem We’re Trying To Solve
So you’re an indie game developer and you want to show a clip of video in your commercial cross-platform (PC/Mac/Linux/other?) game! Obviously you want a patent-free open source unrestricted license to do it.
Wait, can’t I go commercial?
Better than that, you could just use the built-in codecs on a platform! I’d suggest this if you are targeting a single platform, iPhone / iOS for example.
Otherwise, you’ll be using Bink, a commercial solution at $8500 / platform. I emailed about their “indie licenses” and never heard back.
The Open Source Options I didn’t like much
Here’s what we have for patent free open source codecs .. and their various problems.
Xiph Theora – Probably the best known codec. To get it working you have to have libogg, libvorbis, and libtheora all built for your target platforms. To me, that seemed like a lot to ask. Also, the libtheora API is a MONSTER. playtheora is a SDL example (similar to this one) that covers some of that ugliness, so I’d recommend checking that out if you want to use theora.
Dirac / Schroedinger – the BBC funded codec. I couldn’t get this one to build. It doesn’t seem to be all that popular.
Motion Jpeg – This isn’t so much of a codec as an idea. Make your own movie file with a ton of .jpg’s in it. I tried this. The files get really huge really fast. I wouldn’t recommend this.
Motion JPEG 2000 – This implementation was also pretty confusing. I couldn’t find where to start. And, yeah, this isn’t all that popular either.
libvpx .. why I chose it
WebM / libvpx – Backed by google this is a new contendor on the block. The thing that sold me was the sample encoder which was pretty simple. It also depends on nothing. Also, building it on OS X and Linux was trivial. Also they offer a pre-built Windows binary. Also, they just had their 1.0.0 release a few days ago.
So, yeah, having a supported, up and coming, easy to build codec was key to me.
How to encode for IVF / libvpx
Since it’s a new codec, not much supports it right now. I used a fresh build of ffmpeg under linux that I built with this configure command:
./configure --enable-encoders --enable-libvpx
Then I was able to use ffmpeg to encode ivf files pretty easily:
ffmpeg -i Untitled.mov -vcodec libvpx -b 1000k -s 1024x512 movie.ivf
Note: we’re not dealing with WebM files. WebM files are container files that also contain audio. Again, you’ll have to store your audio separately, or create your own container file, or figure out what WebM is on your own time.
So .. what’s the bottom line? Do we get any code?
Yes! I created a libSDL player that plays back the video at max speed possible and it converts the YUV data to RGB data and loads it as a texture. Here are the functions I provide:
void playvpx_init(Vpxdata *data, const char *_fname) ;
Just init your Vpxdata with a filename “movie.ivf” .. It’ll try and get libvpx up and running for you.
bool playvpx_loop(Vpxdata *data) ;
Call this once per frame to have it decode a frame of video. It will return false once it has run out of frames. If you want to mess with the libvpx YUV data yourself, it’s data->img. See the playvpx.cpp source or the libvpx example above to see what that structure provides. It’s pretty simple.
int playvpx_get_texture(Vpxdata *data) ;
Call this once per frame to have it convert the YUV data to RGB and upload the texture to OpenGL. It will return 0 on failure or a OpenGL texture ID on success. I convert on your CPU, so it’s not super fast, but it should work fine on modern computers. If anyone cares to provide a Shader version of this function, or provide a SIMD / MMX / SSE version .. well, that would be faster!
void playvpx_deinit(Vpxdata *data) ;
Call this function when you’re done to cleanup.
Conclusion and Source Code
Okay, here’s playvpx for you to check out. It’s a C-style API, but I’m sure I use some minor C++ in there. Probably wouldn’t be hard to make it C-only if you require C for your project.
Oh, and I include the libvpx binary for Windows, OS X, and Linux. So you may not have to build it for any platforms!
The code is licensed under the libvpx BSD-style license. My code here is a gutted version of their sample_decoder.c, so .. that seems to make most sense to me.