{"id":1014,"date":"2012-02-02T17:50:59","date_gmt":"2012-02-02T23:50:59","guid":{"rendered":"http:\/\/www.philhassey.com\/blog\/?p=1014"},"modified":"2012-06-15T07:27:13","modified_gmt":"2012-06-15T13:27:13","slug":"how-to-create-and-play-ivf-vp8-webm-libvpx-video-in-opengl","status":"publish","type":"post","link":"https:\/\/www.philhassey.com\/blog\/2012\/02\/02\/how-to-create-and-play-ivf-vp8-webm-libvpx-video-in-opengl\/","title":{"rendered":"How to create and play IVF \/ VP8 \/ WebM \/ libvpx video in OpenGL"},"content":{"rendered":"<p><em>Disclaimer: 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&#8217;s trivial to play audio via their own audio system.  So you&#8217;ll have two files per movie &#8220;movie.ivf&#8221; and &#8220;movie.ogg&#8221; or whatever.  As an exercise to the reader, you could easily jam both into a single file if you really wanted to.<\/em><\/p>\n<p><strong>The Problem We&#8217;re Trying To Solve<\/strong><\/p>\n<p>So you&#8217;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.<\/p>\n<p><strong>Wait, can&#8217;t I go commercial?<\/strong><\/p>\n<p>Better than that, you could just use the built-in codecs on a platform!  I&#8217;d suggest this if you are targeting a single platform, iPhone \/ iOS for example.<\/p>\n<p>Otherwise, you&#8217;ll be using <a href=\"http:\/\/www.radgametools.com\/bnkmain.htm\">Bink<\/a>, a commercial solution at $8500 \/ platform.  I emailed about their &#8220;indie licenses&#8221; and never heard back.<\/p>\n<p><strong>The Open Source Options I didn&#8217;t like much<\/strong><\/p>\n<p>Here&#8217;s what we have for patent free open source codecs .. and their various problems.<\/p>\n<p><a href=\"http:\/\/theora.org\/\">Xiph Theora<\/a> &#8211; 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.  <a href=\"http:\/\/icculus.org\/theoraplay\/\">playtheora<\/a> is a SDL example (similar to this one) that covers some of that ugliness, so I&#8217;d recommend checking that out if you want to use theora.<\/p>\n<p><a href=\"http:\/\/diracvideo.org\/\">Dirac \/ Schroedinger<\/a> &#8211; the BBC funded codec.  I couldn&#8217;t get this one to build.  It doesn&#8217;t seem to be all that popular.<\/p>\n<p><a href=\"http:\/\/en.wikipedia.org\/wiki\/Motion_JPEG\">Motion Jpeg<\/a> &#8211; This isn&#8217;t so much of a codec as an idea.  Make your own movie file with a ton of .jpg&#8217;s in it.  I tried this.  The files get really huge really fast.  I wouldn&#8217;t recommend this.<\/p>\n<p><a href=\"http:\/\/www.openjpeg.org\/\">Motion JPEG 2000<\/a> &#8211; This implementation was also pretty confusing.  I couldn&#8217;t find where to start.  And, yeah, this isn&#8217;t all that popular either.<\/p>\n<p><strong>libvpx .. why I chose it<\/strong><\/p>\n<p><a href=\"http:\/\/www.webmproject.org\/code\/\">WebM \/ libvpx<\/a> &#8211; Backed by google this is a new contendor on the block.  The thing that sold me was the <a href=\"http:\/\/www.webmproject.org\/tools\/vp8-sdk\/example__simple__decoder.html\">sample encoder<\/a> 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.<\/p>\n<p>So, yeah, having a supported, up and coming, easy to build codec was key to me.<\/p>\n<p><strong>How to encode for IVF \/ libvpx<\/strong><\/p>\n<p>Since it&#8217;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:<\/p>\n<pre>.\/configure --enable-encoders --enable-libvpx<\/pre>\n<p>Then I was able to use ffmpeg to encode ivf files pretty easily:<\/p>\n<pre>ffmpeg -i Untitled.mov -vcodec libvpx -b 1000k -s 1024x512 movie.ivf<\/pre>\n<p>Note: we&#8217;re not dealing with WebM files.  WebM files are container files that also contain audio.  Again, you&#8217;ll have to store your audio separately, or create your own container file, or figure out what WebM is on your own time.<\/p>\n<p><strong>So .. what&#8217;s the bottom line?  Do we get any code?<\/strong><\/p>\n<p>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:<\/p>\n<pre>void playvpx_init(Vpxdata *data, const char *_fname) ;<\/pre>\n<p>Just init your Vpxdata with a filename &#8220;movie.ivf&#8221; .. It&#8217;ll try and get libvpx up and running for you.<\/p>\n<pre>bool playvpx_loop(Vpxdata *data) ;<\/pre>\n<p>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&#8217;s data->img.  See the playvpx.cpp source or the libvpx example above to see what that structure provides.  It&#8217;s pretty simple.<\/p>\n<pre>int playvpx_get_texture(Vpxdata *data) ;<\/pre>\n<p>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&#8217;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!<\/p>\n<pre>void playvpx_deinit(Vpxdata *data) ;<\/pre>\n<p>Call this function when you&#8217;re done to cleanup.<\/p>\n<p><strong>Conclusion and Source Code<\/strong><\/p>\n<p>Okay, here&#8217;s <a href='http:\/\/www.galcon.com\/stuff\/playvpx.zip'>playvpx<\/a> for you to check out.  It&#8217;s a C-style API, but I&#8217;m sure I use some minor C++ in there.  Probably wouldn&#8217;t be hard to make it C-only if you require C for your project.<\/p>\n<p>Oh, and I include the libvpx binary for Windows, OS X, and Linux.  So you may not have to build it for any platforms!<\/p>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disclaimer: 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&#8217;s trivial to play audio via their own audio system. So you&#8217;ll have two files per movie &#8220;movie.ivf&#8221; and &#8220;movie.ogg&#8221; or whatever. As an exercise [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,6],"tags":[],"class_list":["post-1014","post","type-post","status-publish","format-standard","hentry","category-c","category-development"],"_links":{"self":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/1014","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/comments?post=1014"}],"version-history":[{"count":8,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/1014\/revisions"}],"predecessor-version":[{"id":1164,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/1014\/revisions\/1164"}],"wp:attachment":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/media?parent=1014"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/categories?post=1014"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/tags?post=1014"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}