On Android 12 (API level 31) and higher, the system can automatically convert videos recorded in formats such as HEVC (H.265) to AVC (H.264) when the videos are opened by an app that does not support HEVC. This feature allows video capture apps to utilize more modern, storage-efficient encoding for videos recorded on the device without sacrificing compatibility with other apps.
The following formats can be automatically transcoded for content that's created on-device:
Media format | XML Attribute | MediaFormat mime type |
---|---|---|
HEVC (H.265) | HEVC | MediaFormat.MIMETYPE_VIDEO_HEVC |
HDR10 | HDR10 | MediaFeature.HdrType.HDR10 |
HDR10+ | HDR10Plus | MediaFeature.HdrType.HDR10_PLUS |
Android assumes that apps can support playback of all media formats, so compatible media transcoding is off by default.
When to use transcoding
Transcoding is a computationally expensive operation and adds a significant delay when opening a video file. For example, a one minute HEVC video file takes roughly 20 seconds to transcode into AVC on a Pixel 3 phone. For this reason, you should transcode a video file only when you are sending it off the device. For example, when sharing a video file with other users of the same app, or a cloud server which does not support modern video formats.
Do not transcode when opening video files for on-device playback or for creating thumbnail images.
Configuring transcoding
Apps can control their transcoding behavior by declaring their media capabilities. There are two ways to declare these capabilities: in code, or in a resource.
Declare capabilities in code
You can declare media capabilities in code by constructing an instance of an
ApplicationMediaCapabilities
object using a builder:
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();
Use this object when accessing media content via methods such as
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. }
This method allows granular control for particular code paths, such as invoking transcoding only when transferring a video file off-device. It takes precedence over the method described below.
Declare capabilities in a resource
Declaring capabilities in a resource allows blanket control over transcoding. This method should only be used in very specific cases. For example, if your app only receives video files from other apps (rather than opening them directly) and uploads them to a server which does not support modern video codecs (see example scenario 1 below).
Using this method when not absolutely necessary might invoke transcoding in unintended scenarios, such as when thumbnailing videos, resulting in a degraded user experience.
To use this method, create a media_capabilities.xml
resource file:
<?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>
In this example, HDR videos recorded on the device are seamlessly transcoded to AVC SDR (standard dynamic range) video, while HEVC videos are not.
Use a property
tag within the application
tag to add a reference to the media
capabilities file. Add these properties to your AndroidManifest.xml
file:
<property
android:name="android.media.PROPERTY_MEDIA_CAPABILITIES"
android:resource="@xml/media_capabilities" />
Using another app's media capabilities to open a video file
If your app shares a video file with another app, the video file might need to be transcoded before the receiving app can open it.
You can handle this case by opening a video file using openTypedAssetFileDescriptor
and specifying the UID of the receiving app, which can be obtained using Binder.getCallingUid
.
The platform then uses the receiving app's media capabilities to determine
whether the video file should be transcoded.
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. }
Example scenarios
The following diagrams demonstrate the two common use cases. In both cases the original video is stored in HEVC format and the video sharing app does not support HEVC.
Example 1. Transcoding is initiated by video capture app.
The video sharing app declares that it does not support HEVC in its media
capabilities resource file. It then requests a video from the video capture app. The video capture
app handles the request and opens the file using openTypedAssetFileDescriptor
, specifying the sharing app's UID. This initiates the transcoding process.
When the transcoded video is received it is supplied to the sharing app, which uploads it to a server in the cloud.
Example 2. Transcoding is initiated by video sharing app.
The video capture app shares a video with the video sharing app using a
MediaStore
URI. The video sharing app opens the video file using openTypedAssetFileDescriptor
, specifying that it does not support HEVC in its media capabilities. This
initiates the transcoding process, and once complete, the file is uploaded to
a server in the cloud.
Undeclared formats
Compatible media transcoding is enabled for all formats that are declared unsupported, and is disabled for all formats that are declared supported. For other formats that are not declared, the platform decides whether to transcode or not. In Android 12 transcoding is disabled for all undeclared formats. This behavior might change for new formats in the future.
Developer options
You can use the following developer options to override Android's default transcoding behavior:
Override transcoding defaults This setting determines whether or not the platform controls automatic transcoding. When override is enabled, the platform defaults are ignored and the enable transcoding setting controls automatic transcoding. This option is disabled by default.
Enable transcoding This setting specifies whether or not undeclared formats are automatically transcoded. It is enabled by default, but it only has an effect if override transcoding defaults is also enabled.
Assume apps support modern formats This setting controls what happens when the app tries to play an undeclared format. This happens when the manifest does not declare whether or not the app supports a particular format, or Google hasn't added the app to the server-side force-transcode list. When the setting is enabled, the app does not transcode, when it's disabled, the app does transcode. This option is enabled by default.
Show transcoding notifications When enabled, the app displays a transcoding progress notification when transcoding is triggered by reading an unsupported media file. This option is enabled by default.
Disable transcoding cache If enabled, apps that require transcoding do not use the transcoding cache. This can be helpful during development to easily trigger transcoding on an unsupported media file, but can cause poor device performance. This option is disabled by default.