Le API Transformer in Jetpack Media3 sono progettate per rendere l'editing dei contenuti multimediali efficiente e affidabile. Transformer supporta una serie di operazioni, tra cui:
- Modifica di un video con taglio, ridimensionamento e rotazione
- Aggiunta di effetti come overlay e filtri
- Elaborazione di formati speciali come video HDR e slow motion
- Esportazione di un elemento multimediale dopo aver applicato le modifiche
Questa pagina illustra alcuni dei principali casi d'uso trattati da Transformer. Per maggiori dettagli, consulta le nostre guide complete su Media3 Transformer.
Inizia
Per iniziare, aggiungi una dipendenza dai moduli Transformer, Effect e Common di 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"
Assicurati di sostituire 1.9.3 con la versione della libreria che preferisci. Puoi consultare le
note sulla versione
per visualizzare l'ultima versione.
Classi importanti
| Classe | Finalità |
|---|---|
Transformer |
Avvia e interrompi le trasformazioni e controlla gli aggiornamenti sullo stato di avanzamento di una trasformazione in corso. |
EditedMediaItem |
Rappresenta un elemento multimediale da elaborare e le modifiche da applicare. |
Effects |
Una raccolta di effetti audio e video. |
Configura l'output
Con Transformer.Builder, ora puoi specificare la directory videoMimeType e audioMimetype impostando la funzione senza dover creare un oggetto TransformationRequest.
Transcodifica tra formati
Il seguente codice mostra come configurare un oggetto Transformer per generare 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 dei contenuti multimediali di input corrisponde già alla richiesta di trasformazione per audio o video, Transformer passa automaticamente al transmuxing, ovvero alla copia dei campioni compressi dal container di input al container di output senza modifiche. In questo modo si evitano i costi di calcolo e la potenziale perdita di qualità della decodifica e della ricodifica nello stesso formato.
Imposta la modalità HDR
Se il file multimediale di input è in formato HDR, puoi scegliere tra diverse modalità di elaborazione delle informazioni HDR da parte di Transformer. Probabilmente ti consigliamo di utilizzare 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. | Esegue il tonemapping dell'input HDR in SDR utilizzando un tonemapper OpenGL, il che significa che il formato di output sarà in SDR. |
| Assistenza | Supportato sui livelli API 31 e successivi per i dispositivi che includono un encoder con la FEATURE_HdrEditing funzionalità. |
Supportato sui livelli API 29 e successivi. |
| Errori | Se non è supportato, tenta di utilizzare 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 versioni successive, gli oggetti Transformer consentono di modificare i video HDR.
HDR_MODE_KEEP_HDR è la modalità predefinita quando crei l'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();
Prepara un elemento multimediale
Un MediaItem rappresenta un elemento audio
o video nella tua app. Un EditedMediaItem raccoglie un MediaItem insieme
alle trasformazioni da applicare.
Taglia un video
Per rimuovere le parti indesiderate di un video, puoi impostare posizioni di inizio e fine personalizzate aggiungendo un ClippingConfiguration al 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();
Utilizza gli effetti integrati
Media3 include una serie di effetti video integrati per le trasformazioni comuni, ad esempio:
| Classe | Effetto |
|---|---|
Presentation |
Ridimensiona l'elemento multimediale in base alla risoluzione o alle proporzioni |
ScaleAndRotateTransformation |
Ridimensiona l'elemento multimediale in base a un moltiplicatore e/o ruota l'elemento multimediale |
Crop |
Ritaglia l'elemento multimediale in un frame più piccolo 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
istanze che trasformeranno i dati audio non elaborati (PCM). Ad esempio, puoi utilizzare
un ChannelMixingAudioProcessor
per mixare e scalare i canali audio.
Per utilizzare questi effetti, crea un'istanza dell'effetto o del processore audio, crea un'istanza di Effects con gli effetti audio e video che vuoi applicare all'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();
Crea effetti personalizzati
Estendendo 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 in modo da riempire il frame durante 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 un
GlShaderProgram. Il metodo queueInputFrame() viene utilizzato per elaborare i frame di input. Ad esempio, per
sfruttare le funzionalità di machine learning di
MediaPipe, puoi utilizzare un
MediaPipe FrameProcessor
per inviare ogni frame tramite un grafico MediaPipe. Puoi vedere un esempio di questa operazione nell'
app demo di Transformer.
Visualizza l'anteprima degli effetti
Con ExoPlayer, puoi visualizzare l'anteprima degli effetti
aggiunti a un elemento multimediale prima di avviare il processo di esportazione. Utilizzando lo stesso
Effects oggetto di EditedMediaItem, chiama setVideoEffects() sull'istanza
di 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 l'istanza di ExoPlayer, passa un RenderersFactory personalizzato che configura i renderer audio del player per generare l'audio in un AudioSink che utilizza la sequenza AudioProcessor. Nell'esempio seguente, lo facciamo sostituendo il 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 un Transformer per applicare le modifiche e iniziare a esportare 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().
Controlla gli aggiornamenti sullo stato di avanzamento
Transformer.start viene restituito immediatamente e viene eseguito in modo asincrono. Per eseguire una query sullo
stato di avanzamento attuale di una trasformazione, chiama
Transformer.getProgress().
Questo metodo accetta un ProgressHolder e, se lo stato di avanzamento è disponibile, ovvero se il metodo restituisce PROGRESS_STATE_AVAILABLE, il ProgressHolder fornito verrà aggiornato con la percentuale di avanzamento attuale.
Puoi anche collegare un
listener
al tuo Transformer per ricevere una notifica degli eventi di completamento o di errore.