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: 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 आर्ग्युमेंट में, लोड नहीं हो पाने की वजह के बारे में ज़्यादा जानकारी होती है. इससे गड़बड़ी के टाइप या लोड नहीं हो पाने के अनुरोध के आधार पर लॉजिक को पसंद के मुताबिक बनाया जा सकता है.
एक्सट्रैक्टर फ़्लैग को पसंद के मुताबिक बनाना
एक्सट्रैक्टर फ़्लैग का इस्तेमाल करके, यह तय किया जा सकता है कि प्रोग्रेसिव मीडिया से अलग-अलग फ़ॉर्मैट कैसे निकाले जाएं. इन्हें DefaultExtractorsFactory पर सेट किया जा सकता है, जो DefaultMediaSourceFactory को दिया जाता है. नीचे दिए गए उदाहरण में, एक फ़्लैग पास किया गया है. इससे 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 फ़्लैग के साथ कॉन्स्टेंट बिटरेट की मान्यता का इस्तेमाल करके, अनुमानित सीकिंग की सुविधा चालू की जा सकती है.
इन फ़्लैग को अलग-अलग एक्सट्रैक्टर के लिए सेट किया जा सकता है. इसके लिए, ऊपर बताए गए individual
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) और इसके बाद के वर्शन वाले डिवाइसों पर मैन्युअल तरीके से चालू किया जा सकता है. उन डिवाइसों पर इस सुविधा को चालू करें जिन पर आपको फ़्रेम ड्रॉप होने या ऑडियो में रुकावट आने की समस्या दिखती है. खास तौर पर, DRM से सुरक्षित या ज़्यादा फ़्रेम रेट वाला कॉन्टेंट चलाते समय.
सबसे आसान मामले में, आपको प्लेयर में 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 कंस्ट्रक्टर को new DefaultMediaCodecAdapter.Factory(context).forceEnableAsynchronous() पास करें.
ForwardingSimpleBasePlayer की मदद से कार्रवाइयों को पसंद के मुताबिक बनाना
Player के किसी इंस्टेंस के कुछ व्यवहार को अपनी पसंद के मुताबिक बनाया जा सकता है. इसके लिए, उसे ForwardingSimpleBasePlayer की सबक्लास में रैप करें. इस क्लास की मदद से, सीधे तौर पर Player के तरीकों को लागू करने के बजाय, कुछ खास 'ऑपरेशन' को इंटरसेप्ट किया जा सकता है. इससे यह पक्का किया जाता है कि play(), pause(), और setPlayWhenReady(boolean) जैसे कॉम्पोनेंट एक जैसा काम करें. इससे यह भी पक्का होता है कि स्टेटस में हुए सभी बदलाव, रजिस्टर किए गए Player.Listener इंस्टेंस को सही तरीके से भेजे गए हैं. ज़्यादातर मामलों में, एक जैसे नतीजे मिलने की गारंटी की वजह से, ForwardingSimpleBasePlayer को ForwardingPlayer की तुलना में ज़्यादा प्राथमिकता दी जानी चाहिए. ऐसा इसलिए, क्योंकि ForwardingPlayer में गड़बड़ी होने की आशंका ज़्यादा होती है.
उदाहरण के लिए, इमेज के क्रम वाला ऐनिमेशन शुरू या बंद होने पर, कुछ कस्टम लॉजिक जोड़ने के लिए:
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 निर्देश को अनुमति न देने के लिए (और यह पक्का करने के लिए कि Player.seekToNext कोई कार्रवाई नहीं करता है):
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 को पसंद के मुताबिक बनाना
ऊपर दिए गए उदाहरणों में, सभी MediaItem ऑब्जेक्ट के लिए, पसंद के मुताबिक बनाए गए कॉम्पोनेंट डाले जाते हैं. इन ऑब्जेक्ट को प्लेयर को पास किया जाता है, ताकि उन्हें चलाया जा सके. अगर आपको ज़्यादा बारीकी से बदलाव करने हैं, तो अलग-अलग MediaSource इंस्टेंस में पसंद के मुताबिक बनाए गए कॉम्पोनेंट भी डाले जा सकते हैं. इन्हें सीधे तौर पर प्लेयर को पास किया जा सकता है. यहां दिए गए उदाहरण में बताया गया है कि कस्टम DataSource.Factory, ExtractorsFactory, और LoadErrorHandlingPolicy का इस्तेमाल करने के लिए, ProgressiveMediaSource को कैसे पसंद के मुताबिक बनाया जाए:
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का इस्तेमाल करके कॉम्पोनेंट को भेजना चाहिए. प्लेबैक थ्रेड पर डिलीवर किए जाने वाले मैसेज भेजने से यह पक्का होता है कि उन्हें उसी क्रम में लागू किया जाए जिस क्रम में प्लेयर पर अन्य कार्रवाइयां की जा रही हैं.