SurfaceTexture
は、サーフェスとOpenGL ES (GLES)テクスチャの組み合わせです。 SurfaceTexture
インスタンスは、GLES テクスチャに出力するサーフェスを提供するために使用されます。
SurfaceTexture
アプリがコンシューマとなるBufferQueue
のインスタンスが含まれています。 onFrameAvailable()
コールバックは、プロデューサーが新しいバッファーをキューに入れるとアプリに通知します。次に、アプリはupdateTexImage()
を呼び出します。これにより、以前に保持されていたバッファーが解放され、キューから新しいバッファーが取得され、 EGL呼び出しが行われて、バッファーが外部テクスチャとして GLES で使用できるようになります。
外部 GLES テクスチャ
外部 GLES テクスチャ ( GL_TEXTURE_EXTERNAL_OES
) は、次の点で従来の GLES テクスチャ ( GL_TEXTURE_2D
) とは異なります。
- 外部テクスチャは、
BufferQueue
から受け取ったデータから直接テクスチャ付きポリゴンをレンダリングします。 - 外部テクスチャ レンダラーは、従来の GLES テクスチャ レンダラーとは異なる構成になっています。
- 外部テクスチャは、従来の GLES テクスチャ アクティビティをすべて実行できるわけではありません。
外部テクスチャの主な利点は、 BufferQueue
データから直接レンダリングできることです。 SurfaceTexture
インスタンスは、外部テクスチャのBufferQueue
インスタンスを作成するときにコンシューマ使用フラグをGRALLOC_USAGE_HW_TEXTURE
に設定して、バッファ内のデータが GLES によって認識可能であることを確認します。
SurfaceTexture
インスタンスは EGL コンテキストと対話するため、アプリは、テクスチャを所有する EGL コンテキストが呼び出し側スレッド上にある間のみメソッドを呼び出すことができます。詳細については、 SurfaceTexture
クラスのドキュメントを参照してください。
タイムスタンプと変換
SurfaceTexture
インスタンスには、タイムスタンプを取得するgetTimeStamp()
メソッドと、変換行列を取得するgetTransformMatrix()
メソッドが含まれます。 updateTexImage()
を呼び出すと、タイムスタンプと変換行列の両方が設定されます。 BufferQueue
が渡す各バッファには、変換パラメータとタイムスタンプが含まれています。
変換パラメータは効率化に役立ちます。場合によっては、ソース データが消費者にとって間違った方向になっている可能性があります。コンシューマーに送信する前にデータを回転する代わりに、データを修正する変換を使用してその方向でデータを送信します。データの使用時に変換行列を他の変換とマージして、オーバーヘッドを最小限に抑えることができます。
タイムスタンプは、時間に依存するバッファ ソースに役立ちます。たとえば、 setPreviewTexture()
がプロデューサー インターフェイスをカメラの出力に接続すると、カメラからのフレームを使用してビデオを作成できます。各フレームには、アプリがフレームを受信したときではなく、フレームがキャプチャされたときのプレゼンテーション タイムスタンプが必要です。カメラ コードはバッファーで提供されるタイムスタンプを設定するため、より一貫性のある一連のタイムスタンプが得られます。
ケーススタディ: Grafika の継続的キャプチャ
Grafika の連続キャプチャには、デバイスのカメラからフレームを記録し、それらのフレームを画面に表示することが含まれます。フレームを記録するには、 MediaCodecクラスのcreateInputSurface()
メソッドでサーフェスを作成し、そのサーフェスをカメラに渡します。フレームを表示するには、 SurfaceView
のインスタンスを作成し、そのサーフェスをsetPreviewDisplay()
に渡します。フレームの記録とそれらのフレームの表示は、より複雑なプロセスであることに注意してください。
連続キャプチャアクティビティでは、ビデオの録画中にカメラからのビデオが表示されます。この場合、エンコードされたビデオはメモリ内の循環バッファに書き込まれ、いつでもディスクに保存できます。
このフローには 3 つのバッファ キューが含まれます。
-
App
— アプリは、SurfaceTexture
インスタンスを使用してカメラからフレームを受信し、それらを外部 GLES テクスチャに変換します。 -
SurfaceFlinger
— アプリは、フレームを表示するためのSurfaceView
インスタンスを宣言します。 -
MediaServer
— ビデオを作成するための入力サーフェスを使用してMediaCodec
エンコーダーを構成します。
下の図では、矢印はカメラからのデータの伝播を示しています。 BufferQueue
インスタンスは色で表示されます (プロデューサーは青緑色、コンシューマーは緑色)。
エンコードされた H.264 ビデオは、アプリ プロセスの RAM 内の循環バッファーに保存されます。ユーザーがキャプチャ ボタンを押すと、 MediaMuxer
クラスはエンコードされたビデオをディスク上の MP4 ファイルに書き込みます。
すべてのBufferQueue
インスタンスは、GLES 操作が UI スレッドで実行される間、アプリ内の単一の EGL コンテキストで処理されます。エンコードされたデータの処理 (循環バッファの管理とディスクへの書き込み) は別のスレッドで行われます。
SurfaceView
クラスを使用する場合、 surfaceCreated()
コールバックは、ディスプレイとビデオ エンコーダー用のEGLContext
インスタンスとEGLSurface
インスタンスを作成します。新しいフレームが到着すると、 SurfaceTexture
4 つのアクティビティを実行します。- フレームを取得します。
- フレームを GLES テクスチャとして利用できるようにします。
- GLES コマンドを使用してフレームをレンダリングします。
-
EGLSurface
の各インスタンスの変換とタイムスタンプを転送します。
次に、エンコーダ スレッドは、エンコードされた出力をMediaCodec
から取得し、メモリに隠します。
安全なテクスチャビデオの再生
Android は、保護されたビデオ コンテンツの GPU 後処理をサポートしています。これにより、アプリは複雑な非線形ビデオ効果 (ワープなど) に GPU を使用し、保護されたビデオ コンテンツをテクスチャにマッピングして、一般的なグラフィック シーン (GLES を使用するなど) や仮想現実 (VR) で使用できるようになります。
サポートは、次の 2 つの拡張機能を使用して有効になります。
- EGL 拡張— (
EGL_EXT_protected_content
) 保護された GL コンテキストおよびサーフェスの作成を有効にし、どちらも保護されたコンテンツに対して操作できます。 - GLES 拡張— (
GL_EXT_protected_textures
) テクスチャを保護としてタグ付けできるようにし、フレームバッファ テクスチャ アタッチメントとして使用できるようにします。
Android では、 SurfaceTexture
と ACodec ( libstagefright.so
) が、ウィンドウのサーフェスがSurfaceFlinger
キューに登録されていない場合でも、保護されたコンテンツを送信できるようにし、保護されたコンテキスト内で使用するための保護されたビデオ サーフェスを提供します。これは、保護されたコンテキスト (ACodec によって検証) で作成されたサーフェスに保護されたコンシューマー ビット ( GRALLOC_USAGE_PROTECTED
) を設定することによって行われます。
安全なテクスチャ ビデオ再生は、OpenGL ES 環境での強力な DRM 実装の基盤を確立します。 Widevine レベル 1 などの強力な DRM 実装がなければ、多くのコンテンツ プロバイダーは、価値の高いコンテンツを OpenGL ES 環境でレンダリングすることを許可せず、VR での DRM 保護されたコンテンツの視聴などの重要な VR ユースケースを妨げます。
AOSP には、安全なテクスチャ ビデオ再生のためのフレームワーク コードが含まれています。ドライバーのサポートは OEM 次第です。デバイス実装者は、 EGL_EXT_protected_content
およびGL_EXT_protected_textures extensions
を実装する必要があります。独自のコーデック ライブラリを使用する場合 ( libstagefright
を置き換えるため)、 GRALLOC_USAGE_PROTECTED
でマークされたバッファをANativeWindow
に送信できるようにする/frameworks/av/media/libstagefright/SurfaceUtils.cpp
の変更に注意してください ( ANativeWindow
直接キューに登録されない場合でも) windowコンポーザー)、コンシューマー使用量ビットにGRALLOC_USAGE_PROTECTED
が含まれている限り。拡張機能の実装に関する詳細なドキュメントについては、Khronos レジストリ ( EGL_EXT_protected_content
およびGL_EXT_protected_textures
) を参照してください。