Media3 Transformer kullanarak temel bir video düzenleme uygulaması oluşturma

Jetpack Media3'teki Transformer API'leri, medya düzenleme işlemlerini etkili ve güvenilir hale getirmek için tasarlanmıştır. Dönüştürücü, aşağıdakiler de dahil olmak üzere çeşitli işlemleri destekler:

  • Kırpma, ölçeklendirme ve döndürme özellikleriyle videoda değişiklik yapma
  • Yer paylaşımı ve filtre gibi efektler ekleme
  • HDR ve ağır çekim video gibi özel biçimler işleniyor
  • Düzenlemeler uygulandıktan sonra medya öğesini dışa aktarma

Bu sayfada, Transformer'ın kapsadığı bazı temel kullanım alanları açıklanmaktadır. Daha fazla bilgi için Media3 Transformer kılavuzlarımıza bakabilirsiniz.

Başlayın

Başlamak için Jetpack Media3'ün Transformer, Effect ve Common modüllerine bağımlılık ekleyin:

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

1.3.1 öğesini tercih ettiğiniz kitaplık sürümüyle değiştirmeyi unutmayın. En yeni sürümü görmek için sürüm notlarına bakabilirsiniz.

Önemli dersler

Sınıf Amaç
Transformer Dönüşümleri başlatıp durdurun ve çalışan bir dönüşümün ilerleme güncellemelerini kontrol edin.
EditedMediaItem İşlenecek bir medya öğesini ve buna uygulanacak düzenlemeleri temsil eder.
Effects Ses ve video efektleri koleksiyonu.

Çıkışı yapılandırma

Transformer.Builder sayesinde artık TransformationRequest nesnesi oluşturmaya gerek kalmadan işlevi ayarlayarak videoMimeType ve audioMimetype dizinlerini belirtebilirsiniz.

Biçimler arasında kod dönüştürme

Aşağıdaki kod, bir Transformer nesnesinin H.265/AVC video ve AAC ses çıkışı için nasıl yapılandırılacağını gösterir:

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();

Medya girişi biçimi zaten ses veya video için dönüştürme isteğiyle eşleşiyorsa Dönüştürücü, otomatik olarak işleme, yani sıkıştırılmış örnekleri giriş container'ından herhangi bir değişiklik yapılmadan çıkış kapsayıcısına kopyalamaya geçer. Bu da işlem maliyetini ve aynı biçimdeki kod çözme ve yeniden kodlama kalitesinde yaşanabilecek kalite kaybını önler.

HDR modunu ayarla

Giriş medya dosyası HDR biçimindeyse Transformer'ın HDR bilgilerini işleme şekline ilişkin birkaç farklı mod arasından seçim yapabilirsiniz. Muhtemelen HDR_MODE_KEEP_HDR veya HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL kullanmak istersiniz.

HDR_MODE_KEEP_HDR HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
Açıklama HDR verilerini koruyun. Diğer bir deyişle, HDR çıkış biçimi, HDR giriş biçimiyle aynı olur. Bir OpenGL ton eşleyici kullanarak HDR girişini SDR'ye eşleme yapın. Bu, çıkış biçiminin SDR biçiminde olacağı anlamına gelir.
Destek FEATURE_HdrEditing özelliğine sahip kodlayıcıya sahip cihazlar için 31 ve üzeri API düzeylerinde desteklenir. 29 ve üzeri API düzeylerinde desteklenir.
Hatalar Desteklenmiyorsa bunun yerine HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL kullanmayı deneyin. Desteklenmiyorsa ExportException gönderir.

Gerekli kodlama özelliklerini destekleyen ve Android 13 (API düzeyi 33) veya sonraki sürümleri çalıştıran cihazlarda Transformer nesneleri, HDR videoları düzenlemenize olanak tanır. Aşağıdaki kodda gösterildiği gibi HDR_MODE_KEEP_HDR, Composition nesnesini oluştururken varsayılan moddur:

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();

Medya öğesi hazırlama

MediaItem, uygulamanızdaki bir ses veya video öğesini temsil eder. EditedMediaItem, kendisine uygulanacak dönüşümlerle birlikte bir MediaItem toplar.

Video kırpma

Videonun istenmeyen bölümlerini kaldırmak için MediaItem öğesine ClippingConfiguration ekleyerek özel başlangıç ve bitiş konumları ayarlayabilirsiniz.

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();

Yerleşik efektleri kullanma

Media3, yaygın dönüşümler için çeşitli yerleşik video efektleri içerir. Örneğin:

Sınıf Etki
Presentation Medya öğesini çözünürlüğe veya en boy oranına göre ölçeklendirme
ScaleAndRotateTransformation Medya öğesini bir çarpana göre ölçeklendirin ve/veya medya öğesini döndürün
Crop Medya öğesini daha küçük veya daha büyük bir kareye kırpın
OverlayEffect Medya öğesinin üstüne metin veya resim yer paylaşımı eklemek

Ses efektleri için, ham (PCM) ses verilerini dönüştürecek bir AudioProcessor örneği dizisi ekleyebilirsiniz. Örneğin, ses kanallarını karıştırmak ve ölçeklendirmek için ChannelMixingAudioProcessor kullanabilirsiniz.

Bu efektleri kullanmak için efekt veya ses işlemcisinin bir örneğini oluşturun, medya öğesine uygulamak istediğiniz ses ve video efektleriyle bir Effects örneği oluşturun, ardından Effects nesnesini bir EditedMediaItem öğesine ekleyin.

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();

Özel efekt oluşturma

Media3'te yer alan efektlerin kapsamını genişleterek kullanım alanlarınıza özgü özel efektler oluşturabilirsiniz. Aşağıdaki örnekte, videoyu oynatmanın ilk saniyesinde kareyi dolduracak şekilde yakınlaştırmak için MatrixTransformation alt sınıfını kullanın:

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();

Bir efektin davranışını daha da özelleştirmek için GlShaderProgram uygulayın. Giriş çerçevelerini işlemek için queueInputFrame() yöntemi kullanılır. Örneğin, MediaPipe'in makine öğrenimi özelliklerinden yararlanmak için her kareyi bir MediaPipe grafiği üzerinden göndermek üzere bir MediaPipe FrameProcessor kullanabilirsiniz. Bunun bir örneğini Transformer demo uygulamasında görebilirsiniz.

Efektleri önizle

ExoPlayer ile dışa aktarma işlemine başlamadan önce bir medya öğesine eklenen efektleri önizleyebilirsiniz. EditedMediaItem ile aynı Effects nesnesini kullanarak ExoPlayer örneğinizde setVideoEffects() çağrısı yapın.

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();

Ses efektlerini ExoPlayer ile de önizleyebilirsiniz. ExoPlayer örneğinizi oluştururken, oynatıcının ses oluşturucularını AudioProcessor dizinizi kullanan bir AudioSink'ye ses çıkışı verecek şekilde yapılandıran özel bir RenderersFactory iletin. Aşağıdaki örnekte bunu, DefaultRenderersFactory için buildAudioSink() yöntemini geçersiz kılarak yapıyoruz.

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();

Dönüşüm başlatma

Son olarak, düzenlemelerinizi uygulamak ve ortaya çıkan medya öğesini dışa aktarmaya başlamak için bir Transformer oluşturun.

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);

Benzer şekilde, gerekirse Transformer.cancel() ile dışa aktarma işlemini iptal edebilirsiniz.

İlerleme durumu güncellemelerini kontrol edin

Transformer.start hemen döndürülür ve eşzamansız olarak çalışır. Bir dönüşümün mevcut ilerleme durumunu sorgulamak için Transformer.getProgress() çağrısı yapın. Bu yöntem bir ProgressHolder alır ve ilerleme durumu mevcutsa (yani yöntem PROGRESS_STATE_AVAILABLE döndürürse) sağlanan ProgressHolder değeri, mevcut ilerleme yüzdesiyle güncellenir.

Ayrıca, tamamlanma veya hata olaylarıyla ilgili bildirim almak için Transformer cihazınıza bir dinleyici ekleyebilirsiniz.