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
例項以顏色顯示 (生產者為藍綠色,消費者為綠色)。

圖 1. Grafika 的持續擷取活動
經過編碼的 H.264 影片會傳送至應用程式程序中 RAM 的循環緩衝區。當使用者按下擷取按鈕時,MediaMuxer
類別會將已編碼的影片寫入磁碟上的 MP4 檔案。
當 GLES 作業在 UI 執行緒上執行時,所有 BufferQueue
例項都會使用應用程式中的單一 EGL 上下文進行處理。在個別執行緒中處理編碼資料 (管理循環緩衝區並將其寫入磁碟)。
SurfaceView
類別時,surfaceCreated()
回呼會為顯示器和影片編碼器建立 EGLContext
和 EGLSurface
例項。收到新影格時,SurfaceTexture
會執行四項活動:
- 取得影格。
- 將影格做為 GLES 紋理提供。
- 使用 GLES 指令算繪影格。
- 將每個
EGLSurface
例項的轉換和時間戳記轉發。
接著,編碼器執行緒會從 MediaCodec
提取已編碼的輸出內容,並將其儲存在記憶體中。
安全的紋理影片播放
Android 支援保護影片內容的 GPU 後製處理。這項功能可讓應用程式使用 GPU 處理複雜的非線性影片效果 (例如扭曲),將受保護的影片內容對應至紋理,以便在一般圖像場景 (例如使用 GLES) 和虛擬實境 (VR) 中使用。

圖 2. 安全的紋理影片播放
支援功能是透過下列兩個擴充功能啟用:
- EGL 擴充功能:(
EGL_EXT_protected_content
) 可用來建立受保護的 GL 情境和介面,兩者皆可在受保護的內容上運作。 - GLES 擴充功能 - (
GL_EXT_protected_textures
) 可將紋理標記為受保護,以便做為 framebuffer 紋理附件使用。
Android 可讓 SurfaceTexture
和 ACodec (libstagefright.so
) 傳送受保護的內容,即使視窗的表面未排入 SurfaceFlinger
的佇列,也能提供受保護的影片表面,供受保護的內容中使用。方法是在受保護的背景 (由 ACodec 驗證) 中建立的表面上,設定受保護的消費者位元 (GRALLOC_USAGE_PROTECTED
)。
安全的紋理影片播放功能可為 OpenGL ES 環境中強大的 DRM 實作奠定基礎。如果沒有強大的 DRM 實作 (例如 Widevine Level 1),許多內容供應商都不會允許在 OpenGL ES 環境中算繪高價值內容,導致無法在 VR 中觀看受 DRM 保護的內容等重要 VR 用途。
Android 開放原始碼計畫包含用於安全紋理影片播放的架構程式碼。驅動程式支援功能由原始設備製造商 (OEM) 提供。裝置實作者必須實作 EGL_EXT_protected_content
和 GL_EXT_protected_textures extensions
。使用自訂編解碼器程式庫 (用於取代 libstagefright
) 時,請注意 /frameworks/av/media/libstagefright/SurfaceUtils.cpp
中的變更,以便將標示為 GRALLOC_USAGE_PROTECTED
的緩衝區傳送至 ANativeWindow
(即使 ANativeWindow
未直接排入視窗編寫器的佇列),只要使用者用途位元包含 GRALLOC_USAGE_PROTECTED
即可。如需實作擴充功能的詳細說明文件,請參閱 Khronos 登錄檔 (EGL_EXT_protected_content
和 GL_EXT_protected_textures
)。