Android 12 推出的相容媒體轉碼功能,可讓裝置使用更先進、節省儲存空間的媒體格式 (例如 HEVC) 拍攝影片,同時維持與應用程式的相容性。裝置製造商可透過這項功能,預設使用 HEVC 取代 AVC,在降低儲存空間和頻寬需求量的同時,提升影片畫質。如果裝置已啟用相容的媒體轉碼功能,當應用程式開啟以 HEVC 或 HDR 等格式錄製的影片 (長度最多一分鐘) 時,Android 會自動轉換影片格式,方便應用程式播放。即使裝置以較新的格式拍攝影片,應用程式也能正常運作。
相容媒體轉碼功能預設為關閉。如要要求媒體轉碼,應用程式必須宣告媒體功能。如要進一步瞭解如何宣告媒體功能,請參閱 Android 開發人員網站上的「相容的媒體轉碼」一文。
運作方式
相容媒體轉碼功能包含兩個主要部分:
- 媒體架構中的轉碼服務:這些服務會使用硬體將檔案從一種格式轉換為另一種格式,以實現低延遲和高品質的轉換。包括轉碼 API、轉碼服務、自訂篩選器的 OEM 外掛程式和硬體。詳情請參閱架構總覽。
- 媒體供應商中相容的媒體轉碼功能:媒體供應商中的這個元件會攔截應用程式存取媒體檔案的行為,並根據應用程式宣告的功能,提供原始檔案或轉碼檔案。如果應用程式支援媒體檔案格式,則不需要特殊處理。如果應用程式不支援該格式,當應用程式存取檔案時,架構會將檔案轉換為較舊的格式,例如 AVC。
圖 1 顯示媒體轉碼程序的總覽。
圖 1. 相容媒體轉碼總覽。
支援的格式
相容媒體轉碼功能支援下列格式轉換:
- HEVC (8 位元) 轉為 AVC:透過連結一個 mediacodec 解碼器和一個 mediacode 編碼器,即可執行轉碼器轉換。
- HDR10+ (10 位元) 轉換為 AVC (SDR):系統會使用 mediacodec 執行個體,並透過供應商外掛程式掛鉤到解碼器執行個體,將 HDR 轉換為 SDR。詳情請參閱「HDR 轉 SDR 編碼」。
支援的內容來源
相容的媒體轉碼功能支援裝置上由原生 OEM 相機應用程式產生的媒體,這些媒體會儲存在主要外部磁碟區的 DCIM/Camera/
資料夾中。這項功能不支援次要儲存空間中的媒體。
系統不支援透過電子郵件或 SD 卡傳輸到裝置的內容。
應用程式會根據各種檔案路徑存取檔案。以下說明啟用或略過轉碼的檔案路徑:
已啟用轉碼:
- 應用程式透過 MediaStore API 存取
- 透過直接檔案路徑 API (包括 Java 和原生程式碼) 存取應用程式
- 透過儲存空間存取架構 (SAF) 存取應用程式
- 透過 OS 分享表單 Intent 存取應用程式。(僅限 MediaStore URI)
- 透過 MTP/PTP 將檔案從手機傳輸到電腦
已略過轉碼:
- 取出 SD 卡,將檔案從裝置移出
- 使用鄰近分享或藍牙傳輸等選項,在裝置間轉移檔案。
新增自訂轉碼檔案路徑
裝置製造商可選擇在 DCIM/
目錄下新增媒體轉碼的檔案路徑。如果路徑不在 DCIM/
目錄中,系統會拒絕要求。為符合電信業者規定或當地法規,可能需要新增這類檔案路徑。
如要新增檔案路徑,請使用轉碼路徑 runtime resource overlay (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),或從快取傳回轉碼版本 (如有)。
要求轉碼檔案
相容媒體轉碼功能預設為停用。應用程式可使用下列選項要求轉碼素材資源:
- 在資訊清單檔案中宣告不支援的格式。詳情請參閱「在資源中宣告功能」和「在程式碼中宣告功能」。
- 在執行階段使用應用程式相容性架構停用支援的格式 (使用者也可以在「設定」中為每個應用程式停用這項功能)。
- 使用
MediaStore
開啟檔案,同時透過openTypedAssetFileDescriptor
API 明確指定不支援的格式。
如果是透過 USB 傳輸 (裝置到電腦),轉碼功能預設為停用,但使用者可以選擇在「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
延長影片長度限制
如要進行測試,可以使用下列指令,延長轉碼影片長度限制 (1 分鐘)。執行這項指令後,可能需要重新啟動裝置。
adb shell device_config put storage_native_boot transcode_max_duration_ms <LARGE_NUMBER_IN_MS>
Android 開放原始碼計畫來源和參考資料
以下是與相容媒體轉碼相關的 Android 開放原始碼計畫原始碼。
轉碼系統 API (僅供 MediaProvider 使用)
ApplicationMediaCapabilities API
frameworks/base/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
MediaTranscoding Service
frameworks/av/services/mediatranscoding/
frameworks/av/media/libmediatranscoding/
Native MediaTranscoder
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 會在 Codec 2.0 介面和 android.hardware.media.c2
HAL 介面之間,提供位於 android::hardware::media::c2
的適應層實作項目。對於篩選器外掛程式,AOSP 包含包裝機制,可將解碼器與篩選器外掛程式包裝在一起。MediaCodec
將這些包裝元件視為具有篩選功能的解碼器。
總覽
FilterWrapper
類別會採用供應商轉碼器,並將包裝的轉碼器傳回 media.c2
調適層。FilterWrapper
類別會透過 FilterWrapper::Plugin
API 載入 libc2filterplugin.so
,並記錄外掛程式提供的可用篩選器。建立時,FilterWrapper
會例項化所有可用的篩選器。只有會改變緩衝區的篩選器會在啟動時啟動。
圖 4. 篩選器外掛程式架構。
篩選器外掛程式介面
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
類別。
創作
包裝元件會在建立時,例項化基礎解碼器和所有已定義的篩選器。
查詢和設定
封裝元件會根據篩選器說明,將傳入的參數與查詢或設定要求分開。舉例來說,篩選器控制項參數的設定會傳送至對應的篩選器,而篩選器中受影響的參數會出現在查詢中 (而不是從具有不受影響參數的解碼器讀取)。
圖 5. 查詢和設定。
Start
在啟動時,包裝元件會啟動解碼器和所有會變更緩衝區的篩選器。如果未啟用任何篩選器,封裝元件會啟動解碼器和直通緩衝區,並將指令傳送至解碼器本身。
緩衝區處理
圖 6. 緩衝區處理。
排入包裝解碼器佇列的緩衝區會傳送至基礎解碼器。封裝元件會透過 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