ExoPlayer kitaplığının temelinde Player arayüzü bulunur. Player,
medya arabelleğe alma, oynatma, duraklatma ve arama gibi geleneksel üst düzey medya oynatıcı işlevlerini sunar. Varsayılan uygulama ExoPlayer, oynatılan medyanın türü, nasıl ve nerede depolandığı ve nasıl oluşturulduğu hakkında çok az varsayımda bulunacak (ve dolayısıyla çok az kısıtlama getirecek) şekilde 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ı iletildiğinde eklenen bileşenlere devreder.
Tüm ExoPlayer uygulamalarında ortak olan bileşenler şunlardır:
- Oynatılacak medyayı tanımlayan, medyayı yükleyen ve yüklenen medyanın okunabileceği
MediaSourceörnekleri. Oyuncunun içindeki birMediaSource.Factory,MediaItemkullanarakMediaSourceörneği oluşturur. Ayrıca, medya kaynağı tabanlı oynatma listesi API'si kullanılarak doğrudan oynatıcıya da aktarılabilirler. MediaItemdeğeriniMediaSourcedeğerine dönüştüren birMediaSource.Factoryörneği.MediaSource.Factory, oynatıcı oluşturulduğunda eklenir.- Medyanın ayrı ayrı bileşenlerini oluşturan
Rendererörnek. Bunlar, oynatıcı oluşturulduğunda eklenir. MediaSourcetarafından sağlanan parçaları seçerek her birRenderertarafından kullanılmasını sağlayanTrackSelector. Oynatıcı oluşturulduğunda birTrackSelectoreklenir.MediaSourceöğesinin ne zaman daha fazla medya arabelleğe alacağını ve ne kadar medyanın arabelleğe alınacağını kontrol eden birLoadControl. Oynatıcı oluşturulduğunda birLoadControleklenir.- 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 bir
LivePlaybackSpeedControl. Oynatıcı oluşturulduğunda birLivePlaybackSpeedControleklenir.
Oynatıcı işlevinin parçalarını uygulayan bileşenleri ekleme kavramı, kitaplığın tamamında mevcuttur. Bazı bileşenlerin varsayılan uygulamaları, işi daha fazla eklenen bileşene devreder. Bu sayede birçok alt bileşen, özel olarak yapılandırılmış uygulamalarla ayrı ayrı değiştirilebilir.
Oynatıcı özelleştirme
Bileşen ekleyerek oynatıcıyı özelleştirmeyle ilgili bazı yaygın örnekler aşağıdaki bölümlerde 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 var.
Ağdan yüklenen veriler önbelleğe alınıyor
Geçici anlık önbelleğe alma ve medya indirme ile ilgili kılavuzları inceleyin.
Sunucu etkileşimlerini özelleştirme
Bazı uygulamalar HTTP isteklerini ve yanıtlarını kesmek isteyebilir. Özel istek başlıkları eklemek, sunucunun yanıt başlıklarını okumak, isteklerin URI'lerini değiştirmek vb. isteyebilirsiniz. Örneğin, uygulamanız medya segmentlerini isterken başlık 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, eklenen HttpDataSource her HTTP isteğine "Header: Value" başlığını ekler. Bu davranış, bir HTTP kaynağıyla her etkileşim için sabitlenmiştir.
Daha ayrıntılı bir yaklaşım için ResolvingDataSource kullanarak tam zamanında davranış ekleyebilirsiniz. Aşağıdaki kod snippet'i, bir HTTP kaynağıyla etkileşime girmeden hemen önce istek başlıklarının nasıl ekleneceğini gösterir:
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 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 isteyebilir veya oyuncunun her yeniden deneme arasında ne kadar bekleyeceğini kontrol eden geri alma mantığını özelleştirmek isteyebilir. Aşağıdaki snippet'te, özel geri yükleme aralığı mantığının nasıl uygulanacağı gösterilmektedir:
Kotlin
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor( loadErrorInfo: LoadErrorHandlingPolicy.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(LoadErrorHandlingPolicy.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
Çıkarıcı işaretleri, her bir biçimin progresif medyadan nasıl çıkarılacağını özelleştirmek için kullanılabilir. DefaultMediaSourceFactory için sağlanan DefaultExtractorsFactory üzerinde ayarlanabilir. Aşağıdaki örnekte, MP3 akışları için dizine dayalı 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ı aramasını etkinleştirme
MP3, ADTS ve AMR akışları için FLAG_ENABLE_CONSTANT_BITRATE_SEEKING işaretleriyle sabit bit hızı varsayımını kullanarak yaklaşık aramayı etkinleştirebilirsiniz.
Bu işaretler, daha önce açıklandığı gibi ayrı DefaultExtractorsFactory.setXyzExtractorFlags yöntemleri kullanılarak ayrı ayıklayıcılar için ayarlanabilir. Sabit bit hızı arama özelliğini destekleyen tüm ayıklayıcılar için bu özelliği etkinleştirmek istiyorsanız DefaultExtractorsFactory.setConstantBitrateSeekingEnabled kullanın.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
ExtractorsFactory, daha önce ayıklayıcı işaretlerini özelleştirme bölümünde açıklandığı gibi DefaultMediaSourceFactory kullanılarak yerleştirilebilir.
Eşzamansız arabellek sıraya almayı etkinleştirme
Eşzamansız arabellek sıraya alma, ExoPlayer'ın oluşturma ardışık düzeninde yapılan bir geliştirmedir. MediaCodec örneklerini eşzamansız modda çalıştırır ve verilerin kodunu çözüp oluşturmayı planlamak için ek iş parçacıkları kullanır. Bu ayarı etkinleştirmek, kare düşüşlerini ve ses kesintilerini azaltabilir.
Eşzamansız arabellek sırası, Android 12 (API düzeyi 31) veya sonraki sürümleri çalıştıran cihazlarda varsayılan olarak etkindir ve Android 6.0 (API düzeyi 23) sürümünden itibaren manuel olarak etkinleştirilebilir. Özellikle DRM korumalı veya yüksek kare hızlı içerikler oynatılırken kare düşüşleri ya da ses kesintileri gözlemlediğiniz belirli cihazlar için 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 oluşturucularına new
DefaultMediaCodecAdapter.Factory(context).forceEnableAsynchronous() değerini iletin.
ForwardingSimpleBasePlayer ile işlemleri özelleştirme
Bir Player örneğinin bazı davranışlarını, ForwardingSimpleBasePlayer alt sınıfına sarmalayarak özelleştirebilirsiniz. Bu sınıf, Player yöntemlerini doğrudan uygulamak yerine belirli "işlemleri" kesmenize olanak tanır. Bu sayede, örneğin play(), pause() ve setPlayWhenReady(boolean) gibi işlevlerin tutarlı bir şekilde çalışması sağlanır. Ayrıca tüm durum değişikliklerinin kayıtlı Player.Listener örneklerine doğru şekilde yayılmasını sağlar. Çoğu özelleştirme kullanım alanında, bu tutarlılık garantileri nedeniyle hataya daha açık olan ForwardingPlayer yerine ForwardingSimpleBasePlayer tercih edilmelidir.
Örneğin, oynatma başlatıldığında veya durdurulduğunda özel bir 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
public static final 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 komutuna izin vermemek (ve Player.seekToNext komutunun işlem yapmamasını sağlamak) 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
public static final 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ştirmesi
Yukarıdaki örnekler, oynatıcıya iletilen tüm MediaItem nesnelerinin oynatılması sırasında kullanılacak özelleştirilmiş bileşenleri ekler. Ayrıntılı özelleştirme gerektiğinde, özelleştirilmiş bileşenleri doğrudan oynatıcıya aktarılabilen ayrı MediaSource örneklerine eklemek de mümkündür. Aşağıdaki örnekte, özel bir DataSource.Factory, ExtractorsFactory ve LoadErrorHandlingPolicy kullanmak için 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 dışı 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ın desteklemediği bir medya türünü işlemek için özel birRendereruygulamak isteyebilirsiniz.TrackSelector: Özel birTrackSelectoruygulamak, uygulama geliştiricinin,MediaSourcetarafından sunulan parçaların mevcutRenderer'lerin her biri tarafından kullanılmak üzere seçilme şeklini değiştirmesine olanak tanır.LoadControl: Özel birLoadControluygulamak, uygulama geliştiricinin oynatıcının arabelleğe alma politikasını değiştirmesine olanak tanır.Extractor: Kitaplık tarafından desteklenmeyen bir kapsayıcı biçimini desteklemeniz gerekiyorsa özel birExtractorsınıfı uygulamayı düşünebilirsiniz.MediaSource: Oluşturuculara özel bir şekilde beslenecek medya örnekleri elde etmek veya özelMediaSourcebirleştirme davranışı uygulamak istiyorsanız özel birMediaSourcesınıfı uygulamak uygun olabilir.MediaSource.Factory: Özel birMediaSource.Factoryuygulamak, bir uygulamanınMediaItemöğesindenMediaSourceoluşturma şeklini özelleştirmesine olanak tanır.DataSource: ExoPlayer'ın üst paketinde, farklı kullanım alanları için çeşitliDataSourceuygulamaları zaten mevcuttur. Verileri başka bir şekilde (ör. özel bir protokol üzerinden, özel bir HTTP yığını kullanarak veya özel bir kalıcı önbellekten) yüklemek için kendiDataSourcesınıfınızı uygulamak isteyebilirsiniz.
Özel bileşenler oluştururken aşağıdakileri yapmanızı öneririz:
- Özel bir bileşenin uygulamaya etkinlikleri geri bildirmesi gerekiyorsa bunu mevcut ExoPlayer bileşenleriyle aynı modeli kullanarak yapmanızı öneririz. Örneğin,
EventDispatchersınıflarını kullanarak veya bileşenin oluşturucusuna bir dinleyiciyle birlikteHandlerileterek. - Ö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ı öneririz. Bunun için özel bileşenler
PlayerMessage.Targetarayüzünü uygulamalı ve yapılandırma değişikliklerinihandleMessageyönteminde almalıdır. Uygulama kodu, ExoPlayer'ıncreateMessageyöntemini çağırarak, mesajı yapılandırarak vePlayerMessage.sendkullanarak bileşene göndererek yapılandırma değişikliklerini iletmelidir. Mesajların oynatma iş parçacığında yayınlanmak üzere gönderilmesi, oynatıcıda gerçekleştirilen diğer işlemlerle sırayla yürütülmesini sağlar.