Las APIs de Transformer en Jetpack Media3 están diseñadas para facilitar la edición de contenido multimedia de alto rendimiento y confiabilidad. Transformer admite varias operaciones, como:
- Modificar un video con recorte, escalamiento y rotación
- Agregar efectos como superposiciones y filtros
- Procesamiento de formatos especiales, como HDR y video en cámara lenta
- Cómo exportar un elemento multimedia después de aplicar cambios
En esta página, se explican algunos de los casos de uso clave que abarcan Transformador Para obtener más detalles, consulta nuestras guías completas sobre Transformador de Media3.
Comenzar
Para comenzar, agrega una dependencia en los módulos Transformer, Effect y Common de 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"
Asegúrate de reemplazar 1.4.0
por tu versión preferida del elemento
biblioteca. Puedes consultar el
notas de la versión
para ver la versión más reciente.
Clases importantes
Clase | Propósito |
---|---|
Transformer |
Inicia y detén las transformaciones y verifica las actualizaciones de progreso de una transformación en ejecución. |
EditedMediaItem |
Representa un elemento multimedia que se procesará y las ediciones que se le aplicarán. |
Effects |
Una colección de efectos de audio y video. |
Configura el resultado
Con Transformer.Builder
, ahora puedes especificar videoMimeType
y
audioMimetype
estableciendo la función sin necesidad de crear un
TransformationRequest
.
Transcodifica entre formatos
En el siguiente código, se muestra cómo configurar un objeto Transformer
para
salida de video H.265/AVC y audio 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();
Si el formato de entrada multimedia ya coincide con la solicitud de transformación para audio video, Transformer cambia automáticamente a transmuxing, es decir, copia las muestras comprimidas del contenedor de entrada al contenedor de salida sin en caso de que haya modificaciones. Esto evita el costo de procesamiento y la posible pérdida de calidad de y volver a codificarlos en el mismo formato.
Configura el modo HDR
Si el archivo multimedia de entrada está en formato HDR, puedes elegir entre varias
y los diferentes modos de Transformer
procesa la información de HDR. Probablemente
deseas usar HDR_MODE_KEEP_HDR
o
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
---|---|---|
Descripción | Conserva los datos HDR, lo que significa que el formato de salida HDR es el mismo que el formato de entrada HDR. | Asigna tonos de la entrada HDR al SDR con un asignador de tonos OpenGL, lo que significa que el formato de salida estará en SDR. |
Asistencia | Compatible con el nivel de API 31 y versiones posteriores para dispositivos que incluyan un codificador con la función FEATURE_HdrEditing . |
Compatible con el nivel de API 29 y versiones posteriores. |
Errores | Si no se admite, intenta usar HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL en su lugar. |
Si no es compatible, arroja una ExportException . |
En dispositivos que admiten las capacidades de codificación requeridas y ejecutan Android 13
Los objetos Transformer
(nivel de API 33) o versiones posteriores te permiten editar videos HDR.
HDR_MODE_KEEP_HDR
es el modo predeterminado cuando se compila el objeto Composition
.
como se muestra en el siguiente código:
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();
Cómo preparar un elemento multimedia
Un objeto MediaItem
representa un audio.
o video en tu app. Un EditedMediaItem
recolecta un MediaItem
a lo largo
con las transformaciones que se le aplican.
Cómo cortar un video
Para quitar partes no deseadas de un video, puedes configurar el inicio y la finalización personalizados
agregando un ClippingConfiguration
a 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();
Cómo usar efectos integrados
Media3 incluye una serie de efectos de video integrados para transformaciones comunes, por ejemplo:
Clase | Efecto |
---|---|
Presentation |
Ajustar el elemento multimedia por resolución o relación de aspecto |
ScaleAndRotateTransformation |
Ajustar el elemento multimedia con un multiplicador o rotar el elemento multimedia |
Crop |
Recortar el elemento multimedia a un marco más pequeño o más grande |
OverlayEffect |
Agrega una superposición de texto o imagen sobre el elemento multimedia. |
Para los efectos de audio, puedes agregar una secuencia de
AudioProcessor
instancias que transformarán los datos de audio sin procesar (PCM). Por ejemplo, puedes usar
un ChannelMixingAudioProcessor
para mezclar y escalar canales de audio.
Para usar estos efectos, crea una instancia del
efecto o procesador de audio, compila
una instancia de Effects
con los efectos de audio y video a los que quieres aplicar
el elemento multimedia y, luego, agrega el objeto Effects
a un 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();
Cómo crear efectos personalizados
Al extender los efectos incluidos en Media3, puedes crear efectos personalizados
específicas de tus casos de uso. En el siguiente ejemplo, usa la subclase
MatrixTransformation
para hacer zoom en el video y llenar el fotograma sobre el primer
segundo de la reproducción:
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 aún más el comportamiento de un efecto, implementa un
GlShaderProgram
El
El método queueInputFrame()
se usa para procesar los marcos de entrada. Por ejemplo, para
aprovechar las capacidades de aprendizaje automático de
MediaPipe, puedes usar un
MediaPipe FrameProcessor
para enviar cada fotograma a través de un gráfico de MediaPipe. Puedes ver un ejemplo de esto en la
App de demostración de Transformer.
Obtener vista previa de los efectos
Con ExoPlayer, puedes obtener una vista previa de los efectos.
agregado a un elemento multimedia antes de comenzar el proceso de exportación. Usa el mismo
Effects
. En cuanto al EditedMediaItem
, llama a setVideoEffects()
en tu
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();
También puedes obtener una vista previa de los efectos de audio con ExoPlayer. Cuando crees tu
ExoPlayer
, pasa un RenderersFactory
personalizado que configure la
del reproductor de audio para transmitir el audio a un AudioSink
que use tu
AudioProcessor
. En el siguiente ejemplo, lo hacemos anulando el
método buildAudioSink()
de un 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();
Inicia una transformación
Por último, crea un Transformer
para aplicar tus ediciones y comenzar a exportar
elemento multimedia 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);
De manera similar, puedes cancelar el proceso de exportación si es necesario con
Transformer.cancel()
Comprueba si hay actualizaciones del progreso
Transformer.start
se muestra de inmediato y se ejecuta de forma asíncrona. Para consultar
progreso actual de una transformación, llamar
Transformer.getProgress()
Este método toma un elemento ProgressHolder
y, si el estado de progreso está disponible,
es decir, si el método muestra PROGRESS_STATE_AVAILABLE
, el valor proporcionado
ProgressHolder
se actualizará con el porcentaje de progreso actual.
También puedes adjuntar un
oyente
a tu Transformer
para recibir notificaciones sobre eventos completados o de error.