相容媒體轉碼

Android 12 中引入的相容媒體轉碼功能可讓裝置使用更現代、儲存效率更高的媒體格式(例如 HEVC)進行視訊捕獲,同時保持與應用程式的相容性。借助此功能,設備製造商可以預設使用 HEVC 而不是 AVC,以提高視訊質量,同時降低儲存和頻寬要求。對於啟用了相容媒體轉碼的設備,當影片被不支援該格式的應用程式開啟時,Android 可以自動轉換以 HEVC 或 HDR 等格式錄製的影片(長度最多一分鐘)。即使在設備上以較新的格式捕獲視頻,應用程式也可以正常運行。

相容媒體轉碼功能預設為關閉。要請求媒體轉碼,應用程式必須聲明其媒體功能。有關聲明媒體功能的更多信息,請參閱 Android 開發人員網站上的兼容媒體轉碼

怎麼運作的

相容媒體轉碼功能由兩個主要部分組成:

  • 媒體框架中的轉碼服務:這些服務使用硬體將檔案從一種格式轉換為另一種格式,以實現低延遲和高品質的轉換。這包括轉碼 API、轉碼服務、用於自訂過濾器的 OEM 插件和硬體。有關更多詳細信息,請參閱架構概述
  • 媒體提供者中的相容媒體轉碼功能:媒體提供者中的此元件會攔截存取媒體檔案的應用程序,並根據應用程式聲明的功能提供原始檔案或轉碼檔案。如果應用程式支援媒體檔案的格式,則不需要特殊處理。如果應用程式不支援該格式,則當應用程式存取該檔案時,框架會將檔案轉換為較舊的格式,例如 AVC。

圖 1 顯示了媒體轉碼過程的概述。

相容媒體轉碼流程

圖 1.相容媒體轉碼概述。

支援的格式

相容的媒體轉碼功能支援以下格式轉換:

  • HEVC(8位元)到AVC:透過連接1個媒體編解碼器和1個媒體編解碼器進行編解碼器轉換。
  • HDR10+(10 位元)到 AVC (SDR): HDR 到 SDR 的轉換是使用媒體編解碼器實例和連接到解碼器實例的供應商插件來執行的。有關詳細信息,請參閱HDR 到 SDR 編碼

支援的內容來源

相容的媒體轉碼功能支援由本機 OEM 相機應用程式產生的裝置上媒體,該應用程式儲存在主外部磁碟區的DCIM/Camera/資料夾中。此功能不支援輔助儲存上的媒體。不支援透過電子郵件或 SD 卡傳遞到裝置的內容。

應用程式根據各種檔案路徑存取檔案。以下描述了啟用或繞過轉碼的檔案路徑:

  • 啟用轉碼:

    • 透過 MediaStore API 存取應用程式
    • 透過直接檔案路徑 API(包括 Java 和本機程式碼)存取應用程式
    • 透過儲存存取框架 (SAF) 進行應用程式存取
    • 應用程式透過作業系統共享表意圖進行存取。 (僅限 MediaStore URI)
    • MTP/PTP 檔案從手機傳輸到 PC
  • 繞過轉碼:

    • 透過彈出 SD 卡從裝置傳輸文件
    • 使用附近共用或藍牙傳輸等選項在裝置之間傳輸檔案。

新增自訂檔案路徑以進行轉碼

設備製造商可以選擇在DCIM/目錄下新增用於媒體轉碼的檔案路徑。 DCIM/目錄之外的任何路徑都將被拒絕。可能需要添加此類文件路徑以滿足運營商要求或當地法規。

若要新增檔案路徑,請使用轉碼路徑執行時間資源覆寫 (RRO)config_supported_transcoding_relative_paths 。以下是如何新增檔案路徑的範例:

<string-array name="config_supported_transcoding_relative_paths" translatable="false">
    <item>DCIM/JCF/</item>
</string-array>

若要驗證配置的檔案路徑,請使用:

adb shell dumpsys activity provider com.google.android.providers.media.module/com.android.providers.media.MediaProvider | head -n 20

架構概述

本節介紹媒體轉碼功能的架構。

媒體轉碼架構

圖 2.媒體轉碼架構。

媒體轉碼架構由下列元件組成:

  • MediaTranscodingManager系統API:允許客戶端與MediaTranscoding服務通訊的介面。 MediaProvider模組使用此 API。
  • MediaTranscodingService:管理客戶端連線、安排轉碼請求以及管理TranscodingSessions簿記的本機服務。
  • MediaTranscoder:執行轉碼的本機庫。該庫構建在媒體框架 NDK 之上,以與模組兼容。

相容的媒體轉碼功能在服務和媒體轉碼器中記錄轉碼指標。用戶端和服務端程式碼位於 MediaProvider 模組中,以便及時修復和更新錯誤。

文件訪問

相容的媒體轉碼建構在使用者空間檔案系統 (FUSE) 檔案系統之上,該系統用於範圍儲存。 FUSE 使 MediaProvider 模組能夠檢查使用者空間中的檔案操作,並根據允許、拒絕或編輯存取的策略來控制對檔案的存取。

當應用程式嘗試存取檔案時,FUSE 守護程式會攔截來自應用程式的檔案讀取存取權限。如果應用程式支援較新的格式(例如 HEVC),則傳回原始檔案。如果應用程式不支援該格式,則檔案會轉碼為較舊的格式(例如 AVC),或者如果轉碼版本可用,則會從快取中傳回。

請求轉碼文件

預設情況下,相容媒體轉碼功能處於停用狀態,這表示如果裝置支援 HEVC,Android 不會對檔案進行轉碼,除非應用程式在清單檔案或強制轉碼清單中指定。

應用程式可以使用以下選項請求轉碼資產:

  • 在清單文件中聲明不支援的格式。有關詳細信息,請參閱在資源中聲明功能在程式碼中聲明功能
  • 將應用程式新增至MediaProvider模組中包含的強制轉碼清單中。這可以為尚未更新其清單檔案的應用程式啟用轉碼。一旦應用程式使用不支援的格式更新其清單文件,就必須將其從強制轉碼清單中刪除。設備製造商可以透過提交修補程式報告錯誤來指定將其應用程式新增至強制轉碼清單或從強制轉碼清單中刪除。 Android 團隊會定期審核該列表,並可能從列表中刪除應用程式。
  • 在運行時使用應用程式相容性框架停用支援的格式(使用者也可以在「設定」中為每個應用程式停用此功能)。
  • 使用MediaStore開啟文件,同時使用openTypedAssetFileDescriptor API 明確指定不支援的格式。

對於 USB 傳輸(裝置到 PC),預設會停用轉碼,但使用者可以選擇使用USB 首選項設定畫面中的將影片轉換為 AVC開關啟用轉碼,如圖 3 所示。

切換以啟用媒體轉碼

圖 3.在 USB 首選項畫面中切換以啟用媒體轉碼。

請求轉碼檔案的限制

為了防止轉碼請求長時間鎖定係統資源,請求轉碼會話的應用程式僅限於:

  • 連續10場
  • 總運轉時間三分鐘

如果應用程式超出所有這些限制,框架將傳回原始檔案描述符。

設備要求

為了支援相容的媒體轉碼功能,設備必須滿足以下要求:

  • 裝置的本機相機應用程式預設為啟用 HEVC 編碼
  • (支援 HDR 轉 SDR 轉碼的裝置)支援 HDR 影片拍攝的設備

為了確保媒體轉碼的設備效能,必須優化視訊硬體和儲存讀取/寫入存取效能。當媒體編解碼器的優先權配置為1時,編解碼器必須以盡可能高的吞吐量運作。我們建議轉碼效能至少達到 200 fps。若要測試您的硬體效能,請在frameworks/av/media/libmediatranscoding/transcoder/benchmark執行媒體轉碼器基準測試。

驗證

若要驗證相容的媒體轉碼功能,請執行下列 CTS 測試:

  • android.media.mediatranscoding.cts
  • android.mediaprovidertranscode.cts

全域啟用媒體轉碼

若要透過轉碼測試媒體轉碼框架或應用程式行為,您可以全域啟用或停用相容的媒體轉碼功能。在「設定」>「系統」>「開發人員」>「媒體轉碼開發人員選項」頁面中,將「覆蓋轉碼預設值」開關設為「開」 ,然後將「啟用轉碼」開關設為“開”“關” 。如果啟用此設置,則媒體轉碼可能會在您正在開發的應用程式以外的應用程式的背景進行。

檢查轉碼狀態

在測試過程中,您可以使用下列 ADB shell 指令來檢查轉碼狀態,包括目前和過去的轉碼工作階段:

adb shell dumpsys media.transcoding

延長視頻長度限制

出於測試目的,您可以使用以下命令延長轉碼的一分鐘視訊長度限制。運行此命令後可能需要重新啟動。

adb shell device_config put storage_native_boot transcode_max_duration_ms <LARGE_NUMBER_IN_MS>

AOSP 來源和參考資料

以下是與媒體轉碼相關的AOSP源碼。

HDR 到 SDR 編碼

為了支援 HDR 到 SDR 編碼,設備製造商可以使用位於/platform/frameworks/av/media/codec2/hidl/plugin/ AOSP 範例 Codec 2.0 過濾器外掛程式。本節介紹過濾器插件的工作原理、如何實現插件以及如何測試插件。

如果裝置不包含支援 HDR 到 SDR 編碼的插件,則存取 HDR 影片的應用程式將取得原始檔案描述符,無論清單中聲明的應用程式的媒體功能為何。

怎麼運作的

本節介紹 Codec 2.0 過濾器插件的一般行為。

背景

Android 在Codec 2.0介面和android.hardware.media.c2 HAL 介面之間提供了一個適配層實作android::hardware::media::c2 。對於過濾器插件,AOSP 包含一個包裝器機制,將解碼器與過濾器插件包裝在一起。 MediaCodec將這些包裝的組件識別為具有過濾功能的解碼器。

概述

FilterWrapper類別採用供應商編解碼器並將包裝好的編解碼器返回media.c2適配器。 FilterWrapper類別透過FilterWrapper::Plugin API 載入libc2filterplugin.so並記錄插件中的可用過濾器。建立時, FilterWrapper實例化所有可用的過濾器。只有改變緩衝區的過濾器才會在啟動時啟動。

過濾器插件架構

圖 1.過濾器插件架構。

過濾器插件接口

FilterPlugin.h介面定義了以下 API 來公開過濾器:

  • std::shared_ptr<C2ComponentStore>getComponentStore()

    傳回包含篩選器的C2ComponentStore物件。這與供應商的 Codec 2.0 實現公開的內容是分開的。通常,此儲存空間僅包含FilterWrapper類別所使用的過濾器。

  • bool describe(C2String name, Descriptor *desc)

    除了C2ComponentStore中可用的內容之外,還描述了過濾器。定義了以下描述:

    • controlParam :控制過濾器行為的參數。例如,對於 HDR 到 SDR 色調映射器,控制參數是目標傳遞函數。
    • affectedParams :受過濾操作影響的參數。例如,對於 HDR 到 SDR 色調映射器,受影響的參數是顏色方面。
  • bool isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf)

    如果過濾器元件變更緩衝區,則傳回true 。例如,如果目標傳遞函數是 SDR 且輸入傳遞函數是 HDR(HLG 或 PQ),則色調映射濾波器會傳回true

FilterWrapper 詳細信息

本節描述FilterWrapper類別的詳細資訊。

創建

包裝的元件在創建時實例化底層解碼器和所有定義的過濾器。

查詢與配置

包裝組件根據過濾器描述將傳入參數與查詢或配置請求分開。例如,過濾器控制參數的配置被路由到相應的過濾器,並且來自過濾器的受影響的參數出現在查詢上(而不是從具有未受影響的參數的解碼器讀取)。

查詢與配置

圖 2.查詢和配置。

開始

開始時,包裝的組件啟動解碼器和所有改變緩衝區的過濾器。如果沒有啟用過濾器,則包裝的元件將啟動解碼器和傳遞緩衝區,並向解碼器本身發送命令。

緩衝區處理

緩衝區處理

圖 3.緩衝區處理。

排隊到包裝解碼器的緩衝區將轉到底層解碼器。包裝的組件透過onWorkDone_nb()回呼從解碼器取得輸出緩衝區,然後將其排隊到過濾器。最後一個過濾器的最終輸出緩衝區將報告給客戶端。

為了使此緩衝區處理起作用,包裝的元件必須將C2PortBlockPoolsTuning配置為最後一個過濾器,以便框架從預期的區塊池輸出緩衝區。

停止、重置和釋放

停止時,包裝的元件會停止解碼器和所有已啟動的啟用過濾器。在重置和釋放時,所有元件都會重置或釋放,無論它們是否啟用。

實作範例過濾器插件

若要啟用該插件,請執行以下操作:

  1. 在庫中實作FilterPlugin介面並將其放置在/vendor/lib[64]/libc2filterplugin.so.
  2. 如果需要,請為mediacodec.te新增其他權限。
  3. 將適配層更新至Android 12並重建media.c2服務。

測試插件

若要測試範例插件,請執行以下操作:

  1. 重建並刷新設備。
  2. 使用以下命令建立範例插件:

    m sample-codec2-filter-plugin
    
  3. 重新安裝設備並重新命名供應商插件,以便編解碼器服務可以識別它。

    adb root
    adb remount
    adb reboot
    adb wait-for-device
    adb root
    adb remount
    adb
    push /out/target/<...>/lib64/sample-codec2-filter-plugin.so \
    
    /vendor/lib64/libc2filterplugin.so
    adb push
    /out/target/<...>/lib/sample-codec2-filter-plugin.so \
    
    /vendor/lib/libc2filterplugin.so
    adb reboot