3

私の Android アプリでは、次の Z オーダーで 3 つのビューをレンダリングする必要があります。

  1. 下部には、MediaCodec画面全体をカバーするデコーダーの出力面があります。によって生成された画像を変換する必要があるという要件がありますMediaCodec(たとえば、スケーリングする)
  2. 中央には、GLSurfaceView(または私が定義した GL シェーダーを実行している他のサーフェス/ビュー) が画面全体をカバーしています。MediaCodec明らかに、このレイヤーの一部のピクセルは、下の出力を見るために透明になります。
  3. その上に、他のビュー - と言うImageView。これらの最上部のビューに透明性が必要かどうかはわかりませんが、おそらく完全に不透明な長方形のビューで問題ありません。画面全体をカバーするわけではなく、移動します。

これは不可能のように見えますが、何かが欠けているか、より低いレベルでより多くの努力を払ってそれを行う方法がある可能性があります (たとえば、EGL コンテキストなど... 現在理解していません)。

これを機能させることができず、不可能ではないかと心配している理由は次のとおりです。

  • 一番下のMediaCodec出力レイヤー (1) では、画像を変換できる必要があります。したがって、レンダリングする MediaCodec に指定するサーフェスは、TextureView
  • GLSurfaceView中央(2)の透明なピクセルを通して見ることができるようにするには、を呼び出す必要がありますGLSurfaceView.setZOrderOnTop(true)。それ以外の場合、GLSurfaceView は不透明です。
  • ただし、呼び出しGLSurfaceView.setZOrderOnTop(true)は、他のビュー (3) が の上にレンダリングされないことを意味しますGLSurfaceView。たとえば、ImageViewは常に の不透明なピクセルの後ろに表示されGLSurfaceViewます。

呼び出しGLSurfaceView.setZOrderMediaOverlay(true)の代わりに、GLSurfaceView.setZOrderOnTop(true)これに対処し、このタイプの Z オーダーを容易にすることを意図しているようです。そして、最下層のMediaCodec出力レイヤーがSurfaceView. しかし、私はそれをTextureView変換できるようにする必要があります。その下にGLSurfaceView.setZOrderMediaOverlay(true)がある場合は機能しないようです。透明なピクセルを通して表示されるのではなく、中間レイヤーによって完全に隠されています。TextureViewTextureViewGLSurfaceView

この Z オーダーは不可能であるというのは正しいですか? それとも、EGL やコンテキストなどをいじることで実現できますか?

4

1 に答える 1

2

ここでは、EGL コンテキストはあまり関係ありません。あなたの戦いは、SurfaceFlinger とビュー システムです。

実行adb shell dumpsys SurfaceFlingerすると、システム コンポジターが認識しているすべてのレイヤーの完全なリストが表示されます。で 320x240 のビデオを再生している場合SurfaceView、次のようになります (簡潔にするために、いくつかの列と他の多くのものを削除しています)。

    type    |          source crop              |           frame           name 
------------+-----------------------------------+--------------------------------
        HWC | [    0.0,    0.0,  320.0,  240.0] | [   48,  411, 1032, 1149] SurfaceView
        HWC | [    0.0,   75.0, 1080.0, 1776.0] | [    0,   75, 1080, 1776] com.android.grafika/com.android.grafika.PlayMovieSurfaceActivity
        HWC | [    0.0,    0.0, 1080.0,   75.0] | [    0,    0, 1080,   75] StatusBar
        HWC | [    0.0,    0.0, 1080.0,  144.0] | [    0, 1776, 1080, 1920] NavigationBar
  FB TARGET | [    0.0,    0.0, 1080.0, 1920.0] | [    0,    0, 1080, 1920] HWC_FRAMEBUFFER_TARGET

レイヤーは、後ろから前へ Z オーダーになっています。SurfaceView の表面レイヤーは背面にあり、アプリ UI レイヤーはその上にあり、システム ステータス + ナビゲーション バーはすべての上にあります。

アプリのビュー階層のすべてが単一のレイヤーにレンダリングされます。それが含まれTextureViewます。他のハードウェア合成レイヤーに対する Z オーダーを制御することはできません。

SurfaceViewView 部分は単なる透明なプレースホルダーであり、実際のアクションは別のレイヤーで発生し、その Z オーダーを (少し) 制御できるという点で素晴らしいです。次の 3 つの異なるレベルに配置できます。

  • 「メディア」(デフォルト)
  • 「メディアオーバーレイ」
  • (アプリUIはこちら)
  • 「パネル」(ZOrderOnTop)

MediaCodecしたがって、出力をデフォルト レイヤーに置き、GLES 出力を「メディア オーバーレイ」レイヤーに置きます。でこれらの両方を行う必要がありますSurfaceView

解決しようとしている問題 (つまり、何を構築しているのか) ではなく、試みた解決策で発生している問題を説明したため、ここからより良いアドバイスを提供することは困難ですが、いくつかの提案を提供できます。

まず、SurfaceViewをスケーリングできます。上記の dumpsys 出力を見ると、「SurfaceView」行に 320x240 (ビデオのサイズ) のソース トリミング四角形と 984x738 の宛先四角形があることがわかります。これは、ビデオの 4:3 アスペクト比を維持するために SurfaceView のサイズを変更したGrafika の「Play video (SurfaceView)」から来ています。SurfaceFlinger は、ビューに合わせてコンテンツをスケーリングします。

次に、DRM で保護されたビデオ コンテンツを表示していない場合は、それを に送信し、SurfaceTexture他のすべてをレンダリングしているときに GLES でレンダリングすることができます。(これはまさにTextureView、ハードウェア アクセラレーションが必要な理由です。) たとえば、Grafika の「連続キャプチャ」を参照してください。

更新: Android System-Level Graphics docで、より長い説明を見つけることができます。

于 2014-03-22T00:37:10.420 に答える