SurfaceTexture

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 อินสแตนซ์จะแสดงพร้อมตัวบ่งชี้ด้วยภาพ เพื่อแยกความแตกต่างระหว่างผู้ผลิต (สีเขียวอมฟ้า) กับผู้บริโภค (สีเขียว)

Grafika continuous
capture activity

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

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

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

เมื่อใช้คลาส SurfaceView คอลแบ็ก surfaceCreated() จะสร้างอินสแตนซ์ EGLContext และ EGLSurface สำหรับการแสดงผลและตัวเข้ารหัสวิดีโอ เมื่อเฟรมใหม่มาถึง SurfaceTexture จะทำกิจกรรม 4 อย่างต่อไปนี้

  1. รับเฟรม
  2. ทำให้เฟรมพร้อมใช้งานเป็นพื้นผิว GLES
  3. แสดงผลเฟรมด้วยคำสั่ง GLES
  4. ส่งต่อการแปลงและการประทับเวลาสำหรับอินสแตนซ์แต่ละรายการของ 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)