พื้นผิว

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 เป็นสี (ผู้ผลิตเป็นสีเขียวเทอร์ควอยซ์ ผู้บริโภคเป็นสีเขียว)

กิจกรรมการจับภาพอย่างต่อเนื่องของ Grafika

รูปที่ 1 กิจกรรมการจับภาพต่อเนื่องของ Grafika

วิดีโอ H.264 ที่เข้ารหัสแล้วจะไปยังบัฟเฟอร์แบบวนซ้ำใน RAM ในกระบวนการของแอป เมื่อผู้ใช้กดปุ่มจับภาพ MediaMuxer class จะเขียนวิดีโอที่เข้ารหัสลงในไฟล์ MP4 บนดิสก์

ระบบจะจัดการอินสแตนซ์ BufferQueue ทั้งหมดด้วยบริบท EGL รายการเดียวในแอป ขณะที่การดำเนินการ GLES จะดำเนินการในเธรด UI การจัดการข้อมูลที่เข้ารหัส (การจัดการบัฟเฟอร์แบบวนซ้ำและการเขียนลงในดิสก์) จะดำเนินการในเธรดแยกต่างหาก

เมื่อใช้คลาส SurfaceView นั้น ฟังก์ชันการเรียกกลับ surfaceCreated() จะสร้างอินสแตนซ์ EGLContext และ EGLSurface สำหรับโปรแกรมเปลี่ยนไฟล์วิดีโอและจอแสดงผล เมื่อเฟรมใหม่มาถึง SurfaceTexture จะดําเนินการ 4 กิจกรรม ดังนี้
  1. รับเฟรม
  2. ทำให้เฟรมพร้อมใช้งานเป็นพื้นผิว GLES
  3. แสดงผลเฟรมด้วยคําสั่ง GLES
  4. ส่งต่อการเปลี่ยนรูปแบบและการประทับเวลาสําหรับอินสแตนซ์ 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)