Google致力於提高黑人社區的種族平等。 怎麼看。
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

TextureView

TextureView類是將視圖與SurfaceTexture結合在一起的視圖對象。

使用OpenGL ES渲染

TextureView對象包裝SurfaceTexture,響應回調並獲取新的緩衝區。當TextureView獲取新的緩衝區時,TextureView發出視圖無效請求,並使用最新緩衝區的內容作為其數據源進行繪製,無論在何處顯示,但視圖狀態指示應該顯示。

OpenGL ES(GLES) 可以通過將SurfaceTexture傳遞給EGL創建調用來在TextureView上進行渲染,但這會產生問題。當GLES在TextureView上渲染時,BufferQueue生產者和使用者位於同一線程中,這可能導致緩衝區交換調用停止或失敗。例如,如果生產者從UI線程快速連續提交多個緩衝區,則EGL緩衝區交換調用需要從BufferQueue中將緩衝區出隊。但是,由於使用者和生產者在同一線程上,因此不會有任何可用緩衝區,並且swap調用會掛起或失敗。

為確保緩衝區交換不會停止,BufferQueue始終需要一個可用的緩衝區來出隊。為實現此目的,當新緩衝區進入隊列時,BufferQueue丟棄先前獲取的緩衝區的內容,並對最小和最大緩衝區數進行限制,以防止使用者立即使用所有緩衝區。

選擇SurfaceView或TextureView

SurfaceView和TextureView扮演相似的角色,並且都是視圖層次結構的公民。但是,SurfaceView和TextureView具有不同的實現。 SurfaceView與其他視圖採用相同的參數,但是SurfaceView內容在呈現時是透明的。

TextureView比SurfaceView具有更好的Alpha和旋轉處理,但是在合成視頻上分層的UI元素時,SurfaceView具有性能優勢。當客戶端使用SurfaceView進行渲染時,SurfaceView為客戶端提供單獨的合成層。如果設備支持,SurfaceFlinger會將單獨的層構成為硬件覆蓋。當客戶端使用TextureView進行渲染時,UI工具包會使用GPU將TextureView的內容合成到視圖層次結構中。內容的更新可能導致其他視圖元素重新繪製,例如,如果其他視圖位於TextureView的頂部。視圖渲染完成後,SurfaceFlinger會合成應用程序UI層和所有其他層,以便每個可見像素被合成兩次。

案例研究:Grafika的播放視頻

Grafika的Play Video包括一對視頻播放器,一個通過TextureView實現,一個通過SurfaceView實現。活動的視頻解碼部分將來自MediaCodec的幀發送到TextureView和SurfaceView的表面。實現之間的最大區別是呈現正確的縱橫比所需的步驟。

縮放SurfaceView需要自定義實現FrameLayout。 WindowManager需要將新的窗口位置和新的尺寸值發送到SurfaceFlinger。縮放TextureView的SurfaceTexture要求使用TextureView#setTransform()配置轉換矩陣。

給出正確的寬高比後,兩種實現都遵循相同的模式。當SurfaceView / TextureView創建表面時,應用程序代碼將啟用播放。當用戶點擊play時 ,它將啟動視頻解碼線程,並將表面作為輸出目標。此後,應用程序代碼不執行任何操作-合成和顯示由SurfaceFlinger(用於SurfaceView)或TextureView處理。

案例研究:Grafika的雙重解碼

Grafika的Double Decode演示了TextureView內部對SurfaceTexture的操作。

Grafika的Double Decode使用一對TextureView對象來顯示兩個並排播放的視頻,模擬了一個視頻會議應用程序。當屏幕方向改變並且活動重新開始時,MediaCodec解碼器不會停止,從而模擬實時視頻流的回放。為了提高效率,客戶應保持表面活躍。表面是SurfaceTexture的BufferQueue中生產者接口的句柄。因為TextureView管理SurfaceTexture,所以客戶端需要保持SurfaceTexture處於活動狀態以保持曲面處於活動狀態。

為了使SurfaceTexture保持活動狀態,Grafika的Double Decode從TextureView對象獲取對SurfaceTextures的引用,並將其保存在靜態字段中。然後,Grafika的Double Decode從TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed()返回false ,以防止破壞SurfaceTexture。然後,TextureView將onSurfaceTextureDestroyed()傳遞給onSurfaceTextureDestroyed() ,可以在活動配置更改中對其進行維護,客戶端通過setSurfaceTexture()將其傳遞給新的TextureView。

單獨的線程驅動每個視頻解碼器。 Mediaserver將具有解碼輸出的緩衝區發送到SurfaceTextures(即BufferQueue使用者)。 TextureView對象執行渲染並在UI線程上執行。

用SurfaceView實現Grafika的雙重解碼要比使用TextureView實現困難,因為SurfaceView對象會在方向更改時破壞曲面。此外,使用SurfaceView對象會增加兩層,由於硬件上可用疊加層數量的限制,因此並不理想。