TextureView

الفئة TextureView هي كائن عرض يجمع بين طريقة عرض وSurfaceTexture.

العرض باستخدام OpenGL ES

يغلّف كائن TextureView عنصر SurfaceTexture، ويستجيب لعمليات معاودة الاتصال ويحصل على مخازن مؤقتة جديدة. عندما يحصل كائن TextureView على مخازن مؤقتة جديدة، يرسل TextureView طلبًا لإبطال طريقة العرض ويرسم باستخدام محتوى أحدث مخزن مؤقت كمصدر بيانات، ويتم العرض في أي مكان وبأي طريقة تشير إليها حالة العرض.

يمكن لـ OpenGL ES (GLES) العرض على كائن TextureView من خلال تمرير SurfaceTexture إلى طلب إنشاء EGL، ولكن يؤدي ذلك إلى حدوث مشكلة. عندما يعرض 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

يتضمّن تطبيق "تشغيل الفيديو" في Grafika مشغّلَي فيديو، أحدهما تم تنفيذه باستخدام TextureView والآخر تم تنفيذه باستخدام SurfaceView. يرسل جزء فك ترميز الفيديو في النشاط إطارات من MediaCodec إلى مساحة عرض لكل من TextureView وSurfaceView. أكبر فرق بين عمليات التنفيذ هو الخطوات المطلوبة لعرض نسبة العرض إلى الارتفاع الصحيحة.

يتطلّب تغيير حجم SurfaceView تنفيذًا مخصّصًا لـ FrameLayout. يحتاج WindowManager إلى إرسال موضع نافذة جديد وقيم حجم جديدة إلى SurfaceFlinger. يتطلّب تغيير حجم SurfaceTexture لكائن TextureView ضبط مصفوفة تحويل باستخدام TextureView#setTransform().

بعد عرض نسبة العرض إلى الارتفاع الصحيحة، تتّبع كلتا عمليتَي التنفيذ النمط نفسه. عندما تنشئ SurfaceView أو TextureView مساحة العرض، يفعِّل رمز التطبيق التشغيل. عندما ينقر المستخدم على تشغيل، تبدأ سلسلة محادثات فك ترميز الفيديو ، مع مساحة العرض كهدف الإخراج. بعد ذلك، لا يفعل رمز التطبيق أي شيء، إذ تتولّى خدمة SurfaceFlinger (بالنسبة إلى SurfaceView) أو TextureView عملية الدمج والعرض.

دراسة حالة: فك الترميز المزدوج في Grafika

يوضّح تطبيق "فك الترميز المزدوج" في Grafika كيفية معالجة SurfaceTexture داخل TextureView.

يستخدم تطبيق "فك الترميز المزدوج" في Grafika زوجًا من كائنات TextureView لعرض فيديوهَين يتم تشغيلهما جنبًا إلى جنب، ما يحاكي تطبيقًا لعقد مؤتمرات الفيديو. عندما يتغيّر اتجاه الشاشة ويتم إعادة تشغيل النشاط، لا تتوقّف أجهزة فك الترميز في MediaCodec، ما يحاكي تشغيل بث فيديو في الوقت الفعلي. لتحسين الكفاءة، يجب أن يحافظ العميل على مساحة العرض نشطة. مساحة العرض هي مؤشر إلى واجهة المنتج في BufferQueue الخاصة بـ SurfaceTexture. بما أنّ كائن TextureView يدير SurfaceTexture، يحتاج العميل إلى الحفاظ على SurfaceTexture نشطًا للحفاظ على مساحة العرض نشطة.

للحفاظ على SurfaceTexture نشطًا، يحصل تطبيق "فك الترميز المزدوج" في Grafika على مراجع إلى SurfaceTextures من كائنات TextureView ويحفظها في حقل ثابت. بعد ذلك، يعرض تطبيق "فك الترميز المزدوج" في Grafika القيمة false من TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed() لمنع إتلاف SurfaceTexture. بعد ذلك، يمرِّر TextureView عنصر SurfaceTexture إلى onSurfaceTextureDestroyed() يمكن الاحتفاظ به عند تغيير إعدادات النشاط، والذي يمرِّره العميل إلى كائن TextureView الجديد من خلال setSurfaceTexture().

تُشغّل سلاسل محادثات منفصلة كل جهاز فك ترميز فيديو. يرسل Mediaserver مخازن مؤقتة تتضمّن الإخراج الذي تم فك ترميزه إلى SurfaceTextures، أي مستهلكي BufferQueue. تُجري كائنات TextureView عملية العرض وتُنفّذ على سلسلة واجهة المستخدم.

يكون تنفيذ تطبيق "فك الترميز المزدوج" في Grafika باستخدام SurfaceView أصعب من تنفيذه باستخدام TextureView لأنّ كائنات SurfaceView تتلف مساحات العرض أثناء تغييرات الاتجاه. بالإضافة إلى ذلك، يؤدي استخدام كائنات SurfaceView إلى إضافة طبقتَين، وهو أمر غير مثالي بسبب القيود المفروضة على عدد طبقات التراكب المتاحة على الجهاز.