Interfejsy Transformer API w Jetpack Media3 zostały zaprojektowane tak, by zapewnić sprawną i niezawodną edycję multimediów. Transformer obsługuje wiele operacji, w tym:
- Modyfikowanie filmu za pomocą przycinania, skalowania i obracania
- 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 zastosowaniu zmian
Na tej stronie znajdziesz najważniejsze przypadki użycia omawiane przez Transformer. Więcej informacji znajdziesz w pełnych przewodnikach po narzędziu Media3 Transformer.
Rozpocznij
Aby rozpocząć, dodaj zależność do modułów Transformer, Effect i Common w Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.3.1" implementation "androidx.media3:media3-effect:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
Zastąp 1.3.1
wybraną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Ważne zajęcia
Kategoria | Cel |
---|---|
Transformer |
Rozpoczynaj i zatrzymuj przekształcenia oraz sprawdzaj aktualizacje trwającej przekształcenia. |
EditedMediaItem |
Reprezentuje element multimedialny do przetworzenia i zmiany, które mają zostać do niego zastosowane. |
Effects |
Kolekcja efektów audio i wideo. |
Skonfiguruj dane wyjściowe
Za pomocą Transformer.Builder
możesz teraz określić katalog videoMimeType
i audioMimetype
, ustawiając funkcję bez konieczności tworzenia obiektu TransformationRequest
.
Transkoduj między formatami
Poniższy kod pokazuje, jak skonfigurować obiekt Transformer
, aby zapewnić wyjście 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 nośnika wejściowego pasuje już do żądania przekształcenia audio lub wideo, Transformer automatycznie przełącza się na transmuksowanie, czyli skopiuje skompresowane próbki 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.
Ustaw tryb 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 zechcesz 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 jest taki sam jak format wyjściowy HDR. | Zmapowanie tonalnego obrazu HDR do SDR za pomocą mapera tonów OpenGL – oznacza to, że format wyjściowy będzie zapisany w SDR. |
Pomoc | Obsługiwane na poziomach API 31 i nowszych w przypadku urządzeń z koderem z obsługą FEATURE_HdrEditing . |
Obsługiwane na poziomach API 29 i nowszych. |
Błędy | Jeśli ta funkcja nie jest obsługiwana, spróbuj użyć interfejsu HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL . |
Jeśli nie jest obsługiwany, wysyła ExportException . |
Na urządzeniach, które obsługują wymagane funkcje kodowania i mają Androida 13 (poziom interfejsu API 33) lub nowszego, obiekty Transformer
umożliwiają edytowanie filmów HDR.
HDR_MODE_KEEP_HDR
to tryb domyślny 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 znacznik MediaItem
wraz z przekształceniami, które mają zostać do niego zastosowane.
Przycinanie filmu
Aby usunąć niechciane fragmenty filmu, możesz ustawić niestandardową pozycję 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 przydatnych w przypadku typowych przekształceń, takich jak:
Kategoria | Efekt |
---|---|
Presentation |
Skaluj element multimedialny według rozdzielczości lub formatu obrazu |
ScaleAndRotateTransformation |
Skaluj element multimedialny o mnożnik lub obróć element multimedialny |
Crop |
Przytnij element multimedialny do mniejszej lub większej klatki |
OverlayEffect |
Dodaj nakładkę z tekstem lub obrazem na element multimedialny. |
W przypadku efektów audio możesz dodać sekwencję instancji AudioProcessor
, która przekształci nieprzetworzone dane audio (PCM). Za pomocą ChannelMixingAudioProcessor
możesz na przykład 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 obiektu 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 podklasy MatrixTransformation
, aby powiększyć film tak, by wypełnił klatkę podczas 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
. Metoda queueInputFrame()
służy do przetwarzania ramek wejściowych. Aby na przykład wykorzystać możliwości systemów uczących się MediaPipe, możesz użyć MediaPipe FrameProcessor
do wysłania każdej klatki za pomocą wykresu MediaPipe. Możesz zobaczyć to w aplikacji demonstracyjnej Transformer.
Podgląd efektów
Korzystając z ExoPlayer, 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 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ż przetestować efekty dźwiękowe w narzędziu ExoPlayer. Podczas tworzenia instancji ExoPlayer
przekaż niestandardowy obiekt RenderersFactory
, który konfiguruje mechanizmy renderowania dźwięku w odtwarzaczu tak, aby wysyłały dźwięk do obiektu AudioSink
, który używa sekwencji AudioProcessor
. W poniższym przykładzie zastępujemy 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();
Rozpocznij przekształcanie
Na koniec utwórz plik Transformer
, aby zastosować zmiany, i zacznij eksportować wynikowy element multimedialny.
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 podobny sposób w razie potrzeby możesz anulować proces eksportowania przy użyciu Transformer.cancel()
.
Sprawdzanie aktualnych informacji o postępach
Funkcja Transformer.start
wraca natychmiast i działa asynchronicznie. Aby wysłać zapytanie o bieżący postęp przekształcenia, wywołaj Transformer.getProgress()
.
Ta metoda wymaga ProgressHolder
. Jeśli stan postępu jest dostępny, czyli jeśli metoda zwraca PROGRESS_STATE_AVAILABLE
, podana wartość ProgressHolder
zostanie zaktualizowana o bieżącą wartość procentową postępu.
Możesz też dołączyć detektor do urządzenia Transformer
, aby otrzymywać powiadomienia o zdarzeniach ukończenia lub błędów.