TextureView

The TextureView क्लास, व्यू ऑब्जेक्ट है. यह व्यू को SurfaceTexture के साथ जोड़ता है.

OpenGL ES की मदद से रेंडर करना

TextureView ऑब्जेक्ट, SurfaceTexture को रैप करता है. यह कॉलबैक का जवाब देता है और नए बफ़र हासिल करता है. जब TextureView ऑब्जेक्ट नए बफ़र हासिल करता है, तो TextureView, व्यू को अमान्य करने का अनुरोध जारी करता है. साथ ही, डेटा सोर्स के तौर पर सबसे नए बफ़र के कॉन्टेंट का इस्तेमाल करके ड्रॉ करता है. यह उस जगह और तरीके से रेंडर करता है जहां और जैसे व्यू की स्थिति से पता चलता है.

OpenGL ES (GLES), EGL क्रिएशन कॉल को SurfaceTexture पास करके, TextureView ऑब्जेक्ट पर रेंडर कर सकता है. हालांकि, इससे एक समस्या पैदा होती है. जब GLES, TextureView पर रेंडर करता है, तो BufferQueue के प्रोड्यूसर और कंज्यूमर एक ही थ्रेड में होते हैं. इससे बफ़र स्वैप कॉल रुक सकती है या फ़ेल हो सकती है. उदाहरण के लिए, अगर कोई प्रोड्यूसर यूज़र इंटरफ़ेस (यूआई) थ्रेड से, एक के बाद एक कई बफ़र सबमिट करता है, तो EGL बफ़र स्वैप कॉल को BufferQueue से एक बफ़र को डीक्यू करना होगा. हालांकि, कंज्यूमर और प्रोड्यूसर एक ही थ्रेड पर होने की वजह से, कोई बफ़र उपलब्ध नहीं होगा. साथ ही, स्वैप कॉल रुक जाएगी या फ़ेल हो जाएगी.

बफ़र स्वैप के रुकने से बचाने के लिए, BufferQueue को डीक्यू करने के लिए हमेशा एक बफ़र उपलब्ध होना चाहिए. इसके लिए, नया बफ़र क्यू में शामिल होने पर, BufferQueue पहले से हासिल किए गए बफ़र के कॉन्टेंट को खारिज कर देता है. यह कम से कम और ज़्यादा से ज़्यादा बफ़र की संख्या पर भी पाबंदियां लगाता है, ताकि कोई कंज्यूमर एक साथ सभी बफ़र का इस्तेमाल न कर सके.

SurfaceView या TextureView चुनना

SurfaceView और TextureView एक जैसी भूमिकाएं निभाते हैं. साथ ही, दोनों व्यू हाइरार्की के एलिमेंट हैं. हालांकि, SurfaceView और TextureView को अलग-अलग तरीके से लागू किया जाता है. SurfaceView ऑब्जेक्ट, अन्य व्यू के जैसे ही पैरामीटर लेता है. हालांकि, रेंडर किए जाने पर SurfaceView का कॉन्टेंट पारदर्शी होता है.

TextureView में, SurfaceView की तुलना में बेहतर तरीके से अल्फ़ा और रोटेशन को हैंडल किया जाता है. हालांकि, वीडियो पर लेयर किए गए यूज़र इंटरफ़ेस (यूआई) एलिमेंट को कंपोज़िट करने पर, SurfaceView की परफ़ॉर्मेंस बेहतर होती है. जब कोई क्लाइंट, SurfaceView ऑब्जेक्ट की मदद से रेंडर करता है, तो SurfaceView, क्लाइंट को कंपोज़िशन की एक अलग लेयर उपलब्ध कराता है. अगर डिवाइस पर हार्डवेयर ओवरले की सुविधा उपलब्ध है, तो SurfaceFlinger, अलग लेयर को हार्डवेयर ओवरले के तौर पर कंपोज़ करता है. जब कोई क्लाइंट, TextureView की मदद से रेंडर करता है, तो यूज़र इंटरफ़ेस (यूआई) टूलकिट, TextureView ऑब्जेक्ट के कॉन्टेंट को जीपीयू की मदद से व्यू हाइरार्की में कंपोज़ करता है. कॉन्टेंट में किए गए अपडेट की वजह से, अन्य व्यू एलिमेंट फिर से ड्रॉ हो सकते हैं. उदाहरण के लिए, अगर अन्य व्यू, TextureView के ऊपर मौजूद हैं. व्यू रेंडरिंग पूरी होने के बाद, SurfaceFlinger, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) लेयर और अन्य सभी लेयर को कंपोज़ करता है, ताकि दिखने वाला हर पिक्सल दो बार कंपोज़ हो.

केस स्टडी: Grafika का Play Video

Grafika के Play Video में, वीडियो प्लेयर के दो वर्शन शामिल हैं. इनमें से एक को TextureView और दूसरे को SurfaceView की मदद से लागू किया गया है. ऐक्टिविटी का वीडियो डिकोडिंग वाला हिस्सा, MediaCodec से फ़्रेम को TextureView और SurfaceView, दोनों के लिए एक सरफ़ेस पर भेजता है. इन दोनों को लागू करने के तरीके में सबसे बड़ा अंतर, सही आसपेक्ट रेशियो दिखाने के लिए ज़रूरी चरणों का है.

SurfaceView को स्केल करने के लिए, FrameLayout को कस्टम तरीके से लागू करना ज़रूरी है. WindowManager को SurfaceFlinger को विंडो की नई पोज़िशन और नए साइज़ की वैल्यू भेजनी होगी. TextureView ऑब्जेक्ट के SurfaceTexture को स्केल करने के लिए, TextureView#setTransform() की मदद से ट्रांसफ़ॉर्मेशन मैट्रिक्स को कॉन्फ़िगर करना ज़रूरी है.

सही आसपेक्ट रेशियो दिखाने के बाद, दोनों को लागू करने के तरीके एक जैसे होते हैं. जब SurfaceView या TextureView, सरफ़ेस बनाता है, तो ऐप्लिकेशन का कोड, प्लेबैक की सुविधा चालू करता है. जब कोई उपयोगकर्ता चलाएं पर टैप करता है, तो यह वीडियो डिकोडिंग थ्रेड शुरू करता है. इसमें, सरफ़ेस को आउटपुट टारगेट के तौर पर इस्तेमाल किया जाता है. इसके बाद, ऐप्लिकेशन का कोड कुछ नहीं करता. कंपोज़िशन और डिसप्ले को SurfaceFlinger (SurfaceView के लिए) या TextureView हैंडल करता है.

केस स्टडी: Grafika का Double Decode

Grafika का Double Decode, SurfaceTexture के मैनिपुलेशन को TextureView में दिखाता है.

Grafika का Double Decode, दो वीडियो को साथ-साथ दिखाने के लिए TextureView ऑब्जेक्ट के दो वर्शन का इस्तेमाल करता है. इससे वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन जैसा अनुभव मिलता है. स्क्रीन का ओरिएंटेशन बदलने और ऐक्टिविटी रीस्टार्ट होने पर, MediaCodec डिकोडर नहीं रुकते. इससे रीयल-टाइम वीडियो स्ट्रीम के प्लेबैक जैसा अनुभव मिलता है. परफ़ॉर्मेंस बेहतर बनाने के लिए, क्लाइंट को सरफ़ेस को चालू रखना चाहिए. सरफ़ेस, SurfaceTexture के BufferQueue में प्रोड्यूसर इंटरफ़ेस का हैंडल होता है. TextureView ऑब्जेक्ट, SurfaceTexture को मैनेज करता है. इसलिए, क्लाइंट को सरफ़ेस को चालू रखने के लिए, SurfaceTexture को चालू रखना होगा.

SurfaceTexture को चालू रखने के लिए, Grafika का Double Decode, TextureView ऑब्जेक्ट से SurfaceTexture के रेफ़रंस हासिल करता है और उन्हें स्टैटिक फ़ील्ड में सेव करता है. इसके बाद, Grafika का Double Decode, SurfaceTexture को डिस्ट्रॉय होने से बचाने के लिए, TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed() से false दिखाता है. TextureView फिर onSurfaceTextureDestroyed() को एक SurfaceTexture पास करता है. इसे ऐक्टिविटी कॉन्फ़िगरेशन में बदलाव के दौरान भी बनाए रखा जा सकता है. क्लाइंट इसे setSurfaceTexture() के ज़रिए, नए TextureView ऑब्जेक्ट को पास करता है.

हर वीडियो डिकोडर को अलग-अलग थ्रेड ड्राइव करते हैं. Mediaserver, डिकोड किए गए आउटपुट वाले बफ़र को SurfaceTexture, BufferQueue के कंज्यूमर को भेजता है. TextureView ऑब्जेक्ट, रेंडरिंग करते हैं और यूज़र इंटरफ़ेस (यूआई) थ्रेड पर काम करते हैं.

SurfaceView की मदद से Grafika का Double Decode लागू करना, TextureView की मदद से लागू करने से ज़्यादा मुश्किल है. ऐसा इसलिए, क्योंकि SurfaceView ऑब्जेक्ट, स्क्रीन की दिशा में बदलाव के दौरान सरफ़ेस को बंद कर देते हैं. इसके अलावा, SurfaceView ऑब्जेक्ट का इस्तेमाल करने से दो लेयर जुड़ जाती हैं. यह सही नहीं है, क्योंकि हार्डवेयर पर उपलब्ध ओवरले की संख्या सीमित होती है.