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.
Pierwsze kroki
Aby rozpocząć, dodaj zależność od modułów Transformer, Effect i Common w Jetpack Media3:
Kotlin
implementation("androidx.media3:media3-transformer:1.11.0")
implementation("androidx.media3:media3-effect:1.11.0")
implementation("androidx.media3:media3-common:1.11.0")
Dynamiczny
implementation "androidx.media3:media3-transformer:1.11.0"
implementation "androidx.media3:media3-effect:1.11.0"
implementation "androidx.media3:media3-common:1.11.0"
Pamiętaj, aby zastąpić 1.11.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ć videoMimeType i audioMimetype bezpośrednio, ustawiając funkcję bez konieczności tworzenia obiektu TransformationRequest.
Transkodowanie między formatami
Poniższy kod pokazuje, jak skonfigurować obiekt Transformer, aby generował obraz 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ć 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. | Mapuj tony wejściowego obrazu HDR na SDR za pomocą mapowania tonów OpenGL, co oznacza, że format wyjściowy będzie w 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ługiwane, zamiast tego próbuje użyć HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL. |
Jeśli nieobsługiwane, zgłasza ExportException. |
Na urządzeniach, które obsługują wymagane funkcje kodowania i działają w systemie Android 13 (API na poziomie 33) lub nowszym, 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. An
EditedMediaItem zbiera MediaItem wraz z transformacjami, które mają zostać zastosowane
do niego.
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 wiele 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 według mnożnika lub obracanie elementu multimedialnego. |
Crop |
Przycinanie elementu multimedialnego do mniejszej lub większej klatki. |
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 swoich przypadków użycia. W tym przykładzie użyj podklasy MatrixTransformation, aby powiększyć film tak, aby wypełniał klatkę 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.
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 tych samych Effect obiektów co w przypadku
EditedMediaItem, wywołaj setVideoEffects() w instancji ExoPlayer.
Kotlin
val player = ExoPlayer.Builder(context)
.build()
.also { exoPlayer ->
exoPlayer.setMediaItem(inputMediaItem)
exoPlayer.setVideoEffects(listOf(zoomEffect))
exoPlayer.prepare()
}
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
player.setMediaItem(inputMediaItem);
player.setVideoEffects(ImmutableList.of(zoomEffect));
player.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żące postępy transformacji, wywołaj Transformer.getProgress(). Ta metoda przyjmuje ProgressHolder. Jeśli stan postępu jest dostępny, czyli metoda zwraca PROGRESS_STATE_AVAILABLE, podany ProgressHolder zostanie zaktualizowany o bieżący procent postępu.
Możesz też dołączyć do Transformer słuchacza, aby otrzymywać powiadomienia o
zdarzeniach zakończenia lub błędach.