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

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

  • Kırpma, ölçeklendirme ve döndürme ile video değiştirme
  • Yer paylaşımları ve filtreler gibi efektler ekleme
  • HDR ve ağır çekim video gibi özel formatların işlenmesi
  • Düzenlemeler uygulandıktan sonra medya öğesini dışa aktarma

Bu sayfada, Transformer'ın kapsadığı bazı önemli kullanım alanları açıklanmaktadır. Daha fazla bilgi için Media3 Transformer ile ilgili tam kılavuzlarımıza göz atabilirsiniz.

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.7.1"
implementation "androidx.media3:media3-effect:1.7.1"
implementation "androidx.media3:media3-common:1.7.1"

1.7.1 yerine tercih ettiğiniz kitaplık sürümünü kullandığınızdan emin olun. En son sürümü görmek için sürüm notlarına bakabilirsiniz.

Önemli kartlar

Sınıf Amaç
Transformer Dönüşümleri başlatma ve durdurma, devam eden bir dönüşümle ilgili ilerleme güncellemelerini kontrol etme
EditedMediaItem İşlenecek bir medya öğesini ve bu öğeye uygulanacak düzenlemeleri temsil eder.
Effects Ses ve video efektleri koleksiyonu.

Çıkışı yapılandırma

Transformer.Builder ile artık videoMimeType ve audioMimetype dizinini, TransformationRequest nesnesi oluşturmanıza gerek kalmadan işlevi ayarlayarak belirleyebilirsiniz.

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

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

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

Giriş medya biçimi, ses veya video için dönüştürme isteğiyle zaten eşleşiyorsa Transformer otomatik olarak transmukslama işlemine geçer. Bu işlem, sıkıştırılmış örnekleri giriş kapsayıcısından çıkış kapsayıcısına değiştirmeden kopyalama işlemidir. Bu sayede, aynı biçimde kod çözme ve yeniden kodlamanın hesaplama maliyeti ve olası kalite kaybı önlenir.

HDR modunu ayarlama

Giriş medya dosyası HDR biçimindeyse Transformer'ın HDR bilgilerini işleme şekli için 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 isteyeceksiniz.

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ı olmalıdır. OpenGL ton eşleyici kullanarak HDR girişini SDR'ye dönüştürür. Bu durumda çıkış biçimi SDR olur.
Destek FEATURE_HdrEditing özelliğine sahip bir kodlayıcı içeren cihazlarda API düzeyi 31 ve üzeri sürümlerde desteklenir. API düzeyi 29 ve sonraki sürümlerde desteklenir.
Hatalar Desteklenmiyorsa bunun yerine HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL kullanılmaya çalışılır. Desteklenmiyorsa ExportException oluşturur.

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, Composition nesnesi oluşturulurken HDR_MODE_KEEP_HDR 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, MediaItem öğesini ve buna uygulanacak dönüşümleri toplar.

Video kırpma

Bir videonun istenmeyen kısımlarını kaldırmak için ClippingConfiguration simgesini MediaItem simgesine 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();

Dahili efektleri kullanma

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

Sınıf Efekt
Presentation Medya öğesini çözünürlüğe veya en boy oranına göre ölçeklendirme
ScaleAndRotateTransformation Medya öğesini bir çarpanla ölçeklendirme ve/veya döndürme
Crop Medya öğesini daha küçük veya daha büyük bir çerçeveye kırpma
OverlayEffect Medya öğesinin üzerine metin veya resim yer paylaşımı ekleme

Ses efektleri için, ham (PCM) ses verilerini dönüştürecek bir dizi AudioProcessor örneği 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 Effects örneğini 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 efektler oluşturma

Media3'te yer alan efektleri genişleterek kullanım alanlarınıza özel efektler oluşturabilirsiniz. Aşağıdaki örnekte, videoyu oynatmanın ilk saniyesinde çerçeveyi dolduracak şekilde yakınlaştırmak için subclass MatrixTransformation 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'ın makine öğrenimi özelliklerinden yararlanmak için her kareyi bir MediaPipe grafiği üzerinden göndermek üzere MediaPipe FrameProcessor kullanabilirsiniz. Bunun bir örneğini Transformer demo uygulamasında görebilirsiniz.

Efektleri önizleme

ExoPlayer ile dışa aktarma işlemine başlamadan önce bir medya öğesine eklenen efektleri önizleyebilirsiniz. EditedMediaItem için kullanılanla aynı Effects nesnesini kullanarak ExoPlayer örneğinizde setVideoEffects() işlevini çağırı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, DefaultRenderersFactory öğesinin buildAudioSink() yöntemini geçersiz kılarak bunu 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 sonuçtaki medya öğesini dışa aktarmaya başlamak için 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);

Gerekirse dışa aktarma işlemini benzer şekilde Transformer.cancel() ile iptal edebilirsiniz.

İlerleme durumu güncellemelerini kontrol etme

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

Tamamlama veya hata etkinlikleri hakkında bildirim almak için Transformer'nize bir dinleyici de ekleyebilirsiniz.