Transformações

O Jetpack Media3 Transformer permite editar, converter e exportar recursos de mídia no Android. Esta página explica como configurar transformações principais:

  • Transcodificação e transmuxação: converta formatos de áudio e vídeo ou ignore a recodificação copiando amostras de contêiner (transmuxação).
  • Remoção de faixas: remova faixas de áudio ou vídeo da mídia.
  • Corte e otimização: recorte a mídia por carimbo de data/hora, com opções para exportações mais rápidas usando listas de edição de MP4 e otimização de corte.
  • Efeitos de vídeo: dimensione, gire ou aplique efeitos de sombreador OpenGL personalizados, que também podem ser visualizados no ExoPlayer.
  • Entrada de imagem: transforme imagens estáticas em clipes de vídeo com durações personalizadas e frame rates.
  • Processamento de áudio: encadeie instâncias de AudioProcessor para modificar o áudio bruto.

Transcodificar entre formatos

É possível especificar os formatos de áudio e vídeo de saída que você quer produzir ao criar o Transformer. Por exemplo, o código a seguir mostra como configurar o Transformer para gerar vídeo H.264/AVC e áudio AAC:

Kotlin

Transformer.Builder(context)
  .setVideoMimeType(MimeTypes.VIDEO_H264)
  .setAudioMimeType(MimeTypes.AUDIO_AAC)
  .build()

Java

new Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H264)
    .setAudioMimeType(MimeTypes.AUDIO_AAC)
    .build();

Se o formato de mídia de entrada já corresponder às configurações de áudio ou vídeo, o Transformer vai mudar automaticamente para transmuxação, ou seja, copiar as amostras compactadas do contêiner de entrada para o contêiner de saída sem modificação. Isso evita o custo computacional e a possível perda de qualidade da decodificação e recodificação no mesmo formato.

Remover áudio ou vídeo

Remova áudio ou vídeo usando EditedMediaItem.Builder, por exemplo:

Kotlin

EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()

Java

new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();

Cortar um clipe

É possível remover qualquer mídia fora dos carimbos de data/hora de início e fim especificados definindo a configuração de recorte no item de mídia de entrada. Por exemplo, para produzir um clipe que contenha apenas a mídia entre 10 e 20 segundos:

Kotlin

val inputMediaItem =
  MediaItem.Builder()
    .setUri(uri)
    .setClippingConfiguration(
      MediaItem.ClippingConfiguration.Builder()
        .setStartPositionMs(10_000)
        .setEndPositionMs(20_000)
        .build()
    )
    .build()

Java

MediaItem inputMediaItem =
    new MediaItem.Builder()
        .setUri(uri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder()
                .setStartPositionMs(10_000)
                .setEndPositionMs(20_000)
                .build())
        .build();

Listas de edição de MP4

Para um corte mais rápido, o Transformer oferece suporte a listas de edição de MP4, permitindo edições "somente de corte" mais eficientes sem a recodificação completa do vídeo. Esse método utiliza amostras codificadas e um "anúncio precedente" na lista de edição, que instrui o player a iniciar a reprodução em um ponto específico, ignorando o segmento inicial indesejado.

Para tornar as edições somente de corte significativamente mais rápidas, chame experimentalSetMp4EditListTrimEnabled(true).

Kotlin

Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build();
É importante observar que nem todos os players de mídia oferecem suporte a uma posição de "anúncio precedente". Isso significa que, quando um player desse tipo é usado, o arquivo começa a reprodução desde o início absoluto da amostra codificada, independentemente de qualquer informação da lista de edição que possa especificar um ponto de partida diferente.

Otimizar cortes

Para reduzir a latência do corte do início de um vídeo, ative a otimização de corte.

Kotlin

Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build();

Isso acelera a exportação decodificando e recodificando o mínimo possível do vídeo e, em seguida, unindo os dados recodificados com o restante do vídeo original. A otimização depende da capacidade de unir parte do arquivo de entrada com a saída recém-codificada, o que significa que o formato de saída do codificador e o formato de entrada precisam ser compatíveis. Portanto, por exemplo, se o arquivo foi produzido originalmente em um dispositivo com uma implementação de codificador diferente, é provável que não seja possível aplicar a otimização. Para que a otimização seja bem-sucedida, o codificador fornecido ao Transformer pela EncoderFactory precisa ter um nível e um perfil compatíveis com o formato de entrada.

Essa otimização só funciona com entrada MP4 de recurso único sem efeitos, exceto efeitos de vídeo sem operação e rotações divisíveis por 90 graus. Se a otimização falhar, o Transformer vai voltar automaticamente para a exportação normal e informar o resultado da otimização em ExportResult.OptimizationResult.

Estamos validando essa funcionalidade e esperamos que ela deixe de ser experimental em uma versão posterior.

Edições de vídeo

Os EditedMediaItems têm listas de processadores de áudio e efeitos de vídeo a serem aplicados em ordem. A biblioteca inclui implementações de efeitos de vídeo para casos de uso comuns. Também é possível gravar efeitos personalizados e transmiti-los ao criar itens de mídia editados.

É possível redimensionar a mídia, o que pode ser útil para economizar recursos de processamento ou largura de banda ao lidar com entradas de alta resolução, como vídeos 4K ou 8K. Por exemplo, para dimensionar proporcionalmente a 480 pixels de altura:

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(Presentation.createForHeight(480)),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(Presentation.createForHeight(480))))
    .build();

Como alternativa, é possível dimensionar por um determinado fator, por exemplo, para reduzir o tamanho pela metade:

Kotlin

val editedMediaItem =
  EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
      Effects(
        /* audioProcessors= */ listOf(),
        /* videoEffects= */ listOf(
          ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()
        ),
      )
    )
    .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build())))
    .build();

É possível configurar a rotação da mesma maneira:

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(
        ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build()
      ),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build())))
    .build();

Efeitos de vídeo personalizados

O construtor Effects aceita uma lista de efeitos de áudio e vídeo a serem aplicados. Internamente, a estrutura de efeitos do Transformer converte a lista de efeitos de vídeo em uma sequência de programas de sombreador GL que são aplicados em ordem. Em alguns casos, a estrutura de efeitos pode aplicar vários efeitos com um programa de sombreador. Por exemplo, um programa de sombreador pode aplicar várias transformações de matriz consecutivas, o que melhora a eficiência e a qualidade.

Os efeitos de vídeo também são compatíveis com a visualização no ExoPlayer, usando ExoPlayer.setVideoEffects. Para um exemplo de como usar essa API, confira o app de demonstração de efeitos.

O app de demonstração inclui exemplos de efeitos de vídeo personalizados.

Entrada de imagem

O Transformer oferece suporte a entradas de imagem tratando-as como clipes de vídeo estáticos. Para configurar uma imagem como uma origem da entrada, siga estas etapas:

  • Crie um MediaItem usando MediaItem.Builder. Especifique a duração da exibição da imagem no vídeo de saída chamando setImageDurationMs.

  • Construa um EditedMediaItem que envolva o MediaItem. Especifique o frame rate de destino para o fluxo de vídeo gerado usando EditedMediaItem.Builder#setFrameRate.

O exemplo a seguir demonstra como configurar uma entrada de imagem para gerar um vídeo de 5 segundos a 30 frames por segundo:

Kotlin

val imageMediaItem =
  MediaItem.Builder()
    .setUri(imageUri)
    .setImageDurationMs(5000) // 5 seconds
    .build()

val editedImageItem =
  EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build()

Java

MediaItem imageMediaItem =
    new MediaItem.Builder()
        .setUri(imageUri)
        .setImageDurationMs(5000) // 5 seconds
        .build();
new EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build();

Edições de áudio

Os efeitos de áudio são implementados aplicando uma sequência de instâncias de AudioProcessor ao áudio bruto (PCM). O ExoPlayer oferece suporte à transmissão de processadores de áudio para o DefaultAudioSink.Builder, que permite visualizar edições de áudio.