Ürün Haberleri

Medya oynatmayı geliştirme: Media3 ile önceden yükleme özelliğinin tanıtımı - 1. Bölüm

Okuma süresi: 8 dk.
View Mayuri Khinvasara Khabya's profile
Mayuri Khinvasara Khabya Geliştirici İlişkileri Mühendisi

Günümüzün medya odaklı uygulamalarında, sorunsuz ve kesintisiz bir oynatma deneyimi sunmak, keyifli bir kullanıcı deneyimi için çok önemlidir. Kullanıcılar videolarının anında başlamasını ve sorunsuz bir şekilde oynatılmasını bekler.

Temel zorluk gecikmedir. Geleneksel olarak, bir video oynatıcı yalnızca kullanıcı oynatılacak bir öğe seçtikten sonra çalışmaya başlar (bağlanma, indirme, ayrıştırma, arabelleğe alma). Bu tepkisel yaklaşım, günümüzün kısa video bağlamında yavaştır. Çözüm, proaktif olmaktır. Kullanıcının sıradaki videosunun ne olacağını tahmin etmemiz ve içeriği önceden hazırlamamız gerekir. Ön yüklemenin özü budur.

Ön yüklemenin temel avantajları şunlardır:

  • 🚀 Daha hızlı oynatma başlangıcı: Videolar oynatılmaya hazır olduğundan öğeler arasında daha hızlı geçiş yapılır ve oynatma daha hızlı başlar.
  • 📉 Daha az arabelleğe alma: Veriler proaktif olarak yüklendiğinden oynatma işleminin duraklaması (ör. ağdaki aksaklıklar nedeniyle) çok daha az olasıdır.
  • ✨ Daha sorunsuz kullanıcı deneyimi: Daha hızlı başlatma ve daha az arabelleğe alma, kullanıcıların keyif alacağı daha akıcı ve sorunsuz bir etkileşim sağlar.

Üç bölümden oluşan bu seride, Media3'ün bileşenleri (ön) yüklemeye yönelik güçlü yardımcı programlarını tanıtacak ve ayrıntılı olarak inceleyeceğiz.

  • 1. bölümde temelleri ele alacağız: Media3'te bulunan farklı önceden yükleme stratejilerini anlama, PreloadConfiguration'ı etkinleştirme ve DefaultPreloadManager'ı ayarlama, uygulamanızın öğeleri önceden yüklemesini sağlama. Bu blogun sonunda, yapılandırdığınız sıralama ve süreyle medya öğelerini önceden yükleyip oynatabileceksiniz.
  • 2. Bölüm'de DefaultPreloadManager'ın daha ileri düzey konularına değineceğiz: analiz için dinleyicileri kullanma, kayan pencere kalıbı ve DefaultPreloadManager ile ExoPlayer'ın özel paylaşılan bileşenleri gibi üretime hazır en iyi uygulamaları keşfetme.
  • 3. bölümde, DefaultPreloadManager ile disk önbelleğe alma konusunu ayrıntılı olarak ele alacağız.

Önceden yükleme yardıma hazır! 🦸‍♀️

Önceden yüklemenin temelinde basit bir fikir yatar: Medya içeriklerini ihtiyaç duymadan önce yükleyin. Kullanıcı bir sonraki videoya kaydırdığında videonun ilk segmentleri indirilmiş ve kullanıma hazır olur.

Bunu bir restorana benzetebiliriz. Yoğun bir mutfakta soğan doğramaya başlamak için sipariş beklenmez. 🧅 Hazırlık çalışmalarını önceden yaparlar. Önceden yükleme, video oynatıcınızın hazırlık çalışmasıdır.

Etkinleştirildiğinde ön yükleme, oynatma arabelleği bir sonraki öğeye ulaşmadan kullanıcı bir sonraki öğeye atladığında katılma gecikmesini en aza indirmeye yardımcı olabilir. Bir sonraki pencerenin ilk dönemi hazırlanır ve video, ses ve metin örnekleri arabelleğe alınır. Önceden yüklenen dönem daha sonra arabelleğe alınmış örneklerle birlikte oynatıcıya gönderilir. Bu örnekler hemen kullanılabilir ve oluşturma için codec'e aktarılmaya hazırdır.

Media3'te önceden yükleme için iki temel API bulunur. Bunların her biri farklı kullanım alanlarına uygundur. Doğru API'yi seçmek ilk adımdır.

1. PreloadConfiguration ile oynatma listesi öğelerini önceden yükleme

Bu basit yaklaşım, oynatma sırasının tahmin edilebilir olduğu (ör. bir dizi bölüm) oynatma listeleri gibi doğrusal ve sıralı medya için kullanışlıdır. ExoPlayer'ın playlist API'lerini kullanarak oynatıcıya medya öğelerinin tam listesini verir ve oynatıcı için PreloadConfiguration'ı ayarlarsınız. Ardından, oynatıcı, yapılandırıldığı şekilde sıradaki öğeleri otomatik olarak önceden yükler. Bu API, oynatma arabelleği bir sonraki öğeyle zaten çakışmadan önce kullanıcı bir sonraki öğeye atladığında katılma gecikmesini optimize etmeye çalışır.

Ön yükleme yalnızca devam eden oynatma için medya yüklenmediğinde başlatılır. Bu sayede, ön yüklemenin birincil oynatma ile bant genişliği için rekabet etmesi önlenir.

Önceden yükleme yapmanız gerekip gerekmediğinden hâlâ emin değilseniz bu API, denemek için harika bir seçenektir.

player.preloadConfiguration =
    PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)

Yukarıdaki PreloadConfiguration ile oynatıcı, oynatma listesindeki bir sonraki öğe için beş saniyelik medyayı önceden yüklemeye çalışır.

Etkinleştirildikten sonra oynatma listesi önceden yükleme özelliği, oynatma listesi önceden yüklemeyi devre dışı bırakmak için PreloadConfiguration.DEFAULT kullanılarak tekrar kapatılabilir:

player.preloadConfiguration = PreloadConfiguration.DEFAULT

2. PreloadManager ile dinamik listeleri önceden yükleme

"Sonraki" öğenin kullanıcı etkileşimiyle belirlendiği dikey feed'ler veya bantlar gibi dinamik kullanıcı arayüzleri için PreloadManager API uygundur. Bu, Media3 ExoPlayer kitaplığında proaktif olarak önceden yükleme için özel olarak tasarlanmış yeni, güçlü ve bağımsız bir bileşendir. Olası MediaSource'ların bir koleksiyonunu yönetir, bunları kullanıcının mevcut konumuna yakınlığa göre önceliklendirir ve önceden yüklenecek içerikler üzerinde ayrıntılı kontrol sunar. Bu özellik, kısa videoların dinamik feed'leri gibi karmaşık senaryolar için uygundur.

PreloadManager'ınızı ayarlama

DefaultPreloadManager, PreloadManager için standart uygulamadır.

DefaultPreloadManager oluşturucusu hem DefaultPreloadManager'ı hem de önceden yüklenmiş içeriğini oynatacak tüm ExoPlayer örneklerini oluşturabilir. DefaultPreloadManager oluşturmak için TargetPreloadStatusControl iletmeniz gerekir. Bu kontrol, önceden yükleme yöneticisinin bir öğe için ne kadar yükleme yapacağını öğrenmek üzere sorgulayabileceği bir kontrol olur. Aşağıdaki bölümde TargetPreloadStatusControl örneğini açıklayıp tanımlayacağız.

val preloadManagerBuilder =
DefaultPreloadManager.Builder(context, targetPreloadStatusControl)
val preloadManager = val preloadManagerBuilder.build()

// Build ExoPlayer with DefaultPreloadManager.Builder
val player = preloadManagerBuilder.buildExoPlayer()

Hem ExoPlayer hem de DefaultPreloadManager için aynı oluşturucuyu kullanmak gerekir. Bu, bileşenlerin doğru şekilde paylaşılmasını sağlar.

İşte bu kadar! Artık talimat almaya hazır bir yöneticiniz var.

TargetPreloadStatusControl ile süreyi ve sıralamayı yapılandırma

Örneğin, 10 saniyelik bir videoyu önceden yüklemek istiyorsanız ne yapmanız gerekir? Medya öğelerinizin karuseldeki konumunu belirtebilirsiniz. DefaultPreloadManager, öğeleri yüklemeye kullanıcının şu anda oynattığı öğeye ne kadar yakın olduğuna göre öncelik verir.

Öğenin ne kadar süre önceden yükleneceğini kontrol etmek istiyorsanız DefaultPreloadManager.PreloadStatus ile döndürerek bunu belirtebilirsiniz.

Örneğin,

  • "A" öğesi en yüksek önceliğe sahip. 5 saniyelik video yükleyin.
  • "B" öğesi orta öncelikli ancak öğeye ulaştığınızda 3 saniyelik video yükleyin.
  • "C" öğesi daha düşük öncelikli olduğundan yalnızca parçalar yüklenir.
  • "D" öğesi daha da az önceliklidir, sadece hazırlanın.
  • Diğer öğeler çok uzakta. Hiçbir şeyi önceden yüklemeyin.

Bu ayrıntılı kontrol, kaynak kullanımınızı optimize etmenize yardımcı olabilir. Bu da sorunsuz bir oynatma için önerilir.

import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus


class MyTargetPreloadStatusControl(
    currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {


    // The app is responsible for updating this based on UI state
    override fun getTargetPreloadStatus(index: Int): PreloadStatus? {

        val distance = index - currentPlayingIndex

        // Adjacent items (Next): preload 5 seconds
        if (distance == 1) { 
        // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
                    return PreloadStatus.specifiedRangeLoaded(5000L)
                } 

        // Adjacent items (Previous): preload 3 seconds
        else if (distance == -1) { 
        // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
                    return PreloadStatus.specifiedRangeLoaded(3000L)
                } 

        // Items two positions away: just select tracks
        else if (distance) == 2) {
        // Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
                    return PreloadStatus.TRACKS_SELECTED
                } 

        // Items four positions away: just select prepare
        else if (abs(distance) <= 4) {
        // Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
                    return PreloadStatus.SOURCE_PREPARED
                }

             // All other items are too far away
             return null
            }
}

İpucu: PreloadManager hem önceki hem de sonraki öğeleri önceden yükleyebilir. PreloadConfiguration ise yalnızca sonraki öğeleri önceden yükler.

Önceden Yüklenen Öğeleri Yönetme

Yöneticinizi oluşturduktan sonra, üzerinde çalışmasını istediğiniz görevleri söylemeye başlayabilirsiniz. Kullanıcınız bir özet akışında gezinirken yaklaşan videoları belirleyip yöneticiye eklersiniz. PreloadManager ile etkileşim, kullanıcı arayüzünüz ile önceden yükleme motoru arasındaki duruma dayalı bir görüşmedir.

1. Medya öğeleri ekleme

Feed'inizi doldururken yöneticinin izlemesi gereken medya hakkında bilgi vermeniz gerekir. Başlangıç aşamasındaysanız önceden yüklemek istediğiniz listenin tamamını ekleyebilirsiniz. Daha sonra, gerektiğinde listeye tek tek öğe eklemeye devam edebilirsiniz. Ön yükleme listesindeki öğeler üzerinde tam kontrol sahibi olursunuz. Bu nedenle, yöneticiye eklenen ve yöneticiden kaldırılan öğeleri de yönetmeniz gerekir.

val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
    preloadManager.add(
        initialMediaItems.get(index),index)
    )
}

Yönetici, artık arka planda bu MediaItem için veri getirmeye başlayacak.

Ekleme işleminden sonra yöneticiden yeni listeyi yeniden değerlendirmesini isteyin (bir öğe ekleme/ kaldırma gibi bir şeyin değiştiğini veya kullanıcının yeni bir öğe oynatmaya geçtiğini belirtin).

preloadManager.invalidate()

2. Öğe Alma ve Oynatma

Ana oynatma mantığı burada devreye girer. Kullanıcı bu videoyu oynatmaya karar verdiğinde yeni bir MediaSource oluşturmanız gerekmez. Bunun yerine, PreloadManager'dan önceden hazırladığı yanıtı vermesini istersiniz. MediaItem'ı kullanarak Preload Manager'dan MediaSource'u alabilirsiniz.

PreloadManager'dan alınan öğe null ise mediaItem henüz önceden yüklenmemiş veya PreloadManager'a eklenmemiştir. Bu durumda mediaItem'ı doğrudan ayarlamayı seçersiniz.

// When a media item is about to displ​​ay on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
  player.setMediaSource(mediaSource)
} else {
  // If mediaSource is null, that mediaItem hasn't been added yet.
  // So, send it directly to the player.
  player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()

PreloadManager'dan alınan MediaSource'u hazırlayarak, bellekteki verileri kullanarak önceden yüklemeden oynatmaya sorunsuz bir şekilde geçiş yapabilirsiniz. Başlangıç süresini hızlandıran faktör budur.

3. Mevcut dizini kullanıcı arayüzüyle senkronize tutma

Feed'imiz / listemiz dinamik olabileceğinden, PreloadManager'ı mevcut oynatma dizininiz hakkında bilgilendirmeniz önemlidir. Böylece PreloadManager, önceden yükleme için her zaman mevcut dizininize en yakın öğelere öncelik verebilir.

preloadManager.setCurrentPlayingIndex(currentIndex)
// Need to call invalidate() to update the priorities
preloadManager.invalidate()

4. Öğe Kaldırma

Yöneticinin verimli çalışmaya devam etmesi için artık izlemesi gerekmeyen öğeleri (ör. kullanıcının mevcut konumundan çok uzakta olan öğeler) kaldırmanız gerekir.

// When an item is too far from the current playing index
preloadManager.remove(mediaItem)

Tüm öğeleri tek seferde temizlemeniz gerekiyorsa preloadManager.reset() numaralı telefonu arayabilirsiniz.

5. Release the Manager

PreloadManager'a artık ihtiyacınız olmadığında (ör. kullanıcı arayüzünüz yok edildiğinde) kaynaklarını boşaltmak için PreloadManager'ı serbest bırakmanız gerekir. Bunu yapmak için en uygun yer, Player'ın kaynaklarını yayınladığınız yerdir. Daha fazla ön yükleme yapmanız gerekmiyorsa oyuncunun oynamaya devam edebilmesi için yöneticinin oyuncudan önce serbest bırakılması önerilir.

// In your Activity's onDestroy() or Composable's onDispose
preloadManager.release()

Demo zamanı

Canlı olarak nasıl çalıştığını görün 👍

Aşağıdaki demoda , PreloadManager'ın etkisini görüyoruz. Sağ tarafta daha hızlı yükleme süreleri var, sol tarafta ise mevcut deneyim gösteriliyor. Ayrıca, demoya ait kod örneğini de görüntüleyebilirsiniz. (Bonus: Her video için başlatma gecikmesini de gösterir.)

Demo-PreloadManager_2.webp

Sırada ne var?

1. Bölümün sonuna geldik. Artık dinamik önceden yükleme sistemi oluşturmak için gereken araçlara sahipsiniz. ExoPlayer'da bir oynatma listesinin sonraki öğesini önceden yüklemek için PreloadConfiguration öğesini kullanabilir veya DefaultPreloadManager oluşturup öğeleri anında ekleyip kaldırabilir, hedef önceden yükleme durumunu yapılandırabilir ve önceden yüklenen içeriği oynatma için doğru şekilde alabilirsiniz.

2. Bölüm'de DefaultPreloadManager hakkında daha ayrıntılı bilgi vereceğiz. Ön yükleme etkinliklerini dinleme, bellek sorunlarını önlemek için kayan pencere kullanma gibi en iyi uygulamalar ve ExoPlayer ile DefaultPreloadManager'ın özel paylaşılan bileşenleri hakkında bilgi edineceksiniz.

Paylaşmak istediğiniz geri bildiriminiz var mı? Görüşlerinizi öğrenmek için sabırsızlanıyoruz.

Bizi takip etmeye devam edin ve uygulamanızı daha hızlı hale getirin. 🚀

Yazan:
Okumaya devam et