互換性のあるメディアのコード変換

Android 12(API レベル 31)以降では、HEVC をサポートしていないアプリで動画を開いたとき、HEVC(H.265)などの形式で記録された動画を自動的に AVC(H.264)に変換できます。この機能により、動画キャプチャ アプリは、他のアプリとの互換性を犠牲にすることなく、デバイスで記録する動画に対してストレージ効率の良い最新のエンコードを利用できます。

デバイス上で作成されたコンテンツについて、以下の形式を自動的にコード変換できます。

メディア形式 XML 属性 MediaFormat MIME タイプ
HEVC(H.265) HEVC MediaFormat.MIMETYPE_VIDEO_HEVC
HDR10HDR10 MediaFeature.HdrType.HDR10
HDR10+ HDR10Plus MediaFeature.HdrType.HDR10_PLUS

Android では、アプリはすべてのメディア形式の再生に対応できると想定されているため、互換性のあるメディアのコード変換はデフォルトではオフになっています。

コード変換を行うケース

コード変換は負荷の高い処理であるため、動画ファイルを開くとき大幅な遅延が発生します。たとえば、Pixel 3 スマートフォンで 1 分間の HEVC 動画ファイルを AVC にコード変換するには、約 20 秒かかります。そのため、動画ファイルのコード変換は、デバイスから送信する場合にのみ行うようにします。たとえば同じアプリの他のユーザーや、最新の動画形式をサポートしていないクラウド サーバーと、動画ファイルを共有する場合などです。

デバイス上での再生やサムネイル画像の作成のために動画ファイルを開く場合は、コード変換しないでください。

コード変換の構成

アプリは、メディア機能を宣言することでコード変換の動作を制御できます。機能の宣言は、コード内またはリソース内で行えます。

コード内で機能を宣言する

コード内でメディア機能を宣言するには、次に示すように、ビルダーを使用して ApplicationMediaCapabilities オブジェクトのインスタンスを作成します。

Kotlin

val mediaCapabilities = ApplicationMediaCapabilities.Builder()
    .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10_PLUS)
    .build()

Java

ApplicationMediaCapabilities mediaCapabilities = new ApplicationMediaCapabilities.Builder()
        .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC)
        .addUnsupportedHdrType(MediaFeature.HdrType.HDR10)
        .addUnsupportedHdrType(MediaFeature.HdrType.HDR10_PLUS)
        .build();

このオブジェクトは、ContentResolver#openTypedAssetFileDescriptor() などのメソッドでメディア コンテンツにアクセスする際に使用します。

Kotlin

val providerOptions = Bundle().apply {
    putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, mediaCapabilities)
}
contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)
    .use { fileDescriptor ->
        // Content will be transcoded based on values defined in the
        // ApplicationMediaCapabilities provided.
    }

Java

Bundle providerOptions = new Bundle();
providerOptions.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, mediaCapabilities);
try (AssetFileDescriptor fileDescriptor =  contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)) {
    // Content will be transcoded based on values defined in the
    // ApplicationMediaCapabilities provided.
}

この方法では、動画ファイルをデバイス外に転送するときにのみコード変換を行うなど、特定のコードパスを細かく制御できます。後述の方法よりも優先されます。

リソース内で機能を宣言する

リソース内で機能を宣言すると、コード変換を包括的に制御できます。この方法は、非常に限られたケースでのみ使用してください。たとえば、アプリが動画ファイルを(直接開くのではなく)他のアプリから受け取り、最新の動画コーデックをサポートしていないサーバーにアップロードする場合などです(後述のシナリオ例 1 をご覧ください)。

絶対に必要というわけではない場合にこの方法を使用すると、動画をサムネイル表示するときなど、意図しない場面でコード変換が行われてユーザー エクスペリエンスが低下する可能性があります。

この方法を使用するには、media_capabilities.xml リソース ファイルを作成します。

<?xml version="1.0" encoding="utf-8"?>
<media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
    <format android:name="HEVC" supported="true"/>
    <format android:name="HDR10" supported="false"/>
    <format android:name="HDR10Plus" supported="false"/>
</media-capabilities>

この例では、デバイス上で記録された HDR 動画は AVC SDR(標準ダイナミック レンジ)動画にシームレスにコード変換されますが、HEVC 動画は変換されません。

application タグ内で property タグを使用し、メディア機能ファイルへの参照を追加します。次のプロパティを AndroidManifest.xml ファイルに追加します。

<property
    android:name="android.media.PROPERTY_MEDIA_CAPABILITIES"
    android:resource="@xml/media_capabilities" />

別のアプリのメディア機能を使用して動画ファイルを開く

アプリが別のアプリと動画ファイルを共有する場合、受信側アプリによって開かれる前に、動画ファイルをコード変換する必要があります。

この場合、openTypedAssetFileDescriptor を使用して動画ファイルを開き、Binder.getCallingUid を使用して取得可能な受信側アプリの UID を指定することで対処できます。プラットフォームは受信側アプリのメディア機能を使用して、動画ファイルをコード変換するかどうかを判断します。

Kotlin

val providerOptions = Bundle().apply {
    putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, Binder.getCallingUid())
}
contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)
    .use { fileDescriptor ->
        // Content will be transcoded based on the media capabilities of the
        // calling app.
    }

Java

Bundle providerOptions = new Bundle();
providerOptions.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, Binder.getCallingUid());
try (AssetFileDescriptor fileDescriptor =  contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)) {
    // Content will be transcoded based on the media capabilities of the
    // calling app.
}

シナリオ例

次の図に、一般的なユースケースを 2 つ示します。どちらのケースも、元の動画は HEVC 形式で保存されており、動画共有アプリは HEVC をサポートしていません。

例 1: 動画キャプチャ アプリがコード変換を開始する。例 1動画共有アプリは、HEVC をサポートしていないことをメディア機能のリソース ファイル内で宣言します。その後、動画キャプチャ アプリに動画をリクエストします。動画キャプチャ アプリはリクエストの処理を行い、共有アプリの UID を指定して openTypedAssetFileDescriptor を使用し、ファイルを開きます。これによりコード変換プロセスが開始します。コード変換された動画が受け取られると、共有アプリに送られ、クラウドのサーバーにアップロードされます。

例 2: 動画共有アプリがコード変換を開始する。例 2動画キャプチャ アプリは、MediaStore URI を使用して動画を動画共有アプリと共有します。動画共有アプリは、メディア機能で HEVC をサポートしていないことを指定し、openTypedAssetFileDescriptor を使用して動画ファイルを開きます。これによりコード変換プロセスが開始します。完了すると、クラウドのサーバーにファイルがアップロードされます。

宣言されていない形式

互換性のあるメディアのコード変換は、サポートされていないと宣言されたすべての形式に対して有効になり、サポートされていると宣言されたすべての形式に対して無効になります。宣言されていないその他の形式については、コード変換するかどうかをプラットフォームが判断します。Android 12 では、宣言されていないすべての形式に対してコード変換が無効になります。この動作は今後、新しい形式について変更される可能性があります。

開発者向けオプション

次の開発者向けオプションを使用すると、Android のデフォルトのコード変換動作をオーバーライドできます。

  • [デフォルトのコード変換をオーバーライド]: 自動コード変換をプラットフォームで制御するかどうかを指定します。オーバーライドを有効にするとプラットフォームのデフォルトが無視され、[コード変換を有効にする] 設定で自動コード変換が制御されます。このオプションはデフォルトでは無効になっています。

  • [コード変換を有効にする]: 宣言されていない形式を自動的にコード変換するかどうかを指定します。これはデフォルトで有効になっていますが、[デフォルトのコード変換をオーバーライド] も有効になっている場合にのみ効果があります。

  • [アプリによる最新形式のサポートを想定]: 宣言されていない形式をアプリが再生しようとしたときの動作を指定します。これは、アプリが特定の形式をサポートしているかどうかをマニフェストで宣言していない場合や、Google がサーバーサイド強制コード変換リストにアプリを追加していない場合に発生します。この設定を有効にするとアプリはコード変換を行わず、無効にするとコード変換を行います。このオプションはデフォルトで有効になっています。

  • [コード変換に関する通知の表示]: 有効にすると、サポートされていないメディア ファイルを読み取ってコード変換がトリガーされたとき、アプリがコード変換の進行状況に関する通知を表示します。このオプションはデフォルトで有効になっています。

  • [コード変換のキャッシュを無効にする]: 有効にすると、コード変換を必要とするアプリはコード変換のキャッシュを使用しません。これはサポートされていないメディア ファイルに対してコード変換を簡単にトリガーできるため、開発時に役立ちますが、デバイスのパフォーマンスが低下する可能性があります。このオプションはデフォルトでは無効になっています。