SurfaceTextureレンダラ ( 画像を1度だけ画面に描画 )



SurfaceTexture に出力した画像を、画面に描画する方法を解説します。

本項では、画像を1度だけ画面に描画するSurfaceTextureレンダラを作成します。

解説

大きな処理の流れは以下です。

  1. SurfaceからCanvasを取得し、Canvasの描画命令を用いて画像を描画します。結果として、SurfaceTexture の画像が更新されます。
  2. SurfaceTexture の画像が更新されると、onFrameAvailable コールバック関数が呼び出されます。
  3. onFrameAvailable コールバック関数の呼び出しをトリガとして、updateTexImage関数を呼び出します。
  4. updateTexImage 関数を呼び出すと、SurfaceTexture に出力した画像が、GLESの外部テクスチャとして使用できるようになります。
  5. GLESの描画命令を用いて、GLESの外部テクスチャを、画面に描画します。

実装

アプリの仕様

プロジェクトの作成

(開発環境としては、Android Studio 4.2.2 を使用しています)

(この設定でプロジェクトを作成しなければいけない、というわけではありません。)

「Welcome to Android Studio」画面の「Create New Project」をクリックします。


Empty Activity」を選択し、「Next」ボタンを押します。


Nameに、「SurfaceTextureRendererTest」と入力します。
Package nameのドメイン部分に、会社のドメイン名を指定します。
Save locationに、プロジェクトを保存するフォルダパスを指定します。
Minimum SDKを選択します(たとえば、「API 23: Android 6.0 (Marshmallow)」)。
「Finish」ボタンを押します。

しばらく待ちます。
Android Studio のステータスバーに「Gradle sync finished in ・・・」や「*daemon started successfully ・・・」と出るまで待ちます。

以上で、プロジェクトができました。

クラスファイルの作成

2つのクラスファイルを作成します。
①便利関数を集めたユーティリティクラス ( MyUtilsクラス )
②SurfaceTextureレンダラクラス ( SurfaceTextureRendererクラス )

①便利関数を集めたユーティリティクラス ( MyUtilsクラス )の作成
「Project」ペインの「app > java > パッケージ名」を右クリックします。
右クリックメニュー「New > Java Class」を選択します。


クラス名欄に「MyUtils」と入力しエンターキーを押します。


(変更なし)
「OK」ボタンを押します。
「MyUtils」クラスファイルができました。

②SurfaceTextureレンダラクラス ( SurfaceTextureRendererクラス )の作成
「Project」ペインの「app > java > ドメイン.パッケージ名」を右クリックします。
右クリックメニュー「New > Java Class」を選択します。


クラス名欄に「SurfaceTextureRenderer」と入力しエンターキーを押します。


INTERFACES欄に「GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener」と入力します。
「OK」ボタンを押します。
「SurfaceTextureRenderer」クラスファイルができました。

ユーティリティクラス ( MyUtilsクラス )の定義

便利関数を集めたユーティリティクラス ( MyUtilsクラス )に以下の定義を追加します。

クラス全体としては、以下のようにします。



「Cannot resolve symbol」エラーは、「Alt + Enter」で、必要なクラスをimportします。

SurfaceTextureレンダラクラス ( SurfaceTextureRendererクラス )の定義

SurfaceTextureレンダラクラス ( SurfaceTextureRendererクラス )に、以下の定義を追加します。

処理の流れは、以下です。

  1. SurfaceTextureをインスタンス化の際に、コンストラクタ関数が呼ばれます。コンストラクタ関数では、でメンバー変数の初期化を行います。
  2. アプリケーションが開始した際や、一時停止状態から再開した際に、onSurfaceCreated関数が呼ばれます。onSurfaceCreated関数では、GLESの初期化処理、および、SurfaceTextureとSurfaceの作成を行います。
  3. アプリケーションが開始した際や、一時停止状態から再開した際や、画面の向きを変更した際に、onSurfaceChanged関数が呼ばれます。onSurfaceChanged関数では、ビューポート設定処理、テクスチャの大きさの変更処理、および、「Surfaceでの描画」関数呼び出しを行います。
  4. 「Surfaceでの描画」関数では、SurfaceからCanvasを取得し、Canvasの描画命令を用いて画像を描画します。結果として、SurfaceTexture の画像が更新されます。
  5. SurfaceTexture の画像が更新されると、onFrameAvailable コールバック関数が呼び出されます。
  6. onFrameAvailableコールバック関数では、m_bNewFrameAvailableのフラグを立てます。
  7. onDrawFrame関数は、高頻度で繰り返し呼び出されます。m_bNewFrameAvailableのフラグが立っているときは、SurfaceTextureの画像が変わっているので、onDrawFrame関数では、updateTexImage関数を呼び出し、m_bNewFrameAvailableのフラグを倒します。
  8. updateTexImage関数を呼び出すと、SurfaceTexture に出力した画像が、GLESの外部テクスチャとして使用できるようになります。
  9. onDrawFrame関数では、GLESの描画命令を用いて、GLESの外部テクスチャを、画面に描画します。

クラス全体としては、以下のようにします。



「Cannot resolve symbol」エラーは、「Alt + Enter」で、必要なクラスをimportします。

レイアウトの変更

メインアクティビティのレイアウトを変更します。

「Project」ペインの「app > res > layout > activity_main.xml」を開きます。

「Code」タブをクリックし、コードビューに変更します。

「TextView」定義を削除します。
「GLSurfaceView」定義を追加します。

activity_main.xmlの内容を以下のようにします。

メインアクティビティクラスの変更

メインアクティビティの、onCreate関数内で、以下を行います。

  1. GLSurfaceVeiwオブジェクトを取得します。
  2. GLESバージョンとしてGLES 2.0 を指定します。
  3. 「SurfaceTextureRenderer」クラスのオブジェクトを生成します。
  4. 3.で生成した「SurfaceTextureRenderer」オブジェクトを、1.で取得したGLSurfaceViewオブジェクトに、setRenderer関数でセットします。
  5. GLSurfaceViewの描画モードは、「絶え間なく描画するというモード」と「描画要求があったときだけ描画するというモード」があります。「絶え間なく描画するというモード」にします。

GLSurfaceViewクラスのオブジェクトメンバー変数を追加します。

メインアクティビティに、「初回表示時、および、ポーズからの復帰時」に呼ばれる関数である onResume関数と、「別のアクティビティ(か別のアプリ)に移行したことで、バックグラウンドに追いやられた時」に呼ばれる関数である onPause関数を追加します。

クラス全体としては、以下のようにします。



「Cannot resolve symbol」エラーは、「Alt + Enter」で、必要なクラスをimportします。
リビルドし、エラー、警告がないことを確認します。

実行

Android端末にて、動作確認。



アプリを起動すると、メインアクティビティが表示されます。
背景色は、灰色。
左上座標値 ( 200, 300 )、右下座標値 ( 400, 600 )、赤色で塗りつぶしの矩形が表示されます。
中心座標値 ( 400, 600 )、半径 200、緑色で、線の太さ30の円が表示されます。

ダウンロード

サンプルコード

関連ページ

SurfaceTextureレンダラ ( 画像を1度だけ画面に描画 ) - 本ページ

SurfaceTextureレンダラ ( 連続画像を画面に描画 )

SurfaceTextureレンダラ ( 頂点バッファオブジェクトの利用 )