Les API Transformer de Jetpack Media3 sont conçues pour rendre la modification de contenus multimédias performante et fiable. Transformer est compatible avec un certain nombre d'opérations, y compris les suivantes :
- Modification d'une vidéo avec découpage, mise à l'échelle et rotation
- Ajout d'effets tels que des superpositions et des filtres
- Traitement de formats spéciaux tels que la vidéo HDR et au ralenti
- Exportation d'un élément multimédia après application des modifications
Cette page vous présente quelques-uns des principaux cas d'utilisation couverts par Transformer. Pour en savoir plus, consultez nos guides complets sur Media3 Transformer.
Premiers pas
Pour commencer, ajoutez une dépendance aux modules Transformer, Effect et Common de Jetpack Media3 :
implementation "androidx.media3:media3-transformer:1.9.3" implementation "androidx.media3:media3-effect:1.9.3" implementation "androidx.media3:media3-common:1.9.3"
Veillez à remplacer 1.9.3 par la version que vous souhaitez utiliser pour la bibliothèque. Vous pouvez consulter les
notes de version
pour connaître la dernière version.
Classes importantes
| Classe | Objectif |
|---|---|
Transformer |
Démarrer et arrêter des transformations, et vérifier les mises à jour de la progression d'une transformation en cours d'exécution. |
EditedMediaItem |
Représente un élément multimédia à traiter et les modifications à lui appliquer. |
Effects |
Collection d'effets audio et vidéo. |
Configurer la sortie
Avec Transformer.Builder, vous pouvez désormais spécifier le répertoire videoMimeType et audioMimetype en définissant la fonction sans avoir à créer d'objet TransformationRequest.
Transcoder entre les formats
Le code suivant montre comment configurer un objet Transformer pour générer une vidéo H.265/AVC et un contenu 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 le format multimédia d'entrée correspond déjà à la demande de transformation pour l'audio ou la vidéo, Transformer passe automatiquement au transmuxage, c'est-à-dire qu'il copie les exemples compressés du conteneur d'entrée vers le conteneur de sortie sans modification. Cela évite le coût de calcul et la perte de qualité potentielle du décodage et du réencodage dans le même format.
Définir le mode HDR
Si le fichier multimédia d'entrée est au format HDR, vous pouvez choisir entre plusieurs modes de traitement des informations HDR par Transformer. Vous souhaiterez probablement utiliser 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 |
|
|---|---|---|
| Description | Conserver les données HDR, ce qui signifie que le format de sortie HDR est identique au format d'entrée HDR. | Mapper le contenu HDR d'entrée au contenu SDR à l'aide d'un mapper de tonalité OpenGL, ce qui signifie que le format de sortie sera au format SDR. |
| Assistance | Compatible avec les niveaux d'API 31 et ultérieurs pour les appareils qui incluent un encodeur avec la FEATURE_HdrEditing fonctionnalité. |
Compatible avec les niveaux d'API 29 et ultérieurs. |
| Erreurs | Si cette option n'est pas compatible, tente d'utiliser HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL à la place. |
Si cette option n'est pas compatible, génère une ExportException. |
Sur les appareils compatibles avec les fonctionnalités d'encodage requises et exécutant Android 13 (niveau d'API 33) ou version ultérieure, les objets Transformer vous permettent de modifier des vidéos HDR.
HDR_MODE_KEEP_HDR est le mode par défaut lors de la création de l'objet Composition, comme indiqué dans le code suivant :
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();
Préparer un élément multimédia
Un MediaItem représente un élément audio
ou vidéo dans votre application. Un EditedMediaItem collecte un MediaItem ainsi
que les transformations à lui appliquer.
Couper une vidéo
Pour supprimer les parties indésirables d'une vidéo, vous pouvez définir des positions de début et de fin personnalisées en ajoutant une ClippingConfiguration au 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();
Utiliser des effets intégrés
Media3 inclut un certain nombre d'effets vidéo intégrés pour les transformations courantes, par exemple :
| Classe | Effet |
|---|---|
Presentation |
Mettre à l'échelle l'élément multimédia par résolution ou format d'image |
ScaleAndRotateTransformation |
Mettre à l'échelle l'élément multimédia par un multiplicateur et/ou le faire pivoter |
Crop |
Rogner l'élément multimédia sur un cadre plus petit ou plus grand |
OverlayEffect |
Ajouter une superposition de texte ou d'image sur l'élément multimédia |
Pour les effets audio, vous pouvez ajouter une séquence d'
AudioProcessor
instances qui transformeront les données audio brutes (PCM). Par exemple, vous pouvez utiliser
un ChannelMixingAudioProcessor
pour mixer et mettre à l'échelle les canaux audio.
Pour utiliser ces effets, créez une instance de l'effet ou du processeur audio, créez une instance d'Effects avec les effets audio et vidéo que vous souhaitez appliquer à l'élément multimédia, puis ajoutez l'objet Effects à 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();
Créer des effets personnalisés
En étendant les effets inclus dans Media3, vous pouvez créer des effets personnalisés spécifiques à vos cas d'utilisation. Dans l'exemple suivant, utilisez la sous-classe MatrixTransformation pour zoomer sur la vidéo afin de remplir le cadre au cours de la première seconde de lecture :
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();
Pour personnaliser davantage le comportement d'un effet, implémentez un
GlShaderProgram. La méthode queueInputFrame() est utilisée pour traiter les frames d'entrée. Par exemple, pour
exploiter les fonctionnalités de machine learning de
MediaPipe, vous pouvez utiliser un
MediaPipe FrameProcessor
pour envoyer chaque frame via un graphique MediaPipe. Pour en voir un exemple, consultez l'application de démonstration
Transformer.
Prévisualiser les effets
Avec ExoPlayer, vous pouvez prévisualiser les effets
ajoutés à un élément multimédia avant de lancer le processus d'exportation. En utilisant le même
Effects objet que pour le EditedMediaItem, appelez setVideoEffects() sur votre
instance 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();
Vous pouvez également prévisualiser les effets audio avec ExoPlayer. Lorsque vous créez votre instance ExoPlayer, transmettez une RenderersFactory personnalisée qui configure les moteurs de rendu audio du lecteur pour générer du contenu audio dans un AudioSink qui utilise votre séquence AudioProcessor. Dans l'exemple ci-dessous, nous le faisons en remplaçant la méthode buildAudioSink() d'une 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();
Lancer une transformation
Enfin, créez un Transformer pour appliquer vos modifications et commencer à exporter l'élément multimédia résultant.
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);
Vous pouvez également annuler le processus d'exportation si nécessaire avec
Transformer.cancel().
Vérifier les mises à jour de la progression
Transformer.start renvoie immédiatement et s'exécute de manière asynchrone. Pour interroger la
progression actuelle d'une transformation, appelez
Transformer.getProgress().
Cette méthode prend un ProgressHolder, et si l'état de progression est disponible, c'est-à-dire si la méthode renvoie PROGRESS_STATE_AVAILABLE, le ProgressHolder fourni est mis à jour avec le pourcentage de progression actuel.
Vous pouvez également associer un
écouteur
à votre Transformer pour être informé des événements de fin ou d'erreur.