Özelleştirme

ExoPlayer kitaplığının temelinde Player arayüzü yer alır. Player; medya arabelleğe alma, oynatma, duraklatma ve arama gibi geleneksel üst düzey medya oynatıcı işlevleri sunar. Varsayılan uygulama ExoPlayer, oynatılan medya türü, nasıl, nerede saklandığı ve nasıl oluşturulduğu hakkında az varsayımda bulunmak (ve dolayısıyla birkaç kısıtlama getirmek) üzere tasarlanmıştır. Medya yükleme ve oluşturma işlemlerini doğrudan uygulamak yerine, ExoPlayer uygulamaları bu işi bir oynatıcı oluşturulduğunda veya oynatıcıya yeni medya kaynakları aktarıldığında yerleştirilen bileşenlere atar. Tüm ExoPlayer uygulamalarında ortak olan bileşenler:

  • Oynatılacak medyayı tanımlayan, medyayı yükleyen ve yüklenen medyanın okunabileceği MediaSource örnekleri. Oynatıcının içindeki bir MediaSource.Factory tarafından MediaItem öğesinden bir MediaSource örneği oluşturulur. Ayrıca, medya kaynağı tabanlı oynatma listesi API'si kullanılarak doğrudan oynatıcıya da iletilebilir.
  • MediaItem öğesini MediaSource öğesine dönüştüren MediaSource.Factory örnekleri. Oynatıcı oluşturulduğunda MediaSource.Factory eklenir.
  • Medyanın bağımsız bileşenlerini oluşturan Renderer örnekleri. Bunlar, oynatıcı oluşturulduğunda eklenir.
  • MediaSource tarafından sağlanan ve mevcut her Renderer tarafından kullanılacak parçaları seçen bir TrackSelector. Oynatıcı oluşturulduğunda bir TrackSelector yerleştirilir.
  • MediaSource öğesinin ne zaman daha fazla medya arabelleğe alacağını ve ne kadar medyanın arabelleğe alınacağını kontrol eden bir LoadControl. Oynatıcı oluşturulduğunda bir LoadControl yerleştirilir.
  • Oynatıcının yapılandırılmış bir canlı ofsete yakın kalmasını sağlamak için canlı oynatmalar sırasında oynatma hızını kontrol eden LivePlaybackSpeedControl. Oynatıcı oluşturulduğunda bir LivePlaybackSpeedControl yerleştirilir.

Oynatıcı işlevi parçaları uygulayan bileşenleri ekleme kavramı kitaplık genelinde mevcuttur. Bazı bileşenlerin varsayılan uygulamaları, yapılan başka yerleştirilen bileşenlere iş yetkisi verir. Bu, birçok alt bileşenin, özel bir şekilde yapılandırılan uygulamalarla tek tek değiştirilmesine olanak tanır.

Oynatıcı özelleştirme

Bileşenleri yerleştirerek oynatıcıyı özelleştirmeyle ilgili yaygın örneklerden bazıları aşağıda açıklanmıştır.

Ağ yığınını yapılandırma

ExoPlayer tarafından kullanılan ağ yığınını özelleştirme ile ilgili bir sayfamız bulunmaktadır.

Ağdan yüklenen verileri önbelleğe alma

Anında önbelleğe alma ve medya indirme kılavuzlarına bakın.

Sunucu etkileşimlerini özelleştirme

Bazı uygulamalar HTTP isteklerine ve yanıtlarına müdahale etmek isteyebilir. Özel istek başlıkları eklemek, sunucunun yanıt başlıklarını okumak, isteklerin URI'larını değiştirmek vb. işlemler isteyebilirsiniz. Örneğin, uygulamanız medya segmentlerini isterken başlık olarak bir jeton ekleyerek kendi kimliğini doğrulayabilir.

Aşağıdaki örnek, DefaultMediaSourceFactory içine özel bir DataSource.Factory ekleyerek bu davranışların nasıl uygulanacağını göstermektedir:

Kotlin

val dataSourceFactory =
  DataSource.Factory {
    val dataSource = httpDataSourceFactory.createDataSource()
    // Set a custom authentication request header.
    dataSource.setRequestProperty("Header", "Value")
    dataSource
  }
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

Java

DataSource.Factory dataSourceFactory =
    () -> {
      HttpDataSource dataSource = httpDataSourceFactory.createDataSource();
      // Set a custom authentication request header.
      dataSource.setRequestProperty("Header", "Value");
      return dataSource;
    };

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

Yukarıdaki kod snippet'inde, eklenen HttpDataSource her HTTP isteğine "Header: Value" üst bilgisini içerir. Bu davranış, bir HTTP kaynağıyla her etkileşim için düzeltilir.

Daha ayrıntılı bir yaklaşım için ResolvingDataSource kullanarak tam zamanında davranış ekleyebilirsiniz. Aşağıdaki kod snippet'i, istek üstbilgilerinin bir HTTP kaynağıyla etkileşim kurmadan hemen önce nasıl ekleneceğini göstermektedir:

Kotlin

val dataSourceFactory: DataSource.Factory =
  ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec ->
    // Provide just-in-time request headers.
    dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri))
  }

Java

    DataSource.Factory dataSourceFactory =
        new ResolvingDataSource.Factory(
            httpDataSourceFactory,
            // Provide just-in-time request headers.
            dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));

Ayrıca, aşağıdaki snippet'te gösterildiği gibi URI'da tam zamanında değişiklikler yapmak için bir ResolvingDataSource kullanabilirsiniz:

Kotlin

val dataSourceFactory: DataSource.Factory =
  ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec ->
    // Provide just-in-time URI resolution logic.
    dataSpec.withUri(resolveUri(dataSpec.uri))
  }

Java

DataSource.Factory dataSourceFactory =
    new ResolvingDataSource.Factory(
        httpDataSourceFactory,
        // Provide just-in-time URI resolution logic.
        dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));

Hata işlemeyi özelleştirme

Özel bir LoadErrorHandlingPolicy uygulamak, uygulamaların ExoPlayer'ın yükleme hatalarına tepki verme şeklini özelleştirmesine olanak tanır. Örneğin, bir uygulama birçok kez yeniden denemek yerine hızlı bir şekilde başarısız olmak veya oynatıcının her yeniden deneme arasında ne kadar bekleyeceğini kontrol eden geri yükleme mantığını özelleştirmek isteyebilir. Aşağıdaki snippet'te özel geri yükleme mantığının nasıl uygulanacağı gösterilmektedir:

Kotlin

val loadErrorHandlingPolicy: LoadErrorHandlingPolicy =
  object : DefaultLoadErrorHandlingPolicy() {
    override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long {
      // Implement custom back-off logic here.
      return 0
    }
  }
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
    )
    .build()

Java

LoadErrorHandlingPolicy loadErrorHandlingPolicy =
    new DefaultLoadErrorHandlingPolicy() {
      @Override
      public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
        // Implement custom back-off logic here.
        return 0;
      }
    };

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context)
                .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy))
        .build();

LoadErrorInfo bağımsız değişkeni, mantığı hata türüne veya başarısız isteğe göre özelleştirmek için başarısız yükleme hakkında daha fazla bilgi içerir.

Ayıklayıcı işaretlerini özelleştirme

Ayıklayıcı işaretleri, tek tek biçimlerin progresif medyadan kaldırılma şeklini özelleştirmek için kullanılabilir. Bunlar, DefaultMediaSourceFactory için sağlanan DefaultExtractorsFactory öğesinde ayarlanabilir. Aşağıdaki örnek, MP3 akışları için dizine dayalı aramayı etkinleştiren bir işaret iletir.

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING)
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory))
    .build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING);

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

Sabit bit hızıyla sarmalama sağlama

MP3, ADTS ve AMR akışlarında FLAG_ENABLE_CONSTANT_BITRATE_SEEKING işaretleriyle sabit bit hızı varsayımı kullanarak yaklaşık aramayı etkinleştirebilirsiniz. Bu işaretler, yukarıda açıklandığı gibi bağımsız DefaultExtractorsFactory.setXyzExtractorFlags yöntemleri kullanılarak ayrı ayıklayıcılar için ayarlanabilir. Destekleyen tüm ayıklayıcılarda sabit bit hızı arama özelliğini etkinleştirmek için DefaultExtractorsFactory.setConstantBitrateSeekingEnabled kullanın.

Kotlin

val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);

Ardından ExtractorsFactory, yukarıda ayıklayıcı işaretlerini özelleştirmek için açıklandığı gibi DefaultMediaSourceFactory aracılığıyla eklenebilir.

Eşzamansız arabellek kuyruğunu etkinleştirme

Eşzamansız arabellek kuyruğuna ekleme, ExoPlayer'ın oluşturma ardışık düzenindeki bir geliştirmedir. Bu özellik, MediaCodec örneklerini eşzamansız modda çalıştırır ve verilerin kod çözmeyi ve işlenmesini planlamak için ek iş parçacıkları kullanır. Bu özelliği etkinleştirmek kare atlamalarını ve ses eksikliğini azaltabilir.

Eşzamansız arabellek kuyruğu oluşturma özelliği, Android 12 (API düzeyi 31) ve sonraki sürümleri çalıştıran cihazlarda varsayılan olarak etkindir. Android 6.0 (API düzeyi 23) sürümünden itibaren ise manuel olarak etkinleştirilebilir. Özellikle DRM korumalı veya yüksek kare hızlı içerikleri oynatırken, karelerin düştüğünü veya sesin azaldığını gözlemlediğiniz belirli cihazlarda bu özelliği etkinleştirmeyi düşünün.

En basit durumda, oynatıcıya aşağıdaki şekilde bir DefaultRenderersFactory eklemeniz gerekir:

Kotlin

val renderersFactory = 
  DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing()
val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()

Java

DefaultRenderersFactory renderersFactory =
    new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing();
ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();

Oluşturucuları doğrudan örnekliyorsanız MediaCodecVideoRenderer ve MediaCodecAudioRenderer kurucularına bir AsynchronousMediaCodecAdapter.Factory iletin.

ForwardingPlayer ile yöntem çağrılarına müdahale ediliyor

Bir Player örneğinin davranışını, ForwardingPlayer alt sınıfında sarmalayarak ve yöntemleri geçersiz kılarak aşağıdakilerden birini yapabilirsiniz:

  • Parametrelere, yetki verilmiş Player kullanıcısına iletmeden önce erişin.
  • Döndürmeden önce, yetki verilmiş Player tarafından döndürülen değere erişin.
  • Yöntemi tamamen yeniden uygulayın.

ForwardingPlayer yöntemlerini geçersiz kılarken, özellikle aynı veya ilgili davranışa sahip yöntemleri ele alırken uygulamanın kendinden tutarlı ve Player arayüzüyle uyumlu kalmasını sağlamak çok önemlidir. Örneğin:

  • Her "oynat" işlemini geçersiz kılmak istiyorsanız hem ForwardingPlayer.play hem de ForwardingPlayer.setPlayWhenReady değerlerini geçersiz kılmanız gerekir. Çünkü arayan, playWhenReady = true olduğunda bu yöntemlerin davranışlarının aynı olmasını bekler.
  • İleri sarma artışını değiştirmek isterseniz özelleştirilmiş artışınızla arama yapmak için ForwardingPlayer.seekForward değerini ve arayana doğru özelleştirilmiş artışı bildirmek için ForwardingPlayer.getSeekForwardIncrement değerini geçersiz kılmanız gerekir.
  • Bir oynatıcı örneği tarafından hangi Player.Commands için reklam yayınlandığını kontrol etmek isterseniz hem Player.getAvailableCommands() hem de Player.isCommandAvailable() öğelerini geçersiz kılmanız ve temel oynatıcıdan gelen değişikliklerden haberdar olmak için Player.Listener.onAvailableCommandsChanged() geri çağırmasını dinlemeniz gerekir.

MediaSource özelleştirmesi

Yukarıdaki örneklerde, oynatıcıya geçirilen tüm MediaItem nesnelerinin oynatılması sırasında kullanılmak üzere özelleştirilmiş bileşenler eklenir. Ayrıntılı özelleştirmenin gerekli olduğu durumlarda, özelleştirilmiş bileşenleri doğrudan oynatıcıya iletilebilecek ayrı MediaSource örneklerine de ekleyebilirsiniz. Aşağıdaki örnekte, özel bir DataSource.Factory, ExtractorsFactory ve LoadErrorHandlingPolicy kullanmak için bir ProgressiveMediaSource öğesinin nasıl özelleştirileceği gösterilmektedir:

Kotlin

val mediaSource =
  ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory)
    .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy)
    .createMediaSource(MediaItem.fromUri(streamUri))

Java

ProgressiveMediaSource mediaSource =
    new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory)
        .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy)
        .createMediaSource(MediaItem.fromUri(streamUri));

Özel bileşenler oluşturma

Kitaplık, yaygın kullanım alanları için bu sayfanın üst kısmında listelenen bileşenlerin varsayılan uygulamalarını sağlar. ExoPlayer, bu bileşenleri kullanabilir ancak standart olmayan davranışlar gerekiyorsa özel uygulamalar kullanacak şekilde de oluşturulabilir. Özel uygulamaların bazı kullanım alanları şunlardır:

  • Renderer – Kitaplık tarafından sağlanan varsayılan uygulamalar tarafından desteklenmeyen bir medya türünü işlemek için özel bir Renderer uygulamak isteyebilirsiniz.
  • TrackSelector – Özel TrackSelector uygulamak, uygulama geliştiricilerin, MediaSource tarafından sunulan kanalların mevcut Renderer'lerin her biri tarafından tüketilmek üzere seçilme şeklini değiştirmesine olanak tanır.
  • LoadControl – Özel bir LoadControl uygulamak, uygulama geliştiricisinin oynatıcının arabelleğe alma politikasını değiştirmesine olanak tanır.
  • Extractor: Şu anda kitaplık tarafından desteklenmeyen bir kapsayıcı biçimini desteklemeniz gerekiyorsa özel bir Extractor sınıfı uygulamayı düşünebilirsiniz.
  • MediaSource – Medya örneklerini oluşturuculara özel bir şekilde beslemek veya özel MediaSource birleştirme davranışı uygulamak istiyorsanız özel bir MediaSource sınıfı uygulamak uygun olabilir.
  • MediaSource.Factory – Özel bir MediaSource.Factory uygulamak, bir uygulamanın MediaItem öğesinden MediaSource oluşturma şeklini özelleştirmesine olanak tanır.
  • DataSource: ExoPlayer'ın yukarı akış paketi, farklı kullanım alanları için halihazırda bir dizi DataSource uygulaması içermektedir. Verileri özel bir protokol üzerinden, özel bir HTTP yığını kullanarak veya özel bir kalıcı önbellekten başka bir şekilde yüklemek için kendi DataSource sınıfınızı uygulamak isteyebilirsiniz.

Özel bileşenler oluştururken aşağıdakileri yapmanızı öneririz:

  • Bir özel bileşenin etkinlikleri uygulamaya geri bildirmesi gerekiyorsa bunu mevcut ExoPlayer bileşenleriyle aynı modeli kullanarak yapmanızı (örneğin, EventDispatcher sınıflarını kullanarak veya bileşeni oluşturan oluşturucuya bir işleyiciyle birlikte bir Handler geçirerek) öneririz.
  • Oynatma sırasında uygulamanın yeniden yapılandırılmasına olanak tanımak için özel bileşenlerin mevcut ExoPlayer bileşenleriyle aynı modeli kullanmalarını öneririz. Bunu yapmak için özel bileşenlerin PlayerMessage.Target uygulaması ve handleMessage yönteminde yapılandırma değişiklikleri alması gerekir. Uygulama kodu, yapılandırma değişikliklerini ExoPlayer'ın createMessage yöntemini çağırarak, mesajı yapılandırarak ve PlayerMessage.send ile bileşene göndererek geçmelidir. Oynatma iş parçacığında teslim edilecek mesajların gönderilmesi, mesajların oynatıcıda gerçekleştirilen diğer işlemlerle birlikte sırayla yürütülmesini sağlar.