【iOS】【Android】動画をOpenGL ESで描画する方法
iOSとAndroidで動画をOpenGL ESで描画したかったのでその方法を調査しました。
iOSの場合
iOSはiOS Dev Centerにこれを実現するためのサンプルコードが提供されていました。
Real-time Video Processing Using AVPlayerItemVideoOutput
ミソはAVPlayerItemVideoOutputというクラスです。
このクラスを使用すれば任意の時間のCVPixelBufferRefというバッファデータが取得できます。
このバッファデータが任意の時間における動画の画像情報となります。
このCVPixelBufferRefのオブジェクトから、CVOpenGLESTextureCacheCreateTextureFromImage()関数でCVOpenGLESTextureRefオブジェクトを取得し、これをCVOpenGLESTextureGetTarget()関数の引数に指定する事によって、OpenGLにおけるテクスチャIDが取得できます。
取得したテクスチャIDでテクスチャをバインドさせる事により、動画から取得した画像データが使用できます。
ちなみに、サンプルコードではAVPlayerItemVideoOutputからYUV420形式で画像データを取得しており、フラグメントシェーダーでは2枚のテクスチャ(Y情報とUV情報のテクスチャ)からRGBへと変換して描画していました。
ちなみに余談ですが、OpenGL ESでなくMetalでも動画を描画する事が可能みたいです。
Androidの場合
AndroidではGitHubにアップされていた以下のサンプルコードを参考にさせていただきました。
crossle/MediaPlayerSurface · GitHub
また実装してから気づいたのですが、以下のサイトのページがすごいまとまっていました。
SurfaceTextureでMediaPlayerやカメラ映像をOpenGLテクスチャとして使う場合の注意点 - eaglesakuraの技術ブログ
AndroidではMediaPlayerとSurfaceTextureの組み合わせで実現が可能でした。
このSurfaceTextureというクラスですが、OpenGL ESのテクスチャとして動画のデータを取得できるみたいです。
注意点としては、OpenGL ESのExtension機能が使用されている点です。
テクスチャターゲットにはGL_TEXTURE_2Dの代わりにGL_TEXTURE_EXTERNAL_OESを使用しなければなりません。
またフラグメントシェーダーでは先頭行に#extension GL_OES_EGL_image_external : require
を記述して、サンプラーのタイプをsamplerExternalOESで指定する必要があります。
詳細は上記のサンプルコードやサイトを参考にしてみてください。