ExoPlayer लाइब्रेरी का मुख्य इंटरफ़ेस Player
है. Player
, मीडिया प्लेयर के पारंपरिक हाई-लेवल फ़ंक्शन दिखाता है. जैसे, मीडिया को बफ़र करना, चलाना, रोकना, और आगे-पीछे करना. डिफ़ॉल्ट तौर पर लागू होने वाले ExoPlayer
को, चलाए जा रहे मीडिया के टाइप, उसे कैसे और कहां सेव किया जाता है, और उसे कैसे रेंडर किया जाता है, इनके बारे में कुछ अनुमान लगाने के लिए डिज़ाइन किया गया है. इसलिए, इस पर कुछ पाबंदियां भी लगाई जाती हैं. मीडिया के लोड और रेंडरिंग को सीधे तौर पर लागू करने के बजाय,
ExoPlayer
इंप्लिमेंटेशन यह काम, प्लेयर के बनाए जाने या प्लेयर को नए मीडिया सोर्स पास किए जाने पर लगाए गए कॉम्पोनेंट के लिए करता है.
ExoPlayer
लागू करने के लिए, ये कॉम्पोनेंट ज़रूरी हैं:
MediaSource
इंस्टेंस, चलाए जाने वाले मीडिया की जानकारी देते हैं, मीडिया को लोड करते हैं, और लोड किए गए मीडिया को पढ़ते हैं. प्लेयर में मौजूदMediaSource.Factory
,MediaItem
सेMediaSource
इंस्टेंस बनाता है. मीडिया सोर्स पर आधारित प्लेलिस्ट एपीआई का इस्तेमाल करके, इन्हें सीधे प्लेयर को भी भेजा जा सकता है.MediaSource.Factory
का ऐसा इंस्टेंस जोMediaItem
कोMediaSource
में बदलता है. प्लेयर बनाने पर,MediaSource.Factory
को इंजेक्ट किया जाता है.Renderer
ऐसे इंस्टेंस जो मीडिया के अलग-अलग कॉम्पोनेंट को रेंडर करते हैं. ये तब इंजेक्ट किए जाते हैं, जब प्लेयर बनाया जाता है.- ऐसा
TrackSelector
जोMediaSource
से मिले ट्रैक चुनता है, ताकि हर उपलब्धRenderer
का इस्तेमाल किया जा सके. प्लेयर बनाने पर,TrackSelector
इंजेक्ट किया जाता है. LoadControl
, जो यह कंट्रोल करता है किMediaSource
कब ज़्यादा मीडिया को बफ़र करे और कितने मीडिया को बफ़र करे. खिलाड़ी बनाने पर,LoadControl
इंजेक्ट किया जाता है.- ऐसा
LivePlaybackSpeedControl
जो लाइव वीडियो चलाने के दौरान, वीडियो चलाने की स्पीड को कंट्रोल करता है. इससे प्लेयर, कॉन्फ़िगर किए गए लाइव ऑफ़सेट के आस-पास रहता है. प्लेयर बनाने पर,LivePlaybackSpeedControl
इंजेक्ट किया जाता है.
लाइब्रेरी में, प्लेयर की सुविधाओं को लागू करने वाले कॉम्पोनेंट इंजेक्ट करने का कॉन्सेप्ट मौजूद है. कुछ कॉम्पोनेंट के डिफ़ॉल्ट तौर पर लागू होने पर, काम को इंजेक्ट किए गए अन्य कॉम्पोनेंट को सौंप दिया जाता है. इससे कई सब-कॉम्पोनेंट को अलग-अलग लागू करने के तरीके से बदला जा सकता है, जिन्हें पसंद के मुताबिक कॉन्फ़िगर किया गया है.
प्लेयर को पसंद के मुताबिक बनाना
कॉम्पोनेंट को इंजेक्ट करके प्लेयर को पसंद के मुताबिक बनाने के कुछ सामान्य उदाहरण नीचे दिए गए हैं.
नेटवर्क स्टैक को कॉन्फ़िगर करना
हमारे पास ExoPlayer के इस्तेमाल किए जाने वाले नेटवर्क स्टैक को पसंद के मुताबिक बनाने के बारे में एक पेज है.
नेटवर्क से लोड किए गए डेटा को कैश मेमोरी में सेव करना
इस्तेमाल के दौरान कुछ समय के लिए कैश मेमोरी में सेव करने और मीडिया डाउनलोड करने के बारे में गाइड देखें.
सर्वर इंटरैक्शन को पसंद के मुताबिक बनाना
ऐसा हो सकता है कि कुछ ऐप्लिकेशन, एचटीटीपी अनुरोधों और जवाबों को रोकना चाहें. हो सकता है कि आप कस्टम अनुरोध हेडर इंजेक्ट करना चाहें, सर्वर के रिस्पॉन्स हेडर पढ़ें, अनुरोधों के यूआरआई में बदलाव करें वगैरह. उदाहरण के लिए, मीडिया सेगमेंट का अनुरोध करते समय, आपका ऐप्लिकेशन हेडर के तौर पर टोकन इंजेक्ट करके अपनी पुष्टि कर सकता है.
इस उदाहरण में बताया गया है कि DefaultMediaSourceFactory
में कस्टम DataSource.Factory
इंजेक्ट करके, इन व्यवहार को कैसे लागू किया जाता है:
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();
ऊपर दिए गए कोड स्निपेट में, इंजेक्ट किए गए HttpDataSource
में हर एचटीटीपी अनुरोध में हेडर
"Header: Value"
शामिल होता है. एचटीटीपी सोर्स से होने वाले हर इंटरैक्शन के लिए, यह व्यवहार ठीक किया जाता है.
ज़्यादा जानकारी वाले तरीके के लिए, ResolvingDataSource
का इस्तेमाल करके, 'जस्ट-इन-टाइम' व्यवहार को इंजेक्ट किया जा सकता है. नीचे दिया गया कोड स्निपेट यह दिखाता है कि किसी एचटीटीपी सोर्स से इंटरैक्ट करने से ठीक पहले, अनुरोध हेडर कैसे इंजेक्ट करें:
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)));
यूआरआई में ज़रूरत के हिसाब से बदलाव करने के लिए, ResolvingDataSource
का इस्तेमाल भी किया जा सकता है. इस बारे में यहां दिए गए स्निपेट में बताया गया है:
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)));
गड़बड़ी ठीक करने की सुविधा को पसंद के मुताबिक बनाना
पसंद के मुताबिक बनाया गया LoadErrorHandlingPolicy
लागू करने से, ऐप्लिकेशन उस तरीके को पसंद के मुताबिक बना सकते हैं
जिससे ExoPlayer, लोड होने वाली गड़बड़ियों पर प्रतिक्रिया देता है. उदाहरण के लिए, हो सकता है कि कोई ऐप्लिकेशन कई बार कोशिश करने के बजाय, तुरंत फ़ेल हो जाए. इसके अलावा, वह बैक-ऑफ़ लॉजिक को पसंद के मुताबिक बनाना चाहे. यह लॉजिक यह कंट्रोल करता है कि हर बार कोशिश करने के बीच प्लेयर कितनी देर इंतज़ार करता है. नीचे दिए गए स्निपेट में, कस्टम बैक-ऑफ़ लॉजिक को लागू करने का तरीका बताया गया है:
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
आर्ग्युमेंट में, लोड न हो पाने के बारे में ज़्यादा जानकारी होती है, ताकि गड़बड़ी के टाइप या अनुरोध पूरा न होने के आधार पर लॉजिक को पसंद के मुताबिक बनाया जा सके.
एक्सट्रैक्टर फ़्लैग को पसंद के मुताबिक बनाना
एक्सट्रैक्टर फ़्लैग का इस्तेमाल करके, यह तय किया जा सकता है कि प्रोग्रेसिव मीडिया से अलग-अलग फ़ॉर्मैट कैसे निकाले जाएं. इन्हें DefaultMediaSourceFactory
के लिए दिए गए DefaultExtractorsFactory
पर सेट किया जा सकता है. नीचे दिए गए उदाहरण में एक फ़्लैग पास किया गया है, जो 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();
लगातार बिटरेट में वीडियो चलाने की सुविधा चालू करना
MP3, ADTS, और AMR स्ट्रीम के लिए, FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
फ़्लैग के साथ, बिटरेट की एक तय दर का अनुमान लगाकर, करीब-करीब सटीक जगह पर जाने की सुविधा चालू की जा सकती है.
ऊपर बताए गए अलग-अलग DefaultExtractorsFactory.setXyzExtractorFlags
तरीकों का इस्तेमाल करके, अलग-अलग एक्सट्रैक्टर के लिए ये फ़्लैग सेट किए जा सकते हैं. डेटा इकट्ठा करने वाले उन सभी टूल के लिए, कॉन्स्टेंट बिटरेट को चुनने की सुविधा चालू करने के लिए जो इस पर काम करते हैं. इसके लिए, DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
का इस्तेमाल करें.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
इसके बाद, ExtractorsFactory
को DefaultMediaSourceFactory
के ज़रिए इंजेक्ट किया जा सकता है, जैसा कि ऊपर एक्सट्रैक्टर फ़्लैग को पसंद के मुताबिक बनाने के लिए बताया गया है.
एसिंक्रोनस बफ़र सूची को चालू करना
एसिंक्रोनस बफ़र सूची, ExoPlayer की रेंडरिंग पाइपलाइन को
बेहतर बनाती है, जो एसिंक्रोनस मोड में MediaCodec
इंस्टेंस ऑपरेट करती है. साथ ही, डेटा को डिकोड करने और रेंडर करने के शेड्यूल के लिए अतिरिक्त थ्रेड का इस्तेमाल करती है. इसे चालू करने से, फ़्रेम और ऑडियो के रुकने की समस्या कम हो सकती है.
असिंक्रोनस बफ़र कतार की सुविधा, Android 12 (एपीआई लेवल 31) और इसके बाद के वर्शन वाले डिवाइसों पर डिफ़ॉल्ट रूप से चालू होती है. साथ ही, Android 6.0 (एपीआई लेवल 23) से इसे मैन्युअल तरीके से चालू किया जा सकता है. जिन डिवाइसों पर फ़्रेम या ऑडियो के रुकने की समस्या आ रही है उन पर यह सुविधा चालू करें. ऐसा खास तौर पर, डीआरएम (डिजिटल राइट्स मैनेजमेंट) से सुरक्षित या ज़्यादा फ़्रेम रेट वाला कॉन्टेंट चलाते समय करें.
सबसे आसान मामले में, आपको प्लेयर में DefaultRenderersFactory
को इस तरह इंजेक्ट करना होगा:
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();
अगर सीधे तौर पर रेंडरर को इंस्टैंशिएट किया जा रहा है, तो MediaCodecVideoRenderer
और MediaCodecAudioRenderer
कंस्ट्रक्टर को AsynchronousMediaCodecAdapter.Factory
पास करें.
ForwardingPlayer
की मदद से, मेथड कॉल को इंटरसेप्ट करना
Player
इंस्टेंस के कुछ व्यवहार को पसंद के मुताबिक बनाया जा सकता है. इसके लिए, उसे ForwardingPlayer
के सबक्लास में रैप करें और इनमें से कोई भी काम करने के लिए, तरीकों को बदलें:
- पैरामीटर को,
Player
को पास करने से पहले ऐक्सेस करें. - रिटर्न वैल्यू को वापस करने से पहले, उसे
Player
से ऐक्सेस करें. - उस तरीके को फिर से पूरी तरह से लागू करें.
ForwardingPlayer
के तरीकों को ओवरराइड करते समय, यह पक्का करना ज़रूरी होता है कि लागू करने की प्रोसेस, Player
इंटरफ़ेस के हिसाब से और अपने-आप में एक जैसी बनी रहे. खास तौर पर तब, जब लागू किए गए तरीके एक जैसे या मिलते-जुलते व्यवहार वाले हों. उदाहरण के लिए:
- अगर आपको हर 'चलाएं' ऑपरेशन को बदलना है, तो आपको
ForwardingPlayer.play
औरForwardingPlayer.setPlayWhenReady
, दोनों को बदलना होगा. ऐसा इसलिए, क्योंकि कॉलर को उम्मीद होगी किplayWhenReady = true
के दौरान, इन तरीकों का व्यवहार एक जैसा होगा. - अगर आपको आगे बढ़ने की सुविधा में बदलाव करना है, तो आपको अपने हिसाब से तय किए गए इंक्रीमेंट के साथ आगे बढ़ने के लिए,
ForwardingPlayer.seekForward
और कॉलर को सही इंक्रीमेंट की जानकारी देने के लिए,ForwardingPlayer.getSeekForwardIncrement
, दोनों को बदलना होगा. - अगर आपको यह कंट्रोल करना है कि किसी प्लेयर इंस्टेंस से किन
Player.Commands
का विज्ञापन दिखाया जाए, तो आपकोPlayer.getAvailableCommands()
औरPlayer.isCommandAvailable()
, दोनों को बदलना होगा. साथ ही, प्लेयर से होने वाले बदलावों की सूचना पाने के लिए,Player.Listener.onAvailableCommandsChanged()
कॉलबैक को भी सुनना होगा.
MediaSource को पसंद के मुताबिक बनाना
ऊपर दिए गए उदाहरणों में, प्लेयर को पास किए गए सभी MediaItem
ऑब्जेक्ट के प्लेबैक के दौरान इस्तेमाल करने के लिए, पसंद के मुताबिक कॉम्पोनेंट इंजेक्ट किए गए हैं. अगर आपको ज़्यादा बदलाव करने हैं, तो अलग-अलग MediaSource
इंस्टेंस में पसंद के मुताबिक कॉम्पोनेंट इंजेक्ट किए जा सकते हैं. इन्हें सीधे प्लेयर को पास किया जा सकता है. यहां दिए गए उदाहरण में, ProgressiveMediaSource
को पसंद के मुताबिक बनाने का तरीका बताया गया है, ताकि कस्टम DataSource.Factory
, ExtractorsFactory
, और 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));
कस्टम कॉम्पोनेंट बनाना
लाइब्रेरी, इस्तेमाल के सामान्य उदाहरणों के लिए, इस पेज पर सबसे ऊपर दिए गए कॉम्पोनेंट को डिफ़ॉल्ट रूप से लागू करती है. ExoPlayer
इन कॉम्पोनेंट का इस्तेमाल कर सकता है. हालांकि, अगर स्टैंडर्ड व्यवहार की ज़रूरत नहीं है, तो कस्टम तरीके से लागू करने के लिए भी इसे बनाया जा सकता है. अपनी ज़रूरत के हिसाब से लागू करने के लिए, इस्तेमाल के कुछ उदाहरण यहां दिए गए हैं:
Renderer
– लाइब्रेरी से डिफ़ॉल्ट रूप से लागू किए गए तरीकों से काम न करने वाले मीडिया टाइप को मैनेज करने के लिए, कस्टमRenderer
लागू किया जा सकता है.TrackSelector
– पसंद के मुताबिकTrackSelector
लागू करने से, ऐप्लिकेशन डेवलपर यह तय कर सकता है कि हर उपलब्धRenderer
में,MediaSource
के दिखाए गए ट्रैक को इस्तेमाल करने के लिए किस तरीके का इस्तेमाल किया जाए.LoadControl
– कस्टमLoadControl
लागू करने से, ऐप्लिकेशन डेवलपर को प्लेयर की बफ़रिंग नीति बदलने की अनुमति मिलती है.Extractor
– अगर आपको कोई ऐसा कंटेनर फ़ॉर्मैट इस्तेमाल करना है जो फ़िलहाल लाइब्रेरी के साथ काम नहीं करता, तो पसंद के मुताबिकExtractor
क्लास लागू करने पर विचार करें.MediaSource
– अगर आपको रेंडरर को फ़ीड करने के लिए, मीडिया सैंपल को अपनी पसंद के मुताबिक पाना है याMediaSource
कंपोजिट करने का तरीका अपनी पसंद के मुताबिक लागू करना है, तो कस्टमMediaSource
क्लास लागू करना सही रहेगा.MediaSource.Factory
– पसंद के मुताबिकMediaSource.Factory
लागू करने से, ऐप्लिकेशन कोMediaItem
सेMediaSource
बनाने के तरीके को पसंद के मुताबिक बनाने की अनुमति मिल जाती है.DataSource
– ExoPlayer के अपस्ट्रीम पैकेज में, इस्तेमाल के अलग-अलग उदाहरणों के लिए, पहले से ही कईDataSource
लागू हैं. ऐसा हो सकता है कि डेटा को किसी अन्य तरीके से लोड करने के लिए, आप अपनेDataSource
क्लास का इस्तेमाल करें. जैसे, कस्टम प्रोटोकॉल पर, कस्टम एचटीटीपी स्टैक का इस्तेमाल करके या कस्टम स्थायी कैश मेमोरी से.
कस्टम कॉम्पोनेंट बनाते समय, हमारा सुझाव है कि आप ये काम करें:
- अगर किसी कस्टम कॉम्पोनेंट को ऐप्लिकेशन में इवेंट की रिपोर्ट भेजनी है, तो हमारा सुझाव है कि आप मौजूदा ExoPlayer कॉम्पोनेंट के जैसे ही मॉडल का इस्तेमाल करें. उदाहरण के लिए,
EventDispatcher
क्लास का इस्तेमाल करना या कॉम्पोनेंट के कन्स्ट्रक्टर में, किसी लिसनर के साथHandler
को पास करना. - हमारा सुझाव है कि कस्टम कॉम्पोनेंट, मौजूदा ExoPlayer कॉम्पोनेंट के जैसे ही मॉडल का इस्तेमाल करें. इससे, वीडियो चलाने के दौरान ऐप्लिकेशन को कॉन्फ़िगर करने की अनुमति मिलती है. ऐसा करने के लिए, कस्टम कॉम्पोनेंट को
PlayerMessage.Target
लागू करना चाहिए औरhandleMessage
तरीके में कॉन्फ़िगरेशन में बदलाव पाना चाहिए. ऐप्लिकेशन कोड को, कॉन्फ़िगरेशन में किए गए बदलावों को पास करना चाहिए. इसके लिए, उसे ExoPlayer केcreateMessage
तरीके को कॉल करना होगा. साथ ही, मैसेज को कॉन्फ़िगर करना होगा औरPlayerMessage.send
का इस्तेमाल करके उसे कॉम्पोनेंट को भेजना होगा. प्लेलिस्ट थ्रेड पर डिलीवर किए जाने वाले मैसेज भेजने से यह पक्का होता है कि वे प्लेयर पर किए जा रहे अन्य ऑपरेशन के क्रम में ही लागू किए जाएं.