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 בהיררכיית התצוגה עם ה-GPU. עדכונים לתוכן עשויים לגרום לרכיבי תצוגה אחרים לצייר מחדש, לדוגמה, אם התצוגות האחרות ממוקמות על גבי TextureView. לאחר סיום עיבוד התצוגה, SurfaceFlinger מרכיב את שכבת ממשק המשתמש של האפליקציה ואת כל השכבות האחרות, כך שכל פיקסל גלוי מורכב פעמיים.

מקרה מבחן: סרטון ההפעלה של גרפיקה

ה-Play Video של 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 בחיים, ה-Double Decode של Grafika משיג הפניות ל-SurfaceTextures מהאובייקטים של TextureView ושומר אותם בשדה סטטי. לאחר מכן, ה-Double Decode של Grafika מחזיר false מ- TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed() כדי למנוע את הרס ה-SurfaceTexture. לאחר מכן, TextureView מעביר SurfaceTexture ל- onSurfaceTextureDestroyed() שניתן לשמור על פני שינוי תצורת הפעילות, אותו מעביר הלקוח ל-TextureView החדש באמצעות setSurfaceTexture() .

חוטים נפרדים מניעים כל מפענח וידאו. Mediaserver שולח מאגרים עם פלט מפוענח ל- SurfaceTextures, צרכני BufferQueue. האובייקטים של TextureView מבצעים רינדור ומבצעים בשרשור ממשק המשתמש.

יישום ה-Double Decode של Grafika עם SurfaceView קשה יותר מהטמעה עם TextureView מכיוון שאובייקטי SurfaceView הורסים משטחים במהלך שינויי כיוון. בנוסף, שימוש באובייקטי SurfaceView מוסיף שתי שכבות, וזה לא אידיאלי בגלל המגבלות על מספר שכבות העל הזמינות בחומרה.