SurfaceTexture

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インスタンスは色で表示されます (プロデューサーは青緑色、コンシューマーは緑色)。

Grafika の継続的キャプチャ アクティビティ

図 1. Grafika の継続的なキャプチャ アクティビティ

エンコードされた H.264 ビデオは、アプリ プロセスの RAM 内の循環バッファーに保存されます。ユーザーがキャプチャ ボタンを押すと、 MediaMuxerクラスはエンコードされたビデオをディスク上の MP4 ファイルに書き込みます。

すべてのBufferQueueインスタンスは、GLES 操作が UI スレッドで実行される間、アプリ内の単一の EGL コンテキストで処理されます。エンコードされたデータの処理 (循環バッファの管理とディスクへの書き込み) は別のスレッドで行われます。

SurfaceViewクラスを使用する場合、 surfaceCreated()コールバックは、ディスプレイとビデオ エンコーダー用のEGLContextインスタンスとEGLSurfaceインスタンスを作成します。新しいフレームが到着すると、 SurfaceTexture 4 つのアクティビティを実行します。
  1. フレームを取得します。
  2. フレームを GLES テクスチャとして利用できるようにします。
  3. GLES コマンドを使用してフレームをレンダリングします。
  4. EGLSurfaceの各インスタンスの変換とタイムスタンプを転送します。

次に、エンコーダ スレッドは、エンコードされた出力をMediaCodecから取得し、メモリに隠します。

安全なテクスチャビデオの再生

Android は、保護されたビデオ コンテンツの GPU 後処理をサポートしています。これにより、アプリは複雑な非線形ビデオ効果 (ワープなど) に GPU を使用し、保護されたビデオ コンテンツをテクスチャにマッピングして、一般的なグラフィック シーン (GLES を使用するなど) や仮想現実 (VR) で使用できるようになります。

安全なテクスチャビデオ再生

図 2.安全なテクスチャ ビデオの再生

サポートは、次の 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 ) を参照してください。