Transformer API di Jetpack Media3 dirancang untuk membuat pengeditan media berperforma tinggi dan andal. Transformer mendukung sejumlah operasi, termasuk:
- Memodifikasi video dengan memangkas, menskalakan, dan memutar
- Menambahkan efek seperti overlay dan filter
- Memproses format khusus seperti video HDR dan video slow-motion
- Mengekspor item media setelah menerapkan pengeditan
Halaman ini akan memandu Anda memahami beberapa kasus penggunaan utama yang dicakup oleh Transformer. Untuk mengetahui detail selengkapnya, Anda dapat membuka panduan lengkap kami tentang Media3 Transformer.
Mulai
Untuk memulai, tambahkan dependensi pada modul Transformer, Effect, dan Common 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")
Groovy
implementation "androidx.media3:media3-transformer:1.11.1"
implementation "androidx.media3:media3-effect:1.11.1"
implementation "androidx.media3:media3-common:1.11.1"
Pastikan untuk mengganti 1.11.1 dengan versi library pilihan Anda. Anda dapat melihat catatan rilis untuk mengetahui versi terbaru.
Class penting
| Class | Tujuan |
|---|---|
Transformer |
Memulai dan menghentikan transformasi serta memeriksa update progres pada transformasi yang sedang berjalan. |
EditedMediaItem |
Merepresentasikan item media yang akan diproses dan pengeditan yang akan diterapkan ke item tersebut. |
Effects |
Kumpulan efek audio dan video. |
Mengonfigurasi output
Dengan Transformer.Builder, Anda kini dapat menentukan videoMimeType dan
audioMimetype secara langsung dengan menyetel fungsi tanpa perlu membuat
objek TransformationRequest.
Melakukan transcoding antar-format
Kode berikut menunjukkan cara mengonfigurasi objek Transformer untuk menghasilkan
video H.265/AVC dan audio 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();
Jika format media input sudah cocok dengan permintaan transformasi untuk audio atau video, Transformer akan otomatis beralih ke transmuxing, yaitu menyalin sampel yang dikompresi dari penampung input ke penampung output tanpa modifikasi. Hal ini menghindari biaya komputasi dan potensi penurunan kualitas akibat dekode dan encoding ulang dalam format yang sama.
Menyetel mode HDR
Jika file media input dalam format HDR, Anda dapat memilih di antara beberapa
mode berbeda untuk cara Transformer memproses informasi HDR. Anda mungkin ingin menggunakan HDR_MODE_KEEP_HDR atau HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
|---|---|---|
| Deskripsi | Mempertahankan data HDR, yang berarti format output HDR sama dengan format input HDR. | Memetakan tone input HDR ke SDR menggunakan pemeta tone OpenGL, yang berarti format output akan dalam SDR. |
| Dukungan | Didukung di level API 31+ untuk perangkat yang menyertakan encoder dengan kapabilitas FEATURE_HdrEditing. |
Didukung di level API 29+. |
| Error | Jika tidak didukung, coba gunakan HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL. |
Jika tidak didukung, menampilkan ExportException. |
Pada perangkat yang mendukung kapabilitas encoding yang diperlukan dan menjalankan Android 13
(level API 33) atau yang lebih tinggi, objek Transformer memungkinkan Anda mengedit video HDR.
HDR_MODE_KEEP_HDR adalah mode default saat mem-build objek Composition,
seperti yang ditunjukkan dalam kode berikut:
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();
Menyiapkan item media
MediaItem mewakili item audio atau video di aplikasi Anda. EditedMediaItem mengumpulkan MediaItem beserta transformasi yang akan diterapkan
padanya.
Memangkas video
Untuk menghapus bagian video yang tidak diinginkan, Anda dapat menetapkan posisi awal dan akhir kustom dengan menambahkan ClippingConfiguration ke 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();
Menggunakan efek bawaan
Media3 menyertakan sejumlah efek video bawaan untuk transformasi umum, misalnya:
| Class | Efek |
|---|---|
Presentation |
Menskalakan item media berdasarkan resolusi atau rasio aspek |
ScaleAndRotateTransformation |
Menskalakan item media dengan pengali dan/atau memutar item media |
Crop |
Memangkas item media ke bingkai yang lebih kecil atau lebih besar |
OverlayEffect |
Menambahkan overlay teks atau gambar di atas item media |
Untuk efek audio, Anda dapat menambahkan urutan instance AudioProcessor yang
akan mengubah data audio mentah (PCM). Misalnya, Anda dapat menggunakan
ChannelMixingAudioProcessor untuk menggabungkan dan menskalakan saluran audio.
Untuk menggunakan efek ini, buat instance efek atau pemroses audio, buat
instance Effects dengan efek audio dan video yang ingin Anda terapkan ke
item media, lalu tambahkan objek Effects ke 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();
Membuat efek kustom
Dengan memperluas efek yang disertakan dalam Media3, Anda dapat membuat efek kustom
khusus untuk kasus penggunaan Anda. Dalam contoh berikut, gunakan subclass
MatrixTransformation untuk memperbesar video agar memenuhi frame selama detik pertama
pemutaran:
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();
Untuk menyesuaikan perilaku efek lebih lanjut, terapkan GlShaderProgram.
Metode queueInputFrame() digunakan untuk memproses frame input. Misalnya, untuk
memanfaatkan kemampuan machine learning MediaPipe, Anda dapat menggunakan
FrameProcessor MediaPipe untuk mengirim setiap frame melalui grafik
MediaPipe. Lihat contohnya di aplikasi demo Transformer.
Melihat pratinjau efek
Dengan ExoPlayer, Anda dapat melihat pratinjau efek yang ditambahkan ke item media sebelum
memulai proses ekspor. Dengan menggunakan objek Effect yang sama seperti untuk
EditedMediaItem, panggil setVideoEffects() pada instance ExoPlayer Anda.
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();
Anda juga dapat melihat pratinjau efek audio dengan ExoPlayer. Saat mem-build instance ExoPlayer, teruskan RenderersFactory kustom yang mengonfigurasi perender audio pemutar untuk menghasilkan output audio ke AudioSink yang menggunakan urutan AudioProcessor Anda. Pada contoh di bawah, kita melakukannya dengan mengganti
metode buildAudioSink() dari 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();
Memulai transformasi
Terakhir, buat Transformer untuk menerapkan pengeditan dan mulai mengekspor
item media yang dihasilkan.
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);
Anda juga dapat membatalkan proses ekspor jika diperlukan dengan
Transformer.cancel().
Memeriksa info terbaru tentang progres
Transformer.start akan segera ditampilkan dan berjalan secara asinkron. Untuk mengkueri
progres transformasi saat ini, panggil Transformer.getProgress(). Metode
ini menggunakan ProgressHolder, dan jika status progres tersedia, yaitu, jika metode menampilkan PROGRESS_STATE_AVAILABLE, maka ProgressHolder
yang disediakan akan diperbarui dengan persentase progres saat ini.
Anda juga dapat melampirkan pemroses ke Transformer untuk mendapatkan notifikasi tentang peristiwa penyelesaian atau error.