Özelleştirme

ExoPlayer kitaplığının merkezinde Player arayüzü bulunur. Player, medyayı arabelleğe alma, oynatma, duraklatma ve ileri sarma gibi geleneksel üst düzey medya oynatıcı işlevlerini gösterir. Varsayılan uygulama ExoPlayer, oynatılan medya türü, nasıl ve nerede depolandığı ve nasıl oluşturulduğu hakkında az sayıda varsayımda bulunmak (ve dolayısıyla az sayıda kısıtlama uygulamak) için tasarlanmıştır. ExoPlayer uygulamaları, medyanın yüklenmesini ve oluşturulmasını doğrudan uygulamak yerine bu işi, bir oynatıcı oluşturulduğunda veya oynatıcıya yeni medya kaynakları aktarıldığında enjekte edilen bileşenlere devreder. Tüm ExoPlayer uygulamalarında ortak olan bileşenler şunlardır:

  • Oynatılabilecek medyayı tanımlayan, medyayı yükleyen ve yüklenen medyanın okunabildiği MediaSource örnekleri. Oynatıcı içindeki bir MediaSource.Factory, MediaItem öğesinden bir MediaSource örneği oluşturur. Ayrıca, medya kaynağına dayalı oynatma listesi API'si kullanılarak doğrudan oynatıcıya aktarılabilirler.
  • Bir MediaItem değerini MediaSource değerine dönüştüren bir MediaSource.Factory örneği. MediaSource.Factory, oynatıcı oluşturulduğunda eklenir.
  • Renderer örnekleri, medyanın ayrı bileşenlerini oluşturur. Bunlar, oynatıcı oluşturulduğunda eklenir.
  • Mevcut her Renderer tarafından kullanılacak MediaSource tarafından sağlanan parçaları seçen bir TrackSelector. Oynatıcı oluşturulduğunda bir TrackSelector eklenir.
  • MediaSource'un ne zaman daha fazla medyayı arabelleğe aldığını ve ne kadar medyanın arabelleğe alındığını kontrol eden bir LoadControl. Oyuncu oluşturulduğunda bir LoadControl eklenir.
  • Oynatıcının yapılandırılmış canlı ofsetine yakın kalmasını sağlamak için canlı oynatmalar sırasında oynatma hızını kontrol eden bir LivePlaybackSpeedControl. Oyuncu oluşturulduğunda bir LivePlaybackSpeedControl eklenir.

Oyuncu işlevlerinin parçalarını uygulayan bileşenleri ekleme kavramı kitaplığın her yerinde mevcuttur. Bazı bileşenlerin varsayılan uygulamaları, işi daha fazla enjekte edilen bileşenlere devreder. Bu sayede birçok alt bileşen, özel bir şekilde yapılandırılan uygulamalarla tek tek değiştirilebilir.

Oyuncu özelleştirme

Bileşen ekleyerek oynatıcıyı özelleştirmeyle ilgili bazı yaygın örnekler 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 hakkında bir sayfamız var.

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

Geçici anında önbelleğe alma ve medya indirme ile ilgili kılavuzları inceleyin.

Sunucu etkileşimlerini özelleştirme

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

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

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, enjekte edilen HttpDataSource her HTTP isteğinde "Header: Value" üst bilgisini içerir. Bu davranış, bir HTTP kaynağıyla yapılan her etkileşim için sabit olur.

Daha ayrıntılı bir yaklaşım için ResolvingDataSource kullanarak tam zamanında davranış ekleyebilirsiniz. Aşağıdaki kod snippet'inde, istek üst bilgilerinin bir HTTP kaynağıyla etkileşime geçmeden hemen önce nasıl ekleneceği gösterilmektedir:

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

Aşağıdaki snippet'te gösterildiği gibi, URI'de tam zamanında değişiklikler yapmak için 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şleme ayarlarını ö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 çok kez tekrar denemek yerine hızlıca başarısız olmak isteyebilir 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 çekilme 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ıklama işaretlerini özelleştirme

Ayıklama işaretleri, bağımsız biçimlerin aşamalı medyadan nasıl ayıklandığını özelleştirmek için kullanılabilir. DefaultMediaSourceFactory'a sağlanan DefaultExtractorsFactory üzerinde ayarlanabilir. Aşağıdaki örnekte, MP3 akışları için dizin tabanlı aramayı etkinleştiren bir işaret iletilmektedir.

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ı aramayı etkinleştirme

MP3, ADTS ve AMR akışları için 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çıklanan ayrı DefaultExtractorsFactory.setXyzExtractorFlags yöntemleri kullanılarak ayrı 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 seçeneğini kullanın.

Kotlin

val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)

Java

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

Ardından ExtractorsFactory, yukarıdaki ayrıştırıcı işaretlerini özelleştirme bölümünde açıklandığı gibi DefaultMediaSourceFactory aracılığıyla enjekte edilebilir.

Eşzamansız arabellek sırasını etkinleştirme

Zaman uyumsuz tampon sırası, ExoPlayer'ın oluşturma ardışık düzeninde yapılan bir iyileştirmedir. Bu iyileştirme, MediaCodec örneklerini zaman uyumsuz modda çalıştırır ve verilerin kodunun çözülmesini ve oluşturulmasını planlamak için ek iş parçacıkları kullanır. Bu özelliği etkinleştirmek, atlanan kareleri ve ses eksikliklerini azaltabilir.

Asenkron arabellek sırası, Android 12 (API düzeyi 31) ve sonraki sürümleri çalıştıran cihazlarda varsayılan olarak etkindir ve Android 6.0 (API düzeyi 23) ile başlayarak manuel olarak etkinleştirilebilir. Özellikle DRM korumalı veya yüksek kare hızı içeren içerikleri oynatırken kare atlama veya ses eksikliği gözlemlediğiniz belirli cihazlarda bu özelliği etkinleştirebilirsiniz.

En basit durumda, oynatıcıya aşağıdaki gibi 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 örneklendiriyorsanız MediaCodecVideoRenderer ve MediaCodecAudioRenderer yapıcılarına bir AsynchronousMediaCodecAdapter.Factory aktarın.

ForwardingSimpleBasePlayer ile işlemleri özelleştirme

Bir Player örneğini ForwardingSimpleBasePlayer alt sınıfına sarmalayarak davranışının bir kısmını özelleştirebilirsiniz. Bu sınıf, doğrudan Player yöntemlerini uygulamak zorunda kalmak yerine belirli "işlemleri" durdurmanıza olanak tanır. Bu sayede play(), pause() ve setPlayWhenReady(boolean) gibi öğelerin davranışı tutarlı olur. Ayrıca, tüm durum değişikliklerinin kayıtlı Player.Listener örneklerine doğru şekilde dağıtılmasını sağlar. Bu tutarlılık garantileri nedeniyle, çoğu özelleştirme kullanım alanında ForwardingSimpleBasePlayer, hataya daha yatkın ForwardingPlayer yerine tercih edilmelidir.

Örneğin, oynatma işlemi başlatıldığında veya durdurulduğunda özel mantık eklemek için:

Kotlin

class PlayerWithCustomPlay(player: Player) : ForwardingSimpleBasePlayer(player) {
  override fun handleSetPlayWhenReady(playWhenReady: Boolean): ListenableFuture<*> {
    // Add custom logic
    return super.handleSetPlayWhenReady(playWhenReady)
  }
}

Java

class PlayerWithCustomPlay extends ForwardingSimpleBasePlayer {

  public PlayerWithCustomPlay(Player player) {
    super(player);
  }

  @Override
  protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
    // Add custom logic
    return super.handleSetPlayWhenReady(playWhenReady);
  }
}

SEEK_TO_NEXT komutunun kullanılmasına izin vermemek için (ve Player.seekToNext'ün işlem yapmadığından emin olmak için):

Kotlin

class PlayerWithoutSeekToNext(player: Player) : ForwardingSimpleBasePlayer(player) {
  override fun getState(): State {
    val state = super.getState()
    return state
      .buildUpon()
      .setAvailableCommands(
        state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build()
      )
      .build()
  }

  // We don't need to override handleSeek, because it is guaranteed not to be called for
  // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable.
}

Java

class PlayerWithoutSeekToNext extends ForwardingSimpleBasePlayer {

  public PlayerWithoutSeekToNext(Player player) {
    super(player);
  }

  @Override
  protected State getState() {
    State state = super.getState();
    return state
        .buildUpon()
        .setAvailableCommands(
            state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build())
        .build();
  }

  // We don't need to override handleSeek, because it is guaranteed not to be called for
  // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable.
}

MediaSource özelleştirme

Yukarıdaki örneklerde, oynatıcıya iletilen tüm MediaItem nesnelerinin oynatılması sırasında kullanılmak üzere özelleştirilmiş bileşenler enjekte edilir. Ayrıntılı özelleştirmenin gerektiği durumlarda, özelleştirilmiş bileşenleri doğrudan oynatıcıya iletilebilecek tekil MediaSource örneklerine yerleştirmek de mümkündür. 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 en üstünde 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 derlenebilir. Özel uygulamalar için 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 bir TrackSelector uygulamaya koymak, uygulama geliştiricilerin bir MediaSource tarafından sunulan parçaların mevcut Renderer'lerin her biri tarafından tüketilmek üzere seçilme şeklini değiştirmelerine olanak tanır.
  • LoadControl: Özel bir LoadControl uygulamak, uygulama geliştiricinin 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: Oluşturuculara özel bir şekilde beslemek için medya örnekleri elde etmek veya özel MediaSource oluşturma davranışı uygulamak istiyorsanız özel bir MediaSource sınıfı uygulamak uygun olabilir.
  • MediaSource.Factory: Özel bir MediaSource.Factory uygulamaya uygulandığında, uygulamanın MediaItem'den MediaSource oluşturma şeklini özelleştirmesine olanak tanır.
  • DataSource: ExoPlayer'ın yayın paketi, farklı kullanım alanları için zaten bir dizi DataSource uygulaması içerir. Verileri özel bir protokol üzerinden, özel bir HTTP yığını kullanarak veya özel bir kalıcı önbellekten 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ı öneririz. Örneğin, EventDispatcher sınıflarını kullanarak veya bir dinleyiciyle birlikte bir Handler'yi bileşenin kurucusuna ileterek.
  • Özel bileşenlerin, oynatma sırasında uygulama tarafından yeniden yapılandırılabilmesi için mevcut ExoPlayer bileşenleriyle aynı modeli kullanmasını önermiştik. Bunu yapmak için özel bileşenler PlayerMessage.Target'ü uygulamalı ve handleMessage yönteminde yapılandırma değişikliklerini almalıdır. Uygulama kodu, ExoPlayer'ın createMessage yöntemini çağırarak, mesajı yapılandırarak ve PlayerMessage.send kullanarak bileşene göndererek yapılandırma değişikliklerini iletmelidir. Oynatma iş akışında yayınlanacak mesajların gönderilmesi, bu mesajların oynatıcıda gerçekleştirilen diğer işlemlerle birlikte sırayla yürütülmesini sağlar.