Interfejsy API Transformer w Jetpack Media3 zostały zaprojektowane tak, aby edycja multimediów była wydajna i niezawodna. Transformer obsługuje wiele operacji, w tym:
- modyfikowanie filmu przez przycinanie, skalowanie i obracanie;
- dodawanie efektów, takich jak nakładki i filtry;
- przetwarzanie formatów specjalnych, takich jak HDR i filmy w zwolnionym tempie;
- eksportowanie elementu multimedialnego po zastosowaniu zmian.
Na tej stronie znajdziesz opis niektórych najważniejszych przypadków użycia obsługiwanych przez Transformer. Więcej informacji znajdziesz w pełnych przewodnikach dotyczących Media3 Transformer.
Rozpoczęcie
Aby rozpocząć, dodaj zależność od modułów Transformer, Effect i Common w Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.10.0" implementation "androidx.media3:media3-effect:1.10.0" implementation "androidx.media3:media3-common:1.10.0"
Pamiętaj, aby zastąpić 1.10.0 preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w
informacjach o wersji.
Ważne klasy
| Zajęcia | Cel |
|---|---|
Transformer |
Uruchamianie i zatrzymywanie transformacji oraz sprawdzanie postępów w trakcie transformacji. |
EditedMediaItem |
Reprezentuje element multimedialny do przetworzenia i zmiany, które mają zostać zastosowane. |
Effects |
Zbiór efektów audio i wideo. |
Konfigurowanie danych wyjściowych
Za pomocą Transformer.Builder możesz teraz określić katalog videoMimeType i audioMimetype, 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 multimediów wejściowych jest zgodny z żądaniem transformacji audio lub wideo, 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 trybów przetwarzania informacji HDR przez Transformer. Prawdopodobnie będziesz używać trybu 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 wyjściowy format HDR jest taki sam jak wejściowy format HDR. | Mapowanie tonów z wejściowego formatu HDR na SDR za pomocą mapowania tonów OpenGL, co oznacza, że format wyjściowy będzie w formacie 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 urządzeniach z interfejsem API na poziomie 29 lub wyższym. |
| Błędy | Jeśli nie jest obsługiwany, zamiast tego próbuje użyć HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL. |
Jeśli nie jest obsługiwany, zgłasza wyjątek ExportException. |
Na urządzeniach, które obsługują wymagane funkcje kodowania i działają pod kontrolą Androida 13 (API na poziomie 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 transformacjami, które mają zostać zastosowane.
Przycinanie filmu
Aby usunąć niechciane fragmenty filmu, możesz ustawić niestandardowe pozycje początkowe i końcowe, 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();
Używanie wbudowanych efektów
Media3 zawiera kilka wbudowanych efektów wideo do typowych transformacji, np.:
| Zajęcia | Efekt |
|---|---|
Presentation |
Skalowanie elementu multimedialnego według rozdzielczości lub proporcji |
ScaleAndRotateTransformation |
Skalowanie elementu multimedialnego przez mnożnik lub obracanie elementu multimedialnego |
Crop |
Przycinanie elementu multimedialnego do mniejszej lub większej ramki |
OverlayEffect |
Dodawanie nakładki tekstowej lub graficznej na element multimedialny |
W przypadku efektów dźwiękowych 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, utwórz instancję Effects z efektami audio i wideo, które chcesz zastosować do elementu multimedialnego, a następnie 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 zawarte w Media3, możesz tworzyć efekty niestandardowe dostosowane do Twoich przypadków użycia. W tym przykładzie użyj podklasy MatrixTransformation, aby powiększyć film tak, aby wypełniał ramkę 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 a
GlShaderProgram. Metoda queueInputFrame() służy do przetwarzania klatek wejściowych. Aby na przykład wykorzystać możliwości uczenia maszynowego
MediaPipe, możesz użyć
MediaPipe FrameProcessor
aby wysyłać każdą klatkę przez wykres MediaPipe. Przykład znajdziesz w
aplikacji w wersji demonstracyjnej Transformer.
Podgląd efektów
W ExoPlayer możesz wyświetlić podgląd efektów
dodanych do elementu multimedialnego przed rozpoczęciem procesu eksportu. Używając tego samego
Effects obiektu co w przypadku EditedMediaItem, wywołaj setVideoEffects() w instancji
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();
Możesz też wyświetlić podgląd efektów dźwiękowych w ExoPlayer. Podczas tworzenia instancji ExoPlayer przekaż niestandardową RenderersFactory, która konfiguruje renderery audio odtwarzacza tak, aby generowały dźwięk do AudioSink, który używa sekwencji AudioProcessor. W poniższym przykładzie robimy to, zastępując metodę buildAudioSink() w 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 transformacji
Na koniec utwórz 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 za pomocą
Transformer.cancel().
Sprawdzanie postępów
Transformer.start zwraca wartość natychmiast i działa asynchronicznie. Aby sprawdzić
bieżący postęp transformacji, wywołaj
Transformer.getProgress().
Ta metoda przyjmuje ProgressHolder, a jeśli stan postępu jest dostępny, czyli jeśli metoda zwraca PROGRESS_STATE_AVAILABLE, podany ProgressHolder zostanie zaktualizowany o bieżący procent postępu.
Możesz też dołączyć
detektor
do Transformer, aby otrzymywać powiadomienia o zdarzeniach zakończenia lub błędach.