Inti dari library ExoPlayer adalah antarmuka Player
. Player
memaparkan fungsionalitas pemutar media
tingkat tinggi tradisional seperti kemampuan untuk
melakukan buffer media, memutar, menjeda dan mencari. Implementasi default ExoPlayer
adalah
dirancang untuk membuat sedikit asumsi (dan karenanya memberlakukan sedikit batasan)
jenis media yang sedang diputar, bagaimana dan di mana media tersebut disimpan, serta bagaimana media tersebut disimpan
dirender. Daripada menerapkan pemuatan
dan rendering media secara langsung,
Implementasi ExoPlayer
mendelegasikan pekerjaan ini ke komponen yang dimasukkan
saat pemutar dibuat atau saat sumber media baru diteruskan ke pemutar.
Komponen yang umum untuk semua implementasi ExoPlayer
adalah:
- Instance
MediaSource
yang menentukan media yang akan diputar, memuat media, dan dari mana media yang dimuat dapat dibaca. InstanceMediaSource
dibuat dariMediaItem
olehMediaSource.Factory
di dalam pemutar. Mereka juga dapat diteruskan langsung ke pemutar menggunakan API playlist berbasis sumber media. - Instance
MediaSource.Factory
yang mengonversiMediaItem
menjadiMediaSource
. TujuanMediaSource.Factory
dimasukkan saat pemutar dibuat. - Instance
Renderer
yang merender setiap komponen media. Berikut adalah yang dimasukkan saat pemutar dibuat. TrackSelector
yang memilih jalur yang disediakan olehMediaSource
untuk yang digunakan oleh setiapRenderer
yang tersedia.TrackSelector
dimasukkan saat pemutar dibuat.LoadControl
yang mengontrol kapanMediaSource
mem-buffer lebih banyak media, dan berapa banyak media yang di-buffer.LoadControl
dimasukkan saat pemutar dibuat.LivePlaybackSpeedControl
yang mengontrol kecepatan pemutaran selama live streaming pemutaran agar pemutar tetap dekat dengan offset live yang dikonfigurasi. JLivePlaybackSpeedControl
dimasukkan saat pemutar dibuat.
Konsep memasukkan komponen yang mengimplementasikan potongan pemutar fungsionalitas ada di seluruh library. Implementasi {i>default<i} dari beberapa komponen mendelegasikan pekerjaan ke komponen yang dimasukkan lebih lanjut. Hal ini memungkinkan banyak sub-komponen untuk diganti satu per satu dengan penerapan yang dikonfigurasi dengan cara khusus.
Penyesuaian pemutar
Beberapa contoh umum penyesuaian pemutar dengan memasukkan komponen adalah yang dijelaskan di bawah.
Mengonfigurasi tumpukan jaringan
Kami memiliki halaman tentang menyesuaikan stack jaringan yang digunakan oleh ExoPlayer.
Menyimpan data ke dalam cache yang dimuat dari jaringan
Lihat panduan untuk cache dengan cepat untuk sementara dan mendownload media.
Menyesuaikan interaksi server
Beberapa aplikasi mungkin ingin mencegat permintaan dan respons HTTP. Anda mungkin ingin memasukkan header permintaan kustom, membaca header respons server, memodifikasi permintaan URI, dll. Misalnya, aplikasi Anda dapat mengautentikasi dirinya sendiri dengan memasukkan token sebagai header saat meminta segmen media.
Contoh berikut menunjukkan cara menerapkan perilaku ini dengan
dengan memasukkan DataSource.Factory
kustom ke dalam DefaultMediaSourceFactory
:
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();
Dalam cuplikan kode di atas, HttpDataSource
yang dimasukkan mencakup header
"Header: Value"
di setiap permintaan HTTP. Perilaku ini diperbaiki untuk setiap
dengan sumber HTTP.
Untuk pendekatan yang lebih terperinci, Anda bisa menginjeksikan perilaku tepat waktu menggunakan
ResolvingDataSource
. Cuplikan kode berikut menunjukkan cara memasukkan
header permintaan tepat sebelum berinteraksi dengan sumber HTTP:
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)));
Anda juga dapat menggunakan ResolvingDataSource
untuk melakukan
perubahan URI tepat waktu, seperti yang ditunjukkan dalam cuplikan berikut:
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)));
Menyesuaikan penanganan error
Mengimplementasikan LoadErrorHandlingPolicy
kustom memungkinkan aplikasi menyesuaikan
cara ExoPlayer bereaksi terhadap error pemuatan. Misalnya, sebuah aplikasi mungkin ingin gagal dengan cepat
alih-alih mencoba berkali-kali, atau mungkin ingin menyesuaikan logika {i>back-off<i} yang
mengontrol berapa lama pemain menunggu di antara setiap percobaan ulang. Cuplikan berikut
menunjukkan cara menerapkan logika back-off kustom:
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();
Argumen LoadErrorInfo
berisi informasi selengkapnya tentang pemuatan yang gagal ke
menyesuaikan logika berdasarkan jenis
error atau permintaan yang gagal.
Menyesuaikan tanda ekstraktor
Tanda pengekstrak dapat digunakan untuk menyesuaikan cara mengekstrak setiap format
dari media progresif. Parameter ini dapat disetel di DefaultExtractorsFactory
yang
yang diberikan ke DefaultMediaSourceFactory
. Contoh berikut meneruskan flag
yang memungkinkan pencarian berbasis indeks untuk streaming MP3.
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();
Mengaktifkan pencarian kecepatan bit konstan
Untuk streaming MP3, ADTS, dan AMR, Anda dapat mengaktifkan pencarian perkiraan menggunakan
asumsi kecepatan bit konstan dengan tanda FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
.
Tanda ini dapat ditetapkan untuk masing-masing ekstraktor yang menggunakan
DefaultExtractorsFactory.setXyzExtractorFlags
seperti yang dijelaskan di atas. Kepada
mengaktifkan pencarian kecepatan bit konstan untuk semua ekstraktor yang mendukungnya, gunakan
DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
ExtractorsFactory
kemudian dapat dimasukkan melalui DefaultMediaSourceFactory
sebagai
yang dijelaskan untuk menyesuaikan flag ekstrak di atas.
Mengaktifkan antrean buffer asinkron
Antrean buffer asinkron adalah peningkatan dalam rendering ExoPlayer
pipeline, yang mengoperasikan instance MediaCodec
dalam mode asinkron dan
menggunakan thread tambahan untuk menjadwalkan dekode dan rendering data. Mengaktifkannya
dapat mengurangi penurunan {i>frame<i}
dan {i>underrun<i} audio.
Antrean buffer asinkron diaktifkan secara default di perangkat yang menjalankan Android 12 (API level 31) dan yang lebih tinggi, serta dapat diaktifkan secara manual mulai dari Android 6.0 (API level 23). Pertimbangkan untuk mengaktifkan fitur untuk perangkat tertentu yang Anda amati mengalami penurunan {i>frame<i} atau {i>underrun<i} audio, khususnya saat memutar sinyal yang dilindungi DRM atau kecepatan frame tinggi saat ini.
Dalam kasus yang paling sederhana, Anda perlu memasukkan DefaultRenderersFactory
ke
pemutar sebagai berikut:
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();
Jika Anda membuat instance perender secara langsung, teruskan
AsynchronousMediaCodecAdapter.Factory
ke MediaCodecVideoRenderer
dan
Konstruktor MediaCodecAudioRenderer
.
Mengintersepsi panggilan metode dengan ForwardingPlayer
Anda dapat menyesuaikan beberapa perilaku instance Player
dengan menggabungkannya
subclass dari ForwardingPlayer
dan mengganti metode untuk melakukan salah satu
hal berikut:
- Akses parameter sebelum meneruskannya ke
Player
delegasi. - Akses nilai yang ditampilkan dari
Player
delegasi sebelum menampilkannya. - Mengimplementasikan kembali metode ini sepenuhnya.
Saat mengganti metode ForwardingPlayer
, penting untuk memastikan
tetap konsisten mandiri dan mematuhi Player
antarmuka, terutama ketika berhadapan dengan
metode yang dimaksudkan untuk memiliki
perilaku yang identik atau terkait. Contoh:
- Jika Anda ingin mengganti setiap 'putar' operasi, Anda harus mengganti
ForwardingPlayer.play
danForwardingPlayer.setPlayWhenReady
, karena pemanggil akan mengharapkan perilaku metode ini akan identik ketikaplayWhenReady = true
. - Jika Anda ingin mengubah kenaikan pencarian, Anda perlu mengganti keduanya
ForwardingPlayer.seekForward
untuk melakukan pencarian dengan tambahan, danForwardingPlayer.getSeekForwardIncrement
untuk melaporkan kenaikan yang disesuaikan secara benar kembali ke pemanggil. - Jika Anda ingin mengontrol apa
Player.Commands
yang diiklankan oleh pemain Anda harus menggantiPlayer.getAvailableCommands()
danPlayer.isCommandAvailable()
, dan juga mendengarkan CallbackPlayer.Listener.onAvailableCommandsChanged()
untuk mendapatkan notifikasi perubahan dari pemain yang mendasarinya.
Penyesuaian MediaSource
Contoh di atas memasukkan komponen yang disesuaikan untuk digunakan selama pemutaran semua
Objek MediaItem
yang diteruskan ke pemutar. Di mana penyesuaian
yang terperinci
diperlukan, Anda juga dapat memasukkan
komponen khusus ke dalam
Instance MediaSource
, yang dapat diteruskan langsung ke pemutar. Contoh
di bawah ini menunjukkan cara menyesuaikan ProgressiveMediaSource
untuk menggunakan
DataSource.Factory
, ExtractorsFactory
, dan LoadErrorHandlingPolicy
:
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));
Membuat komponen kustom
Library menyediakan implementasi default dari komponen yang tercantum di bagian atas
halaman ini untuk kasus penggunaan umum. ExoPlayer
dapat menggunakan komponen ini, tetapi
juga dapat dibuat untuk menggunakan penerapan kustom jika perilaku non-standar
tidak diperlukan. Beberapa kasus penggunaan untuk penerapan kustom adalah:
Renderer
– Anda mungkin ingin mengimplementasikanRenderer
kustom untuk menangani jenis media ini tidak didukung oleh implementasi default yang disediakan oleh library.TrackSelector
– MengimplementasikanTrackSelector
kustom memungkinkan aplikasi developer untuk mengubah cara jalur yang diekspos olehMediaSource
dipilih untuk digunakan oleh masing-masingRenderer
yang tersedia.LoadControl
– MengimplementasikanLoadControl
kustom memungkinkan aplikasi untuk mengubah kebijakan {i>buffering<i} pemutar.Extractor
– Jika Anda perlu mendukung format penampung yang saat ini tidak didukung didukung oleh library, sebaiknya implementasikan classExtractor
kustom.MediaSource
– Mengimplementasikan classMediaSource
kustom dapat berupa sesuai jika Anda ingin mendapatkan sampel media untuk dimasukkan ke perender dalam cara kustom, atau jika Anda ingin menerapkan pengomposisianMediaSource
kustom perilaku model.MediaSource.Factory
– MenerapkanMediaSource.Factory
kustom memungkinkan aplikasi menyesuaikan cara pembuatanMediaSource
dariMediaItem
.DataSource
– Paket upstream ExoPlayer sudah berisi sejumlah ImplementasiDataSource
untuk berbagai kasus penggunaan. Anda mungkin ingin mengimplementasikan classDataSource
Anda sendiri untuk memuat data dengan cara lain, seperti melalui protokol kustom, menggunakan stack HTTP kustom, atau dari protokol di cache oleh pengguna.
Saat membuat komponen kustom, sebaiknya lakukan tindakan berikut:
- Jika komponen kustom perlu melaporkan peristiwa kembali ke aplikasi, sebaiknya
Anda melakukannya dengan menggunakan model yang sama seperti komponen ExoPlayer yang ada, untuk
contoh menggunakan class
EventDispatcher
atau meneruskanHandler
bersama dengan pemroses ke konstruktor komponen. - Kami merekomendasikan agar komponen kustom menggunakan model yang sama dengan ExoPlayer yang ada
untuk memungkinkan konfigurasi ulang
oleh aplikasi selama pemutaran. Untuk melakukannya:
komponen kustom harus mengimplementasikan
PlayerMessage.Target
dan menerima perubahan konfigurasi dalam metodehandleMessage
. Kode aplikasi harus meneruskan perubahan konfigurasi dengan memanggil metodecreateMessage
ExoPlayer, mengonfigurasi pesan, dan mengirimkannya ke komponen menggunakanPlayerMessage.send
. Mengirim pesan yang akan dikirim di rangkaian pesan pemutaran memastikan bahwa operasi tersebut dijalankan dalam urutan operasi lain yang yang ditampilkan pada pemutar.