As APIs Transformer no Jetpack Media3 foram projetadas para tornar a edição de mídia com bom desempenho e confiabilidade. O Transformer dá suporte a várias operações, incluindo:
- Modificar um vídeo com corte, dimensionamento e rotação
- Adicionar efeitos, como sobreposições e filtros
- Processamento de formatos especiais, como HDR e vídeos em câmera lenta
- Exportar um item de mídia depois de aplicar edições
Esta página mostra alguns dos principais casos de uso abordados pelos transformador. Para mais detalhes, consulte nossos guias completos sobre Transformer da Media3 (em inglês).
Primeiros passos
Para começar, adicione uma dependência aos módulos "Transformer", "Efeito" e "Comum". do Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.4.0" implementation "androidx.media3:media3-effect:1.4.0" implementation "androidx.media3:media3-common:1.4.0"
Substitua 1.4.0
pela versão de sua preferência do
biblioteca. Consulte o
notas da versão
para conferir a versão mais recente.
Aulas importantes
Classe | Objetivo |
---|---|
Transformer |
Iniciar e interromper transformações e verificar se há atualizações do progresso em uma transformação em execução. |
EditedMediaItem |
Representa um item de mídia a ser processado e as edições a serem aplicadas a ele. |
Effects |
Uma coleção de efeitos de áudio e vídeo. |
Configurar a saída
Com Transformer.Builder
, agora é possível especificar videoMimeType
e
audioMimetype
definindo a função sem precisar criar um
objeto TransformationRequest
.
Transcodificar entre formatos
O código a seguir mostra como configurar um objeto Transformer
para
saída de vídeo H.265/AVC e áudio AAC:
Kotlin
val transformer = Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
Transformer transformer = new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
Se o formato de mídia de entrada já corresponder à solicitação de transformação para áudio ou vídeo, o Transformer alterna automaticamente para transmuxing, 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 do decodificação e recodificação no mesmo formato.
Definir o modo HDR
Se o arquivo de mídia de entrada estiver em formato HDR, você pode escolher entre algumas
diferentes modos de como o Transformer processa as informações de HDR. Você provavelmente
quiser usar HDR_MODE_KEEP_HDR
ou
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
---|---|---|
Descrição | Preserva os dados HDR, o que significa que o formato de saída HDR é o mesmo que o formato de entrada HDR. | Mapeamento de tons da entrada HDR para SDR usando um mapeador de tom OpenGL, o que significa que o formato de saída será em SDR. |
Suporte | Tem suporte nos níveis 31 e mais recentes da API para dispositivos que incluem um codificador com o capability FEATURE_HdrEditing . |
Tem suporte nos níveis 29 e mais recentes da API. |
Erros | Se não houver suporte, ele tentará usar HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL . |
Se não houver suporte, uma ExportException será gerada. |
Em dispositivos com suporte aos recursos de codificação necessários e o Android 13
(nível 33 da API) ou versões mais recentes, os objetos Transformer
permitem editar vídeos em HDR.
O HDR_MODE_KEEP_HDR
é o modo padrão ao criar o objeto Composition
.
conforme mostrado no código a seguir:
Kotlin
val composition = Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(HDR_MODE_KEEP_HDR) .build()
Java
Composition composition = new Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(Composition.HDR_MODE_KEEP_HDR) .build();
Preparar um item de mídia
Um MediaItem
representa um
ou item de vídeo no app. Um EditedMediaItem
coleta um MediaItem
junto com
com as transformações que serão aplicadas a eles.
Cortar um vídeo
Para remover partes indesejadas de um vídeo, defina o início e o fim personalizados
posições adicionando um ClippingConfiguration
ao MediaItem
.
Kotlin
val clippingConfiguration = MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build() val mediaItem = MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build()
Java
ClippingConfiguration clippingConfiguration = new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build(); MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build();
Usar efeitos integrados
A Media3 inclui vários efeitos de vídeo integrados para transformações comuns. Por exemplo:
Classe | Efeito |
---|---|
Presentation |
Dimensionar o item de mídia por resolução ou proporção |
ScaleAndRotateTransformation |
Dimensionar o item de mídia por um multiplicador e/ou girar o item de mídia |
Crop |
Cortar o item de mídia em um frame menor ou maior |
OverlayEffect |
Adicione uma sobreposição de texto ou imagem na parte superior do item de mídia |
Para efeitos de áudio, você pode adicionar uma sequência de
AudioProcessor
que vão transformar os dados brutos de áudio (PCM). Por exemplo, é possível usar
ChannelMixingAudioProcessor
para mixar e dimensionar canais de áudio.
Para usar esses efeitos, crie uma instância do efeito ou processador de áudio, crie
uma instância de Effects
com os efeitos de áudio e vídeo que você quer aplicar
o item de mídia e, em seguida, adicione o objeto Effects
a um EditedMediaItem
.
Kotlin
val channelMixingProcessor = ChannelMixingAudioProcessor() val rotateEffect = ScaleAndRotateTransformation.Builder().setRotationDegrees(60f).build() val cropEffect = Crop(-0.5f, 0.5f, -0.5f, 0.5f) val effects = Effects(listOf(channelMixingProcessor), listOf(rotateEffect, cropEffect)) val editedMediaItem = EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build()
Java
ChannelMixingAudioProcessor channelMixingProcessor = new ChannelMixingAudioProcessor(); ScaleAndRotateTransformation rotateEffect = new ScaleAndRotateTransformation.Builder() .setRotationDegrees(60f) .build(); Crop cropEffect = new Crop(-0.5f, 0.5f, -0.5f, 0.5f); Effects effects = new Effects( ImmutableList.of(channelMixingProcessor), ImmutableList.of(rotateEffect, cropEffect) ); EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build();
Criar efeitos personalizados
Ao estender os efeitos incluídos na Media3, você pode criar efeitos personalizados
específicas para seus casos de uso. No exemplo a seguir, use subclasse
MatrixTransformation
para aplicar zoom ao vídeo e preencher o frame no primeiro
segundo da reprodução:
Kotlin
val zoomEffect = MatrixTransformation { presentationTimeUs -> val transformationMatrix = Matrix() // Set the scaling factor based on the playback position val scale = min(1f, presentationTimeUs / 1_000f) transformationMatrix.postScale(/* x */ scale, /* y */ scale) transformationMatrix } val editedMediaItem = EditedMediaItem.Builder(inputMediaItem) .setEffects(Effects(listOf(), listOf(zoomEffect)) .build()
Java
MatrixTransformation zoomEffect = presentationTimeUs -> { Matrix transformationMatrix = new Matrix(); // Set the scaling factor based on the playback position float scale = min(1f, presentationTimeUs / 1_000f); transformationMatrix.postScale(/* x */ scale, /* y */ scale); return transformationMatrix; }; EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(inputMediaItem) .setEffects(new Effects(ImmutableList.of(), ImmutableList.of(zoomEffect))) .build();
Para personalizar ainda mais o comportamento de um efeito, implemente uma
GlShaderProgram
A
O método queueInputFrame()
é usado para processar frames de entrada. Por exemplo, para
aproveitar os recursos de machine learning
MediaPipe, use uma
MediaPipe FrameProcessor
(link em inglês)
para enviar cada frame por um gráfico do MediaPipe. Confira um exemplo disso no
App de demonstração do Transformer.
Visualizar efeitos
Com o ExoPlayer, você pode conferir os efeitos
adicionado a um item de mídia antes de iniciar o processo de exportação. Usando o mesmo
Effects
para EditedMediaItem
, chame setVideoEffects()
nos
Instância do ExoPlayer.
Kotlin
val player = ExoPlayer.builder(context) .build() .also { exoPlayer -> exoPlayer.setMediaItem(inputMediaItem) exoPlayer.setVideoEffects(effects) exoPlayer.prepare() }
Java
ExoPlayer player = new ExoPlayer.builder(context).build(); player.setMediaItem(inputMediaItem); player.setVideoEffects(effects); exoPlayer.prepare();
Você também pode testar efeitos de áudio com o ExoPlayer. Ao criar sua
Instância de ExoPlayer
, transmita uma RenderersFactory
personalizada que configure a
os renderizadores de áudio do player de áudio para enviar áudio a um AudioSink
que usa seu
AudioProcessor
. No exemplo abaixo, fazemos isso substituindo a string
Método buildAudioSink()
de um DefaultRenderersFactory
.
Kotlin
val player = ExoPlayer.Builder(context, object : DefaultRenderersFactory(context) { override fun buildAudioSink( context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean ): AudioSink? { return DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode(if (enableOffload) { DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED } else { DefaultAudioSink.OFFLOAD_MODE_DISABLED }) .setAudioProcessors(arrayOf(channelMixingProcessor)) .build() } }).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context, new DefaultRenderersFactory(context) { @Nullable @Override protected AudioSink buildAudioSink( Context context, boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams, boolean enableOffload ) { return new DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode( enableOffload ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED : DefaultAudioSink.OFFLOAD_MODE_DISABLED) .setAudioProcessors(new AudioProcessor[]{channelMixingProcessor}) .build(); } }).build();
Iniciar uma transformação
Por fim, crie uma Transformer
para aplicar suas edições e comece a exportar o
o item de mídia resultante.
Kotlin
val transformer = Transformer.Builder(context) .addListener(listener) .build() transformer.start(editedMediaItem, outputPath)
Java
Transformer transformer = new Transformer.Builder(context) .addListener(listener) .build(); transformer.start(editedMediaItem, outputPath);
Também é possível cancelar o processo de exportação, se necessário, usando
Transformer.cancel()
Verificar se há atualizações de progresso
Transformer.start
é retornado imediatamente e executado de forma assíncrona. Para consultar
o progresso atual de uma transformação, chame
Transformer.getProgress()
Esse método usa um ProgressHolder
e, se o estado do progresso estiver disponível,
ou seja, se o método retornar PROGRESS_STATE_AVAILABLE
, os valores fornecidos
ProgressHolder
vai ser atualizado com a porcentagem de progresso atual.
Você também pode anexar um
ouvinte
ao Transformer
para receber notificações sobre eventos de conclusão ou erro.