Le API Transformer in Jetpack Media3 sono progettate per rendere l'editing dei contenuti multimediali affidabile e ad alte prestazioni. Transformer supporta una serie di operazioni, tra cui:
- Modificare un video tagliandolo, ridimensionandolo e ruotandolo
- Aggiunta di effetti come overlay e filtri
- Elaborazione di formati speciali come HDR e video in slow motion
- Esportare un elemento multimediale dopo aver applicato le modifiche
Questa pagina illustra alcuni dei casi d'uso principali coperti 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.5.0" implementation "androidx.media3:media3-effect:1.5.0" implementation "androidx.media3:media3-common:1.5.0"
Assicurati di sostituire 1.5.0
con la versione che preferisci della biblioteca. Puoi consultare le note di rilascio per visualizzare la versione più recente.
Classi importanti
Classe | Finalità |
---|---|
Transformer |
Avvia e interrompi le trasformazioni e controlla gli aggiornamenti sull'avanzamento di una trasformazione in esecuzione. |
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 le directory videoMimeType
e
audioMimetype
impostando la funzione senza dover creare un
oggetto TransformationRequest
.
Transcodifica tra formati
Il codice seguente mostra come configurare un oggetto Transformer
per produrre 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 audio o video, Transformer passa automaticamente al transmuxing, ovvero alla copia dei sample compressi dal contenitore di input al contenitore di output senza modifiche. In questo modo si evitano i costi computazionali e la potenziale perdita di qualità della decodifica e della ricodifica nello stesso formato.
Impostare la modalità HDR
Se il file multimediale di input è in formato HDR, puoi scegliere tra alcune modalità diverse per la modalità di elaborazione delle informazioni HDR da parte di Transformer. Probabilmente
vuoi 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 | Conservare i dati HDR, il che significa che il formato di output HDR è lo stesso del formato di input HDR. | Esegui la mappatura tonale dell'input HDR in SDR utilizzando un mappatore tonale OpenGL, il che significa che il formato di output sarà in SDR. |
Assistenza | Supportato nei livelli API 31 e versioni successive per i dispositivi che includono un codificatore con la funzionalità FEATURE_HdrEditing . |
Supportato nei livelli API 29 e versioni successive. |
Errori | Se non supportato, tenta di utilizzare HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL . |
Se non è supportato, viene generato un ExportException . |
Sui dispositivi che supportano le funzionalità di codifica richieste e che eseguono Android 13
(livello API 33) o versioni successive, gli oggetti Transformer
ti consentono di modificare i video HDR.
HDR_MODE_KEEP_HDR
è la modalità predefinita per la creazione dell'oggetto Composition
, come mostrato nel codice seguente:
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 elemento audio o video nella tua app. Un EditedMediaItem
raccoglie un MediaItem
insieme alle trasformazioni da applicare.
Tagliare un video
Per rimuovere 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();
Utilizzare 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 |
Scalare l'elemento multimediale in base a un moltiplicatore e/o ruotarlo |
Crop |
Ritagliare l'elemento multimediale in un riquadro 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 dell'elaboratore 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();
Creare 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 aumentare lo zoom del video in modo che riempia l'inquadratura nel 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 fotogrammi di input. Ad esempio, per sfruttare le funzionalità di machine learning di MediaPipe, puoi utilizzare un FrameProcessor
MediaPipe per inviare ogni frame tramite un grafo MediaPipe. Guarda un esempio nell'app demo Transformer.
Effetti di anteprima
Con ExoPlayer, puoi visualizzare l'anteprima degli effetti aggiunti a un elemento multimediale prima di avviare la procedura di esportazione. Utilizzando lo stesso
Effects
oggetto per EditedMediaItem
, chiama setVideoEffects()
sull'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 un'istanza ExoPlayer
, passa un RenderersFactory
personalizzato che configuri i renderer audio del player in modo da inviare l'audio a 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);
Analogamente, se necessario, puoi annullare il processo di esportazione con
Transformer.cancel()
.
Verificare la disponibilità di aggiornamenti sullo stato di avanzamento
Transformer.start
restituisce immediatamente un valore e viene eseguito in modo asincrono. Per eseguire query sull'avanzamento corrente 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 corrente.
Puoi anche associare un
listener
al tuo Transformer
per ricevere una notifica sugli eventi di completamento o di errore.