SurfaceTexture
SurfaceTexture 類是在 Android 3.0 中引入的。就像 SurfaceView 是 Surface 和 View 的結合一樣,SurfaceTexture 是 Surface 和 GLES texture 的粗糙結合(有幾個警告)。
當你創建了一個 SurfaceTexture,你就創建了你的應用作為消費者的 BufferQueue。當一個新的緩沖區由生產者入對時,你的應用將通過回調 (onFrameAvailable()) 被通知。你的應用調用 updateTexImage(),這將釋放之前持有的緩沖區,并從隊列中獲取新的緩沖區,執行一些 EGL 調用以使緩沖區可作為一個外部 texture 由 GLES 使用。
外部 texture
外部 texture (GL_TEXTURE_EXTERNAL_OES) 與 GLES 創建的 textures (GL_TEXTURE_2D) 不太一樣:你不得不以略微不同的方式配置你的渲染器,且有些東西你不能用它們做。重點是你可以直接用你的 BufferQueue 接收的數據渲染紋理多邊形。gralloc 支持各種各樣的格式,因此我們需要保證緩沖區中的數據的格式是 GLES 能夠識別的。為了做到這一點,當 SurfaceTexture 創建 BufferQueue 時,它設置消費者的使用標記為 GRALLOC_USAGE_HW_TEXTURE,以確保 gralloc 創建的任何緩沖區對 GLES 是可用的。
由于 SurfaceTexture 與 EGL 上下文交互,你必須小心地在正確的線程中調用它的方法(類文檔中有更多細節信息)。
時間戳和轉換
如果你更深入地查看類文檔,你會看到幾個奇怪的調用。一個調用提取了時間戳,另一個提取了轉換矩陣,每個的值都已經由之前 updateTexImage() 調用設置過了。事實證明,BufferQueue 不僅給消費者傳遞緩沖區句柄。每個緩沖區還伴隨有一個時間戳和轉換參數。
轉換是為了效率而提供的。在一些情況下,消費者的源數據可能處于不正確的方向;但不是在發送數據之前旋轉它,我們可以以當前的方向發送數據且伴隨一個轉換來修正它。從數據使用的角度來看轉換矩陣可以與其它的轉換合并,以最小化開銷。
時間戳對某些緩沖區源很有用。比如,假設你將生產者接口與 camera 的輸出連接在一起 (通過 setPreviewTexture())。為了創建一個視頻,你需要為每一幀設置顯示時間戳;但你想要基于幀被捕獲的時間,而不是你的應用接收到緩沖區的時間。與緩沖區一起提供的時間戳是由 camera 的代碼設置的,這使得時間戳更加的一致連續。
SurfaceTexture 和 Surface
如果你近距離查看 API 的話,你將發現應用創建平面 Surface 的僅有的方法是,通過接收一個 SurfaceTexture 作為單獨的參數的構造函數。(在 API 11 之前,Surface 沒有公共構造函數。)如果你將 SurfaceTexture 視為 Surface 和紋理的組合,這可能看起來有點落后。
在引擎蓋下,SurfaceTexture 被稱為 GLConsumer,它更精確地反映了它的角色是 BufferQueue 的擁有者和消費者。當你由 SurfaceTexture 創建 Surface 時,你正在做的事情是創建一個對象表示 SurfaceTexture 的 BufferQueue 的生產者端。
案例研究:Grafika 的持續捕獲
Camera 可以提供一個適合于記錄為視頻的幀流。為了在屏幕上顯示它,你創建一個 SurfaceView,并把 Surface 傳遞給 setPreviewDispaly(),并讓生產者 (camera) 和消費者 (SurfaceFlinger) 完成所有的工作。為了記錄視頻,你以 MediaCodec 的 createInputSurface() 創建一個 Surface,將其傳給 camera,然后坐回去并放松一下。為了同時顯示并記錄它,你不得不更多地參與進去。
持續捕獲 activity 以視頻被記錄的順序顯示來自于 camera 的視頻。在這種情況下,編碼的視頻被寫入一個可以在任何時間被保存到磁盤的內存中的循環緩沖區。只要你追蹤所有內容,就可以直接實現。
這個流程包括三個 BufferQueue:一個由應用程序創建,一個由 SurfaceFlinger 創建,一個有 mediaserver 創建:
-
應用程序。應用程序使用一個 SurfaceTexture 接收來自于 Camera 的幀,并把它們轉為外部 GLES 紋理。
-
SurfaceFinger。應用程序聲明一個 SurfaceView,我們用它顯示幀。
- MediaServer。你可以以一個輸入 Surface 配置 MediaCodec 編碼器來創建視頻。
continuous_capture_activity.png
圖 1 Grafika 的持續捕獲 activity。箭頭表示從 camera 的數據傳播,且 BufferQueue 是彩色的 (生產者是青色的,消費者是綠色的)。
編碼后的 H.264 視頻進入一個應用進程內內存中的循環緩沖區,并且當按下捕獲按鈕時,使用 MediaMuxer 類寫入磁盤上的一個 MP4 文件。
所有的三個 BufferQueue 由應用中一個單獨的 EGL context 處理,且 GLES 操作在 UI 線程中執行。在 UI 線程中執行 SurfaceView 渲染通常是不鼓勵的,但由于我們正在執行由 GLES 驅動異步處理的簡單的操作,所以應該沒什么問題。(如果視頻解碼器鎖定,而我們阻塞并試圖取出緩沖區,則應用將變得無響應。但是在這一點上,我們大概還是會失敗的。) 編碼的數據的處理 - 管理循環緩沖區并將其寫入磁盤 - 在另一個線程中執行。
大部分配置發生在 SurfaceView 的 surfaceCreated() 回調中。創建 EGLConext,為顯示器和視頻編碼器創建 EGLSurfaces。當一個新幀到達時,我們告訴 SurfaceTexture 獲取它并使它可以作為 GLES texture 使用,然后在每個 EGLSurface 上通過 GLES 命令渲染它(從 SurfaceTexture 轉發轉換和時間戳)。編碼器線程從 MediaCodec 拉取編碼后的輸出并將其存儲在內存中。
安全紋理視頻播放
Android 7.0 支持受保護視頻內容的 GPU 后處理。這允許對復雜的非線性視頻效果(比如 warps)使用 GPU,將受保護視頻內容映射到紋理上以用于通用的圖形場景(比如,使用 OpenGL ES),以及虛擬顯示(VR)。
graphics_secure_texture_playback.png
圖 2. 安全紋理視頻播放
使用如下兩個擴展來啟用支持:
-
EGL 擴展 (EGL_EXT_protected_content)。允許創建受保護的 GL 上下文和 surfaces,它可以同時在受保護內容之上操作。
-
EGL 擴展 (GL_EXT_protected_textures)。允許標記紋理為受保護的,以使它們可被用作 framebuffer 紋理附件。
Android 7.0 也更新 SurfaceTexture 和 ACodec (libstagefright.so) 以允許發送受保護的內容,即使窗口的 surface 沒有加入窗口合成器(比如 SurfaceFlinger)的隊列,并提供一個與受保護的上下文一起使用的受保護的視頻 surface。這通過設置在受保護的上下文中創建的 surfaces 的正確的受保護消費者位 (GRALLOC_USAGE_PROTECTED) (由 ACodec 驗證)。
這些改動使得可以創建執行增強視頻效果或在 GL 中使用受保護的上下文來應用視頻紋理的應用的應用開發者(比如,在 VR 中),可以在 GL 環境下(比如,在 VR 中)觀看高價值視頻內容(比如電影和電視節目)的終端用戶,以及由于新增的設備功能(比如在 VR 中觀看 HD 電影)而取得更高銷量的 OEMs受益。新的 EGL 和 GLES 擴展可以被片上系統 (SoCs) 提供者和其它供應商使用,且當前是在 MSM8994 SoC 芯片組上實現并用于 Nexus 6P 的。
安全紋理視頻播放為 OpenGL ES 環境中強大的 DRM 實現建立了基礎。沒有一個諸如 Widevine Level 1 這樣強大的 DRM 實現,許多內容提供者將不允許在 OpenGL ES 環境下渲染它們的高品質內容,并阻礙重要的如觀看 VR 中受 DRM 保護的內容這樣的 VR 用例。
AOSP 包含了安全紋理視頻播放的框架代碼;驅動的支持則依賴于供應商。設備實現者必須實現 EGL_EXT_protected_content 和 GL_EXT_protected_textures extensions。當你使用你自己的編解碼庫(替換 libstagefright )時,注意 /frameworks/av/media/libstagefright/SurfaceUtils.cpp 的修改,其允許緩沖區被標記為 GRALLOC_USAGE_PROTECTED 并發送給 ANativeWindows(即使 ANativeWindow 不直接入隊窗口合成器),且消費者使用位包含 GRALLOC_USAGE_PROTECTED。關于實現擴展的詳細文檔,請參考 Khronos Registry (EGL_EXT_protected_content, GL_EXT_protected_textures)
設備實現者也可能需要修改硬件,以確保受保護的內存映射到 GPU 之后保持對非受保護代碼的受保護和不可讀。
原文
總結
以上是生活随笔為你收集整理的SurfaceTexture的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SurfaceView 和 GLSurf
- 下一篇: TextureView