Einfache Videobearbeitungsanwendung mit Media3 Transformer erstellen

Die Transformer-APIs in Jetpack Media3 ermöglichen die Bearbeitung von Medien und zuverlässig sind. Transformer unterstützt eine Reihe von Vorgängen, einschließlich:

  • Videos durch Zuschneiden, Skalieren und Drehen bearbeiten
  • Effekte wie Overlays und Filter hinzufügen
  • Verarbeitung von Spezialformaten wie HDR und Zeitlupenvideo
  • Medienelement nach dem Übernehmen von Änderungen exportieren

Auf dieser Seite werden einige der wichtigsten Anwendungsfälle Transformator. Weitere Informationen finden Sie in unseren vollständigen Leitfäden Media3 Transformer.

Erste Schritte

Fügen Sie zuerst eine Abhängigkeit für die Module Transformer, Effect und Common hinzu von 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"

Ersetzen Sie 1.4.0 durch Ihre bevorzugte Version des Bibliothek. Weitere Informationen finden Sie in den Versionshinweise um die neueste Version zu sehen.

Wichtige Kurse

Klasse Zweck
Transformer Transformationen starten und stoppen und Statusaktualisierungen für eine laufende Transformation prüfen.
EditedMediaItem Stellt ein zu verarbeitendes Medienelement und die darauf anzuwendenden Änderungen dar.
Effects Eine Sammlung von Audio- und Videoeffekten.

Ausgabe konfigurieren

Mit Transformer.Builder können Sie jetzt videoMimeType und audioMimetype erstellen, indem Sie die Funktion festlegen, ohne ein TransformationRequest-Objekt.

Zwischen Formaten transcodieren

Der folgende Code zeigt, wie ein Transformer-Objekt konfiguriert wird, um H.265/AVC-Video und AAC-Audio:

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 übereinstimmt oder Videos übertragen, wechselt Transformer automatisch zu Transmuxing, d. h. vom Eingabecontainer in den Ausgabecontainer, Änderung. Dadurch werden Computing-Kosten und potenzielle Qualitätsverluste die Decodierung und Neucodierung im selben Format.

HDR-Modus festlegen

Liegt die Eingabemediendatei in einem HDR-Format vor, kannst du zwischen verschiedenen verschiedene Modi an, wie Transformer die HDR-Informationen verarbeitet. Wahrscheinlich HDR_MODE_KEEP_HDR oder HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL.

HDR_MODE_KEEP_HDR HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
Beschreibung Behalten Sie die HDR-Daten bei, das heißt, das HDR-Ausgabeformat entspricht dem HDR-Eingabeformat. Tonemap-HDR-Eingabe für SDR mit einem OpenGL Tonemapper, d. h. das Ausgabeformat ist SDR.
Support Wird auf API-Levels 31 und höher für Geräte mit einem Encoder mit FEATURE_HdrEditing-Funktion unterstützt. Wird auf API-Ebenen ab 29 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 sie nicht unterstützt wird, wird ein ExportException ausgelöst.

Auf Geräten, die die erforderlichen Codierungsfunktionen unterstützen und auf denen Android 13 ausgeführt wird (API-Level 33) oder höher können mit Transformer Objekten HDR-Videos bearbeitet werden. HDR_MODE_KEEP_HDR ist der Standardmodus beim Erstellen des Composition-Objekts. Dies wird 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

MediaItem steht für eine Audiodatei. oder Videoelement in Ihrer App. Ein EditedMediaItem sammelt MediaItem entlang mit den Transformationen, die darauf angewendet werden sollen.

Video zuschneiden

Wenn du unerwünschte Teile aus einem Video entfernen möchtest, kannst du Start und Ende selbst festlegen Positionen hinzu, indem Sie dem MediaItem einen 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 bietet eine Reihe von Videoeffekten für gängige Transformationen. Beispiel:

Klasse Effekt
Presentation Medienelement nach Auflösung oder Seitenverhältnis skalieren
ScaleAndRotateTransformation Medienelement mit einem Multiplikator skalieren und/oder drehen
Crop Medienelement auf einen kleineren oder größeren Frame zuschneiden
OverlayEffect Füge ein Text- oder Bild-Overlay über dem Medienelement hinzu.

Für Audioeffekte kannst du eine Reihe von AudioProcessor Instanzen, die die Rohaudiodaten (PCM) transformieren. So können Sie beispielsweise ChannelMixingAudioProcessor zum Mischen und Skalieren von Audiokanälen.

Um diese Effekte zu verwenden, erstelle eine Instanz des Effekts oder des Audioprozessors, erstelle eine Eine Instanz von Effects mit den Audio- und Videoeffekten, auf die du sie anwenden möchtest das Medienelement und fügen Sie dann das Effects-Objekt zu 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 du die in Media3 enthaltenen Effekte erweiterst, kannst du benutzerdefinierte Effekte erstellen die für Ihre Anwendungsfälle spezifisch sind. Verwenden Sie im folgenden Beispiel eine abgeleitete Klasse MatrixTransformation, um das Video so weit zu vergrößern, dass der Frame über dem ersten Frame ausgefüllt wird Sekunde der Wiedergabe:

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

Sie können das Verhalten eines Effekts weiter anpassen, indem Sie ein GlShaderProgram Die Die Methode queueInputFrame() wird zum Verarbeiten von Eingabeframes verwendet. Wenn Sie beispielsweise dass Sie die ML-Funktionen Ihrer MediaPipe verwenden, können Sie MediaPipe FrameProcessor um jeden Frame über ein MediaPipe-Diagramm zu senden. Ein Beispiel hierzu finden Sie in der Transformer-Demo-App

Effektvorschau ansehen

Mit ExoPlayer kannst du dir eine Vorschau der Effekte ansehen die einem Medienelement hinzugefügt werden, bevor der Exportvorgang gestartet wird. Mit denselben Effects-Objekt wie für EditedMediaItem, rufen Sie setVideoEffects() auf Ihrem ExoPlayer-Instanz.

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

Mit ExoPlayer können Sie Audioeffekte auch in der Vorschau ansehen. Bei der Erstellung eines ExoPlayer-Instanz übergeben Sie eine benutzerdefinierte RenderersFactory, die den Audio-Renderer des Players, um Audio an AudioSink auszugeben, die deine AudioProcessor-Sequenz. Im folgenden Beispiel überschreiben wir den Parameter buildAudioSink()-Methode einer 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();

Transformation starten

Erstellen Sie abschließend eine Transformer, um die Änderungen zu übernehmen und mit dem Exportieren der Ergebnis des Medienelements.

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

Auf ähnliche Weise können Sie den Exportvorgang abbrechen: Transformer.cancel()

Nach Updates suchen

Transformer.start wird sofort zurückgegeben und wird asynchron ausgeführt. Für die Abfrage des aktuellen Fortschritt einer Transformation, rufen Sie Transformer.getProgress() Diese Methode verwendet einen ProgressHolder. Wenn der Fortschrittsstatus verfügbar ist, Wenn die Methode also PROGRESS_STATE_AVAILABLE zurückgibt, ist der angegebene Wert ProgressHolder wird mit dem aktuellen Fortschrittsprozentsatz aktualisiert.

Sie können auch eine Listener an Transformer, um über Abschluss- oder Fehlerereignisse benachrichtigt zu werden.