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:
- Videos durch Zuschneiden, Skalieren und Drehen bearbeiten
- Effekte wie Overlays und Filter hinzufügen
- Verarbeitung von Spezialformaten wie HDR und Zeitlupe
- Exportieren eines Medienelements nach dem Anwenden von Änderungen
Auf dieser Seite werden Sie durch einige der wichtigsten Anwendungsfälle von Transformer geführt. Weitere Informationen finden Sie in unseren vollständigen Leitfäden zu Media3 Transformer.
Erste Schritte
Fügen Sie zunächst eine Abhängigkeit von den Modulen Transformer, Effect und allgemeinen Jetpack Media3-Modulen hinzu:
implementation "androidx.media3:media3-transformer:1.3.1" implementation "androidx.media3:media3-effect:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
Ersetzen Sie 1.3.1
durch Ihre bevorzugte Version der Bibliothek. Die neueste Version finden Sie in den Versionshinweisen.
Wichtige Klassen
Klasse | Zweck |
---|---|
Transformer |
Starten und stoppen Sie Transformationen und prüfen Sie, ob Updates zum Fortschritt einer laufenden Transformation vorliegen. |
EditedMediaItem |
Stellt ein zu verarbeitendes Medienelement und die Änderungen dar, die darauf angewendet werden sollen. |
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.
Zwischen Formaten transcodieren
Der folgende Code zeigt, wie ein Transformer
-Objekt für die Ausgabe von H.265/AVC-Video und AAC-Audio konfiguriert wird:
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 zu Transmuxing, d. h., die komprimierten Samples werden unverändert aus dem Eingabecontainer in den Ausgabecontainer kopiert. Dadurch werden die Rechenkosten und der potenzielle Qualitätsverlust bei der Decodierung und Neucodierung im selben Format vermieden.
HDR-Modus festlegen
Wenn die Eingabemediendatei ein HDR-Format hat, können Sie zwischen verschiedenen Modi für die Verarbeitung der HDR-Informationen durch Transformer wählen. Sie sollten 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 | Behalten Sie die HDR-Daten bei. Das HDR-Ausgabeformat entspricht also dem HDR-Eingabeformat. | Die Tonemap-HDR-Eingabe für SDR über einen OpenGL Tone-Mapper, d. h. das Ausgabeformat erfolgt im SDR. |
Support | Wird auf API-Level 31 und höher für Geräte unterstützt, die einen Encoder mit der FEATURE_HdrEditing -Funktion enthalten. |
Wird auf API-Levels 29 und höher unterstützt. |
Fehler | Wenn die Funktion nicht unterstützt wird, wird versucht, stattdessen HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL zu verwenden. |
Wenn diese Funktion nicht unterstützt wird, wird ein ExportException ausgelöst. |
Auf Geräten, die die erforderlichen Codierungsfunktionen unterstützen und Android 13 (API-Level 33) oder höher ausführen, kannst du mit Transformer
-Objekten HDR-Videos bearbeiten.
HDR_MODE_KEEP_HDR
ist der Standardmodus beim Erstellen des Composition
-Objekts, wie im folgenden Code dargestellt:
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();
Medienelement vorbereiten
Ein MediaItem
steht für ein Audio- oder Videoelement in Ihrer App. Ein EditedMediaItem
erfasst ein MediaItem
zusammen mit den Transformationen, die darauf angewendet werden sollen.
Video zuschneiden
Wenn du unerwünschte Teile eines Videos entfernen möchtest, kannst du benutzerdefinierte Start- und Endpositionen festlegen, indem du eine ClippingConfiguration
zum MediaItem
hinzufügst.
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 bietet eine Reihe von integrierten Videoeffekten für gängige Transformationen, z. B.:
Klasse | Effekt |
---|---|
Presentation |
Medienelement nach Auflösung oder Seitenverhältnis skalieren |
ScaleAndRotateTransformation |
Skalieren Sie das Medienelement um einen Multiplikator und/oder drehen Sie es. |
Crop |
Medienelement auf einen kleineren oder größeren Frame zuschneiden |
OverlayEffect |
Fügen Sie dem Medienelement ein Text- oder Bild-Overlay hinzu. |
Für Audioeffekte können Sie eine Abfolge von AudioProcessor
-Instanzen hinzufügen, die die PCM-Audiodaten (Rohdaten) transformieren. Sie können beispielsweise ChannelMixingAudioProcessor
verwenden, um Audiokanäle zu mischen und zu skalieren.
Um diese Effekte zu verwenden, erstellen Sie eine Instanz des Effekts oder Audioprozessors, erstellen Sie eine Instanz von Effects
mit den Audio- und Videoeffekten, die Sie auf das Medienelement anwenden möchten, und fügen Sie dann das Effects
-Objekt 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
Wenn Sie die in Media3 enthaltenen Effekte erweitern, können Sie benutzerdefinierte Effekte erstellen, die für Ihre Anwendungsfälle spezifisch sind. Verwenden Sie im folgenden Beispiel die abgeleitete Klasse MatrixTransformation
, um das Video so zu vergrößern, dass es den Frame nach der ersten Wiedergabesekunde 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();
Implementieren Sie GlShaderProgram
, um das Verhalten eines Effekts weiter anzupassen. Die Methode queueInputFrame()
wird zum Verarbeiten von Eingabeframes verwendet. Wenn Sie beispielsweise die ML-Funktionen von MediaPipe nutzen möchten, können Sie mit einer MediaPipe FrameProcessor
jeden Frame über eine MediaPipe-Grafik senden. Ein Beispiel hierfür finden Sie in der Transformer-Demo-App.
Effekte in der Vorschau ansehen
Mit ExoPlayer können Sie sich eine Vorschau der Effekte ansehen, die einem Medienelement hinzugefügt wurden, bevor Sie den Exportvorgang starten. Verwenden Sie dasselbe Effects
-Objekt wie für EditedMediaItem
und rufen Sie setVideoEffects()
in der ExoPlayer-Instanz auf.
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 Audioeffekte auch mit ExoPlayer in der Vorschau ansehen. Übergeben Sie beim Erstellen Ihrer ExoPlayer
-Instanz ein benutzerdefiniertes RenderersFactory
-Element, mit dem die Audio-Renderer des Players so konfiguriert werden, dass Audioinhalte an ein AudioSink
-Element ausgegeben werden, in dem Ihre AudioProcessor
-Sequenz verwendet wird. Im folgenden Beispiel wird die Methode buildAudioSink()
einer DefaultRenderersFactory
überschrieben.
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 abschließend eine Transformer
, um Ihre Änderungen zu übernehmen und mit dem Exportieren des resultierenden Medienelements zu beginnen.
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);
Bei Bedarf können Sie den Export mit Transformer.cancel()
abbrechen.
Auf Updates zum Fortschritt prüfen
Transformer.start
gibt sofort etwas zurück und wird asynchron ausgeführt. Rufen Sie Transformer.getProgress()
auf, um den aktuellen Fortschritt einer Transformation abzufragen.
Diese Methode verwendet ein ProgressHolder
. Wenn der Fortschrittsstatus verfügbar ist, d. h. wenn die Methode PROGRESS_STATE_AVAILABLE
zurückgibt, wird die angegebene ProgressHolder
mit dem aktuellen Fortschrittsprozentsatz aktualisiert.
Sie können Ihrem Transformer
auch einen Listener hinzufügen, um bei Abschluss- oder Fehlerereignissen benachrichtigt zu werden.