Ürün Haberleri

Medya oynatmayı iyileştirme: Media3 ile önceden yükleme özelliğini kullanma - 1. bölüm

Okuma süresi: 8 dk.
Mayuri Khinvasara Khabya adlı kullanıcının profilini görüntüleyin
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 duraklatılmadan sorunsuz bir şekilde oynatılmasını bekler.

Temel zorluk gecikmedir. Geleneksel olarak, video oynatıcılar yalnızca kullanıcı oynatmak için bir öğe seçtikten sonra çalışmaya (bağlanma, indirme, ayrıştırma, arabelleğe alma) başlar. Bu tepkisel yaklaşım, günümüzün kısa video bağlamı için yavaş kalıyor. Çö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. Önceden yüklemenin özü budur.

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

  • 🚀 Daha hızlı oynatma başlangıcı: Videolar önceden hazırlandığı için öğ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 sırasında ağ sorunları gibi nedenlerle duraklama olasılığı çok daha düşüktür.
  • ✨ Sonuç olarak daha sorunsuz bir 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.

Bu üç bölümlük seride, Media3'ün bileşenleri (önceden) yüklemeye yönelik güçlü yardımcı programlarını tanıtacak ve ayrıntılı olarak inceleyeceğiz.

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

Önceden yükleme imdadınıza yetişiyor. 🦸‍♀️

Önceden yüklemenin temelindeki fikir basittir: Medya içeriğini ihtiyacınız olmadan önce yükleyin. Kullanıcı bir sonraki videoya geçtiğinde videonun ilk segmentleri indirilmiş ve kullanıma hazır hale gelmiş olur. Böylece video hemen oynatılabilir.

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

Önceden yükleme etkinleştirildiğinde, oynatma arabelleği bir sonraki öğeye ulaşmadan önce kullanıcı bir sonraki öğeye atladığında katılma gecikmesini en aza indirmeye yardımcı olabilir. 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 oynatıcıda sıraya alınır. Arabelleğe alınmış örnekler hemen kullanılabilir ve oluşturma için codec'e beslenmeye hazır olur.

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

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

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

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

Önceden yüklemeye ihtiyacınız olup olmadığından hâlâ emin değilseniz bu API, denemek için harika ve kolay 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.

Özelliği etkinleştirdikten sonra, oynatma listesi önceden yükleme özelliğini devre dışı bırakmak için PreloadConfiguration.DEFAULT kullanarak tekrar kapatabilirsiniz:

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 ön yükleme için özel olarak tasarlanmış yeni ve güçlü bir bağımsız bileşendir. Olası MediaSource'lardan oluşan bir koleksiyonu yönetir, bunları kullanıcının mevcut konumuna yakınlığa göre önceliklendirir ve önceden yüklenecek öğeler üzerinde ayrıntılı kontrol sunar. Bu, 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 ExoPlayer örneklerini oluşturabilir. DefaultPreloadManager oluşturmak için TargetPreloadStatusControl'ü iletmeniz gerekir. Önceden yükleme yöneticisi, bir öğe için ne kadar yükleme yapılacağını öğrenmek üzere bu kontrolü sorgulayabilir. Aşağıdaki bölümde TargetPreloadStatusControl ile ilgili bir örneği açıklayacak ve 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ı builder'ın kullanılması gerekir. Bu sayede, arka plandaki bileşenler doğru şekilde paylaşılır.

İş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, videonun 10 saniyesini önceden yüklemek istiyorsanız ne yapmanız gerekir? Medya öğelerinizin konumunu bantta belirtebilirsiniz. DefaultPreloadManager, öğeleri kullanıcının oynattığı öğeye yakınlığına göre önceliklendirerek yükler.

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

Örneğin,

  • "A" öğesi en yüksek önceliğe sahiptir ve 5 saniyelik video yükler.
  • "B" öğesi orta önceliklidir ancak bu öğeye ulaştığınızda 3 saniyelik video yükleyin.
  • "C" öğesinin önceliği daha düşüktür, yalnızca parçaları yükleyin.
  • "D" öğesi daha da az öncelikli, sadece hazırlık yapın.
  • Diğer öğeler uzakta. Hiçbir şeyi önceden yükleme.

Bu ayrıntılı kontrol, kaynak kullanımınızı optimize etmenize yardımcı olabilir. Bu, 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üklenmiş olarak tutabilir. PreloadConfiguration ise yalnızca sonraki öğeleri önceden yükler.

Önceden yüklenen öğeleri yönetme

Yöneticinizi oluşturduktan sonra, üzerinde çalışacağı konuları belirtebilirsiniz. Kullanıcınız bir feed'de gezinirken, yaklaşan videoları tanımlayıp yöneticiye eklersiniz. PreloadManager ile etkileşim, kullanıcı arayüzünüz ile önceden yükleme motoru arasında duruma dayalı bir iletişimdir.

1. Medya öğeleri ekleme

Feed'inizi doldururken yöneticiye izlemesi gereken medya hakkında bilgi vermeniz gerekir. Yeni başlıyorsanız önceden yüklemek istediğiniz listenin tamamını ekleyebilirsiniz. Daha sonra, gerektiğinde listeye tek bir öğe eklemeye devam edebilirsiniz. Önceden yükleme listesindeki öğeler üzerinde tam kontrole sahip olursunuz. Bu, yöneticiye eklenen ve yöneticiden kaldırılan öğeleri de yönetmeniz gerektiği anlamına gelir.

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

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

Öğeyi ekledikten sonra yöneticiye yeni listesini yeniden değerlendirmesini söyleyin (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 daha önce hazırladığı bir planı istersiniz. MediaItem'ı kullanarak MediaSource'u Preload Manager'dan alabilirsiniz.

PreloadManager'dan alınan öğe boşsa mediaItem henüz önceden yüklenmemiş veya PreloadManager'a eklenmemiştir. Bu nedenle, 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, önceden yüklemeden oynatmaya sorunsuz bir şekilde geçiş yapabilir ve bellekteki verileri kullanabilirsiniz. Başlangıç zamanını hızlandıran da budur.

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

Feed'imiz / listemiz dinamik olabileceğinden, PreloadManager'a mevcut oynatma dizininizi bildirmeniz önemlidir. Böylece, ö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ışmasını sağlamak için artık izlemesi gerekmeyen öğeleri (ör. kullanıcının mevcut konumundan 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() yöntemini çağırabilirsiniz.

5. Yöneticiyi serbest bırakın

PreloadManager'a artık ihtiyacınız olmadığında (ör. kullanıcı arayüzünüz yok edildiğinde) kaynaklarını serbest bırakmak için PreloadManager'ı serbest bırakmanız gerekir. Bunu yapmak için en uygun yer, oyuncunuzun kaynaklarını zaten serbest bıraktığınız yerdir. Daha fazla ön yükleme yapmanız gerekmiyorsa oynatıcı oynatmaya devam edebileceğinden, oynatıcıdan önce yöneticinin serbest bırakılması önerilir.

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

Demo zamanı

Canlı olarak deneyin 👍

Aşağıdaki demoda, PreloadManager'ın etkisini sağ tarafta görüyoruz. Bu tarafta yükleme süreleri daha hızlıdır. Sol tarafta ise mevcut deneyim gösterilmektedir. Demo için kod örneğini de görüntüleyebilirsiniz. (Bonus: Her videonun başlangıç gecikmesini de gösterir.)

Demo-PreloadManager_2.webp

Sırada ne var?

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

2. bölümde DefaultPreloadManager konusunu daha ayrıntılı olarak ele alacağız. Ön yükleme etkinliklerini nasıl dinleyeceğinizi keşfedecek, bellek sorunlarını önlemek için kayan pencere kullanma gibi en iyi uygulamaları ele alacak ve ExoPlayer ile DefaultPreloadManager'ın özel paylaşılan bileşenlerini inceleyeceğiz.

Paylaşmak istediğiniz bir geri bildiriminiz var mı? Görüşlerinizi öğrenmekten memnuniyet duyarız.

Takipte kalın ve uygulamanızı hızlandırın. 🚀

Yazan:
Okumaya devam et