TextureView

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

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

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

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

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

SurfaceView या TextureView चुनना

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

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

केस स्टडी: Grafika का गेमप्ले वीडियो

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

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

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

केस स्टडी: Grafika का डबल डिकोड

Grafika के डबल डिकोड में, TextureView में मौजूद SurfaceTexture में बदलाव करने का तरीका दिखाया गया है.

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

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

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

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