相容媒體轉碼

Android 12 中推出的相容媒體轉碼功能,可讓裝置使用更現代化且節省儲存空間的媒體格式 (例如 HEVC) 進行錄影,同時維持與應用程式的相容性。有了這項功能,裝置製造商就能預設使用 HEVC (而非 AVC),以提升視訊品質,同時減少儲存空間和頻寬需求。針對已啟用相容媒體轉碼功能的裝置,Android 可以在不支援此格式的應用程式開啟影片時,自動轉換 HEVC 或 HDR 等格式錄製的影片。如此一來,即使裝置以較新的格式擷取影片,應用程式也能正常運作。

相容的媒體轉碼功能預設為關閉。若要要求媒體轉碼,應用程式必須宣告其媒體功能。如要進一步瞭解如何宣告媒體功能,請參閱 Android 開發人員網站的相容媒體轉碼

運作方式

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

  • 媒體架構中的轉碼服務:這些服務會使用硬體將檔案從一種格式轉換成另一種格式,藉此提供低延遲和高品質的轉換。這包括轉碼 API、轉碼服務、自訂篩選器的 OEM 外掛程式和硬體。詳情請參閱架構總覽
  • 媒體供應商中的相容媒體轉碼功能:媒體供應商中找到的元件會攔截存取媒體檔案的應用程式,並根據應用程式宣告的功能提供原始檔案或轉碼檔案。如果應用程式支援媒體檔案格式,就不需要進行特殊處理。如果應用程式不支援此格式,架構會在應用程式存取檔案時,將檔案轉換為舊版格式,例如 AVC。

圖 1 顯示媒體轉碼程序的總覽。

相容媒體轉碼程序

圖 1 相容媒體轉碼總覽。

支援的格式

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

  • HEVC (8 位元) 到 AVC:如要執行轉碼器轉換,請將一個 Mediacodec 解碼器和一個媒體程式碼編碼器連線。
  • HDR10+ (10 位元) 到 AVC (SDR):HDR 到 SDR 轉換是使用 mediacodec 執行個體執行,而廠商外掛程式會掛接到解碼器執行個體。詳情請參閱 HDR 到 SDR 編碼

支援的內容來源

相容的媒體轉碼功能支援原生原始設備製造商 (OEM) 相機應用程式產生的裝置端媒體,儲存在主要外部磁碟區的 DCIM/Camera/ 資料夾中。這項功能不支援次要儲存空間中的媒體。 系統不支援透過電子郵件或 SD 卡傳送到裝置的內容。

應用程式會根據各種檔案路徑存取檔案。以下說明啟用或略過轉碼功能的檔案路徑:

  • 已啟用轉碼功能:

    • 透過 MediaStore API 存取應用程式
    • 透過直接檔案路徑 API (包括 Java 和原生程式碼) 存取應用程式
    • 透過儲存空間存取架構 (SAF) 存取應用程式
    • 透過 OS 分享工作表 Intent 存取應用程式。(僅限 MediaStore URI)
    • 從手機將 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 Daemon 會攔截應用程式中的檔案讀取權限。如果應用程式支援較新的格式 (例如 HEVC),便會傳回原始檔案。如果應用程式不支援此格式,檔案會轉碼成舊版格式 (例如 AVC),或是如果有轉碼版本,則會從快取傳回。

要求轉碼檔案

相容的媒體轉碼功能預設為停用。也就是說,如果裝置支援 HEVC,則除非在資訊清單檔案或強制轉碼清單中指定的應用程式,否則 Android 不會轉碼檔案。

應用程式可以使用以下選項,要求轉碼後的素材資源:

  • 在資訊清單檔案中宣告不支援的格式。詳情請參閱在資源中宣告功能在程式碼中宣告功能
  • 將應用程式新增至 MediaProvider 模組中包含的強制轉碼清單。這樣可為尚未更新資訊清單檔案的應用程式啟用轉碼功能。如果應用程式使用不支援的格式更新資訊清單檔案,您必須將該檔案從強制轉碼清單中移除。裝置製造商可以提交修補程式回報錯誤,指定將自家應用程式從強制轉碼清單新增或移除。Android 團隊會定期審查清單,且可能會將應用程式從清單中移除。
  • 在執行階段停用應用程式相容性架構支援的格式 (使用者也可以在「設定」中為各個應用程式停用此功能)。
  • 使用 MediaStore 開啟檔案,同時使用 openTypedAssetFileDescriptor API 明確指定不支援的格式。

如果是 USB 傳輸 (裝置對電腦),轉碼功能預設為停用,但使用者可以選擇透過「USB Preferences」設定畫面,使用「Convert videos to AVC」切換功能來啟用轉碼功能 (如圖 3 所示)。

切換即可啟用媒體轉碼

圖 3. 切換即可啟用「USB 偏好設定」畫面中的媒體轉碼。

要求轉碼檔案的限制

為了防止轉碼要求長時間鎖定系統資源,要求轉碼工作階段的應用程式僅限於:

  • 連續 10 個工作階段
  • 總執行時間為 3 分鐘

如果應用程式超出上述所有限制,架構會傳回原始檔案描述元。

裝置需求

如要支援相容的媒體轉碼功能,裝置必須符合下列需求:

  • 裝置預設在原生相機應用程式上啟用 HEVC 編碼
  • (支援 HDR 至 SDR 轉碼的裝置) 裝置支援 HDR 錄影功能

為確保裝置媒體轉碼的效能,影片硬體和儲存空間讀取/寫入存取效能必須最佳化。當媒體轉碼器設定優先順序等於 1 時,轉碼器必須盡可能以最高的處理量運作。我們建議轉碼效能至少達到 200 fps。如要測試硬體效能,請在 frameworks/av/media/libmediatranscoding/transcoder/benchmark 執行媒體轉碼器基準。

驗證

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

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

全域啟用媒體轉碼

如要使用轉碼功能測試媒體轉碼架構或應用程式行為,您可以全域啟用或停用相容的媒體轉碼功能。在「設定」>「系統」>「開發人員」>「媒體轉碼」開發人員選項頁面中,將「覆寫轉碼預設值」切換鈕設為「on」,然後將「啟用轉碼功能」切換鈕設為「on」或「off」。啟用這項設定後,除了您正在開發的應用程式以外,可能會在背景執行媒體轉碼。

檢查轉碼狀態

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

adb shell dumpsys media.transcoding

延長影片長度限制

為了進行測試,您可以使用下列指令,延長 1 分鐘的影片長度限制。執行這個指令後,可能需要重新啟動。

adb shell device_config put storage_native_boot transcode_max_duration_ms <LARGE_NUMBER_IN_MS>

Android 開放原始碼計畫來源和參考資料

以下是與相容媒體轉碼相關的 Android 開放原始碼計畫原始碼。

HDR 到 SDR 編碼

如要支援 HDR 至 SDR 編碼,裝置製造商可以使用 /platform/frameworks/av/media/codec2/hidl/plugin/ 中的 Android 開放原始碼計畫範例 Codec 2.0 篩選器外掛程式。本節說明篩選器外掛程式的運作方式、如何實作外掛程式及測試外掛程式。

如果裝置中沒有支援 HDR 至 SDR 編碼的外掛程式,那麼無論資訊清單中宣告的應用程式媒體功能為何,存取 HDR 影片的應用程式都會取得原始檔案描述元。

運作方式

本節說明 Codec 2.0 篩選器外掛程式的一般行為。

背景

Android 在 Codec 2.0 介面和 android::hardware::media::c2android.hardware.media.c2 HAL 介面之間提供調整層實作。針對篩選器外掛程式,Android 開放原始碼計畫提供包裝函式機制,可將解碼器與篩選器外掛程式一併包裝。MediaCodec 會將這些包裝的元件視為具有篩選功能的解碼器。

總覽

FilterWrapper 類別會採用供應商轉碼器,並將經過包裝的轉碼器傳回 media.c2 調整層。FilterWrapper 類別會透過 FilterWrapper::Plugin API 載入 libc2filterplugin.so,並記錄外掛程式中的可用篩選器。建立時,FilterWrapper 會執行個體化所有可用的篩選器。只有在開始時,才會啟動修改緩衝區的篩選器。

篩選外掛程式架構

圖 1 篩選外掛程式架構。

篩選外掛程式介面

FilterPlugin.h 介面會定義下列 API 來公開篩選器:

  • std::shared_ptr<C2ComponentStore>getComponentStore()

    傳回包含篩選器的 C2ComponentStore 物件。這與廠商的 Codec 2.0 實作公開內容不同。通常,此儲存庫僅包含 te 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