Interfejsy API Transformer w Jetpack Media3 zostały zaprojektowane tak, aby edycja multimediów była wydajna i niezawodna. Transformer obsługuje wiele operacji, m.in.:
- Modyfikowanie filmu przez przycinanie, skalowanie i obracanie
- dodawanie efektów, takich jak nakładki i filtry;
- przetwarzanie specjalnych formatów, takich jak HDR i filmy w zwolnionym tempie;
- Eksportowanie elementu multimedialnego po wprowadzeniu zmian
Na tej stronie znajdziesz opis niektórych kluczowych zastosowań modelu Transformer. Więcej informacji znajdziesz w naszych pełnych przewodnikach dotyczących Media3 Transformer.
Rozpocznij
Aby rozpocząć, dodaj zależność od modułów Transformer, Effect i Common Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.8.0" implementation "androidx.media3:media3-effect:1.8.0" implementation "androidx.media3:media3-common:1.8.0"
Zastąp 1.8.0 preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Ważne klasy
| Kategoria | Cel |
|---|---|
Transformer |
rozpoczynać i zatrzymywać przekształcenia oraz sprawdzać postępy w przekształcaniu; |
EditedMediaItem |
Reprezentuje element multimedialny do przetworzenia i zmiany, które mają zostać w nim wprowadzone. |
Effects |
Zbiór efektów audio i wideo. |
Konfigurowanie danych wyjściowych
Dzięki Transformer.Builder możesz teraz określić videoMimeType i audioMimetype katalog, ustawiając funkcję bez konieczności tworzenia obiektu TransformationRequest.
Transkodowanie między formatami
Poniższy kod pokazuje, jak skonfigurować obiekt Transformer, aby generować wideo H.265/AVC i dźwięk 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();
Jeśli format wejściowego pliku multimedialnego jest zgodny z żądaniem przekształcenia w przypadku dźwięku lub filmu, Transformer automatycznie przełącza się na transmuksowanie, czyli kopiowanie skompresowanych próbek z kontenera wejściowego do kontenera wyjściowego bez modyfikacji. Pozwala to uniknąć kosztów obliczeniowych i potencjalnej utraty jakości związanej z dekodowaniem i ponownym kodowaniem w tym samym formacie.
Ustawianie trybu HDR
Jeśli wejściowy plik multimedialny jest w formacie HDR, możesz wybrać jeden z kilku różnych trybów przetwarzania informacji HDR przez Transformer. Prawdopodobnie chcesz użyć HDR_MODE_KEEP_HDR lub HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
|---|---|---|
| Opis | Zachowaj dane HDR, co oznacza, że format wyjściowy HDR jest taki sam jak format wejściowy HDR. | Mapowanie tonów z HDR na SDR za pomocą mapowania tonów OpenGL, co oznacza, że format wyjściowy będzie SDR. |
| Pomoc | Obsługiwane na urządzeniach z interfejsem API na poziomie 31 lub wyższym, które mają koder z funkcją FEATURE_HdrEditing. |
Obsługiwane na poziomach API 29 i nowszych. |
| Błędy | Jeśli nie jest obsługiwany, próbuje użyć HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL. |
Jeśli nie jest obsługiwana, zgłasza ExportException. |
Na urządzeniach, które obsługują wymagane możliwości kodowania i mają Androida 13 (poziom API 33) lub nowszego, obiekty Transformer umożliwiają edytowanie filmów HDR.
HDR_MODE_KEEP_HDR to domyślny tryb podczas tworzenia obiektu Composition, jak pokazano w tym kodzie:
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();
Przygotowywanie elementu multimedialnego
MediaItem reprezentuje element audio lub wideo w aplikacji. EditedMediaItem zbiera MediaItem wraz z przekształceniami, które mają być do niego zastosowane.
Przycinanie filmu
Aby usunąć niechciane fragmenty filmu, możesz ustawić niestandardowe pozycje początkową i końcową, dodając ClippingConfiguration do 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();
Korzystanie z wbudowanych efektów
Media3 zawiera wiele wbudowanych efektów wideo do typowych przekształceń, np.:
| Kategoria | Efekt |
|---|---|
Presentation |
Skalowanie elementu multimedialnego według rozdzielczości lub formatu obrazu |
ScaleAndRotateTransformation |
Skalowanie elementu multimedialnego za pomocą mnożnika lub obracanie go |
Crop |
Przycinanie elementu multimedialnego do mniejszej lub większej ramki |
OverlayEffect |
Dodaj tekst lub obraz na wierzchu elementu multimedialnego. |
W przypadku efektów audio możesz dodać sekwencję AudioProcessor instancji, które przekształcą surowe dane audio (PCM). Możesz na przykład użyć ChannelMixingAudioProcessor, aby miksować i skalować kanały audio.
Aby użyć tych efektów, utwórz instancję efektu lub procesora audio, a następnie instancję Effects z efektami audio i wideo, które chcesz zastosować do elementu multimedialnego. Potem dodaj obiekt Effects do 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();
Tworzenie efektów niestandardowych
Rozszerzając efekty dostępne w Media3, możesz tworzyć efekty niestandardowe dostosowane do Twoich potrzeb. W tym przykładzie użyj subclass
MatrixTransformation, aby powiększyć film i wypełnić kadr w ciągu pierwszej
sekundy odtwarzania:
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();
Aby jeszcze bardziej dostosować działanie efektu, zaimplementuj GlShaderProgram. Do przetwarzania klatek wejściowych używana jest metoda queueInputFrame(). Aby na przykład wykorzystać możliwości uczenia maszynowego MediaPipe, możesz użyć FrameProcessor MediaPipe do przesyłania każdej klatki przez wykres MediaPipe. Przykład znajdziesz w aplikacji demonstracyjnej Transformer.
Podgląd efektów
W ExoPlayerze możesz wyświetlić podgląd efektów dodanych do elementu multimedialnego przed rozpoczęciem procesu eksportowania. Używając tego samego obiektu Effects co w przypadku EditedMediaItem, wywołaj setVideoEffects() w instancji ExoPlayera.
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();
Możesz też wyświetlić podgląd efektów audio w ExoPlayerze. Podczas tworzenia instancji ExoPlayer przekaż niestandardowy obiekt RenderersFactory, który konfiguruje renderery audio odtwarzacza, aby przesyłać dźwięk do obiektu AudioSink korzystającego z sekwencji AudioProcessor. W przykładzie poniżej robimy to, zastępując metodę buildAudioSink() klasy 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();
Rozpoczynanie przekształcenia
Na koniec kliknij Transformer, aby zastosować zmiany i rozpocząć eksportowanie wynikowego elementu multimedialnego.
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);
W razie potrzeby możesz też anulować proces eksportu, klikając Transformer.cancel().
Sprawdzanie aktualizacji postępów
Transformer.start zwraca wartość natychmiast i działa asynchronicznie. Aby wysłać zapytanie o bieżący postęp przekształcenia, wywołaj funkcję
Transformer.getProgress().
Ta metoda przyjmuje wartość ProgressHolder, a jeśli stan postępu jest dostępny, tzn. jeśli metoda zwraca wartość PROGRESS_STATE_AVAILABLE, podana wartość ProgressHolder zostanie zaktualizowana o bieżący procent postępu.
Możesz też dołączyć odbiornik do Transformer, aby otrzymywać powiadomienia o zakończeniu lub błędach.