Membuat aplikasi pengeditan video dasar menggunakan Transformer Media3

Transformer API di Jetpack Media3 dirancang untuk membuat pengeditan media berperforma tinggi dan andal. Transformer mendukung sejumlah operasi, termasuk:

  • Mengubah video dengan memangkas, menskalakan, dan memutar
  • Menambahkan efek seperti overlay dan filter
  • Memproses format khusus seperti HDR dan video gerak lambat
  • Mengekspor item media setelah menerapkan hasil edit

Halaman ini akan memandu Anda melalui beberapa kasus penggunaan utama yang dicakup oleh Transformator. Untuk detail lebih lanjut, Anda dapat membuka panduan lengkap kami di Transformer Media3.

Memulai

Untuk memulai, tambahkan dependensi pada modul Transformer, Effect, dan Common dari Jetpack Media3:

implementation "androidx.media3:media3-transformer:1.4.1"
implementation "androidx.media3:media3-effect:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"

Pastikan untuk mengganti 1.4.1 dengan versi versi pilihan Anda library. Anda dapat merujuk ke catatan rilis untuk melihat versi terbaru.

Class penting

Class Tujuan
Transformer Memulai dan menghentikan transformasi serta memeriksa pembaruan progres pada transformasi yang sedang berjalan.
EditedMediaItem Mewakili item media yang akan diproses dan hasil edit yang akan diterapkan pada item tersebut.
Effects Kumpulan efek audio dan video.

Mengonfigurasi output

Dengan Transformer.Builder, Anda kini dapat menentukan videoMimeType dan audioMimetype 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 otomatis beralih ke transmuxing, yaitu menyalin sampel terkompresi dari container input ke container output tanpa modifikasi. Hal ini menghindari biaya komputasi dan potensi hilangnya kualitas decoding dan pengkodean ulang dalam format yang sama.

Setel mode HDR

Jika file media input menggunakan format HDR, Anda dapat memilih antara beberapa berbagai mode 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, artinya format output HDR sama dengan format input HDR. Memetakan input HDR ke SDR menggunakan tone-mapper OpenGL, yang berarti format output akan berada dalam SDR.
Dukungan Didukung pada level API 31 ke atas untuk perangkat yang menyertakan encoder dengan kemampuan FEATURE_HdrEditing. Didukung pada API level 29+.
Error Jika tidak didukung, coba gunakan HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL sebagai gantinya. Jika tidak didukung, tampilkan ExportException.

Di perangkat yang mendukung kemampuan encoding yang diperlukan dan menjalankan Android 13 (API level 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 pada 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 audio atau item video di aplikasi Anda. EditedMediaItem mengumpulkan MediaItem bersama transformasi yang dapat diterapkan padanya.

Memangkas video

Untuk menghapus bagian video yang tidak diinginkan, Anda dapat menyetel awal dan akhir kustom posisi 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();

Gunakan 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 pengganda 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 rangkaian AudioProcessor yang akan mentransformasikan data audio mentah (PCM). Misalnya, Anda dapat menggunakan ChannelMixingAudioProcessor untuk mencampur dan menskalakan saluran audio.

Untuk menggunakan efek ini, buat instance efek atau prosesor audio, bangun instance Effects dengan efek audio dan video yang ingin Anda terapkan 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();

Buat efek kustom

Dengan memperluas efek yang disertakan dalam Media3, Anda dapat membuat efek kustom khusus untuk kasus penggunaan Anda. Pada contoh berikut, gunakan subclass MatrixTransformation untuk memperbesar video agar memenuhi frame lebih dari yang pertama detik 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, implementasikan GlShaderProgram Tujuan Metode queueInputFrame() digunakan untuk memproses frame input. Misalnya, untuk memanfaatkan kemampuan machine learning MediaPipe, Anda dapat menggunakan MediaPipe FrameProcessor untuk mengirim setiap {i>frame<i} melalui grafik MediaPipe. Lihat contohnya di Aplikasi demo transformer.

Pratinjau efek

Dengan ExoPlayer, Anda dapat melihat pratinjau efeknya yang ditambahkan ke item media sebelum memulai proses ekspor. Menggunakan Objek Effects seperti untuk EditedMediaItem, panggil setVideoEffects() di Instance 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();

Anda juga dapat melihat pratinjau efek audio dengan ExoPlayer. Saat membangun Dalam instance ExoPlayer, teruskan RenderersFactory kustom yang mengonfigurasi perender audio pemutar untuk menghasilkan audio ke AudioSink yang menggunakan AudioProcessor. Dalam contoh di bawah ini, kami 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 hasil edit Anda 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 pembaruan progres

Transformer.start langsung ditampilkan dan berjalan secara asinkron. Untuk melakukan kueri kemajuan transformasi terkini, panggil Transformer.getProgress() Metode ini menggunakan ProgressHolder, dan jika status progres tersedia, yaitu, jika metode menampilkan PROGRESS_STATE_AVAILABLE, maka elemen yang diberikan ProgressHolder akan diperbarui dengan persentase progres saat ini.

Anda juga dapat melampirkan pemroses ke Transformer Anda untuk diberi tahu tentang peristiwa penyelesaian atau error.