表面紋理

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() 。請注意,記錄幀並同時顯示它們是一個更複雜的過程。

在錄製視頻時,連續捕獲活動會顯示來自攝像機的視頻。在這種情況下,編碼的視頻被寫入內存中的循環緩衝區,可以隨時保存到磁盤。

此流程涉及三個緩衝區隊列:

  • App — 應用程序使用SurfaceTexture實例從相機接收幀,將它們轉換為外部 GLES 紋理。
  • SurfaceFlinger — 應用聲明一個SurfaceView實例來顯示幀。
  • MediaServer — 使用輸入表面配置MediaCodec編碼器以創建視頻。

在下圖中,箭頭表示來自相機的數據傳播。 BufferQueue實例是彩色的(生產者是藍綠色的,消費者是綠色的)。

Grafika 連續捕獲活動

圖 1. Grafika 的連續捕獲活動

編碼的 H.264 視頻在應用程序進程中進入 RAM 中的循環緩衝區。當用戶按下捕獲按鈕時, MediaMuxer類將編碼的視頻寫入磁盤上的 MP4 文件。

所有BufferQueue實例都在應用程序中使用單個 EGL 上下文進行處理,而 GLES 操作在 UI 線程上執行。編碼數據的處理(管理循環緩衝區並將其寫入磁盤)在單獨的線程上完成。

使用SurfaceView類時, surfaceCreated()回調會為顯示器和視頻編碼器創建EGLContextEGLSurface實例。當新幀到達時, SurfaceTexture執行四個活動:
  1. 獲取幀。
  2. 使框架可用作 GLES 紋理。
  3. 使用 GLES 命令渲染框架。
  4. 轉發每個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 奠定了基礎。如果沒有強大的 DRM 實施,例如 Widevine Level 1,許多內容提供商不允許在 OpenGL ES 環境中渲染他們的高價值內容,從而阻止重要的 VR 用例,例如在 VR 中觀看受 DRM 保護的內容。

AOSP 包括用於安全紋理視頻播放的框架代碼。驅動程序支持取決於 OEM。設備實現者必須實現EGL_EXT_protected_contentGL_EXT_protected_textures extensions 。使用您自己的編解碼器庫(替換libstagefright )時,請注意/frameworks/av/media/libstagefright/SurfaceUtils.cpp中的更改允許將標記為GRALLOC_USAGE_PROTECTED的緩衝區發送到ANativeWindow (即使ANativeWindow不直接排隊到窗口作曲家)只要消費者使用位包含GRALLOC_USAGE_PROTECTED 。有關實現擴展的詳細文檔,請參閱 Khronos 註冊表( EGL_EXT_protected_contentGL_EXT_protected_textures )。