Créer une application de montage vidéo basique à l'aide de Media3 Transformer

Les API Transformer de Jetpack Media3 sont conçues pour le montage multimédia performante et fiable. Transformer accepte un certain nombre d'opérations, y compris:

  • Modifier une vidéo avec le découpage, la mise à l'échelle et la rotation
  • Ajouter des effets tels que des superpositions et des filtres
  • Traitement de formats spéciaux tels que la technologie HDR et le ralenti
  • Exporter un élément multimédia après application des modifications

Cette page décrit certains des principaux cas d'utilisation couverts par "Transformateur". Pour en savoir plus, vous pouvez consulter nos guides complets 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.4.0"
implementation "androidx.media3:media3-effect:1.4.0"
implementation "androidx.media3:media3-common:1.4.0"

Veillez à remplacer 1.4.0 par la version de votre choix bibliothèque. Vous pouvez consulter Notes de version pour afficher la dernière version.

Classes importantes

Classe Objectif
Transformer Démarrez et arrêtez des transformations, et vérifiez l'état d'avancement d'une transformation en cours d'exécution.
EditedMediaItem Représente un élément multimédia à traiter et les modifications à y appliquer.
Effects Ensemble d'effets audio et vidéo.

Configurer le résultat

Avec Transformer.Builder, vous pouvez maintenant spécifier videoMimeType et audioMimetype en définissant la fonction sans avoir à créer de TransformationRequest.

Transcodage d'un format à un autre

Le code suivant montre comment configurer un objet Transformer pour sortie vidéo H.265/AVC et 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 du média d'entrée correspond déjà à la requête de transformation pour l'audio ou vidéo, Transformer passe automatiquement au transmuxing, c'est-à-dire copier les échantillons compressés du conteneur d'entrée vers le conteneur de sortie sans modification. Cela permet d'éviter les coûts de calcul et la perte potentielle de qualité décodage et 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 avez le choix entre plusieurs différents modes de traitement des informations HDR. Vous avez probablement souhaitez 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 Conservez les données HDR, c'est-à-dire que le format de sortie HDR est identique au format d'entrée HDR. Entrée de carte de tonalité HDR en SDR à l'aide d'un tone-mapper OpenGL, ce qui signifie que le format de sortie est au format SDR.
Assistance Compatible avec les niveaux d'API 31 et supérieurs pour les appareils qui incluent un encodeur avec la capacité FEATURE_HdrEditing. Compatible avec les niveaux d'API 29 et supérieurs.
Erreurs Si elle n'est pas compatible, essayez d'utiliser HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL à la place. S'il n'est pas compatible, une exception ExportException est générée.

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 avec les transformations à lui appliquer.

Couper une vidéo

Pour supprimer les parties non désirées d'une vidéo, vous pouvez personnaliser le début et la fin en ajoutant un ClippingConfiguration à 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 Ajuster l'élément multimédia en fonction de la résolution ou du format
ScaleAndRotateTransformation Mettre à l'échelle l'élément multimédia selon un multiplicateur et/ou le faire pivoter
Crop Recadrer l'élément multimédia dans un cadre plus petit ou plus grand
OverlayEffect Ajoutez du texte ou une image en superposition sur l'élément multimédia.

Pour les effets audio, vous pouvez ajouter une séquence AudioProcessor qui transformeront les données audio brutes (PCM). Par exemple, vous pouvez utiliser un ChannelMixingAudioProcessor pour combiner et adapter les canaux audio.

Pour utiliser ces effets, créez une instance de l'effet ou du processeur audio, Une instance de Effects avec les effets audio et vidéo auxquels 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

Créez des effets personnalisés en développant les effets inclus dans Media3 spécifiques à vos cas d'utilisation. Dans l'exemple suivant, utilisez sous-classe MatrixTransformation pour zoomer sur la vidéo afin de remplir l'image à partir de la première image 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 une GlShaderProgram La La méthode queueInputFrame() permet de traiter les frames d'entrée. Par exemple, pour les fonctionnalités de machine learning MediaPipe, vous pouvez utiliser un MediaPipe FrameProcessor pour envoyer chaque image via un graphique MediaPipe. Vous trouverez un exemple dans la Application de démonstration Transformer

Prévisualiser les effets

Avec ExoPlayer, vous pouvez prévisualiser les effets à un élément multimédia avant de lancer le processus d'exportation. En utilisant les mêmes Effects comme pour 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 des effets audio avec ExoPlayer. Lorsque vous créez votre ExoPlayer, transmettez un RenderersFactory personnalisé qui configure le vers les moteurs de rendu audio du lecteur afin de diffuser le contenu audio vers un AudioSink qui utilise votre Séquence AudioProcessor. Pour ce faire, dans l'exemple ci-dessous, la valeur Méthode buildAudioSink() d'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();

Lancer une transformation

Enfin, créez un Transformer pour appliquer vos modifications et commencer à exporter les l'élément multimédia généré.

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 aussi annuler le processus d'exportation si nécessaire avec Transformer.cancel()

Vérifier la progression

Transformer.start renvoie immédiatement un résultat et s'exécute de manière asynchrone. Pour interroger la la progression actuelle d'une transformation, appelez Transformer.getProgress() Cette méthode utilise un ProgressHolder, et si l'état de progression est disponible, Autrement dit, si la méthode renvoie PROGRESS_STATE_AVAILABLE, les valeurs ProgressHolder sera mis à jour avec le pourcentage de progression actuel.

Vous pouvez également joindre un écouteur à votre Transformer pour être averti des événements d'achèvement ou d'erreur.