SurfaceTexture
คือการรวมกันของพื้นผิวและเท็กซ์เจอร์ OpenGL ES (GLES)
SurfaceTexture
ใช้เพื่อจัดหา Surface ที่เอาต์พุต
ไปยังเท็กซ์เจอร์ GLES
SurfaceTexture
มีอินสแตนซ์ของ BufferQueue
ซึ่งแอปเป็นผู้ใช้ 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 เกี่ยวข้องกับการบันทึกเฟรมจากกล้องของอุปกรณ์และแสดงเฟรมเหล่านั้นบนหน้าจอ หากต้องการบันทึกเฟรม ให้สร้าง Surface ด้วยเมธอด createInputSurface()
ของคลาส
MediaCodec
แล้วส่ง Surface ไปยังกล้อง หากต้องการแสดงเฟรม ให้สร้างอินสแตนซ์ของ
SurfaceView
แล้วส่งพื้นผิวไปยัง setPreviewDisplay()
โปรดทราบว่าการบันทึกเฟรมและการแสดงเฟรมพร้อมกันเป็นกระบวนการที่ซับซ้อนกว่า
กิจกรรมการจับภาพต่อเนื่องจะแสดงวิดีโอจากกล้องขณะที่ กำลังบันทึกวิดีโอ ในกรณีนี้ ระบบจะเขียนวิดีโอที่เข้ารหัสลงใน บัฟเฟอร์แบบวงกลมในหน่วยความจำซึ่งสามารถบันทึกลงในดิสก์ได้ทุกเมื่อ
ขั้นตอนการทำงานนี้เกี่ยวข้องกับคิวบัฟเฟอร์ 3 คิว ได้แก่
App
— แอปใช้อินสแตนซ์SurfaceTexture
เพื่อรับเฟรมจากกล้อง แล้วแปลงเป็นเท็กซ์เจอร์ GLES ภายนอกSurfaceFlinger
— แอปประกาศSurfaceView
อินสแตนซ์เพื่อแสดงเฟรมMediaServer
— กำหนดค่าMediaCodec
โปรแกรมเปลี่ยนไฟล์ที่มี พื้นผิวอินพุตเพื่อสร้างวิดีโอ
ในรูปที่ 1 ลูกศรแสดงการเผยแพร่ข้อมูลจากกล้อง BufferQueue
อินสแตนซ์จะแสดงพร้อมตัวบ่งชี้ด้วยภาพ
เพื่อแยกความแตกต่างระหว่างผู้ผลิต (สีเขียวอมฟ้า) กับผู้บริโภค (สีเขียว)

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

รูปที่ 2 การเล่นวิดีโอพื้นผิวอย่างปลอดภัย
โดยเปิดใช้การรองรับโดยใช้ส่วนขยาย 2 รายการต่อไปนี้
- ส่วนขยาย EGL —
(
EGL_EXT_protected_content
) ช่วยให้สร้างบริบทและพื้นผิว GL ที่ได้รับการปกป้อง ซึ่งทั้ง 2 อย่างนี้ สามารถทำงานกับเนื้อหาที่ได้รับการปกป้องได้ - ส่วนขยาย GLES —
(
GL_EXT_protected_textures
) เปิดใช้การติดแท็กเท็กซ์เจอร์เป็นแบบป้องกันเพื่อให้ใช้เป็นไฟล์แนบเท็กซ์เจอร์ของเฟรมบัฟเฟอร์ได้
Android ช่วยให้ SurfaceTexture
และ ACodec
(libstagefright.so
) ส่งเนื้อหาที่ได้รับการคุ้มครองได้แม้ว่า Surface ของหน้าต่าง
จะไม่ได้จัดคิวไปยัง SurfaceFlinger
และมี Surface วิดีโอที่ได้รับการคุ้มครอง
สำหรับการใช้งานภายในบริบทที่ได้รับการคุ้มครอง โดยทำได้ด้วยการตั้งค่าบิตผู้บริโภคที่ได้รับการปกป้อง (GRALLOC_USAGE_PROTECTED
) ในแพลตฟอร์ม
ที่สร้างขึ้นในบริบทที่ได้รับการปกป้อง (ได้รับการยืนยันโดย ACodec)
การเล่นวิดีโอพื้นผิวอย่างปลอดภัยเป็นรากฐานของการติดตั้งใช้งานการจัดการสิทธิ์ดิจิทัล (DRM) ที่มีประสิทธิภาพในสภาพแวดล้อม OpenGL ES หากไม่มีการติดตั้งใช้งาน DRM ที่มีประสิทธิภาพ เช่น Widevine ระดับ 1 ผู้ให้บริการเนื้อหาจำนวนมากจะไม่อนุญาตให้แสดงเนื้อหาที่มีมูลค่าสูงในสภาพแวดล้อม OpenGL ES ซึ่งจะทำให้ไม่สามารถใช้งาน VR ในกรณีสำคัญๆ เช่น การดูเนื้อหาที่ได้รับการคุ้มครองด้วย DRM ใน VR
โปรเจ็กต์โอเพนซอร์ส Android (AOSP) มีโค้ดเฟรมเวิร์กสำหรับการเล่นวิดีโอพื้นผิวที่ปลอดภัย
การรองรับไดรเวอร์ขึ้นอยู่กับ OEM ผู้ติดตั้งใช้งานอุปกรณ์ต้อง
ติดตั้งใช้งานส่วนขยาย EGL_EXT_protected_content
และ
GL_EXT_protected_textures
เมื่อใช้ไลบรารีตัวแปลงรหัสของคุณเอง (เพื่อแทนที่ libstagefright
) โปรดทราบการเปลี่ยนแปลงใน /frameworks/av/media/libstagefright/SurfaceUtils.cpp
ซึ่งอนุญาตให้ส่งบัฟเฟอร์ที่ทำเครื่องหมายด้วย GRALLOC_USAGE_PROTECTED
ไปยัง ANativeWindow
(แม้ว่า ANativeWindow
จะไม่ได้จัดคิวไปยังคอมโพสเซอร์หน้าต่างโดยตรง) ตราบใดที่บิตการใช้งานของผู้บริโภคมี GRALLOC_USAGE_PROTECTED
โปรดดูเอกสารประกอบแบบละเอียดเกี่ยวกับการ
ติดตั้งใช้งานส่วนขยายในรีจิสทรีของ Khronos (
EGL_EXT_protected_content
) และ (
GL_EXT_protected_textures
)