उपयोगकर्ता, मोबाइल डिवाइसों पर ज़्यादातर समय मीडिया देखने में बिताते हैं. इसलिए, मीडिया चलाने का अनुभव बेहतरीन, असरदार, और बैटरी की खपत को ध्यान में रखकर बनाया जाना चाहिए. इसके अलावा, उपयोगकर्ता चाहते हैं कि उन्हें फ़ोन से लेकर लिविंग रूम में मौजूद टीवी और अन्य डिवाइसों पर भी, बिना किसी रुकावट के कॉन्टेंट देखने का अनुभव मिले.
जानें कि Media3 और ExoPlayer के आर्किटेक्चर में किए गए अपडेट, अलग-अलग फ़ॉर्म फ़ैक्टर पर मीडिया को बिना किसी रुकावट के चलाने में कैसे मदद करते हैं. इस सेशन में, Media3 Compose यूज़र इंटरफ़ेस (यूआई) टूलकिट की मदद से रिस्पॉन्सिव इंटरफ़ेस बनाने के बारे में बताया गया है. साथ ही, नए PreloadManager का इस्तेमाल करके फ़ीड में बफ़रिंग की समस्या को खत्म करने और CastPlayer और स्पेशल ऑडियो की मदद से, अपने ऐप्लिकेशन को लिविंग रूम की स्क्रीन और Android XR पर उपलब्ध कराने के बारे में बताया गया है.
ट्रांसक्रिप्ट
ठीक है।
सभी का स्वागत है.
मेरा नाम टोनी है.
मैं Android मीडिया टीम में इंजीनियर हूं.
साथ ही, क्रिस्टीना और डोनोवन के साथ मिलकर, हम इस बारे में बात करेंगे कि Jetpack Media3, Android पर आपकी मीडिया से जुड़ी सभी ज़रूरतों को पूरा करने में कैसे मदद कर सकता है.
Media3, Android की एक सपोर्ट लाइब्रेरी है. इसमें मीडिया से जुड़ी हर चीज़ शामिल है. जैसे, ExoPlayer की मदद से मीडिया चलाना, मीडिया सेशन और Cast की मदद से मीडिया शेयर करना, ट्रांसफ़ॉर्मर की मदद से मीडिया में बदलाव करना या मीडिया की जांच करना, जैसे कि फ़्रेम या मेटाडेटा निकालना.
Media3, इस पूरे स्पेस को एक ही लाइब्रेरी ग्रुप में कवर करता है.
यह एक सपोर्ट लाइब्रेरी है, इसलिए इसे आपके ऐप्लिकेशन में बंडल किया जाता है.
इसका मतलब है कि हम एक जैसा अनुभव दे सकते हैं. इससे सभी ओएस वर्शन और सभी डिवाइसों पर एक ही कोड काम करता है.
इससे अपडेट की क्षमता भी बेहतर होती है.
हम जो भी गड़बड़ी ठीक करते हैं वह एपीआई 24 तक पहुंचती है. साथ ही, यह किसी ओएस रिलीज़ साइकल से नहीं जुड़ी होती है.
साथ ही, सपोर्ट लाइब्रेरी के तौर पर, हम पसंद के मुताबिक बनाने के कई विकल्प दे सकते हैं. ऐसा Android फ़्रेमवर्क में नहीं किया जा सकता.
GitHub पर एक लाइब्रेरी के तौर पर, हम ओपन-सोर्स को प्राथमिकता देते हैं.
इसका मतलब है कि हम जो भी बदलाव करते हैं वह GitHub पर तुरंत उपलब्ध हो जाता है.
हमारे पास एक ऐक्टिव Issue Tracker है. साथ ही, हम पुल के अनुरोध स्वीकार कर रहे हैं.
यहां हाइलाइट करने वाली मुख्य बात यह है कि इस्तेमाल के इन सभी उदाहरणों में, हम हर लेवल की जानकारी का ध्यान रखते हैं. इसमें हाई-लेवल यूज़र इंटरफ़ेस (यूआई) एलिमेंट से लेकर, इस्तेमाल के लिए तैयार आसान एपीआई शामिल हैं. साथ ही, इसमें पसंद के मुताबिक बनाने के बेहतर विकल्प, अलग-अलग फ़ॉर्मैट और स्टैंडर्ड के लिए ज़्यादा सहायता, और इन सभी को बेहतर बनाने वाली परफ़ॉर्मेंस और क्षमता शामिल है.
Media3 में ये सभी सुविधाएं शामिल हैं.
आज हम इनमें से कुछ विषयों पर ज़्यादा गहराई से बात करेंगे.
हम अपने नए Compose यूज़र इंटरफ़ेस (यूआई) मॉड्यूल और नए CastPlayer के बारे में बात करेंगे. CastPlayer की मदद से, मीडिया सेशन के साथ शेयर करना और भी आसान हो जाता है. साथ ही, हम नए ऐडवांस इफ़ेक्ट वाली, फिर से तैयार की गई एडिटिंग पाइपलाइन, मेटाडेटा और फ़्रेम को वापस पाने के लिए नए टूल, और स्ट्रीमिंग की कुछ नई टेक्नोलॉजी के बारे में बात करेंगे. खास तौर पर, Eclipsa वीडियो और ऑडियो के बारे में. इसके अलावा, हम पहले से लोड करने, आगे-पीछे करने, और बैटरी की बचत के लिए, अनुभव की क्वालिटी को बेहतर बनाने वाली कई उपयोगिता के बारे में बात करेंगे.
अब सीधे पहले विषय पर आते हैं. इसमें हम जानेंगे कि Media3, मीडिया के लिए यूज़र इंटरफ़ेस (यूआई) एलिमेंट बनाने में कैसे मदद कर सकता है.
हमने हाल ही में दो नए मॉड्यूल पब्लिश किए हैं: Media3 UI Compose और Media3 UI Compose Material 3.
यहां आपको हाई-लेवल प्लेयर कंपोज़ेबल दिख रहा है. इसे Media3 1.10 में लॉन्च किया गया था और इसमें कोई बदलाव नहीं किया गया है.
@Composable
fun videoScreen() {
Player(viewModel.exoPlayer)
}यह पहले से मौजूद होता है.
इसके लिए, सिर्फ़ Media3 प्लेयर की ज़रूरत होती है.
यहां दिए गए उदाहरण में, यह एक ExoPlayer है, जो आम तौर पर आपके व्यू मॉडल में होता है.
हालांकि, यह CastPlayer, मीडिया कंट्रोलर या आपके ऐप्लिकेशन में मौजूद कोई अन्य प्लेयर भी हो सकता है.
यह बताना ज़रूरी है कि ExoPlayer ही यहां सोर्स ऑफ़ ट्रुथ है.
इसमें सारी जानकारी होती है. साथ ही, प्लेयर कंपोज़ेबल, यूज़र इंटरफ़ेस (यूआई) को रेंडर करने और हर चीज़ को जोड़ने का काम करता है.
लेकिन, अगर आपको इस यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाना है, तो क्या होगा? जैसे, नए बटन, अलग-अलग पोज़िशन, अलग-अलग स्टाइल, टेक्स्ट ओवरले वगैरह?
प्लेयर कंपोज़ेबल, बिल्डिंग ब्लॉक से बना होता है.
आपके पास उन्हें बदलने का विकल्प होता है.
हर ब्लॉक को अपनी पसंद के मुताबिक बनाया जा सकता है. इसके अलावा, उन्हें अपने ऐप्लिकेशन में कहीं भी अलग से इस्तेमाल किया जा सकता है.
उदाहरण के लिए, सबसे ऊपर, बीच में, और bottomControls को अलग-अलग पसंद के मुताबिक बनाया जा सकता है.
शटर के दिखने के तरीके को भी पसंद के मुताबिक बनाया जा सकता है. यह तब दिखता है, जब वीडियो नहीं चल रहे हों या गड़बड़ी का ओवरले दिख रहा हो.
हालांकि, यह तो सिर्फ़ पहला कदम है.
डिफ़ॉल्ट सेंटर और bottomControls में, ज़्यादा जानकारी वाले स्लॉट भी होते हैं जिन्हें पसंद के मुताबिक बनाया जा सकता है.
उदाहरण के लिए, बीच वाले बटन को बदला जा सकता है और बाकी सभी चीज़ों को पहले जैसा ही रखा जा सकता है. इसके अलावा, स्लाइडर के ऊपर या नीचे एलिमेंट जोड़े जा सकते हैं.
Media3 Compose में वे सभी बिल्डिंग ब्लॉक मौजूद हैं जिनकी मदद से ऐसा किया जा सकता है.
उदाहरण के लिए, हमारे पास कई बटन हैं. जैसे, चलाएं/रोकें बटन, रिपीट मोड, शफ़ल मोड, 'म्यूट करें' बटन वगैरह.
इसके बाद, प्रोग्रेस इंडिकेटर होते हैं. जैसे, स्क्रीन पर दिखने वाला स्लाइडर और पोज़िशन टेक्स्ट.
इसमें कई कंटेनर और ओवरले भी हैं.
मैंने आपको हाई-लेवल प्लेयर कंपोज़ेबल का एक उदाहरण दिखाया है. हालांकि, इसके और भी उदाहरण हैं. जैसे, गड़बड़ी के ओवरले या सबटाइटल वगैरह.
इसके अलावा, हमारे पास अन्य काम के कॉम्पोनेंट भी हैं. जैसे, यहां मौजूद यह मिनी कंट्रोलर.
जब उपयोगकर्ता आपके ऐप्लिकेशन पर नेविगेट कर रहा हो, तब इसे बॉटम शीट में रखा जा सकता है.
अभी और भी बहुत कुछ आना बाकी है.
हम इस लाइब्रेरी को लगातार बेहतर बना रहे हैं. उदाहरण के लिए, हम जल्द ही इसमें बदलाव करने के नए कंट्रोल जोड़ेंगे. जैसे, क्लिपिंग स्लाइडर.
अब, चलिए इस कस्टमाइज़ेशन को इस्तेमाल करके देखते हैं कि इन बिल्डिंग ब्लॉक का इस्तेमाल कैसे किया जाता है.
Player(viewModel.exoPlayer)मान लें कि हमें पोज़िशन और अवधि वाले टेक्स्ट को स्लाइडर के बगल से हटाकर, उसके ऊपर ले जाना है.
Player(
player = viewModel.exoPlayer,
bottomControls = {
PlayerDefaults.BottomControls(
player,
left = {}, right = {},
above = {
PositionAndDurationText(
player, separator = " • ")
},
)
},
)इसलिए, हम इन bottomControls को बदल सकते हैं.
हम अब भी डिफ़ॉल्ट कॉम्पोनेंट का इस्तेमाल कर सकते हैं. हालांकि, हम बाईं और दाईं ओर मौजूद स्लॉट को खाली सेट कर देते हैं, ताकि वे न दिखें.
इसके बजाय, हम पोज़िशन और अवधि के टेक्स्ट को ऊपर वाले स्लॉट में रखते हैं. साथ ही, इसे ज़्यादा दिलचस्प बनाने के लिए, कस्टम सेपरेटर का इस्तेमाल करते हैं.
अब मान लें कि हमें centerControls ओवरले को पूरी तरह से हटाना है. इसके बजाय, हमें स्लाइडर के ठीक ऊपर एक 'चलाएं' बटन जोड़ना है. साथ ही, स्पीड कंट्रोल और 'म्यूट करें' बटन भी जोड़ना है.
Player(
player = viewModel.exoPlayer,
centerControls = {},
bottomControls = { ...
above = {
Row(Modifier.fillMaxWidth()) {
PositionAndDurationText(...)
Spacer(Modifier.weight(1f))
PlaybackSpeedToggleButton(player)
MuteButton(player)
PlayPauseButton(player)
}
},
)
}यह भी बिलकुल वही आइडिया है.
हम centerControls को खाली पर सेट कर सकते हैं, ताकि वे दिखना बंद हो जाएं. साथ ही, हम स्लाइडर के ऊपर मौजूद स्लॉट को कुछ अतिरिक्त जगह और उन तीन बटन के साथ बड़ा कर सकते हैं जिन्हें हमें दिखाना है.
ध्यान दें कि ये बटन लाइब्रेरी से ही लिए गए हैं. इसलिए, आपको इसमें कोई अतिरिक्त कोड डालने की ज़रूरत नहीं है.
बस इतना ही करना है.
इन एलिमेंट को स्टाइल करने के लिए, इस पाथ का इस्तेमाल जारी रखा जा सकता है.
अगर आपको 'म्यूट करें' बटन का आइकॉन बदलना है, लेकिन उसकी सुविधा को पहले जैसा ही रखना है, तो यह भी उसी तरह काम करता है.
Player(
...
bottomControls = { ...
above = {
...
MuteButton(player,
painter = { painterResource(
if (showMuted)
R.drawable.muted
else
R.drawable.unmuted )})
}
},
)जैसा कि यहां देखा जा सकता है, बटन के लिए कस्टम पेंटर तय किया जा सकता है और आइकॉन खुद चुने जा सकते हैं.
यह कॉम्पोनेंट आपको कुछ मेटाडेटा उपलब्ध कराता है. इसलिए, आपको बस सही आइकॉन चुनने के लिए, स्टेट को देखना होगा. जैसे, इस उदाहरण में showMuted.
Media3 Compose का मुख्य फ़ायदा यही है.
आपको सिर्फ़ अपने ऐप्लिकेशन के लुक और स्टाइल पर ध्यान देना होगा. बाकी काम Media3 संभाल लेगा.
यह प्लेयर से स्थिति को पढ़ता है, प्लेयर के साथ इंटरैक्ट करता है, और इस दौरान होने वाले सभी ट्रांज़िशन और ऐनिमेशन को मैनेज करता है.
चलिए, अब यूज़र इंटरफ़ेस से आगे बढ़ते हैं और मीडिया शेयर करने के बारे में जानते हैं.
आपके पास उसी डिवाइस पर मौजूद अन्य ऐप्लिकेशन या रिमोट डिवाइसों से कनेक्ट किए गए ऐप्लिकेशन के साथ, मीडिया चलाने की स्थिति शेयर करने का विकल्प होता है.
MediaSession का इस्तेमाल करके, मौजूदा प्लेबैक को पब्लिश किया जा सकता है.
इससे आपके प्लेबैक की स्थिति और मेटाडेटा दूसरों के लिए उपलब्ध हो जाता है. साथ ही, उन्हें आपके प्लेबैक को कंट्रोल करने की अनुमति मिलती है.
Gemini, सिस्टम यूज़र इंटरफ़ेस (यूआई) की मीडिया सूचना, Cast, Wear OS या Android Auto के कंपैनियन ऐप्लिकेशन, आपके ऐप्लिकेशन से इसी तरह इंटरैक्ट करते हैं.
MediaSession, Media3 प्लेयर को रैप करता है. प्लेयर होने पर, इसे बनाना बहुत आसान होता है.
MediaSession.Builder(context, player).build()यह ExoPlayer या आपके ऐप्लिकेशन में मौजूद कोई अन्य प्लेयर हो सकता है, जैसा कि Compose यूज़र इंटरफ़ेस (यूआई) में होता है.
अगर आपको बैकग्राउंड में मीडिया चलाना है, तो आम तौर पर इसे MediaSessionService या MediaLibraryService में होस्ट किया जाता है. यह आपके लिए, लाइफ़ साइकल और सूचना जैसी चीज़ों को अपने-आप मैनेज करता है.
class PlaybackService : MediaSessionService() {
private lateinit var mediaSession:
MediaSession
override fun onGetSession(
info: ControllerInfo) : MediaSession?
= mediaSession
}हालांकि, अगर आपके पास कोई मीडिया ऐप्लिकेशन है, तो आपको पहले से ही यह सब पता होगा.
मैं आपको एक नई और दिलचस्प चीज़ दिखाना चाहता हूं. यह है हमारा नया CastPlayer.
Google Cast की मदद से, अपने लोकल प्लेबैक को किसी रिमोट डिवाइस पर ट्रांसफ़र किया जा सकता है. जैसे, Android TV, Chromecast या स्मार्ट स्पीकर.
हम पहले एक अलग Cast SDK टूल पब्लिश करते थे, जो अब मेंटेनेंस मोड में है.
इसके बजाय, Media3 Cast इसे पूरी तरह से बदल देता है. इसकी वजह यह है कि यह ज़्यादा आसान और बेहतर तरीके से इंटिग्रेशन की सुविधा देता है.
यहां सबसे अहम एलिमेंट CastPlayer है. यह ExoPlayer की तरह ही स्टैंडर्ड प्लेयर इंटरफ़ेस लागू करता है.
ExoPlayer का इस्तेमाल, लोकल प्लेबैक के लिए किया जाता है. वहीं, CastPlayer एक ऐसा डेलिगेटिंग इंस्टेंस है जो ExoPlayer के ज़रिए लोकल तौर पर या Cast प्रोटोकॉल के ज़रिए रिमोट तौर पर मीडिया चला सकता है.
यह हर चीज़ का ध्यान रखता है.
यह आउटपुट डिवाइस में होने वाले बदलावों को सुनता है, कनेक्शन बनाता है, और स्थिति को सिंक करता है. साथ ही, ज़रूरत पड़ने पर आपके लिए प्लेबैक को ट्रांसफ़र करता है.
इस वजह से, CastPlayer को अपने ऐप्लिकेशन में इंटिग्रेट करना बहुत आसान है.
val player = ExoPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()ExoPlayer बनाकर उसे MediaSession के साथ शेयर करने के बजाय, CastPlayer का इस्तेमाल करें. बस इतना ही.
Cast.getSingletonInstance(context).initialize()
val player = CastPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()इसके अलावा, आपको सिर्फ़ Cast सिस्टम को शुरू करना होगा. इसके बाद ही, इसे आपके ऐप्लिकेशन में कहीं इस्तेमाल किया जा सकेगा.
ध्यान दें कि यह CastPlayer, लोकल प्लेबैक के लिए ExoPlayer को इंटरनल तौर पर बनाता है. इसलिए, लोकल प्लेयर को और पसंद के मुताबिक बनाने के लिए, अपना ExoPlayer भी बनाया जा सकता है. साथ ही, इसे इस CastPlayer में लोकल प्लेयर के तौर पर पास किया जा सकता है.
Cast.getSingletonInstance(context).initialize()
val exoPlayer = ExoPlayer.Builder(context).build()
val player = CastPlayer.Builder(context)
.setLocalPlayer(exoPlayer).build()
mediaSession = MediaSession.Builder(context,player)
.build()यह भी Media3 का ही सिद्धांत है.
हम एपीआई के लिए, इस्तेमाल करने में आसान और पहले से मौजूद बिल्डिंग ब्लॉक उपलब्ध कराते हैं. साथ ही, आपको अपनी ज़रूरत के हिसाब से एपीआई को पसंद के मुताबिक बनाने के लिए, सभी विकल्प भी देते हैं.
आपको यह जानने में दिलचस्पी हो सकती है कि इस सेटअप में, उपयोगकर्ता लोकल और रिमोट प्लेबैक के बीच कैसे स्विच करता है.
यह सुविधा, मीडिया सूचना में सिस्टम आउटपुट स्विचर डायलॉग के साथ पहले से ही काम करती है.
यह कोने में मौजूद छोटा बटन है.
हालांकि, अगर आपको कास्ट बटन को आसानी से खोजने लायक बनाने के लिए, उसे प्लेबैक स्क्रीन पर दिखाना है, तो क्या करना होगा?
क्या आपको पसंद के मुताबिक बनाया गया Compose यूज़र इंटरफ़ेस (यूआई) याद है, जिसे हमने कुछ मिनट पहले ही बनाया था?
Player(
exoPlayer,
centerControls = {}
bottomControls = { /* customized */ },
)Media3 Cast, एक आउट-ऑफ़-द-बॉक्स बटन भी उपलब्ध कराता है. इसे वहां रखा जा सकता है.
उदाहरण के लिए, पहले से तैयार MediaRouteButton को topControls में जोड़ना बहुत आसान है. हमें सेट अप करने के लिए किसी और पैरामीटर की ज़रूरत नहीं है. बस इतना ही.
Player(
castPlayer,
centerControls = {}
bottomControls = { /* customized */ },
topControls = {
PlayerDefaults.TopControls(castPlayer) {
MediaRouteButton(
Modifier.align(Alignment.TopEnd))
}
},
)इस बटन पर क्लिक करने से, सिस्टम आउटपुट स्विचर का डायलॉग बॉक्स खुलता है. इसके बाद, CastPlayer आपके लिए मीडिया प्लेबैक को ट्रांसफ़र कर देता है.
आपने यह भी देखा होगा कि मैंने CastPlayer को यूज़र इंटरफ़ेस (यूआई) से कनेक्ट किया है. इससे यह पक्का किया जा सकता है कि रिमोट तौर पर जो भी हो रहा है वह आपके लोकल यूज़र इंटरफ़ेस (यूआई) में दिखे.
अब मैं क्रिस्टीना को बुलाना चाहूंगी, ताकि वे आपको एडिटिंग के बारे में बता सकें.
धन्यवाद.
नमस्ते, अब एडिटिंग और ऐडवांस इफ़ेक्ट के बारे में बात करते हैं.
Media3 एपीआई में कई कॉम्पोनेंट होते हैं.
सबसे पहले, Transformer हमारे एडिटिंग एपीआई का मुख्य एंट्री पॉइंट है.
ट्रांसफ़ॉर्मर, मीडिया को प्रोसेस और ट्रांसकोड करता है. साथ ही, उसे किसी फ़ाइल में एक्सपोर्ट करता है.
इसके बाद, CompositionPlayer आता है. यह आपके मीडिया कंपोज़िशन की रीयल-टाइम झलक दिखाता है.
इससे आपको फ़ाइनल एक्सपोर्ट से पहले, बदलावों की झलक देखने और उन्हें बेहतर बनाने का मौका मिलता है.
इसके बाद, इफ़ेक्ट का विकल्प आता है.
इससे आपको फ़्रेम-दर-फ़्रेम प्रोसेसिंग पर पूरा कंट्रोल मिलता है. इससे आपको सामान्य विज़ुअल इफ़ेक्ट या ग्राफ़िक ओवरले जोड़ने में मदद मिलती है.
आखिर में, हमारे पास मक्सर है.
यह हमारी पाइपलाइन में आखिरी आउटपुट स्टेज के तौर पर काम करता है. यह प्रोसेस किए गए ऑडियो, वीडियो, और मेटाडेटा ट्रैक लेता है और उन्हें स्टैंडर्ड MP4 कंटेनर में लिखता है.
पिछले साल, हमने वीडियो एडिटिंग पाइपलाइन को नए सिरे से तैयार करने और उसे बेहतर बनाने पर काम किया. आज मुझे इसमें किए गए अहम सुधारों के बारे में बताते हुए बेहद खुशी हो रही है.
हमने पाइपलाइन को फिर से क्यों बनाया?
इसलिए, लेगसी आर्किटेक्चर की वजह से कई चुनौतियां सामने आईं.
पहला, यह प्रोसेसिंग के सभी चरणों में मेटाडेटा को लागू नहीं कर पाता था.
यह OpenGL से गहराई से जुड़ा हुआ था. इस वजह से, आधुनिक ग्राफ़िक टूल के लिए इसमें ज़्यादा सुविधाएं नहीं थीं.
इसके जटिल एपीआई की वजह से, डेवलपर के लिए इसे पसंद के मुताबिक बनाना और मैनेज करना मुश्किल हो गया था.
इन चुनौतियों से निपटने के लिए, हमने एक नई प्रोसेसिंग पाइपलाइन बनाई.
सबसे पहले, कई ऐसेट वाले मुश्किल कंपोज़िशन को असेंबल करना अब काफ़ी आसान हो गया है.
दूसरा, OpenGL से अलग होने पर, आपको WebGPU जैसे आधुनिक ग्राफ़िक फ़्रेमवर्क का इस्तेमाल करने की पूरी आज़ादी मिलती है.
आखिर में, Media3 अब डिकोडर और एन्कोडर को सीधे तौर पर मैनेज करता है. इससे सभी डिवाइसों पर बेहतर परफ़ॉर्मेंस और एक जैसा अनुभव मिलता है.
आइए, इस पाइपलाइन के काम करने के तरीके को करीब से देखें.
डिकोडर, फ़्रेम को सीधे तौर पर हार्डवेयर बफ़र में आउटपुट करते हैं. इन्हें Media3 मैनेज करता है.
फ़्रेम एग्रीगेटर, कई सीक्वेंस में फ़्रेम को कोऑर्डिनेट करता है. इससे आपके कस्टम फ़्रेम प्रोसेसर को उन बफ़र को पढ़ने और प्रोसेस करने का सीधा ऐक्सेस मिलता है. इसके बाद, उन्हें एन्कोडर को भेजा जाता है.
FrameProcessor इंटरफ़ेस, ऐप्लिकेशन-लेवल की प्रोसेसिंग के लिए मुख्य एक्सटेंशन पॉइंट के तौर पर काम करता है.
public interface FrameProcessor
extends AutoCloseable {
interface Listener {
void onWakeup();
void onError(
VideoFrameProcessingException exception);
void onFrameProcessed(
Frame frame,
@Nullable SyncFenceWrapper onCompleteFence);
}
interface Factory {
FrameProcessor create(
FrameWriter output,
Executor listenerExecutor,
Listener listener);
}
boolean queue(List<AsyncFrame> frames);
void signalEndOfStream();
}लिसनर इंटरफ़ेस के ज़रिए, आपका ऐप्लिकेशन Media3 को हर बार फ़्रेम प्रोसेस होने की सूचना देता है. साथ ही, सिंक्रनाइज़ेशन फ़ेंस को पास करता है, ताकि Media3 को पता चल सके कि बफ़र को सुरक्षित तरीके से कब फिर से इस्तेमाल किया जा सकता है.
यूनिफ़ाइड मेमोरी के बारे में जानकारी: Media3 को हार्डवेयर बफ़र का मालिकाना हक देने से, आपका ऐप्लिकेशन सीधे तौर पर डेटा को पढ़ सकता है और उसमें बदलाव कर सकता है.
इस ज़ीरो-कॉपी तरीके से, मेमोरी ओवरहेड कम होता है और प्रोसेसिंग बहुत तेज़ होती है.
Adobe, उन डेवलपर में से एक है जो बदलाव करने की सुविधा देने वाले नए एपीआई का फ़ायदा ले रहे हैं.
Adobe Premiere की टीम ने अपने मीडिया एडिटिंग इन्फ़्रास्ट्रक्चर के लिए, Media3 एडिटिंग एपीआई का इस्तेमाल किया. इससे उन्हें Android ईकोसिस्टम के साथ बेहतर तरीके से काम करने में मदद मिली. साथ ही, उन्हें अपनी पसंद के मुताबिक पाइपलाइन और WebGPU का इस्तेमाल करने की सुविधा भी मिली.
इसके अलावा, मुझे यह बताते हुए खुशी हो रही है कि हम Media3 1.12 रिलीज़ के तहत नए इफ़ेक्ट रिलीज़ कर रहे हैं.
सबसे पहले, वीडियो को बेहतर बनाने की सुविधा के बारे में जानते हैं.
हमारा आर्किटेक्चर, मॉड्यूलर सेटअप पर आधारित है.
आपका ऐप्लिकेशन, Media3 इफ़ेक्ट Play Services के साथ इंटिग्रेट होता है. यह Play Services Enhancement मॉड्यूल के साथ इंटरफ़ेस करता है.
वीडियो को बेहतर बनाने वाले मॉड्यूल में टोनमैपिंग, ग़ैर-ज़रूरी आवाज़ें कम करने, धुंधलापन कम करने, और सुपर रिज़ॉल्यूशन की सुविधाएं शामिल हैं.
Video Enhance को अपनी पाइपलाइन में इंटिग्रेट करने के लिए, आपको कोड की कुछ ही लाइनें लिखनी होंगी.
val frameProcessorFactory = EnhancementSessionDecorator.Builder(/* context = */ this, baseGlFactory)
.setTonemappingEnabled(true)
.setDeblurAndDenoiseEnabled(true)
.setUpscaleVideoEnabled(true)
.build()
val transformerBuilder = Transformer.Builder(/* context = */ this)
.setFrameProcessorFactory(frameProcessorFactory)EnhancementSessionDecorator.Builder का इस्तेमाल करके, टोनमैपिंग, फ़ोटो या वीडियो से ब्लर हटाना या क्वालिटी को बेहतर बनाने की प्रोसेस जैसी केपबिलिटी को चुनिंदा तौर पर चालू किया जा सकता है. साथ ही, नतीजे के तौर पर मिलने वाले frameProcessorFactory और हार्डवेयर बफ़र हेल्पर को Transformer.Builder में पास किया जा सकता है.
Media3 1.12 में एक और शानदार इफ़ेक्ट जोड़ा गया है. इसका नाम है स्टूडियो साउंड.
स्टूडियो साउंड की सुविधा, आपके वीडियो के ऑडियो ट्रैक का अपने-आप विश्लेषण करती है. साथ ही, उसे अलग-अलग स्टेम में बांटती है. जैसे, बोली, आस-पास का शोर, और संगीत.
क्रिएटर्स, हवा या भीड़ की आवाज़ को आसानी से कम कर सकते हैं. साथ ही, डायलॉग और संगीत को साफ़ तौर पर सुना सकते हैं.
स्टूडियो साउंड को इंटिग्रेट करने के लिए, स्टूडियो साउंड ऑडियो प्रोसेसर को इफ़ेक्ट ऑब्जेक्ट में पास करें.
val editedMediaItem =
EditedMediaItem.Builder(MediaItem.fromUri(media.uri))
.setEffects(
Effects(
listOf(
soundSeparationAudioProcessor
),
emptyList(), // video effects
)
)
.build()इससे ऑडियो प्रोसेसर, आपके मीडिया आइटम से अटैच हो जाता है.
स्टूडियो साउंड ऑडियो प्रोसेसर बनाते समय, लिसनर कॉलबैक को अटैच करें, ताकि onResult के ज़रिए विश्लेषण किए गए ऑडियो चैनल की मैपिंग मिल सके.
val soundSeparationAudioProcessor =
SoundSeparationAudioProcessor(
getApplication(),
mainExecutor,
object : SoundSeparationAudioProcessor.Listener {
override fun onResult(channelToAudioType: SparseIntArray) {
for (i in 0 until channelToAudioType.size()) {
val channelIndex = channelToAudioType.keyAt(i)
val audioType = channelToAudioType.valueAt(i)
val label = toAudioTypeName(audioType)
detectedChannelVolumes.add(ChannelVolume(channelIndex, audioType, label))
}
}
},
)ऑपरेशन का नतीजा उपलब्ध होने पर, हर चैनल को इटरेट करके चैनल इंडेक्स, पहचाने गए ऑडियो टाइप, और पढ़ने लायक लेबल को एक्सट्रैक्ट करें.
चलिए, स्टूडियो साउंड की सुविधा को काम करते हुए देखते हैं.
पहला असर. बेबी, प्लीज़ रो मत.
हम आपके डिनर के लिए काट रहे हैं.
आपको बैकग्राउंड में बच्चे के रोने की आवाज़ सुनाई दे रही होगी. अब इफ़ेक्ट लागू होने के बाद, यह आवाज़ सुनें.
हां, जैसा कि आपने सुना, बैकग्राउंड में बच्चे के रोने की आवाज़ नहीं थी. इसके लिए, स्टूडियो साउंड इफ़ेक्ट को धन्यवाद.
चलिए, अब मेटाडेटा को वापस पाने के बारे में जानते हैं.
हम देखेंगे कि Media3 की मदद से, कंटेनर के मेटाडेटा को पढ़ना और फ़्रेम निकालना कितना आसान हो जाता है.
MetadataRetriever से शुरू होने वाला यह वर्शन, Kotlin कोरूटीन के साथ आसानी से इंटिग्रेट हो जाता है. इससे साफ़ और नॉन-ब्लॉकिंग कोड मिलता है.
इसका डिज़ाइन साफ़-सुथरा है और इसमें गड़बड़ी होने की संभावना कम है. इसमें हर मीडिया आइटम के लिए, एक ऐसा रिट्रीवर इस्तेमाल किया जाता है जिसमें बदलाव नहीं किया जा सकता.
यह सभी एपीआई वर्शन और डिवाइसों पर एक जैसा काम करता है.
साथ ही, यह कई तरह के मीडिया फ़ॉर्मैट के साथ काम करता है.
यहां MetadataRetriever का इस्तेमाल करके एक उदाहरण दिया गया है.
MetadataRetriever.Builder(context, mediaItem).build().use { retriever ->
// 1. Duration (in microseconds)
val durationUs = retriever.retrieveDurationUs().await()
// 2. Track formats & container metadata (reuses the same preparation pass)
val trackGroups = retriever.retrieveTrackGroups().await()
for (i in 0 until trackGroups.length) {
val format = trackGroups[i].getFormat(0)
// Video/Audio properties: format.width, format.height, format.colorInfo …
// Rich metadata: SlowMotionData, MotionPhotoMetadata, Mp4TimestampData …
val metadata = format.metadata
}
// 3. Stream structure & manifest info
val timeline = retriever.retrieveTimeline().await()
}Kotlin coroutines का इस्तेमाल करके, एसिंक्रोनस तरीके से अवधि को वापस पाया जा सकता है. साथ ही, ट्रैक के फ़ॉर्मैट और मेटाडेटा की जांच की जा सकती है. यह सब एक ही साफ़ ब्लॉक में किया जा सकता है.
चलिए, अब FrameExtractor के बारे में बात करते हैं.
इससे मीडिया आइटम से डिकोड किए गए वीडियो फ़्रेम को तेज़ी से और बेहतर तरीके से निकाला जा सकता है.
यह डिकोडर जैसे बुनियादी संसाधनों को अपने-आप मैनेज करता है. साथ ही, आपको विज़ुअल इफ़ेक्ट या एचडीआर टोन मैपिंग लागू करने की सुविधा देता है. इसके अलावा, यह आपको वीडियो में सटीक तरीके से आगे-पीछे जाने की सुविधा देता है, ताकि आपको अपनी ज़रूरत के हिसाब से सटीक फ़्रेम मिल सके.
कोड में फ़्रेम एक्सट्रैक्शन ऐसा दिखता है.
FrameExtractor.Builder(context, mediaItem)
.setSeekParameters(SeekParameters.CLOSEST_SYNC) // Fast keyframe seeking
.setEffects(listOf(Presentation.createForHeight(360))) // GPU downscaling
.setExtractHdrFrames(true) // Optional: HLG HDR or UltraHDR
.build()
.use { extractor ->
// Representative thumbnail
val thumbnail = extractor.getThumbnail().await()
// Frame at specific timestamp (bitmap + actual presentationTimeMs)
val frame = extractor.getFrame(positionMs = 5_000L).await()
}सीक पैरामीटर, जीपीयू डाउनस्केलिंग, इफ़ेक्ट, और एचडीआर सपोर्ट जैसे विकल्पों के साथ इंस्टेंस बनाएं. इसके बाद, क्लीन सस्पेंडिंग कॉल का इस्तेमाल करके, एसिंक्रोनस तरीके से थंबनेल और खास फ़्रेम का इंतज़ार करें.
अब डोनोवन की बारी.
धन्यवाद, क्रिस्टीना.
अब हम Media3 में जोड़ी गई स्ट्रीमिंग टेक्नोलॉजी के बारे में बात करेंगे. इसमें Eclipsa Video और Eclipsa Audio जैसे फ़ॉर्मैट के लिए सहायता शामिल है.
इसलिए, Media3 में हमारा मुख्य मकसद, स्ट्रीमिंग के स्टैंडर्ड से आगे रहना है. इससे, जब भी कोई नया स्पेसिफ़िकेशन आता है, तो आपको अपनी मीडिया पाइपलाइन को फिर से लिखने की ज़रूरत नहीं पड़ती.
यहां कुछ उदाहरण दिए गए हैं, जिन्हें हमने हाल ही में शिप किया है.
हमारे पास कॉन्टेंट स्टीयरिंग की सुविधा है. इसकी मदद से, लाइव स्ट्रीम के दौरान बैकएंड सीडीएन पाथवे को डाइनैमिक तरीके से स्विच किया जा सकता है.
हम सर्वर-गाइडेड विज्ञापन इंसर्शन की सुविधा देते हैं, ताकि लोगों की दिलचस्पी के मुताबिक दिखाए जाने वाले विज्ञापनों को आसानी से जोड़ा जा सके.
हमने कई एंट्री पॉइंट पर AV1 की सुविधा भी उपलब्ध कराई है. इसमें AV1 एचडीआर की सुविधा भी शामिल है.
हम Android पर प्रोफ़ेशनल वीडियो बनाने की सुविधा देते हैं, ताकि हाई-फ़िडेलिटी वाले वीडियो कैप्चर किए जा सकें और उनमें बदलाव किया जा सके.
हम JPEG और HEIC, दोनों फ़ॉर्मैट में मोशन फ़ोटो के लिए भी सहायता जोड़ रहे हैं.
साथ ही, हम Eclipsa Video और Eclipsa Audio के लिए भी सहायता जोड़ रहे हैं. इसके बारे में हम जल्द ही ज़्यादा जानकारी देंगे.
अच्छी बात यह है कि डिवाइस पर इस सुविधा के रोल आउट होने के बाद, ये सभी सुविधाएं अपने-आप काम करने लगती हैं.
अब हम एचडीआर के अगले वर्शन, Eclipsa Video पर नज़र डालते हैं. साथ ही, यह भी देखते हैं कि यह किस मुख्य समस्या को हल करने की कोशिश कर रहा है.
इसलिए, पिछले एचडीआर फ़ॉर्मैट में जानकारी देने वाला मेटाडेटा दिया जाता था. इससे यह तय होता था कि सीन कैसा दिखना चाहिए. हालांकि, इससे डिसप्ले को यह नहीं पता चलता था कि उसे रेंडर कैसे करना है.
इसलिए, सबसे पहले इस बात को समझें.
अलग-अलग माहौल के लिए, स्क्रीन की औसत चमक के अलग-अलग सुझाव दिए जाते हैं. इससे आपको कॉन्टेंट को साफ़ तौर पर और आराम से देखने में मदद मिलती है.
इसलिए, कम रोशनी वाले कमरे में यह रेंज 100 से 300 निट के बीच होगी.
इसके बाद, जब आप ज़्यादा रोशनी वाली जगहों पर जाते हैं, तो स्क्रीन को भी ज़्यादा रोशनी देनी पड़ती है, ताकि आप कॉन्टेंट को साफ़ तौर पर देख सकें. जब आप सीधे धूप में फ़ोन देखते हैं, तो स्क्रीन को 1,000, 2,000 या इससे भी ज़्यादा निट तक की रोशनी देनी पड़ सकती है, ताकि आप कॉन्टेंट को देख सकें.
पारंपरिक एसडीआर, 100 से 300 निट की रेंज में काम करता है.
एचडीआर का मकसद, स्क्रीन की चमक को हर जगह बढ़ाना नहीं है.
आपको डाइनैमिक रेंज को बढ़ाना है, ताकि आग और सूरज की रोशनी जैसी चीज़ों के लिए स्थानीय हाइलाइट मिल सकें.
हालांकि, स्मार्टफ़ोन से फ़ोटो खींचने में कुछ मुश्किलें आती हैं. ऐसा इसलिए, क्योंकि हम इन्हें अपने साथ हर जगह ले जाते हैं. जैसे, घर के किसी अंधेरे कमरे में या धूप से भरे किसी समुद्र तट पर.
इसके अलावा, कई ऐप्लिकेशन एसडीआर यूज़र इंटरफ़ेस (यूआई) एलिमेंट को एसडीआर कॉन्टेंट और एचडीआर कॉन्टेंट के साथ मिक्स फ़ीड में मिला रहे हैं. इससे आपको कभी-कभी आंखों को चुभने वाला और चौंधियाने वाला असर देखने को मिल सकता है. खास तौर पर, तब जब देर रात को स्क्रोल किया जा रहा हो.
इसलिए, हमें पता है कि एचडीआर क्यों ज़रूरी है, है न?
इससे हमारा कॉन्टेंट, ज़्यादा प्लैटफ़ॉर्म पर शानदार दिखता है.
हमने यह भी देखा है कि एचडीआर चालू होने पर, लोगों की दिलचस्पी बढ़ जाती है.
हालांकि, मौजूदा एचडीआर फ़ॉर्मैट में इन चीज़ों का ध्यान नहीं रखा जाता.
Eclipsa Video की यही खासियत है.
हंसी के लिए रुकें.
धन्यवाद.
धन्यवाद.
इसलिए, Eclipsa Video, जानकारी देने वाले मेटाडेटा के बजाय, निर्देश देने वाला मेटाडेटा उपलब्ध कराता है.
यह तीन मुख्य स्तंभों पर आधारित है.
पहला पिलर, रेफ़रंस व्हाइट ऐंकर है.
इससे स्टैंडर्ड ब्राइटनेस, डिसप्ले के आस-पास की रोशनी के हिसाब से अडजस्ट किए गए एसडीआर वाइट पॉइंट पर लॉक हो जाती है. इससे ब्राइटनेस में अचानक होने वाली बढ़ोतरी से बचा जा सकता है.
दूसरा पिलर, क्रिएटर के लिए एसडीआर बेसलाइन है.
इससे क्रिएटर के टोन मैपिंग कर्व को एसडीआर में वापस लाया जा सकता है.
तीसरा, हमारे पास हेडरूम अडैप्टिव गेन कर्व हैं. ये हाइलाइट को डिटरमिनिस्टिक तरीके से स्केल करते हैं, ताकि वे डिसप्ले के रीयल-टाइम एचडीआर हेडरूम से मैच कर सकें. इससे कॉन्टेंट, उस माहौल से मैच करता है जिसमें उसे देखा जा रहा है.
यह सुविधा, Android 17 और इसके बाद के वर्शन वाले डिवाइसों पर, Media3 1.11 में ExoPlayer के लिए पहले से उपलब्ध है.
Eclipsa Video को ओपन स्टैंडर्ड पर बनाया गया है, ताकि यह अलग-अलग इंडस्ट्री के साथ काम कर सके.
इसलिए, एचडीआर का इस्तेमाल करने का यह सबसे अच्छा समय है.
ऑडियो के लिए, हमारे पास Eclipsa Audio है. यह एक ओपन-सोर्स, रॉयल्टी-फ़्री, और 3D स्पेशल ऑडियो फ़ॉर्मैट है.
यह Alliance for Open Media के आईएएमएफ़ स्पेसिफ़िकेशन पर आधारित है.
यह सीन पर आधारित ऐंबिसोनिक्स और चैनल पर आधारित ऑडियो को एक ही स्ट्रीम में जोड़ता है. इसमें कई तरह के प्रज़ेंटेशन शामिल होते हैं.
इससे ऑब्जेक्ट की तरह बदलाव किए जा सकते हैं. जैसे, डायलॉग को बेहतर बनाना. यह सुविधा, स्टीरियो हेडफ़ोन से लेकर सराउंड साउंड सेटअप तक, हर चीज़ पर काम करेगी.
Media3 में वीडियो चलाने के दो पाथ हैं.
Android 17 और इसके बाद के वर्शन के लिए, ExoPlayer और Android Audio Framework, Eclipsa Audio को अपने-आप रेंडर करेंगे.
Android 16 और इससे पहले के वर्शन के लिए, आपके पास अब भी एक विकल्प है.
Media3 के वैकल्पिक ऐड-ऑन लाइब्रेरी की मदद से, आईएएमएफ़ एक्सटेंशन को चालू किया जा सकता है.
ऑडियो ट्रैक बनाने के लिए, Media3 मक्सर का इस्तेमाल करके आईएएमएफ़ ऑडियो ट्रैक लिखे जा सकते हैं.
हालांकि, अच्छी क्वालिटी के फ़ॉर्मैट उपलब्ध कराना ही काफ़ी नहीं है.
हमें इस क्वालिटी को बेहतर तरीके से डिलीवर करना होगा.
अब मैं इस बारे में बात करना चाहूंगा कि Media3 हमारी पाइपलाइन को कैसे तेज़ और ज़्यादा असरदार बना रहा है.
आज हमने जिन चीज़ों के बारे में बात की है उनमें से ज़्यादातर परफ़ॉर्मेंस सुधार, Media3 के वर्शन को अप-टू-डेट रखने से ही मिल जाते हैं.
हमारी एक सुविधा का उदाहरण पीसीएम ऑडियो ऑफ़लोड है. यह ऑडियो प्लेबैक को कम पावर वाली प्रोसेसिंग यूनिट पर भेज सकता है.
शुरुआती विश्लेषण में, हमने देखा कि स्क्रीन बंद होने पर ऑडियो चलाने से, बैटरी की खपत में 20% तक की कमी आई है.
पीसीएम ऑडियो ऑफ़लोड के अलावा, हमारे पास डाइनैमिक शेड्यूलिंग की सुविधा है. यह ExoPlayer के इंटरनल रेंडरिंग लूप वेक-अप को वीएसवाईएनसी और डिकोडर बफ़र की उपलब्धता के साथ अलाइन करती है.
हमारे पास रेंडरर प्रीवॉर्मिंग की सुविधा भी है. इसकी मदद से, सेकंडरी वीडियो रेंडरर को प्रीवॉर्म किया जा सकता है. इससे प्लेलिस्ट में तुरंत ट्रांज़िशन किया जा सकता है और विज्ञापन आसानी से जोड़े जा सकते हैं.
हमारे पास प्लेयर के अटकने का पता लगाने और प्री-कैशिंग की सुविधा भी है. इससे, रुके हुए बफ़र और रेंडरर का अपने-आप पता चलता है. साथ ही, प्री-कैश मेमोरी को साफ़ तौर पर बाउंड किया जाता है.
हमारे पास एक और बेहतरीन मोड है, जिसे स्क्रबिंग मोड कहते हैं.
यह उन ऐप्लिकेशन के लिए है जहां आपके उपयोगकर्ता अक्सर कॉन्टेंट को आगे-पीछे करते हैं.
इसलिए, जब स्क्रबिंग मोड चालू किया जाता है, तो सीकबार को खींचना और छोड़ना ज़्यादा आसान और आसान हो जाता है, जैसा कि यहां देखा जा सकता है.
हालांकि, यह सुविधा स्क्रबिंग मोड बंद होने पर ही काम करती है.
दाईं ओर, हमें वीडियो को आगे-पीछे करने का मोड चालू दिखता है.
धन्यवाद.
धन्यवाद.
ठीक है।
चलिए, अब Android सिस्टम की परफ़ॉर्मेंस के बारे में बात करते हैं.
हमें शेयर की गई रैम, सीपीयू, और बैटरी के संसाधनों का ध्यान रखना होगा. Android, ऑडियो हार्डनिंग और फ़ोरग्राउंड सेवाओं से जुड़े अपने नियमों को सख्त कर रहा है. इसलिए, अपनी रॉ सेवाओं और बिटमैप को मैनेज करने वाले ऐप्लिकेशन में अक्सर कुछ गड़बड़ियां आ सकती हैं.
ऐसा हो सकता है कि आपको फ़ोरग्राउंड सेवा शुरू करने की अनुमति न होने या बाइंडर आउट-ऑफ़-मेमोरी से जुड़ी गड़बड़ियां दिखी हों.
इसलिए, हमने मीडिया सर्विस सेशन और मीडिया नोटिफ़िकेशन मैनेजर के साथ-साथ, बिटमैप पाइपलाइन को कई तरीकों से बेहतर बनाया है. जैसे, हम फ़ोरग्राउंड सर्विस के पुराने इंटेंट को रोकते हैं और आर्टवर्क मेमोरी जैसी चीज़ों को सीमित करते हैं.
हालांकि, आपके लिए ज़रूरी बात यह है कि अगर Media3 का इस्तेमाल किया जा रहा है और स्टैंडर्ड दिशा-निर्देशों का पालन किया जा रहा है, तो सिस्टम की परफ़ॉर्मेंस से जुड़ी इन सभी पाबंदियों को आपके लिए मैनेज किया जाता है. इससे आपके ऐप्लिकेशन पर कोई असर नहीं पड़ता.
आखिर में, मैं एक ऐसी सुविधा के बारे में बात करना चाहूंगा जो जल्द ही Media3 में आने वाली है.
वीडियो को एन्कोड या एक्सपोर्ट करते समय, हार्डवेयर की विविधता सबसे बड़ी चुनौतियों में से एक हो सकती है.
कई ऐप्लिकेशन, एक ही कोडेक कॉन्फ़िगरेशन का इस्तेमाल करते हैं. इससे क्वालिटी और परफ़ॉर्मेंस पर असर पड़ता है.
इसलिए, हमने CodecDB बनाया.
CodecDB को असल दुनिया के वीडियो के बड़े पैमाने पर किए गए मेज़रमेंट के आधार पर बनाया गया है. इसके लिए, Android डिवाइसों पर क्वालिटी की स्टैंडर्ड मेट्रिक और हार्डवेयर बेंचमार्किंग का इस्तेमाल किया गया है.
आइए, इसे इस्तेमाल करके देखते हैं.
बाईं ओर, हमारे पास एक वीडियो का फ़्रेम है, जिसे हमने फ़ोन पर रिकॉर्ड किया है. इसमें हमने वीडियो का एक सामान्य कॉन्फ़िगरेशन इस्तेमाल किया है, जिसे हम कई डिवाइसों पर इस्तेमाल कर सकते हैं.
दाईं ओर, हमने CodecDB से मिले डिवाइस-लेवल के ऑप्टिमल कॉन्फ़िगरेशन का इस्तेमाल किया.
तो फिर दोनों में क्या अंतर है?
अगर आप ज़्यादा जानकारी वाले हिस्सों को देखें, तो आपको क्वालिटी में सबसे बड़ा अंतर दिखेगा.
इसलिए, पेड़ों की शाखाओं और झाड़ियों की क्लैरिटी या इमारत के किनारे की शार्पनेस देखें.
इसलिए, हमें यहां वीडियो देखने का बेहतर अनुभव मिल रहा है. यह CodecDB का इस्तेमाल करके, किसी डिवाइस की क्षमताओं का फ़ायदा लेता है.
कोड में CodecDB का इस्तेमाल करना काफ़ी आसान है.
val config = CodecDb.onDevice(context)
.forEncodingFallingBackTo {
constraints -> createFallbackConfig(constraints)
}
.findOptimalSettings()
.forEditing()
.withResolution(1920, 1080, /* frameRate= */ 30.0)
.withAnyCodec()
.targetingQuality(VideoEncoder.QUALITY_LEVEL_VERY_GOOD)
.get()आपको एक फ़्लूएंट स्टेज बिल्डर पैटर्न का इस्तेमाल करना होगा, जो आपको हर ज़रूरी पैरामीटर के बारे में जानकारी देता है.
इसलिए, आपको यह बताना होगा कि आपको डेटा का इस्तेमाल किस काम के लिए करना है.
यहां हम बदलाव करने के लिए इसका इस्तेमाल कर रहे हैं.
इससे CodecDB को पता चलता है कि Media3 एक्सपोर्ट या ट्रांसकोडिंग पाइपलाइन का इस्तेमाल किया जा रहा है.
इसके अलावा, कुछ अन्य इस्तेमाल के उदाहरण भी सेट किए जा सकते हैं. जैसे, अगर आपको कैमरे से फ़ोटो खींचने के लिए इसका इस्तेमाल करना है, तो कैमरा कैप्चर सेट करें.
आपको टारगेट रिज़ॉल्यूशन और फ़्रेमरेट भी पास करना होगा.
इसके बाद, यह अनुमान लगाने के बजाय कि 1080 पिक्सल वाले वीडियो के लिए, आठ मेगाबिट प्रति सेकंड की ज़रूरत है या 15 मेगाबिट प्रति सेकंड की, CodecDB को यह बताया जाता है कि आपको किस कोडेक का इस्तेमाल करना है. साथ ही, परसेप्चुअल क्वालिटी टारगेट के लिए पूछा जाता है.
इस मामले में, हम क्वालिटी लेवल को 'बहुत अच्छा' पर सेट कर रहे हैं.
बैकग्राउंड में, CodecDB उस एसओसी के लिए, अनुभव के आधार पर तय किए गए मानदंड के कर्व को देखता है. साथ ही, सही कोडेक और एन्कोडर पैरामीटर दिखाता है.
हमें उम्मीद है कि CodecDB को जल्द ही Media3 में लॉन्च किया जाएगा. ऐसा होने पर, यह नेटिव Media3 टाइप का इस्तेमाल करेगा.
इसलिए, इसे अपने मौजूदा Media3 कोड के साथ इंटिग्रेट करना बहुत आसान है.
ठीक है।
आज हमने Media3 में कई शानदार सुविधाएं देखीं. चलिए, एक बार फिर से उन पर नज़र डालते हैं.
आज आपने हमारे नए Compose यूज़र इंटरफ़ेस (यूआई) मॉड्यूल, नए CastPlayer, और बदलाव की गई एडिटिंग पाइपलाइन के बारे में जाना. साथ ही, आपने कई नए इफ़ेक्ट के बारे में जाना जिनका इस्तेमाल Media3 में किया जा सकता है.
हमने मेटाडेटा और फ़्रेम को वापस पाने के लिए नए टूल भी देखे हैं.
साथ ही, हमने नई स्ट्रीमिंग टेक्नोलॉजी के लिए सहायता, परफ़ॉर्मेंस को बेहतर बनाने, और यूटिलिटी पर भी ध्यान दिया.
Media3 एक ओपन सोर्स लाइब्रेरी है. इसलिए, GitHub रिपॉज़िटरी में जाकर यह देखा जा सकता है कि हमने इन सभी सुविधाओं को कैसे लागू किया है.
आज की तारीख तक, Media3 की सबसे नई स्टेबल रिलीज़ 1.11.1 है.
इसके अलावा, 1.12.0 वर्शन भी आज़माया जा सकता है. फ़िलहाल, यह वर्शन ऐल्फ़ा स्टेज में है.
साथ ही, इस शॉर्ट लिंक पर क्लिक करें. यह आपको Media3 पर हमारे डेवलपर दस्तावेज़ पर ले जाएगा.
बहुत-बहुत धन्यवाद. एआई डेज़ का आनंद लें.
@Composable
fun videoScreen() {
Player(viewModel.exoPlayer)
}Player(viewModel.exoPlayer)Player(
player = viewModel.exoPlayer,
bottomControls = {
PlayerDefaults.BottomControls(
player,
left = {}, right = {},
above = {
PositionAndDurationText(
player, separator = " • ")
},
)
},
)Player(
player = viewModel.exoPlayer,
centerControls = {},
bottomControls = { ...
above = {
Row(Modifier.fillMaxWidth()) {
PositionAndDurationText(...)
Spacer(Modifier.weight(1f))
PlaybackSpeedToggleButton(player)
MuteButton(player)
PlayPauseButton(player)
}
},
)
}Player(
...
bottomControls = { ...
above = {
...
MuteButton(player,
painter = { painterResource(
if (showMuted)
R.drawable.muted
else
R.drawable.unmuted )})
}
},
)MediaSession.Builder(context, player).build()class PlaybackService : MediaSessionService() {
private lateinit var mediaSession:
MediaSession
override fun onGetSession(
info: ControllerInfo) : MediaSession?
= mediaSession
}val player = ExoPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()Cast.getSingletonInstance(context).initialize()
val player = CastPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()Cast.getSingletonInstance(context).initialize()
val exoPlayer = ExoPlayer.Builder(context).build()
val player = CastPlayer.Builder(context)
.setLocalPlayer(exoPlayer).build()
mediaSession = MediaSession.Builder(context,player)
.build()Player(
exoPlayer,
centerControls = {}
bottomControls = { /* customized */ },
)Player(
castPlayer,
centerControls = {}
bottomControls = { /* customized */ },
topControls = {
PlayerDefaults.TopControls(castPlayer) {
MediaRouteButton(
Modifier.align(Alignment.TopEnd))
}
},
)public interface FrameProcessor
extends AutoCloseable {
interface Listener {
void onWakeup();
void onError(
VideoFrameProcessingException exception);
void onFrameProcessed(
Frame frame,
@Nullable SyncFenceWrapper onCompleteFence);
}
interface Factory {
FrameProcessor create(
FrameWriter output,
Executor listenerExecutor,
Listener listener);
}
boolean queue(List<AsyncFrame> frames);
void signalEndOfStream();
}val frameProcessorFactory = EnhancementSessionDecorator.Builder(/* context = */ this, baseGlFactory)
.setTonemappingEnabled(true)
.setDeblurAndDenoiseEnabled(true)
.setUpscaleVideoEnabled(true)
.build()
val transformerBuilder = Transformer.Builder(/* context = */ this)
.setFrameProcessorFactory(frameProcessorFactory)val editedMediaItem =
EditedMediaItem.Builder(MediaItem.fromUri(media.uri))
.setEffects(
Effects(
listOf(
soundSeparationAudioProcessor
),
emptyList(), // video effects
)
)
.build()val soundSeparationAudioProcessor =
SoundSeparationAudioProcessor(
getApplication(),
mainExecutor,
object : SoundSeparationAudioProcessor.Listener {
override fun onResult(channelToAudioType: SparseIntArray) {
for (i in 0 until channelToAudioType.size()) {
val channelIndex = channelToAudioType.keyAt(i)
val audioType = channelToAudioType.valueAt(i)
val label = toAudioTypeName(audioType)
detectedChannelVolumes.add(ChannelVolume(channelIndex, audioType, label))
}
}
},
)MetadataRetriever.Builder(context, mediaItem).build().use { retriever ->
// 1. Duration (in microseconds)
val durationUs = retriever.retrieveDurationUs().await()
// 2. Track formats & container metadata (reuses the same preparation pass)
val trackGroups = retriever.retrieveTrackGroups().await()
for (i in 0 until trackGroups.length) {
val format = trackGroups[i].getFormat(0)
// Video/Audio properties: format.width, format.height, format.colorInfo …
// Rich metadata: SlowMotionData, MotionPhotoMetadata, Mp4TimestampData …
val metadata = format.metadata
}
// 3. Stream structure & manifest info
val timeline = retriever.retrieveTimeline().await()
}FrameExtractor.Builder(context, mediaItem)
.setSeekParameters(SeekParameters.CLOSEST_SYNC) // Fast keyframe seeking
.setEffects(listOf(Presentation.createForHeight(360))) // GPU downscaling
.setExtractHdrFrames(true) // Optional: HLG HDR or UltraHDR
.build()
.use { extractor ->
// Representative thumbnail
val thumbnail = extractor.getThumbnail().await()
// Frame at specific timestamp (bitmap + actual presentationTimeMs)
val frame = extractor.getFrame(positionMs = 5_000L).await()
}val config = CodecDb.onDevice(context)
.forEncodingFallingBackTo {
constraints -> createFallbackConfig(constraints)
}
.findOptimalSettings()
.forEditing()
.withResolution(1920, 1080, /* frameRate= */ 30.0)
.withAnyCodec()
.targetingQuality(VideoEncoder.QUALITY_LEVEL_VERY_GOOD)
.get()