Interfejsy Transformer API w Jetpack Media3 zostały zaprojektowane tak, aby edytowanie multimediów było wydajne i niezawodne. Transformer obsługuje wiele operacji, w tym:
- 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 zastosowaniu zmian
Na tej stronie znajdziesz kilka najważniejszych przypadków użycia, które obejmuje Transformer. Więcej informacji znajdziesz w naszych pełnych przewodnikach po Media3 Transformer.
Rozpocznij
Aby rozpocząć, dodaj zależność od modułów Transformer, Effect i Common biblioteki Jetpack Media3:
Kotlin
implementation("androidx.media3:media3-transformer:1.11.1")
implementation("androidx.media3:media3-effect:1.11.1")
implementation("androidx.media3:media3-common:1.11.1")
Dynamiczny
implementation "androidx.media3:media3-transformer:1.11.1"
implementation "androidx.media3:media3-effect:1.11.1"
implementation "androidx.media3:media3-common:1.11.1"
Zastąp 1.11.1 preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Ważne zajęcia
| Klasa | Cel |
|---|---|
Transformer |
Uruchamiaj i zatrzymuj przekształcenia oraz sprawdzaj postępy uruchomionego przekształcenia. |
EditedMediaItem |
Reprezentuje element multimedialny do przetworzenia i zmiany, które należy w nim wprowadzić. |
Effects |
Zbiór efektów audio i wideo. |
Konfigurowanie danych wyjściowych
Dzięki Transformer.Builder możesz teraz określać videoMimeType i audioMimetype bezpośrednio przez ustawienie funkcji, 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 wejściowy multimediów jest już zgodny z żądaniem przekształcenia dźwięku lub obrazu, 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 | zachować dane HDR, co oznacza, że format wyjściowy HDR jest taki sam jak format wejściowy HDR; | Mapowanie tonalne danych wejściowych HDR na SDR za pomocą mapowania tonalnego OpenGL, co oznacza, że format wyjściowy będzie w SDR. |
| Pomoc | Obsługiwane na poziomie interfejsu API 31 i nowszych na urządzeniach z koderem z funkcją FEATURE_HdrEditing. |
Obsługiwane na interfejsach API na poziomie 29 lub wyższym. |
| 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ługiwany, zgłasza błąd ExportException. |
Na urządzeniach, które obsługują wymagane funkcje kodowania i mają 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 przekształceniami, które mają zostać do niego zastosowane.
Przycinanie filmu
Aby usunąć niechciane fragmenty filmu, możesz ustawić niestandardowe pozycje początku i końca, 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 szereg wbudowanych efektów wideo do typowych przekształceń, takich jak:
| Klasa | Efekt |
|---|---|
Presentation |
Skalowanie elementu multimedialnego według rozdzielczości lub formatu obrazu |
ScaleAndRotateTransformation |
skalowanie elementu multimedialnego przez mnożnik lub obracanie elementu multimedialnego, |
Crop |
przyciąć element multimedialny do mniejszej lub większej ramki, |
OverlayEffect |
dodawać nakładkę z tekstem lub obrazem na elemencie multimedialnym; |
W przypadku efektów dźwiękowych możesz dodać sekwencję instancji AudioProcessor, które przekształcą nieprzetworzone dane audio (PCM). Możesz na przykład użyć ChannelMixingAudioProcessor do miksowania i skalowania kanałów audio.
Aby użyć tych efektów, utwórz instancję efektu lub procesora dźwięku, utwórz instancję Effects z efektami dźwiękowymi i wizualnymi, 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ć niestandardowe efekty dostosowane do Twoich przypadków użycia. W tym przykładzie użyj podklasy MatrixTransformation, aby powiększyć film i wypełnić kadr w pierwszej sekundzie 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 dostosować działanie efektu, zaimplementuj GlShaderProgram.
Do przetwarzania klatek wejściowych służy metoda queueInputFrame(). Aby na przykład wykorzystać możliwości uczenia maszynowego MediaPipe, możesz użyć FrameProcessor MediaPipe do wysyłania każdej klatki przez wykres MediaPipe. Przykład znajdziesz w aplikacji demonstracyjnej Transformer.
Podgląd efektów
Dzięki ExoPlayer możesz wyświetlić podgląd efektów dodanych do elementu multimedialnego przed rozpoczęciem procesu eksportowania. Używając tych samych obiektów Effect 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świetlać podgląd efektów dźwiękowych za pomocą ExoPlayera. Podczas tworzenia instancji ExoPlayer przekaż niestandardowy obiekt RenderersFactory, który konfiguruje renderery dźwięku odtwarzacza tak, aby odtwarzały dźwięk w obiekcie AudioSink, który używa sekwencji AudioProcessor. W przykładzie poniżej robimy to, zastępując metodę buildAudioSink() obiektu 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 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 eksportowania, używając polecenia Transformer.cancel().
Sprawdzanie postępów
Transformer.start zwraca wynik natychmiast i działa asynchronicznie. Aby sprawdzić bieżący postęp przekształcania, wywołaj Transformer.getProgress(). Ta metoda przyjmuje parametr ProgressHolder. Jeśli stan postępu jest dostępny, czyli metoda zwraca wartość PROGRESS_STATE_AVAILABLE, podany parametr ProgressHolder zostanie zaktualizowany o bieżący procent postępu.
Możesz też dołączyć detektor do obiektu Transformer, aby otrzymywać powiadomienia o zakończeniu lub błędach.