Android 12 中引入的兼容媒體轉碼功能允許設備使用更現代、存儲效率更高的媒體格式進行視頻捕獲,例如 HEVC,同時保持與應用程序的兼容性。借助此功能,設備製造商可以默認使用 HEVC 而非 AVC 來提高視頻質量,同時降低存儲和帶寬要求。對於啟用了兼容媒體轉碼的設備,當視頻被不支持格式的應用打開時,Android 可以自動轉換以 HEVC 或 HDR 等格式錄製的視頻(最長一分鐘)。即使在設備上以較新的格式捕獲視頻,這也允許應用程序運行。
兼容媒體轉碼功能默認關閉。要請求媒體轉碼,應用必須聲明其媒體功能。有關聲明媒體功能的更多信息,請參閱 Android 開發者網站上的兼容媒體轉碼。
這個怎麼運作
兼容媒體轉碼功能包括兩個主要部分:
- 媒體框架中的轉碼服務:這些服務使用硬件將文件從一種格式轉換為另一種格式,以實現低延遲和高質量的轉換。這包括轉碼 API、轉碼服務、自定義過濾器的 OEM 插件和硬件。有關更多詳細信息,請參閱架構概述。
- 媒體提供程序中兼容的媒體轉碼功能:媒體提供程序中的此組件攔截訪問媒體文件的應用程序,並根據應用程序聲明的功能提供原始文件或轉碼文件。如果應用程序支持媒體文件的格式,則不需要特殊處理。如果應用程序不支持該格式,則框架會在應用程序訪問文件時將文件轉換為舊格式,例如 AVC。
圖 1 顯示了媒體轉碼過程的概述。
圖 1.兼容媒體轉碼概述。
支持的格式
兼容的媒體轉碼功能支持以下格式轉換:
- HEVC(8 位)到 AVC:編解碼器轉換是通過連接一個 mediacodec 解碼器和一個 mediacode 編碼器來執行的。
- HDR10+(10 位)到 AVC (SDR):使用媒體編解碼器實例和供應商插件掛鉤到解碼器實例執行 HDR 到 SDR 轉換。有關詳細信息,請參閱HDR 到 SDR 編碼。
支持的內容源
兼容的媒體轉碼功能支持存儲在主外部卷的DCIM/Camera/
文件夾中的本地 OEM 相機應用程序生成的設備上媒體。該功能不支持輔助存儲上的媒體。不支持通過電子郵件或 SD 卡傳遞到設備的內容。
應用程序根據各種文件路徑訪問文件。下面描述了啟用或繞過轉碼的文件路徑:
啟用轉碼:
- 通過 MediaStore API 訪問應用程序
- 通過直接文件路徑 API(包括 Java 和本機代碼)訪問應用程序
- 通過存儲訪問框架 (SAF) 訪問應用程序
- 通過操作系統共享表 Intents 訪問應用程序。 (僅限媒體存儲 URI)
- 從手機到 PC 的 MTP/PTP 文件傳輸
繞過轉碼:
- 通過彈出 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
全局啟用媒體轉碼
要使用轉碼測試媒體轉碼框架或應用行為,您可以全局啟用或禁用兼容媒體轉碼功能。在Settings > System > Developer > Media transcoding developer options 頁面中,將Override transcoding defaults開關設置為on ,然後將Enable transcoding開關設置為on或off 。如果啟用此設置,則可能會在後台為您正在開發的應用程序以外的應用程序進行媒體轉碼。
檢查轉碼狀態
在測試期間,您可以使用以下 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源碼。
轉碼系統 API(僅由 MediaProvider 使用)
應用媒體功能 API
frameworks/base/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
媒體轉碼服務
frameworks/av/services/mediatranscoding/
-
frameworks/av/media/libmediatranscoding/
原生媒體轉碼器
frameworks/av/media/libmediatranscoding/transcoder
MediaTranscoder 的 HDR 示例插件
MediaProvider文件截取和轉碼代碼
MediaTranscoder 基準測試
frameworks/av/media/libmediatranscoding/transcoder/benchmark
CTS 測試
cts/tests/tests/mediatranscoding/
HDR 到 SDR 編碼
為了支持 HDR 到 SDR 編碼,設備製造商可以使用位於/platform/frameworks/av/media/codec2/hidl/plugin/
的 AOSP 示例 Codec 2.0 過濾器插件。本節介紹過濾器插件如何工作,如何實現插件以及如何測試插件。
如果設備不包含支持 HDR 到 SDR 編碼的插件,則訪問 HDR 視頻的應用會獲取原始文件描述符,而不管清單中聲明的應用的媒體功能如何。
這個怎麼運作
本節介紹 Codec 2.0 過濾器插件的一般行為。
背景
Android 在android::hardware::media::c2
提供了Codec 2.0接口和android.hardware.media.c2
HAL 接口之間的適配層實現。對於過濾器插件,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 實現所公開的內容是分開的。通常,此存儲僅包含 teFilterWrapper
類使用的過濾器。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
類的詳細信息。
創建
包裝的組件在創建時實例化底層解碼器和所有定義的過濾器。
查詢和配置
包裝的組件根據過濾器描述將傳入參數與查詢或配置請求分開。例如,過濾器控制參數的配置被路由到相應的過濾器,並且來自過濾器的受影響參數出現在查詢上(而不是從具有未受影響參數的解碼器讀取)。
圖 2.查詢和配置。
開始
在開始時,被包裝的組件啟動解碼器和所有改變緩衝區的過濾器。如果未啟用過濾器,則包裝的組件將啟動解碼器和直通緩衝區,並將命令發送到解碼器本身。
緩衝區處理
圖 3.緩衝區處理。
排隊到包裝解碼器的緩衝區轉到底層解碼器。包裝的組件通過onWorkDone_nb()
回調從解碼器獲取輸出緩衝區,然後將其排隊到過濾器。最後一個過濾器的最終輸出緩衝區報告給客戶端。
為了使緩衝區處理工作,被包裝的組件必須將C2PortBlockPoolsTuning
配置為最後一個過濾器,以便框架從預期的塊池中輸出緩衝區。
停止、重置和釋放
在停止時,包裝的組件會停止解碼器和所有已啟動的啟用過濾器。在重置和釋放時,所有組件都會重置或釋放,無論它們是否啟用。
實現示例過濾器插件
要啟用插件,請執行以下操作:
- 在庫中實現
FilterPlugin
接口並將其放在/vendor/lib[64]/libc2filterplugin.so.
- 如果需要,向
mediacodec.te
添加其他權限。 - 將適配層更新到 Android 12 並重建
media.c2
服務。
測試插件
要測試示例插件,請執行以下操作:
- 重建並刷新設備。
使用以下命令構建示例插件:
m sample-codec2-filter-plugin
重新掛載設備並重命名供應商插件,以便編解碼器服務能夠識別它。
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