SurfaceTexture
הוא שילוב של משטח ומרקם OpenGL ES (GLES). מכונות SurfaceTexture
משמשות לספק משטחים שמפיקים טקסטורות של GLES.
SurfaceTexture
מכיל מופע של BufferQueue
שהאפליקציות הן הצרכנים שלו. פונקציית ה-callback onFrameAvailable()
מעדכנת את האפליקציות כשהבעלים של התוכן הדיגיטלי מוסיפים למאגר נתונים חדש. לאחר מכן, האפליקציות קוראות ל-updateTexImage()
, שמפנה את המאגר שהיה בשימוש, מקבלת את המאגר החדש מהתור ומבצעת קריאות ל-EGL כדי להפוך את המאגר לזמין ל-GLES כטקסטורה חיצונית.
מרקמי GLES חיצוניים
מרקמי GLES חיצוניים (GL_TEXTURE_EXTERNAL_OES
) שונים ממרקמי GLES רגילים (GL_TEXTURE_2D
) בדרכים הבאות:
- טקסטורות חיצוניות יוצרות עיבוד גרפי של פוליגונים עם טקסטורה ישירות מהנתונים שמתקבלים מ-
BufferQueue
. - הגדרת מנועי עיבוד טקסטורות חיצוניים שונה מהגדרת מנועי עיבוד טקסטורות רגילים של GLES.
- אי אפשר לבצע בטקסטורות חיצוניות את כל הפעילויות המסורתיות של טקסטורות GLES.
היתרון העיקרי של טקסטורות חיצוניות הוא היכולת שלהן ליצור רינדור ישירות מנתוני BufferQueue
. מכונות SurfaceTexture
מגדירות את דגלים השימוש של הצרכן ל-GRALLOC_USAGE_HW_TEXTURE
כשיוצרים מכונות BufferQueue
לצורך טקסטורות חיצוניות, כדי לוודא שהנתונים במאגר ניתנים לזיהוי על ידי GLES.
מאחר שמופעים של SurfaceTexture
יוצרים אינטראקציה עם הֶקשר EGL, אפליקציה יכולה להפעיל את השיטות שלו רק כשהֶקשר ה-EGL שבבעלות הטקסטורה הוא הנוכחי בשרשור הקריאה. מידע נוסף זמין במסמכי העזרה של הכיתה SurfaceTexture
.
חותמות זמן וטרנספורמציות
המופעים של SurfaceTexture
כוללים את השיטה getTimeStamp()
, שמאחזרת חותמת זמן, ואת השיטה getTransformMatrix()
, שמאחזרת מטריצת טרנספורמציה. קריאה ל-updateTexImage()
מגדירה גם את חותמת הזמן וגם את מטריצת הטרנספורמציה. כל מאגר שמעבירים ל-BufferQueue
כולל פרמטרים של טרנספורמציה וחותמת זמן.
פרמטרים של טרנספורמציה שימושיים לצורך יעילות. במקרים מסוימים, נתוני המקור עשויים להיות בכיוון שגוי עבור הצרכן. במקום לסובב את הנתונים לפני ששולחים אותם לצרכנים, שולחים את הנתונים בכיוון שלהם עם טרנספורמציה שמתקנת את הכיוון. אפשר למזג את מטריצת הטרנספורמציה עם טרנספורמציות אחרות כשמשתמשים בנתונים, וכך לצמצם את התקורה.
חותמת הזמן שימושית למקורות מאגר תלויים-זמן. לדוגמה, כש-setPreviewTexture()
מחבר את ממשק היוצרים לפלט של המצלמה, אפשר להשתמש בפריימים מהמצלמה כדי ליצור סרטון. לכל פריים צריך להיות חותמת זמן של הצגה מהרגע שבו הפריים צולם, ולא מהרגע שבו האפליקציה קיבלה את הפריים. קוד המצלמה מגדיר את חותמת הזמן שסופקה עם המאגר, וכתוצאה מכך מתקבלת סדרה עקבית יותר של חותמות זמן.
מקרה לדוגמה: תיעוד רציף של Grafika
הקלטת הווידאו הרציפות של Grafika כוללת הקלטה של פריימים מהמצלמה של המכשיר והצגת הפריימים האלה במסך.
כדי להקליט פריימים, יוצרים משטח באמצעות השיטה createInputSurface()
של הכיתה MediaCodec ומעבירים את המשטח למצלמה. כדי להציג מסגרות, יוצרים מופע של SurfaceView
ומעבירים את המשטח אל setPreviewDisplay()
. חשוב לזכור שהקלטה של פריימים והצגתם בו-זמנית היא תהליך מורכב יותר.
בפעילות צילום רציף מוצג וידאו מהמצלמה בזמן ההקלטה. במקרה כזה, הסרטון המקודד נכתב למאגר עגול בזיכרון, שאפשר לשמור בדיסק בכל שלב.
התהליך הזה כולל שלוש תורים של מאגרים:
App
– האפליקציה משתמשת במכונה שלSurfaceTexture
כדי לקבל פריימים מהמצלמה, ולהמיר אותם למרקם GLES חיצוני.SurfaceFlinger
– האפליקציה מגדירה מופע שלSurfaceView
כדי להציג את המסגרות.MediaServer
— מגדירים מקודדMediaCodec
עם משטח קלט כדי ליצור את הסרטון.
בתרשים הבא, החצים מציינים את ההפצה של הנתונים מהמצלמה.
מכונות BufferQueue
מוצגות בצבע (יצרנים בצבע ירוק-כחול, צרכנים בצבע ירוק).

איור 1. הפעילות של תיעוד רציף ב-Grafika
סרטון H.264 מקודד עובר למאגר עגול ב-RAM בתהליך האפליקציה.
כשמשתמש לוחץ על לחצן הצילום, הכיתה MediaMuxer
כותבת את הסרטון המקודד לקובץ MP4 בדיסק.
כל המופעים של BufferQueue
מטופלים באמצעות הקשר EGL יחיד באפליקציה, בעוד שהפעולות של GLES מתבצעות בשרשור של ממשק המשתמש. הטיפול בנתונים המקודדים (ניהול מאגר עגול וכתיבה בדיסק) מתבצע בשרשור נפרד.
SurfaceView
, פונקציית ה-callback surfaceCreated()
יוצרת את המופעים EGLContext
ו-EGLSurface
של המקודד של המסך והווידאו. כשמגיע פריים חדש, SurfaceTexture
מבצע ארבע פעולות:
- רכישת המסגרת.
- הופכת את המסגרת לזמינה כטקסטורת GLES.
- עיבוד הפריימים באמצעות פקודות GLES.
- מעביר את הטרנספורמציה ואת חותמת הזמן לכל מופע של
EGLSurface
.
לאחר מכן, חוט המקודד מושך את הפלט המקודד מ-MediaCodec
ומאחסן אותו בזיכרון.
הפעלת סרטונים עם טקסטורות מאובטחת
Android תומך בעיבוד פוסט-פרודקשן של תוכן וידאו מוגן באמצעות GPU. כך האפליקציות יכולות להשתמש ב-GPU כדי ליצור אפקטים מורכבים ולא לינאריים של וידאו (כמו עיוותים), למפות תוכן וידאו מוגן על טקסטורות לשימוש בסצנות גרפיות כלליות (לדוגמה, באמצעות GLES) ובמציאות וירטואלית (VR).

איור 2. הפעלת סרטונים עם טקסטורות מאובטחת
התמיכה מופעלת באמצעות שני התוספים הבאים:
- תוסף EGL – (
EGL_EXT_protected_content
) מאפשר ליצור הקשרים ומשטחים מוגנים של GL, שיכולים לפעול על תוכן מוגן. - תוסף GLES – (
GL_EXT_protected_textures
) מאפשר לתייג טקסטורות כטקסטורות מוגנות, כדי שניתן יהיה להשתמש בהן כקבצים מצורפים של טקסטורות ב-framebuffer.
Android מאפשרת ל-SurfaceTexture
ול-ACodec (libstagefright.so
) לשלוח תוכן מוגן גם אם שטח החלון לא נכנס לתור ב-SurfaceFlinger
, ומספקת שטח וידאו מוגן לשימוש בהקשר מוגן. לשם כך, מגדירים את הביט המוגן של הצרכן (GRALLOC_USAGE_PROTECTED
) בפלטפורמות שנוצרו בהקשר מוגן (מאומת על ידי ACodec).
הפעלת וידאו מאובטח עם טקסטורות יוצרת את הבסיס להטמעה חזקה של DRM בסביבת OpenGL ES. בלי הטמעה חזקה של DRM, כמו Widevine ברמה 1, ספקי תוכן רבים לא מאפשרים עיבוד של התוכן בעל הערך הגבוה שלהם בסביבת OpenGL ES, וכך מונעים תרחישים לדוגמה חשובים של שימוש ב-VR, כמו צפייה בתוכן שמוגן על ידי DRM ב-VR.
AOSP כולל קוד מסגרת להפעלה מאובטחת של סרטוני טקסטורה. תמיכה בדרייברים היא באחריות יצרני הציוד המקורי (OEM). מי שמטמיע את המכשיר צריך להטמיע את EGL_EXT_protected_content
ואת GL_EXT_protected_textures extensions
. כשמשתמשים בספריית codec משלכם (כדי להחליף את libstagefright
), חשוב לשים לב לשינויים ב-/frameworks/av/media/libstagefright/SurfaceUtils.cpp
שמאפשרים לשלוח למאגר ANativeWindow
מאגרי נתונים שמסומנים ב-GRALLOC_USAGE_PROTECTED
(גם אם ANativeWindow
לא מציב אותם בתור ישירות ל-window composer), כל עוד הביטים של נתוני השימוש של הצרכן מכילים את GRALLOC_USAGE_PROTECTED
. למסמכי עזרה מפורטים בנושא הטמעת התוספים, אפשר לעיין במרשמים של Khronos (EGL_EXT_protected_content
ו-GL_EXT_protected_textures
).