SurfaceTexture
คือพื้นผิวและพื้นผิว OpenGL ES (GLES) ที่รวมกัน อินสแตนซ์ SurfaceTexture
ใช้เพื่อแสดงผลพื้นผิวที่ส่งออกไปยังพื้นผิว GLES
SurfaceTexture
มีอินสแตนซ์ของ BufferQueue
ซึ่งแอปเป็นผู้บริโภค onFrameAvailable()
callback จะแจ้งให้แอปทราบเมื่อผู้ผลิตจัดคิวบัฟเฟอร์ใหม่ จากนั้นแอปจะเรียกใช้ updateTexImage()
ซึ่งจะปล่อยบัฟเฟอร์ที่เก็บไว้ก่อนหน้านี้ รับบัฟเฟอร์ใหม่จากคิว และเรียกใช้ EGL เพื่อให้ GLES เข้าถึงบัฟเฟอร์เป็นพื้นผิวภายนอกได้
พื้นผิว GLES ภายนอก
พื้นผิว GLES ภายนอก (GL_TEXTURE_EXTERNAL_OES
) แตกต่างจากพื้นผิว GLES แบบดั้งเดิม (GL_TEXTURE_2D
) ดังนี้
- พื้นผิวภายนอกจะแสดงผลรูปหลายเหลี่ยมที่มีพื้นผิวจากข้อมูลที่รับจาก
BufferQueue
โดยตรง - โปรแกรมแสดงผลพื้นผิวภายนอกได้รับการกําหนดค่าแตกต่างจากโปรแกรมแสดงผลพื้นผิว GLES แบบดั้งเดิม
- พื้นผิวภายนอกไม่สามารถดําเนินการพื้นผิว GLES แบบดั้งเดิมได้ทั้งหมด
ประโยชน์หลักของพื้นผิวภายนอกคือความสามารถในการแสดงผลจากข้อมูล BufferQueue
โดยตรง SurfaceTexture
อินสแตนซ์ตั้งค่า Flag การใช้งานของผู้บริโภคเป็น GRALLOC_USAGE_HW_TEXTURE
เมื่อสร้างBufferQueue
อินสแตนซ์สำหรับพื้นผิวภายนอกเพื่อให้ GLES จดจำข้อมูลในบัฟเฟอร์ได้
เนื่องจากอินสแตนซ์ SurfaceTexture
โต้ตอบกับบริบท EGL แอปจะเรียกใช้เมธอดของ SurfaceTexture
ได้ก็ต่อเมื่อบริบท EGL ที่เป็นเจ้าของพื้นผิวอยู่ในเธรดเรียกใช้ ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของคลาส SurfaceTexture
การประทับเวลาและการเปลี่ยนรูปแบบ
อินสแตนซ์ SurfaceTexture
ประกอบด้วยเมธอด getTimeStamp()
ซึ่งดึงข้อมูลการประทับเวลา และเมธอด getTransformMatrix()
ซึ่งดึงข้อมูลเมทริกซ์การเปลี่ยนรูปแบบ การเรียกใช้ updateTexImage()
จะตั้งค่าทั้งการประทับเวลาและเมทริกซ์การเปลี่ยนรูปแบบ บัฟเฟอร์แต่ละรายการที่ BufferQueue
ส่งจะมีพารามิเตอร์การเปลี่ยนรูปแบบและการประทับเวลา
พารามิเตอร์การเปลี่ยนรูปแบบมีประโยชน์ในด้านประสิทธิภาพ ในบางกรณี ข้อมูลแหล่งที่มาอาจอยู่ในการวางแนวที่ไม่ถูกต้องสำหรับผู้บริโภค แทนที่จะหมุนข้อมูลก่อนส่งไปยังผู้บริโภค ให้ส่งข้อมูลในแนวการวางแนวที่มีการเปลี่ยนรูปแบบที่แก้ไขข้อมูล คุณสามารถผสานเมทริกซ์การเปลี่ยนรูปแบบเข้ากับการเปลี่ยนรูปแบบอื่นๆ เมื่อใช้ข้อมูลได้ ซึ่งจะช่วยลดค่าใช้จ่าย
การประทับเวลามีประโยชน์สําหรับแหล่งที่มาของบัฟเฟอร์ที่ขึ้นอยู่กับเวลา เช่น เมื่อ setPreviewTexture()
เชื่อมต่ออินเทอร์เฟซของโปรแกรมตัดต่อกับเอาต์พุตของกล้อง จะใช้เฟรมจากกล้องเพื่อสร้างวิดีโอได้ แต่ละเฟรมต้องมีการประทับเวลาของการแสดงผลนับจากเวลาที่จับเฟรม ไม่ใช่นับจากเวลาที่แอปได้รับเฟรม รหัสกล้องจะตั้งค่าการประทับเวลาที่ระบุพร้อมกับบัฟเฟอร์ ซึ่งส่งผลให้ชุดการประทับเวลามีความสอดคล้องกันมากขึ้น
กรณีศึกษา: การจับภาพต่อเนื่องของ Grafika
การจับภาพต่อเนื่องของ Grafika เป็นการบันทึกเฟรมจากกล้องของอุปกรณ์และแสดงเฟรมเหล่านั้นบนหน้าจอ
หากต้องการบันทึกเฟรม ให้สร้างพื้นผิวด้วยเมธอด createInputSurface()
ของคลาส MediaCodec แล้วส่งพื้นผิวไปยังกล้อง หากต้องการแสดงเฟรม ให้สร้างอินสแตนซ์ของ SurfaceView
แล้วส่งผ่านพื้นผิวไปยัง setPreviewDisplay()
โปรดทราบว่าการบันทึกเฟรมและแสดงเฟรมพร้อมกันเป็นกระบวนการที่ซับซ้อนกว่า
กิจกรรมการจับภาพต่อเนื่องจะแสดงวิดีโอจากกล้องขณะบันทึกวิดีโอ ในกรณีนี้ ระบบจะเขียนวิดีโอที่เข้ารหัสไปยังบัฟเฟอร์แบบวนซ้ำในหน่วยความจำ ซึ่งสามารถบันทึกลงในดิสก์ได้ทุกเมื่อ
ขั้นตอนนี้เกี่ยวข้องกับคิวบัฟเฟอร์ 3 คิว ดังนี้
App
— แอปใช้อินสแตนซ์SurfaceTexture
เพื่อรับเฟรมจากกล้อง โดยแปลงเป็นพื้นผิว GLES ภายนอกSurfaceFlinger
— แอปประกาศอินสแตนซ์SurfaceView
เพื่อแสดงเฟรมMediaServer
— กำหนดค่าโปรแกรมเปลี่ยนไฟล์MediaCodec
ด้วยแพลตฟอร์มการรับอินพุตเพื่อสร้างวิดีโอ
ในรูปภาพด้านล่าง รูปลูกศรแสดงการแพร่กระจายข้อมูลจากกล้อง
อินสแตนซ์ BufferQueue
เป็นสี (ผู้ผลิตเป็นสีเขียวเทอร์ควอยซ์ ผู้บริโภคเป็นสีเขียว)

รูปที่ 1 กิจกรรมการจับภาพต่อเนื่องของ Grafika
วิดีโอ H.264 ที่เข้ารหัสแล้วจะไปยังบัฟเฟอร์แบบวนซ้ำใน RAM ในกระบวนการของแอป
เมื่อผู้ใช้กดปุ่มจับภาพ MediaMuxer
class จะเขียนวิดีโอที่เข้ารหัสลงในไฟล์ MP4 บนดิสก์
ระบบจะจัดการอินสแตนซ์ BufferQueue
ทั้งหมดด้วยบริบท EGL รายการเดียวในแอป ขณะที่การดำเนินการ GLES จะดำเนินการในเธรด UI การจัดการข้อมูลที่เข้ารหัส (การจัดการบัฟเฟอร์แบบวนซ้ำและการเขียนลงในดิสก์) จะดำเนินการในเธรดแยกต่างหาก
SurfaceView
นั้น ฟังก์ชันการเรียกกลับ surfaceCreated()
จะสร้างอินสแตนซ์ EGLContext
และ EGLSurface
สำหรับโปรแกรมเปลี่ยนไฟล์วิดีโอและจอแสดงผล เมื่อเฟรมใหม่มาถึง SurfaceTexture
จะดําเนินการ 4 กิจกรรม ดังนี้
- รับเฟรม
- ทำให้เฟรมพร้อมใช้งานเป็นพื้นผิว GLES
- แสดงผลเฟรมด้วยคําสั่ง GLES
- ส่งต่อการเปลี่ยนรูปแบบและการประทับเวลาสําหรับอินสแตนซ์
EGLSurface
แต่ละรายการ
จากนั้นเธรดโปรแกรมเปลี่ยนไฟล์จะดึงเอาเอาต์พุตที่เข้ารหัสจาก MediaCodec
และเก็บไว้ในหน่วยความจำ
การเล่นวิดีโอพื้นผิวที่ปลอดภัย
Android รองรับการประมวลผลผลลัพธ์ขั้นสุดท้ายของเนื้อหาวิดีโอที่ได้รับการคุ้มครองด้วย GPU ซึ่งจะช่วยให้แอปใช้ GPU สำหรับเอฟเฟกต์วิดีโอที่ซับซ้อนและไม่ใช่แบบเชิงเส้น (เช่น การบิดเบือน) การแมปเนื้อหาวิดีโอที่ได้รับการคุ้มครองไปยังพื้นผิวเพื่อใช้ในฉากกราฟิกทั่วไป (เช่น การใช้ GLES) และเวอร์ชวลเรียลลิตี (VR)

รูปที่ 2 การเล่นวิดีโอพื้นผิวที่ปลอดภัย
คุณจะเปิดใช้การสนับสนุนได้โดยใช้ส่วนขยาย 2 รายการต่อไปนี้
- ส่วนขยาย EGL —
(
EGL_EXT_protected_content
) เปิดใช้การสร้างบริบทและแพลตฟอร์ม GL ที่ปกป้อง ซึ่งทั้ง 2 อย่างสามารถทำงานกับเนื้อหาที่ได้รับการปกป้องได้ - ส่วนขยาย GLES —
(
GL_EXT_protected_textures
) เปิดใช้การติดแท็กพื้นผิวเป็น "ที่ได้รับการปกป้อง" เพื่อให้ใช้เป็นไฟล์แนบพื้นผิวของเฟรมบัฟเฟอร์ได้
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
เมื่อใช้ไลบรารีโค้ดของคุณเอง (เพื่อแทนที่ libstagefright
) โปรดสังเกตการเปลี่ยนแปลงใน /frameworks/av/media/libstagefright/SurfaceUtils.cpp
ที่อนุญาตให้ส่งบัฟเฟอร์ที่มีเครื่องหมาย GRALLOC_USAGE_PROTECTED
ไปยัง ANativeWindow
(แม้ว่า ANativeWindow
จะไม่จัดคิวไปยังคอมโพเซอร์ของกรอบโดยตรง) ตราบใดที่บิตการใช้งานของผู้บริโภคมี GRALLOC_USAGE_PROTECTED
ดูเอกสารประกอบโดยละเอียดเกี่ยวกับการใช้ส่วนขยายได้ที่รีจิสทรี Khronos (EGL_EXT_protected_content
และ GL_EXT_protected_textures
)