Transcodificación de contenido multimedia compatible

Android 12 incluye una función nueva que permite que las apps de captura de video usen codificación más moderna y eficiente en cuanto al almacenamiento para los videos que se graban en el dispositivo sin sacrificar la compatibilidad con otras apps.

Android puede convertir automáticamente videos grabados en formatos del tipo de HEVC (H.265) a AVC (H.264) cuando los videos se abren mediante una app que no admite HEVC.

Los siguientes formatos se pueden transcodificar automáticamente para el contenido creado en el dispositivo:

Formato multimedia Atributo XML Tipo de MIME de MediaFormat
HEVC (H.265) HEVC MediaFormat.MIMETYPE_VIDEO_HEVC
HDR10HDR10 MediaFeature.HdrType.HDR10
HDR10+ HDR10Plus MediaFeature.HdrType.HDR10_PLUS

Android supone que las apps pueden admitir la reproducción de todos los formatos, por lo que la transcodificación de contenido multimedia compatible está desactivada de manera predeterminada.

Cuándo usar la transcodificación

La transcodificación es una operación costosa en términos de procesamiento y produce un retraso significativo cuando se abre un archivo de video. Por ejemplo, un archivo de video HEVC de un minuto tarda aproximadamente 20 segundos en transcodificarse en AVC en un teléfono Pixel 3. Por este motivo, debes transcodificar un archivo de video solamente cuando este sale del dispositivo. Por ejemplo, cuando compartes un archivo de video con otros usuarios de la misma app o un servidor en la nube que no admite formatos de video modernos.

No transcodifiques cuando abras archivos de video para reproducirlos en el dispositivo o para crear imágenes en miniatura.

Configura la transcodificación

Para controlar su comportamiento de transcodificación, las apps pueden declarar sus capacidades multimedia. Hay dos maneras de declarar estas capacidades: en el código o en un recurso.

Declara capacidades en el código

Puedes declarar capacidades multimedia en el código creando una instancia de un objeto ApplicationMediaCapabilities mediante un compilador de la siguiente manera:

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();

Usa este objeto cuando accedas al contenido multimedia con métodos como 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.
}

Este método permite controlar de forma detallada rutas particulares de código, por ejemplo, invocar la transcodificación solo cuando un archivo de video sale del dispositivo. Tiene prioridad sobre el método que se describe a continuación.

Declara capacidades en un recurso

Declarar capacidades de un recurso brinda un control general sobre la transcodificación. Este método solo debe usarse en casos muy específicos. Por ejemplo, si la app solo recibe archivos de video de otras apps (en lugar de abrirlos directamente) y los sube a un servidor que no admite códecs modernos de video (consulta la situación 1 de ejemplo más adelante).

Usar este método cuando no sea absolutamente necesario podría invocar la transcodificación en situaciones no deseadas, por ejemplo, cuando se crean videos en miniatura, lo que afectaría la experiencia del usuario.

Para usar este método, crea un archivo de recursos 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>

En este ejemplo, los videos HDR grabados en el dispositivo se transcodifican sin interrupciones al video AVC SDR (rango dinámico estándar), mientras que los videos HEVC no lo hacen.

Usa una etiqueta property dentro de la etiqueta application a fin de agregar una referencia al archivo de capacidades multimedia. Agrega estas propiedades al archivo AndroidManifest.xml:

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

Usa las capacidades multimedia de otra app para abrir un archivo de video

Si la app comparte un archivo de video con otra app, es posible que este archivo deba transcodificarse antes de que la app de destino pueda abrirlo.

Para resolver este caso, puedes abrir un archivo de video con openTypedAssetFileDescriptor y especificar el UID de la app de destino, el cual puede obtenerse con Binder.getCallingUid. Luego, la plataforma usa las capacidades multimedia de la app de destino para determinar si se debe transcodificar el archivo de video.

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.
}

Situaciones de ejemplo

En los siguientes diagramas, se muestran los dos casos de uso frecuentes. En ambos, el video original se almacena en formato HEVC, y la app para compartir videos no admite HEVC.

Ejemplo 1: La transcodificación se inicia mediante una app de captura de video. Ejemplo 1 La app para compartir videos declara que no es compatible con HEVC en su archivo de recursos de capacidades multimedia. Luego, solicita un video desde la app de captura de video. Esta app controla la solicitud, abre el archivo con openTypedAssetFileDescriptor y especifica el UID de la app para compartir. De esta manera, se inicia el proceso de transcodificación. Cuando se recibe el video transcodificado, se proporciona a la app para compartir, de modo que pueda subirlo a un servidor en la nube.

Ejemplo 2. La app para compartir videos inicia la transcodificación. Ejemplo 2 La app de captura de video comparte un video con la app para compartir mediante un URI de MediaStore. La app para compartir abre el archivo de video mediante openTypedAssetFileDescriptor y especifica que no admite HEVC en sus capacidades multimedia. De esta manera, se inicia el proceso de transcodificación y, una vez completado, el archivo se sube a un servidor en la nube.

Formatos que no se declararon

La transcodificación de contenido multimedia compatible está habilitada para todos los formatos que se declaran no compatibles y está inhabilitada para todos los formatos que se declaran compatibles. Para otros formatos que no se declararon, la plataforma decide si los transcodifica o no. En Android 12, la transcodificación está inhabilitada para todos los formatos que no se declararon. Es posible que este comportamiento cambie para formatos nuevos en el futuro.

Opciones para programador

Puedes usar las siguientes opciones para desarrolladores a fin de anular el comportamiento predeterminado de transcodificación en Android:

  • Anular los valores predeterminados de transcodificación: Con esta configuración, se determina si la plataforma controla la transcodificación automática o no. Cuando se habilita la anulación, se ignoran los valores predeterminados de la plataforma, y la configuración de Habilitar la transcodificación controla la transcodificación automática. Esta opción está inhabilitada de forma predeterminada.

  • Habilitar la transcodificación: Con esta configuración, se especifica si los formatos que no se declararon se transcodifican automáticamente o no. Está habilitada de forma predeterminada, pero solo produce efecto si también se habilita la opción Anular los valores predeterminados de transcodificación.

  • Suponer que las apps admiten formatos modernos: Con esta configuración, se controla lo que sucede cuando la app intenta reproducir un formato que no se declaró. Esto sucede cuando el manifiesto no declara si la app admite o no un formato particular, o si Google no la agregó a la lista para forzar la transcodificación del servidor. Cuando se habilita la configuración, la app no transcodifica; cuando se inhabilita, la app sí transcodifica. Esta opción está habilitada de forma predeterminada.

  • Mostrar notificaciones de transcodificación: Cuando se habilita, la app muestra una notificación del progreso de la transcodificación en los casos en que esta se activa mediante la lectura de un archivo multimedia no compatible. Esta opción está habilitada de forma predeterminada.

  • Inhabilitar caché de transcodificación: Si se habilita, las apps que requieren transcodificación no usan la caché de este proceso. Puede ser útil durante el desarrollo para activar con facilidad la transcodificación en un archivo multimedia no compatible, pero puede causar un rendimiento deficiente del dispositivo. Esta opción está inhabilitada de forma predeterminada.