日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TextureView

發布時間:2024/4/11 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TextureView 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

TextureView 類是在 Android 4.0 中引入的,且是這里討論的最復雜的 View 對象,它結合了 View 和 SurfaceTexture。

用 GLES 渲染

回憶一下,SurfaceTexture 是一個 "GL 消費者",消費圖形數據緩沖區并使其可用作紋理。TextureView 封裝了一個 SurfaceTexture,并接管了響應回調和獲取新緩沖區的職責。新緩沖區的到達會導致 TextureView 發出 View invalidate 請求。當被請求繪制時,TextureView 使用最近接收到的緩沖區的內容作為它的數據源,無論何時何地在 View 狀態表示它應該渲染時渲染。

你可以像使用 SurfaceView 那樣通過 GLES 在 TextureView 上渲染。僅僅將 SurfaceTexture 傳遞給 EGL 窗口創建調用。然而,這樣做暴露了一個潛在的問題。在大部分我們研究的內容中,BufferQueue 已經在不同進程間傳遞了緩沖區。當用 GLES 向 TextureView 渲染時,生產者和消費者在相同的進程中,且它們甚至可能在同一個線程中處理。假設我們從 UI 線程快速連續地提交了一些緩沖區。EGL 緩沖區交換調用將需要從 BufferQueue 獲取一塊緩沖區,并且它將停止,直到有可用的緩沖區。在消費者獲取一個緩沖區用于渲染之前,將不會有任何可用的緩沖區,但那也會發生在 UI 線程 . . . 所以我們被卡住了。

解決方案是使 BufferQueue 總有一塊可用的緩沖區用于獲取,因此緩沖區交換從來不會停止。保證這一點的一種方式是使 BufferQueue 在新緩沖區入隊時,丟棄之前入隊的緩沖區的內容,并對最小緩沖區計數和獲取的最大緩沖區計數進行限制。(如果你的隊列已經有了三塊緩沖區,且所有的三塊緩沖區都由消費者獲取了,則沒有東西可以獲取了,且緩沖區交換調用必須掛起或失敗。因此我們需要阻止消費者一次獲取多于兩塊緩沖區。)丟棄緩沖區通常是不好的,因此它僅在特定情況下啟用,例如生產者和消費者處于相同進程中。

SurfaceView 或者 TextureView?

SurfaceView 和 TextureView 扮演類似的角色,但實現卻差別巨大。為了確定哪個最好,需要對其中的折中有一個了解。

由于 TextureView 是 View 層次體系的一個良好公民,它的行為就像任何其它的 View,且可以覆蓋其它元素或被其它元素覆蓋。你可以執行任意轉換,并可以通過簡單的 API 調用將其內容提取為 bitmap。

TextureView 的主要弱點是合成步驟的性能。通過 SurfaceView,內容被寫入 SurfaceFlinger 組合的單獨的 layer,理想情況下通過一個 overlay。通過 TextureView,View 合成總是由 GLES 執行,且更新它的內容也可能導致其它 View 元素重繪(如果它們的位置在 TextureView 之上的話)。在 View 渲染完成之后,應用程序 UI layer 必須由 SurfaceFlinger 與其它 layers 合成,因此你在有效地合成每個可見的像素兩次。對于一個全屏視頻播放器,或任何其他實際上只是 UI 元素 layer 在視頻之上的應用程序,SurfaceView 提供更好的性能。

如前所述,DRM保護的視頻只能在 overlay 平面上呈現。 支持受保護內容的視頻播放器必須使用 SurfaceView 實現。

案例研究:Grafika 的播放視頻 (TextureView)

Grafika 包含了一對視頻播放器,一個用 TextureView 實現,另一個用 SurfaceView。視頻解碼的部分,其僅僅將幀從 MediaCodec 發送到 Surface,兩者是相同的。實現之間大部分有趣的差異在請求以正確的長寬比顯示的步驟。

盡管 SurfaceView 請求一個定制的 FrameLayout 實現,改變 SurfaceTexture 的大小是一個通過 TextureView#setTransform() 配置一個轉換矩陣 的簡單問題。對于前者,你在通過 WindowManager 向 SurfaceFlinger 發送新的窗口位置和大小值;對于后者,你只是在做不同的渲染。

此外,兩種實現按照相同的模式。一旦 Surface 創建好了,播放被啟用。當按下 “播放”,視頻解碼線程被啟動,且以 Surface 作為輸出目標。之后,應用程序代碼不需要做任何事情 -- 合成和顯示將由 SurfaceFlinger(對于SurfaceView)或 TextureView 處理。

案例研究:Grafika 的雙重解碼

這個 Activity 演示了 TextureView 內部的 SurfaceTexture 管理。

這個 Activity 的基本結構是一對 TextureViews,它們一邊一個展示了兩個不同的視頻播放。為了模擬視頻會議應用的需求,我們想要在 Activity 由于方向改變而 paused 和 resumed 時保持 MediaCodec 解碼器存活。技巧在于你不能在不完全重新配置它的情況下改變 MediaCodec 解碼器使用的 Surface ,那是一個相當昂貴的操作;因此我們想要保持 Surface 存活。Surface 只是指向SurfaceTexture 的 BufferQueue 中的生產者接口的句柄,且 SurfaceTexture 由 TextureView 管理;因此我們還需要保持 SurfaceTexture 存活。那么我們要如何處理 TextureView 的銷毀呢?

恰好 TextureView 提供的 setSurfaceTexture() 調用正是我們想要的。我們從 TextureViews 獲得 SurfaceTextures 的引用并在靜態成員中保存它們。當 Activity 被關閉時,我們從 onSurfaceTextureDestroyed() 回調中返回 "false" 來阻止 SurfaceTexture 的銷毀。當 Activity 被重啟時,我們把老的 SurfaceTexture 放進新的 TextureView 中。TextureView 負責創建并銷毀 EGL contexts。

每個視頻解碼器都是從單獨的線程驅動的。乍看起來,似乎我們需要每個線程本地的 EGL contexts;但請記住擁有解碼的輸出的緩沖區實際上是從 mediaserver 發送到我們的 BufferQueue 消費者(SurfaceTextures)的。TextureViews 負責為我們渲染,且它們在 UI 線程執行。

以 SurfaceView 實現這個 Activity 更難一點。我們不能僅僅創建一對 SurfaceViews 并把輸出導向它們,由于 Surfaces 將在屏幕方向轉變期間被銷毀。此外,那將添加兩個 layers,關于可用的 overlays 的數量上的限制強烈地激勵我們保持 layers 的數量為最小值。相反,我們想要創建一對 SurfaceTextures 來接收來自于視頻解碼器的輸出,然后在應用中執行渲染,使用 GLES 將兩個紋理四邊形渲染到 SurfaceView 的 Surface 上。

原文

總結

以上是生活随笔為你收集整理的TextureView的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。