架構(gòu)8--TextureView

轉(zhuǎn)自:https://source.android.com/devices/graphics/?hl=zh-cn

TextureView

我們在 Android 4.0 中引入了 TextureView 類雕崩,它結(jié)合了 View 與 SurfaceTexture掠手,是我們在此討論的最復(fù)雜的 View 對象。

使用 GLES 呈現(xiàn)

我們已經(jīng)知道,SurfaceTexture 是一個“GL 消費者”,它會占用圖形數(shù)據(jù)的緩沖區(qū)寿烟,并將它們作為紋理進行提供。TextureView 會對 SurfaceTexture 進行封裝辛燥,并接管對回調(diào)做出響應(yīng)以及獲取新緩沖區(qū)的責任筛武。新緩沖區(qū)的就位會導(dǎo)致 TextureView 發(fā)出 View 失效請求。當被要求進行繪圖時挎塌,TextureView 會使用最近收到的緩沖區(qū)的內(nèi)容作為數(shù)據(jù)源徘六,并根據(jù) View 狀態(tài)的指示,以相應(yīng)的方式在相應(yīng)的位置進行呈現(xiàn)榴都。

您可以使用 GLES 在 TextureView 上呈現(xiàn)內(nèi)容待锈,就像在 SurfaceView 上一樣。只需將 SurfaceTexture 傳遞到 EGL 窗口創(chuàng)建調(diào)用即可嘴高。不過竿音,這樣做會導(dǎo)致潛在問題和屎。

在我們看到的大部分內(nèi)容中,BufferQueue 是在不同進程之間傳遞緩沖區(qū)春瞬。當使用 GLES 呈現(xiàn)到 TextureView 時柴信,生產(chǎn)者和消費者處于同一進程中,它們甚至可能會在單個線程上得到處理宽气。假設(shè)我們以快速連續(xù)的方式從界面線程提交多個緩沖區(qū)随常。EGL 緩沖區(qū)交換調(diào)用需要使一個緩沖區(qū)從 BufferQueue 出列,而在有可用的緩沖區(qū)之前萄涯,它將處于暫停狀態(tài)绪氛。只有當消費者獲取一個緩沖區(qū)用于呈現(xiàn)時才會有可用的緩沖區(qū)程梦,但是這一過程也會發(fā)生在界面線程上…因此我們陷入了困境慎玖。

解決方案是讓 BufferQueue 確保始終有一個可用的緩沖區(qū)能夠出列,以使緩沖區(qū)交換始終不會暫停蒸眠。要保證能夠?qū)崿F(xiàn)這一點袄琳,一種方法是讓 BufferQueue 在新緩沖區(qū)加入隊列時舍棄之前加入隊列的緩沖區(qū)的內(nèi)容询件,并對最小緩沖區(qū)計數(shù)和最大獲取緩沖區(qū)計數(shù)施加限制(如果您的隊列有三個緩沖區(qū)燃乍,而所有這三個緩沖區(qū)均被消費者獲取唆樊,那么就沒有可以出列的緩沖區(qū),緩沖區(qū)交換調(diào)用必然會暫涂绦罚或失敗逗旁。因此我們需要防止消費者一次獲取兩個以上的緩沖區(qū))。丟棄緩沖區(qū)通常是不可取的舆瘪,因此僅允許在特定情況下發(fā)生片效,例如生產(chǎn)者和消費者處于同一進程中時。

SurfaceView 還是 TextureView英古?

SurfaceView 和 TextureView 扮演的角色類似淀衣,但是擁有截然不同的實現(xiàn)。要作出最合適的選擇召调,則需要了解它們各自的利弊膨桥。

因為 TextureView 是 View 層次結(jié)構(gòu)的固有成員,所以其行為與其他所有 View 一樣唠叛,可以與其他元素相互疊加只嚣。您可以執(zhí)行任意轉(zhuǎn)換,并通過簡單的 API 調(diào)用將內(nèi)容檢索為位圖艺沼。

影響 TextureView 的主要因素是合成步驟的表現(xiàn)册舞。使用 SurfaceView 時,內(nèi)容可以寫到 SurfaceFlinger(理想情況下使用疊加層)合成的獨立分層中障般。使用 TextureView 時调鲸,View 合成往往使用 GLES 執(zhí)行盛杰,并且對其內(nèi)容進行的更新也可能會導(dǎo)致其他 View 元素重繪(例如,如果它們位于 TextureView 上方)藐石。View 呈現(xiàn)完成后饶唤,應(yīng)用界面層必須由 SurfaceFlinger 與其他分層合成,以便您可以高效地將每個可見像素合成兩次贯钩。對于全屏視頻播放器募狂,或任何其他相當于位于視頻上方的界面元素的應(yīng)用,SurfaceView 可以帶來更好的效果角雷。

如之前所述祸穷,受 DRM 保護的視頻只能在疊加平面上呈現(xiàn)。支持受保護內(nèi)容的視頻播放器必須使用 SurfaceView 進行實現(xiàn)勺三。

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

Grafika 包括一對視頻播放器雷滚,一個用 TextureView 實現(xiàn),另一個用 SurfaceView 實現(xiàn)吗坚。對于這兩個視頻播放器來說祈远,僅將幀從 MediaCodec 發(fā)送到 Surface 的視頻解碼部分是一樣的。這兩種實現(xiàn)之間最有趣的區(qū)別是呈現(xiàn)正確寬高比所需的步驟商源。

SurfaceView 需要 FrameLayout 的自定義實現(xiàn)车份,而要重新調(diào)整 SurfaceTexture 的大小,只需使用TextureView#setTransform()配置轉(zhuǎn)換矩陣即可牡彻。對于前者扫沼,您會通過 WindowManager 向 SurfaceFlinger 發(fā)送新的窗口位置和大小值;對于后者庄吼,您僅僅是在以不同的方式呈現(xiàn)它缎除。

否則,兩種實現(xiàn)均遵循相同的模式总寻。創(chuàng)建 Surface 后器罐,系統(tǒng)會啟用播放。點擊“播放”時渐行,系統(tǒng)會啟動視頻解碼線程轰坊,并將 Surface 作為輸出目標。之后殊轴,應(yīng)用代碼不需要執(zhí)行任何操作衰倦,SurfaceFlinger(適用于 SurfaceView)或 TextureView 會處理合成和顯示。

案例研究:Grafika 的雙重解碼

此操作組件演示了在 TextureView 中對 SurfaceTexture 的操控旁理。

此操作組件的基本結(jié)構(gòu)是一對顯示兩個并排播放的不同視頻的 TextureView樊零。為了模擬視頻會議應(yīng)用的需求,我們希望在操作組件因屏幕方向發(fā)生變化而暫停和恢復(fù)時,MediaCodec 解碼器能保持活動狀態(tài)驻襟。原因在于夺艰,如果不對 MediaCodec 解碼器使用的 Surface 進行完全重新配置,就無法更改它沉衣,而這是成本相當高的操作郁副;因此我們希望 Surface 保持活動狀態(tài)。Surface 只是 SurfaceTexture 的 BufferQueue 中生產(chǎn)者界面的句柄豌习,而 SurfaceTexture 由 TextureView 管理存谎;因此我們還需要 SurfaceTexture 保持活動狀態(tài)。那么我們?nèi)绾翁幚?TextureView 被關(guān)閉的情況呢肥隆?

TextureView 提供的setSurfaceTexture()調(diào)用正好能夠滿足我們的需求既荚。我們從 TextureView 獲取對 SurfaceTexture 的引用,并將它們保存在靜態(tài)字段中栋艳。當操作組件被關(guān)閉時恰聘,我們從onSurfaceTextureDestroyed()回調(diào)返回“false”,以防止 SurfaceTexture 被銷毀吸占。當操作組件重新啟動時晴叨,我們將原來的 SurfaceTexture 填充到新的 TextureView 中。TextureView 類負責創(chuàng)建和破壞 EGL 上下文矾屯。

每個視頻解碼器都是從單獨的線程驅(qū)動的兼蕊。乍一看,我們似乎需要每個線程的本地 EGL 上下文问拘;但請注意遍略,具有解碼輸出的緩沖區(qū)實際上是從 mediaserver 發(fā)送給我們的 BufferQueue 消費者 (SurfaceTexture)惧所。TextureView 會為我們處理呈現(xiàn)骤坐,并在界面線程上執(zhí)行。

使用 SurfaceView 實現(xiàn)該操作組件可能較為困難下愈。我們不能只創(chuàng)建一對 SurfaceView 并將輸出引導(dǎo)至它們纽绍,因為 Surface 在屏幕方向改變期間會被銷毀。此外势似,這樣做會增加兩個層拌夏,而由于可用疊加層的數(shù)量限制,我們不得不盡量將層數(shù)量減到最少履因。與上述方法不同障簿,我們希望創(chuàng)建一對 SurfaceTexture,以從視頻解碼器接收輸出栅迄,然后在應(yīng)用中執(zhí)行呈現(xiàn)站故,使用 GLES 將兩個紋理間隙呈現(xiàn)到 SurfaceView 的 Surface。

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 3.0 License, and code samples are licensed under theApache 2.0 License. For details, see ourSite Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 九月 6, 2017.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市西篓,隨后出現(xiàn)的幾起案子愈腾,更是在濱河造成了極大的恐慌,老刑警劉巖岂津,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虱黄,死亡現(xiàn)場離奇詭異,居然都是意外死亡吮成,警方通過查閱死者的電腦和手機橱乱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粱甫,“玉大人仅醇,你說我怎么就攤上這事∧е郑” “怎么了析二?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長节预。 經(jīng)常有香客問我叶摄,道長安拟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任糠赦,我火速辦了婚禮,結(jié)果婚禮上拙泽,老公的妹妹穿的比我還像新娘淌山。我一直安慰自己,他們只是感情好顾瞻,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荷荤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蕴纳。 梳的紋絲不亂的頭發(fā)上会油,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音古毛,去河邊找鬼翻翩。 笑死,一個胖子當著我的面吹牛体斩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播絮吵,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼暇昂!你這毒婦竟也來了伴嗡?” 一聲冷哼從身側(cè)響起急波,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤瘪校,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阱扬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡馍刮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年窃蹋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片警没。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡惠奸,死狀恐怖梅誓,靈堂內(nèi)的尸體忽然破棺而出佛南,到底是詐尸還是另有隱情嵌言,我是刑警寧澤嗅回,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布摧茴,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娃豹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一鹃栽、第九天 我趴在偏房一處隱蔽的房頂上張望躯畴。 院中可真熱鬧,春花似錦蓬抄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阅爽。三九已至,卻和暖如春劝赔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背着帽。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工移层, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人观话。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像灵迫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瀑粥,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容