Transcodificação de mídia compatível

No Android 12 (nível 31 da API) e versões mais recentes, o sistema pode converter automaticamente vídeos gravados em formatos como HEVC (H.265) para AVC (H.264) quando eles são abertos por um app que não oferece suporte a HEVC. Esse recurso permite que apps de captura de vídeo usem uma codificação mais moderna e de armazenamento eficiente para vídeos gravados no dispositivo sem sacrificar a compatibilidade com outros apps.

Os formatos a seguir podem ser transcodificados automaticamente para conteúdos criados no dispositivo:

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

O Android pressupõe que os apps são compatíveis com a reprodução de todos os formatos de mídia, portanto, a transcodificação de mídia compatível é desativada por padrão.

Quando usar a transcodificação

A transcodificação é uma operação computacionalmente cara e adiciona um atraso significativo ao abrir um arquivo de vídeo. Por exemplo, um arquivo de vídeo HEVC de um minuto leva cerca de 20 segundos para ser transcodificado para AVC em um smartphone Pixel 3. Por esse motivo, você só precisará transcodificar um arquivo de vídeo quando for enviá-lo para fora do dispositivo. Por exemplo, ao compartilhar um arquivo de vídeo com outros usuários no mesmo app ou em um servidor na nuvem que não seja compatível com os formatos de vídeo modernos.

Não faça a transcodificação ao abrir arquivos de vídeo para reprodução no dispositivo ou para criar imagens em miniatura.

Como configurar a transcodificação

Os apps podem controlar o comportamento de transcodificação declarando as próprias funcionalidades de mídia. Há duas maneiras de declarar essas funcionalidades: no código ou em um recurso.

Declarar funcionalidades no código

Para declarar funcionalidades de mídia no código, crie uma instância de um objeto ApplicationMediaCapabilities usando um 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 esse objeto ao acessar o conteúdo de mídia usando 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.
}

Esse método possibilita um controle granular para determinados caminhos de código, como invocar a transcodificação apenas ao transferir um arquivo de vídeo para fora do dispositivo. Ele tem precedência sobre o método descrito abaixo.

Declarar funcionalidades em um recurso

Declarar funcionalidades em um recurso possibilita controle geral sobre a transcodificação. Esse método só precisa ser usado em casos muito específicos. Por exemplo, se o app receber apenas arquivos de vídeo de outros apps, em vez de abri-los diretamente, e enviá-los para um servidor que não seja compatível com codecs de vídeo modernos, veja o exemplo do cenário 1 abaixo.

Usar esse método quando ele não é absolutamente necessário pode invocar a transcodificação em cenários que ela não é adequada, como durante a criação de miniaturas de vídeos, resultando em uma experiência do usuário prejudicada.

Para usar esse método, crie um arquivo de recurso 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>

Nesse exemplo, os vídeos HDR gravados no dispositivo são perfeitamente transcodificados para vídeos AVC SDR (intervalo dinâmico padrão), enquanto os vídeos HEVC não são.

Use uma tag property na tag application para adicionar uma referência ao arquivo de funcionalidades de mídia. Adicione as seguintes propriedades ao arquivo AndroidManifest.xml:

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

Como usar as funcionalidades de mídia de outro app para abrir um arquivo de vídeo

Se o app compartilhar um arquivo de vídeo com outro, o arquivo pode precisar ser transcodificado antes que o app receptor possa abri-lo.

Para lidar com esse caso, abra um arquivo de vídeo usando openTypedAssetFileDescriptor e especifique o UID do app receptor que pode ser recebido usando Binder.getCallingUid. A plataforma usa os recursos de mídia do app receptor para determinar se o arquivo de vídeo será transcodificado.

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

Cenários de exemplo

Os diagramas a seguir demonstram dois casos de uso comuns. Em ambos os casos, o vídeo original é armazenado no formato HEVC e o app de compartilhamento de vídeos não é compatível com HEVC.

Exemplo 1. A transcodificação é iniciada pelo app de captura de vídeo. Exemplo 1 O app de compartilhamento de vídeo declara que ele não é compatível com HEVC no próprio arquivo de funcionalidades de recursos de mídia. Em seguida, ele solicita um vídeo do app de captura de vídeo. O app de captura processa a solicitação e abre o arquivo usando o openTypedAssetFileDescriptor, especificando o UID do app de compartilhamento. Isso inicia o processo de transcodificação. Quando o vídeo transcodificado for recebido, ele será fornecido ao app de compartilhamento, que o enviará a um servidor na nuvem.

Exemplo 2. A transcodificação é iniciada pelo app de compartilhamento de vídeo. Exemplo 2 O app de captura de vídeo compartilha um vídeo com o app de compartilhamento usando um URI MediaStore. O app de compartilhamento abre o arquivo de vídeo usando o openTypedAssetFileDescriptor e especificando que ele não é compatível com HEVC nas próprias funcionalidades de mídia. Isso iniciará o processo de transcodificação e, depois de concluído, o arquivo será enviado para um servidor na nuvem.

Formatos não declarados

A transcodificação de mídia compatível está ativada para todos os formatos declarados como incompatíveis e é desativada para todos os formatos declarados como compatíveis. Para outros formatos que não forem declarados, a plataforma decidirá se os transcodificará ou não. No Android 12, a transcodificação é desativada para todos os formatos não declarados. Esse comportamento pode mudar para novos formatos no futuro.

Opções do desenvolvedor

É possível usar as opções do desenvolvedor a seguir para substituir o comportamento de transcodificação padrão do Android:

  • Substituir padrões de transcodificação: essa configuração determina se a plataforma controla a transcodificação automática ou não. Quando a substituição está ativada, os padrões da plataforma são ignorados e a configuração Ativar transcodificação controla a transcodificação automática. Esta opção é desativada por padrão.

  • Ativar transcodificação: essa configuração especifica se os formatos não declarados serão transcodificados automaticamente. Ela é ativada por padrão, mas só tem efeito se a opção substituir padrões de transcodificação também estiver ativada.

  • Presumir que os apps sejam compatíveis com formatos modernos: essa configuração controla o que acontece quando o app tenta reproduzir um formato não declarado. Isso acontece quando o manifesto não declara se o app é compatível com um formato específico ou se o Google não adicionou o app à lista para forçar a transcodificação do lado do servidor. Quando a configuração estiver ativada, o app não fará a transcodificação. Quando ela estiver desativada, o app fará a transcodificação. Esta opção é ativada por padrão.

  • Mostrar notificações de transcodificação: quando ativada, o app exibirá uma notificação de progresso de transcodificação quando a ação for acionada pela leitura de um arquivo de mídia não compatível. Esta opção é ativada por padrão.

  • Desativar o cache de transcodificação: se ativada, os apps que exigem a transcodificação não usarão o cache da transcodificação. Isso pode ser útil durante o desenvolvimento para acionar facilmente a transcodificação em um arquivo de mídia incompatível, mas pode causar baixo desempenho do dispositivo. Esta opção é desativada por padrão.