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 वीडियो
Grafika के Play Video में दो वीडियो प्लेयर शामिल हैं. इनमें से एक को TextureView और दूसरे को SurfaceView के साथ लागू किया गया है. वीडियो डिकोडिंग की गतिविधि, MediaCodec से TextureView और SurfaceView, दोनों के लिए फ़्रेम भेजती है. इन दोनों को लागू करने के तरीके में सबसे बड़ा अंतर यह है कि सही आसपेक्ट रेशियो दिखाने के लिए, अलग-अलग चरणों की ज़रूरत होती है.
SurfaceView को स्केल करने के लिए, FrameLayout को पसंद के मुताबिक लागू करना ज़रूरी है.
WindowManager को SurfaceFlinger को नई विंडो की पोज़िशन और नए साइज़ की वैल्यू भेजनी होती हैं. TextureView के SurfaceTexture को स्केल करने के लिए, TextureView#setTransform()
के साथ ट्रांसफ़ॉर्मेशन मैट्रिक्स को कॉन्फ़िगर करना ज़रूरी है.
ऊंचाई-चौड़ाई का सही अनुपात दिखाने के बाद, दोनों लागू करने के तरीके एक जैसे पैटर्न का पालन करते हैं. जब SurfaceView/TextureView, सर्फ़ेस बनाता है, तब ऐप्लिकेशन कोड, वीडियो चलाने की सुविधा चालू करता है. जब कोई उपयोगकर्ता चलाएं पर टैप करता है, तो वीडियो डिकोडिंग थ्रेड शुरू हो जाती है. इसमें, आउटपुट टारगेट के तौर पर डिसप्ले का इस्तेमाल किया जाता है. इसके बाद, ऐप्लिकेशन कोड कुछ नहीं करता. कंपोज़िशन और डिसप्ले को SurfaceFlinger (SurfaceView के लिए) या TextureView मैनेज करता है.
केस स्टडी: Grafika का डबल डिकोड
Grafika's Double Decode, TextureView में SurfaceTexture में बदलाव करने का तरीका दिखाता है.
Grafika का Double Decode, दो TextureView ऑब्जेक्ट का इस्तेमाल करके दो वीडियो दिखाता है. ये वीडियो, वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन की तरह एक साथ चलते हैं. जब स्क्रीन का ओरिएंटेशन बदलता है और गतिविधि फिर से शुरू होती है, तब MediaCodec डिकोडर बंद नहीं होते हैं. इससे रीयल-टाइम वीडियो स्ट्रीम का प्लेबैक सिम्युलेट होता है. बेहतर परफ़ॉर्मेंस के लिए, क्लाइंट को सरफेस चालू रखना चाहिए. सरफ़ेस, SurfaceTexture के BufferQueue में प्रोड्यूसर इंटरफ़ेस का हैंडल होता है. TextureView, SurfaceTexture को मैनेज करता है. इसलिए, क्लाइंट को SurfaceTexture को चालू रखना होगा, ताकि वह Surface को चालू रख सके.
SurfaceTexture को चालू रखने के लिए, Grafika का Double Decode, TextureView ऑब्जेक्ट से SurfaceTexture के रेफ़रंस हासिल करता है और उन्हें स्टैटिक फ़ील्ड में सेव करता है.
इसके बाद, Grafika का Double Decode, false
से TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed()
पर वापस आ जाता है, ताकि SurfaceTexture को डिस्ट्रॉय होने से बचाया जा सके. इसके बाद, TextureView, onSurfaceTextureDestroyed()
को एक SurfaceTexture पास करता है. इसे ऐक्टिविटी कॉन्फ़िगरेशन में बदलाव होने पर भी बनाए रखा जा सकता है. क्लाइंट, onSurfaceTextureDestroyed()
के ज़रिए इसे नए TextureView को पास करता है.setSurfaceTexture()
हर वीडियो डिकोडर को अलग-अलग थ्रेड से चलाया जाता है. मीडियासर्वर, डिकोड किए गए आउटपुट के साथ बफ़र को SurfaceTexture और BufferQueue के उपभोक्ताओं को भेजता है. TextureView ऑब्जेक्ट, रेंडरिंग करते हैं और यूज़र इंटरफ़ेस (यूआई) थ्रेड पर काम करते हैं.
SurfaceView के साथ Grafika के Double Decode को लागू करना, TextureView के साथ लागू करने से ज़्यादा मुश्किल है. ऐसा इसलिए, क्योंकि ओरिएंटेशन में बदलाव के दौरान SurfaceView ऑब्जेक्ट, सर्फ़ेस को डिस्ट्रॉय कर देते हैं. इसके अलावा, SurfaceView ऑब्जेक्ट का इस्तेमाल करने से दो लेयर जुड़ जाती हैं. यह सही नहीं है, क्योंकि हार्डवेयर पर उपलब्ध ओवरले की संख्या सीमित होती है.