表面紋理

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並提供受保護的視訊表面以在受保護的上下文中使用。這是透過在受保護上下文中建立的表面上設定受保護的消費者位元( GRALLOC_USAGE_PROTECTED )來完成的(由 ACodec 驗證)。

安全紋理影片播放為 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 )。