Creare un'app di editing video di base utilizzando Media3 Transformer

Le API Transformer in Jetpack Media3 sono progettate per consentire più performante e affidabile. Transformer supporta una serie di operazioni, tra cui:

  • Modifica di un video tramite ritaglio, ridimensionamento e rotazione
  • Aggiungere effetti come overlay e filtri
  • Elaborazione di formati speciali come HDR e video in slow motion
  • Esportare un elemento multimediale dopo l'applicazione delle modifiche

In questa pagina vengono presentati alcuni dei principali casi d'uso trattati Transformer. Per ulteriori dettagli, puoi consultare le nostre guide complete su Media3 Transformer.

Inizia

Per iniziare, aggiungi una dipendenza ai moduli Transformer, Effect e Common di 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"

Assicurati di sostituire 1.4.0 con la tua versione preferita dell' libreria. Puoi fare riferimento alle note di rilascio per vedere l'ultima versione.

Classi importanti

Classe Finalità
Transformer Avvia e arresta le trasformazioni e controlla la presenza di aggiornamenti di avanzamento per una trasformazione in esecuzione.
EditedMediaItem Rappresenta un elemento multimediale da elaborare e le modifiche da applicarvi.
Effects Una raccolta di effetti audio e video.

Configura l'output

Con Transformer.Builder, ora puoi specificare videoMimeType e audioMimetype impostando la funzione senza dover creare un TransformationRequest oggetto.

Transcodifica tra formati

Il codice seguente mostra come configurare un oggetto Transformer per uscita video H.265/AVC e 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();

Se il formato multimediale di input corrisponde già alla richiesta di trasformazione per l'audio o video, Transformer passa automaticamente alla transmuxing, ovvero alla copia i campioni compressi dal container di input al container di output senza modifica. In questo modo si evitano i costi di calcolo e la potenziale perdita di qualità decodifica e ricodifica nello stesso formato.

Imposta modalità HDR

Se il file multimediale di input è in formato HDR, puoi scegliere tra diversi diverse modalità di elaborazione delle informazioni HDR da parte di Transformer. Probabilmente vuoi usare 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
Descrizione Conserva i dati HDR, il che significa che il formato di output HDR è lo stesso del formato di input HDR. Input Tonemap HDR in SDR utilizzando una mappa dei toni OpenGL, il che significa che il formato di output sarà in SDR.
Assistenza Funzionalità supportata sui livelli API 31+ per i dispositivi che includono un codificatore con la funzionalità FEATURE_HdrEditing. Funzionalità supportata sui livelli API 29 e successivi.
Errori Se non è supportato, prova a usare il criterio HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL. Se non supportato, genera un ExportException.

Sui dispositivi che supportano le funzionalità di codifica richieste ed eseguono Android 13 (livello API 33) o superiore, gli oggetti Transformer ti consentono di modificare i video HDR. HDR_MODE_KEEP_HDR è la modalità predefinita durante la creazione dell'oggetto Composition, come mostrato nel seguente codice:

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();

Preparare un elemento multimediale

Un MediaItem rappresenta un audio o un elemento video nella tua app. EditedMediaItem raccoglie MediaItem insieme con le trasformazioni da applicare.

Tagliare un video

Per rimuovere le parti indesiderate di un video, puoi impostare un inizio e una fine personalizzati posizioni aggiungendo 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();

Usare gli effetti integrati

Media3 include una serie di effetti video integrati per trasformazioni comuni, Ad esempio:

Classe Effetto
Presentation Ridimensiona l'elemento multimediale in base alla risoluzione o alle proporzioni
ScaleAndRotateTransformation Ridimensionare l'elemento multimediale in base a un moltiplicatore e/o ruotare l'elemento multimediale
Crop Ritaglia l'elemento multimediale in modo da avere una cornice più piccola o più grande
OverlayEffect Aggiungi un overlay di testo o immagine sopra l'elemento multimediale.

Per gli effetti audio, puoi aggiungere una sequenza di AudioProcessor che trasformeranno i dati audio non elaborati (PCM). Ad esempio, puoi utilizzare Un ChannelMixingAudioProcessor per mixare e scalare i canali audio.

Per usare questi effetti, crea un'istanza del processore di effetti o audio, costruisci un'istanza di Effects con gli effetti audio e video a cui vuoi applicare l'elemento multimediale, quindi aggiungi l'oggetto 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();

Creare effetti personalizzati

Se estendi gli effetti inclusi in Media3, puoi creare effetti personalizzati specifici per i tuoi casi d'uso. Nell'esempio seguente, utilizza la sottoclasse MatrixTransformation per ingrandire il video e riempire il frame sopra il primo secondo di riproduzione:

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();

Per personalizzare ulteriormente il comportamento di un effetto, implementa una GlShaderProgram La Per elaborare i frame di input viene utilizzato il metodo queueInputFrame(). Ad esempio, per sfruttare le capacità di machine learning MediaPipe, puoi utilizzare un oggetto MediaPipe FrameProcessor per inviare ogni frame attraverso un grafico MediaPipe. Puoi trovare un esempio nella App demo di Transformer.

Visualizzare l'anteprima degli effetti

Con ExoPlayer, puoi visualizzare l'anteprima degli effetti a un elemento multimediale prima di iniziare il processo di esportazione. Lo stesso Effects per quanto riguarda EditedMediaItem, chiama setVideoEffects() su Istanza 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();

Puoi anche visualizzare l'anteprima degli effetti audio con ExoPlayer. Quando crei ExoPlayer, trasmetti un valore RenderersFactory personalizzato che configura renderer audio del player per trasmettere l'audio a un AudioSink che utilizza il tuo AudioProcessor sequenza. Nell'esempio riportato di seguito, per eseguire questa operazione, viene eseguito l'override Metodo buildAudioSink() di 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();

Avvia una trasformazione

Infine, crea una Transformer per applicare le modifiche e iniziare a esportare il l'elemento multimediale risultante.

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);

Se necessario, puoi annullare il processo di esportazione in modo simile con Transformer.cancel()

Verifica la disponibilità di aggiornamenti relativi ai progressi

Transformer.start restituisce immediatamente ed esegue in modo asincrono. Per eseguire query sul avanzamento attuale di una trasformazione, chiama Transformer.getProgress() Questo metodo richiede un ProgressHolder e, se lo stato di avanzamento è disponibile, ossia, se il metodo restituisce PROGRESS_STATE_AVAILABLE, il valore fornito ProgressHolder verrà aggiornato con la percentuale di avanzamento attuale.

Puoi anche allegare ascolto al tuo Transformer per ricevere notifiche su eventi di completamento o di errore.