Die Transformer APIs in Jetpack Media3 wurden für eine leistungsstarke und zuverlässige Medienbearbeitung entwickelt. Transformer unterstützt eine Reihe von Vorgängen, darunter:
- Video mit Zuschneiden, Skalieren und Drehen bearbeiten
- Effekte wie Overlays und Filter hinzufügen
- Spezielle Formate wie HDR- und Zeitlupenvideos verarbeiten
- Mediendatei nach dem Bearbeiten exportieren
Auf dieser Seite werden einige der wichtigsten Anwendungsfälle beschrieben, die von Transformer abgedeckt werden. Weitere Informationen finden Sie in unseren vollständigen Leitfäden zu Media3 Transformer.
Jetzt starten
Fügen Sie zuerst eine Abhängigkeit von den Modulen „Transformer“, „Effect“ und „Common“ von Jetpack Media3 hinzu:
implementation "androidx.media3:media3-transformer:1.9.3" implementation "androidx.media3:media3-effect:1.9.3" implementation "androidx.media3:media3-common:1.9.3"
Ersetzen Sie 1.9.3 durch die gewünschte Version der Bibliothek. Die aktuelle Version finden Sie in den
Versionshinweisen.
Wichtige Klassen
| Klasse | Zweck |
|---|---|
Transformer |
Transformationen starten und beenden und nach Fortschrittsupdates für eine laufende Transformation suchen |
EditedMediaItem |
Stellt eine zu verarbeitende Mediendatei und die darauf anzuwendenden Änderungen dar. |
Effects |
Eine Sammlung von Audio- und Videoeffekten |
Ausgabe konfigurieren
Mit Transformer.Builder können Sie jetzt das Verzeichnis videoMimeType und audioMimetype angeben, indem Sie die Funktion festlegen, ohne ein TransformationRequest-Objekt erstellen zu müssen.
Transcodierung zwischen Formaten
Der folgende Code zeigt, wie Sie ein Transformer-Objekt so konfigurieren, dass es H.265/AVC-Video und AAC-Audio ausgibt:
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();
Wenn das Eingabemedienformat bereits mit der Transformationsanfrage für Audio oder Video übereinstimmt, wechselt Transformer automatisch zum Transmuxing. Dabei werden die komprimierten Samples unverändert vom Eingabe- in den Ausgabecontainer kopiert. So werden die Rechenkosten und der potenzielle Qualitätsverlust durch Decodierung und erneute Codierung im selben Format vermieden.
HDR-Modus festlegen
Wenn die Eingabemediendatei in einem HDR-Format vorliegt, können Sie zwischen verschiedenen Modi auswählen, wie Transformer die HDR-Informationen verarbeitet. Wahrscheinlich möchten Sie entweder HDR_MODE_KEEP_HDR oder HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL verwenden.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
|---|---|---|
| Beschreibung | Die HDR-Daten werden beibehalten. Das HDR-Ausgabeformat ist also dasselbe wie das HDR-Eingabeformat. | HDR-Eingabe wird mit einem OpenGL-Tone-Mapper in SDR umgewandelt. Das Ausgabeformat ist also SDR. |
| Support | Wird auf API-Ebene 31 und höher für Geräte unterstützt, die einen Encoder mit der FEATURE_HdrEditing Funktion enthalten. |
Wird auf API-Ebene 29 und höher unterstützt. |
| Fehler | Wird der Modus nicht unterstützt, wird stattdessen versucht, HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL zu verwenden. |
Wird der Modus nicht unterstützt, wird ExportException ausgelöst. |
Auf Geräten, die die erforderlichen Codierungsfunktionen unterstützen und auf denen Android 13 (API-Ebene 33) oder höher ausgeführt wird, können Sie mit Transformer-Objekten HDR-Videos bearbeiten.
HDR_MODE_KEEP_HDR ist der Standardmodus beim Erstellen des Composition-Objekts, wie im folgenden Code gezeigt:
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();
Mediendatei vorbereiten
Ein MediaItem stellt eine Audio
oder Videodatei in Ihrer App dar. Ein EditedMediaItem enthält ein MediaItem zusammen
mit den darauf anzuwendenden Transformationen.
Video zuschneiden
Wenn Sie unerwünschte Teile eines Videos entfernen möchten, können Sie benutzerdefinierte Start- und Endpositionen festlegen, indem Sie dem MediaItem eine ClippingConfiguration hinzufügen.
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();
Integrierte Effekte verwenden
Media3 enthält eine Reihe integrierter Videoeffekte für gängige Transformationen, z. B.:
| Klasse | Effekte |
|---|---|
Presentation |
Mediendatei nach Auflösung oder Seitenverhältnis skalieren |
ScaleAndRotateTransformation |
Mediendatei mit einem Multiplikator skalieren und/oder drehen |
Crop |
Mediendatei auf einen kleineren oder größeren Rahmen zuschneiden |
OverlayEffect |
Text- oder Bild-Overlays über der Mediendatei einblenden |
Für Audioeffekte können Sie eine Sequenz von AudioProcessor-Instanzen hinzufügen, die die PCM-Rohaudiodaten transformieren. Sie können beispielsweise einen ChannelMixingAudioProcessor verwenden, um Audio-Channels zu mischen und zu skalieren.
Wenn Sie diese Effekte verwenden möchten, erstellen Sie eine Instanz des Effekts oder Audioprozessors, erstellen Sie eine Instanz von Effects mit den Audio- und Videoeffekten, die Sie auf die Mediendatei anwenden möchten, und fügen Sie das Effects-Objekt dann einem EditedMediaItem hinzu.
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();
Benutzerdefinierte Effekte erstellen
Durch Erweitern der in Media3 enthaltenen Effekte können Sie benutzerdefinierte Effekte erstellen, die speziell auf Ihre Anwendungsfälle zugeschnitten sind. Im folgenden Beispiel wird die Unterklasse MatrixTransformation verwendet, um das Video in der ersten Sekunde der Wiedergabe so zu zoomen, dass es den Rahmen ausfüllt:
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();
Wenn Sie das Verhalten eines Effekts weiter anpassen möchten, implementieren Sie ein GlShaderProgram. Die Methode queueInputFrame() wird verwendet, um Eingabe-Frames zu verarbeiten. Wenn Sie beispielsweise die Funktionen für maschinelles Lernen von MediaPipe nutzen möchten, können Sie einen MediaPipe-FrameProcessor verwenden, um jeden Frame durch ein MediaPipe-Diagramm zu senden. Ein Beispiel dafür finden Sie in der Transformer-Demo-App.
Vorschau der Effekte
Mit ExoPlayer können Sie sich eine Vorschau der Effekte ansehen, die einer Mediendatei hinzugefügt wurden, bevor Sie den Exportvorgang starten. Rufen Sie setVideoEffects() für Ihre ExoPlayer-Instanz auf und verwenden Sie dazu dasselbe Effects-Objekt wie für EditedMediaItem.
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();
Sie können sich mit ExoPlayer auch eine Vorschau der Audioeffekte ansehen. Wenn Sie Ihre ExoPlayer-Instanz erstellen, übergeben Sie eine benutzerdefinierte RenderersFactory, die die Audio-Renderer des Players so konfiguriert, dass Audio an eine AudioSink ausgegeben wird, die Ihre AudioProcessor-Sequenz verwendet. Im folgenden Beispiel wird dies durch Überschreiben der Methode buildAudioSink() einer DefaultRenderersFactory erreicht.
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();
Transformation starten
Erstellen Sie zum Schluss einen Transformer, um Ihre Änderungen zu übernehmen und die resultierende Mediendatei zu exportieren.
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);
Sie können den Exportvorgang bei Bedarf auch mit
Transformer.cancel() abbrechen.
Nach Fortschrittsupdates suchen
Transformer.start wird sofort zurückgegeben und asynchron ausgeführt. Wenn Sie den
aktuellen Fortschritt einer Transformation abfragen möchten, rufen Sie
Transformer.getProgress() auf.
Diese Methode verwendet einen ProgressHolder. Wenn der Fortschrittsstatus verfügbar ist, d. h. wenn die Methode PROGRESS_STATE_AVAILABLE zurückgibt, wird der angegebene ProgressHolder mit dem aktuellen Fortschritt in Prozent aktualisiert.
Sie können auch einen Listener an Ihren Transformer anhängen, um über Abschluss- oder Fehlerereignisse benachrichtigt zu werden.