👌

[Android][Kotlin][C++][JNI][OpenGL]動画再生を板ポリ上で実行するサンプルコードを作ってみた。

に公開


板ポリに動画再生って、Androidはライブラリを準備してくれてた。さすがっす。

Abstruct

  • 板ポリに動画再生のサンプルコードを作ってみた。
  • ポイント説明

背景

こないだVuforiaのサンプルコードが動かなくって、修正版をコミットしたんだけど、動画再生のサンプルがないんよねー。昔はあったと思うのだけど。なので、まずは板ポリ上に動画再生するサンプルコードを作ってみた。ExoPlayerって便利なライブラリが助かった。さすがAndroid。おかげで難易度がかなり下がった感じ。
githubの場所はここ↓
https://github.com/aaaa1597/AndKot-VideoPlaybackPlanePolySampleG

準備

  • android端末(シミュレータでも可)
  • 開発用PC(Android Studioのインストールは済ませておく。)
  • android端末をつないで、デバッグができる様にしておく。

ビルドする。

上記のgithubからソースコードをDL→Android Studioでビルドする。
動くはずだから。

ポイント説明

おおまかな処理の流れ

  1. ExoPlayerで動画を再生。出力先はSurfece。
  2. Surface → SurfaceTextureがOpenGLのテクスチャに転送。
  3. GLSurfaceView.Renderで板ポリに描画。

1. ExoPlayerで動画を再生。出力先はSurface。

まず、ExoPlayerを生成して初期化処理する。該当ソースは下記。

ExoPlayerを生成して初期化処理
    private fun initExoPlayer(context: Context) {
        exoPlayer = ExoPlayer.Builder(context).build().apply {
            val surface = Surface(surfaceTexture)
            setVideoSurface(surface)

            /* res/raw にある動画ファイルを指定 */
            val uri = "android.resource://${context.packageName}/${R.raw.vuforiasizzlereel}"
            Log.d("aaaaa", "uri=$uri")
            val mediaItem = MediaItem.fromUri(uri)
            setMediaItem(mediaItem)

            repeatMode = Player.REPEAT_MODE_ONE /* ループ再生 */
            playWhenReady = true /* すぐに再生開始 */

            addListener(object : Player.Listener {
                override fun onVideoSizeChanged(videoSize: VideoSize) {
                    /* C++側に動画サイズを伝える */
                    nativeSetVideoSize(videoSize.width, videoSize.height)
                }
            })

            prepare()
        }
    }

で、ExoPlayerを再生。

ExoPlayerを再生
    override fun onResume() {
        super.onResume()
        exoPlayer?.play()
    }

2. Surface → SurfaceTextureがOpenGLのテクスチャに転送。

テクスチャに転送する設定をするとあとはいい感じにライブラリ側でやってくれる。

テクスチャに転送する設定
            override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
                val textureId = nativeOnSurfaceCreated()
                if (textureId < 0)
                    throw RuntimeException("Failed to create native texture")
                surfaceTexture = SurfaceTexture(textureId)
                surfaceTexture?.setOnFrameAvailableListener(object : SurfaceTexture.OnFrameAvailableListener {
                    override fun onFrameAvailable(surfaceTexture: SurfaceTexture?) {
                        synchronized(this) {
                            isFrameAvailable = true
                            _binding.viwGlsurface.requestRender()
                        }
                    }
                })
                CoroutineScope(Dispatchers.Main).launch {
                    initExoPlayer(this@MainActivity)
                }
            }

3. GLSurfaceView.Renderで板ポリに描画。

SurfaceTextureのupdateTexImage()を実行して、C++側関数 nativeOnDrawFrame()を呼出すと描画される。

板ポリに描画
            override fun onDrawFrame(gl: GL10) {
                synchronized(this) {
                    if (isFrameAvailable) {
                        surfaceTexture?.updateTexImage()
                        isFrameAvailable = false
                    }
                }
                nativeOnDrawFrame()
            }

出来た!!
これでVuforiaの動画再生サンプルが作れる。

Discussion