TextureView

คลาส TextureView คือออบเจ็กต์มุมมองที่รวมมุมมองเข้ากับ SurfaceTexture

การแสดงผลด้วย OpenGL ES

ออบเจ็กต์ TextureView จะรวม SurfaceTexture ไว้ด้วยกัน ตอบสนองต่อคอลแบ็ก และรับบัฟเฟอร์ใหม่ เมื่อ TextureView ได้รับบัฟเฟอร์ใหม่ TextureView จะส่งคำขอทำให้ข้อมูลในมุมมองเป็นโมฆะและวาดโดยใช้เนื้อหาของบัฟเฟอร์ใหม่ล่าสุดเป็นแหล่งข้อมูล แสดงผลในที่ใดและอย่างไรก็ตามที่สถานะมุมมองระบุไว้

OpenGL ES (GLES) สามารถแสดงผลใน TextureView ได้โดยส่ง SurfaceTexture ไปยังการเรียกใช้การสร้าง EGL แต่วิธีนี้ทำให้เกิดปัญหา เมื่อ GLES แสดงผลใน TextureView ผู้ผลิตและผู้บริโภค BufferQueue จะอยู่ในเธรดเดียวกัน ซึ่งอาจทำให้การเรียกใช้การแลกเปลี่ยนบัฟเฟอร์หยุดชะงักหรือดำเนินการไม่สำเร็จ ตัวอย่างเช่น หากผู้ผลิตส่งบัฟเฟอร์หลายรายการจากเธรด UI ติดต่อกันอย่างรวดเร็ว การเรียกใช้การแลกเปลี่ยนบัฟเฟอร์ EGL จะต้องนำบัฟเฟอร์ออกจากคิวจาก BufferQueue อย่างไรก็ตาม เนื่องจากผู้บริโภคและผู้ผลิตอยู่ในเธรดเดียวกัน จึงจะไม่มีบัฟเฟอร์ที่พร้อมใช้งานและการเรียกใช้การแลกเปลี่ยนจะค้างหรือดำเนินการไม่สำเร็จ

BufferQueue ต้องมีบัฟเฟอร์ที่พร้อมที่จะนำออกจากคิวเสมอเพื่อให้การสลับบัฟเฟอร์ไม่หยุดชะงัก ในการใช้งาน BufferQueue จะทิ้งเนื้อหาของบัฟเฟอร์ที่ได้ก่อนหน้านี้เมื่อมีการกําหนดคิวบัฟเฟอร์ใหม่ และจํากัดจํานวนบัฟเฟอร์ขั้นต่ำและสูงสุดเพื่อป้องกันไม่ให้ผู้บริโภคใช้บัฟเฟอร์ทั้งหมดพร้อมกัน

การเลือก SurfaceView หรือ TextureView

SurfaceView และ TextureView มีบทบาทที่คล้ายกัน และทั้งคู่เป็นองค์ประกอบของลําดับชั้นวิว อย่างไรก็ตาม SurfaceView และ TextureView ต่างก็มีการใช้งานที่แตกต่างกัน SurfaceView ใช้พารามิเตอร์เดียวกับมุมมองอื่นๆ แต่เนื้อหาของ SurfaceView จะโปร่งใสเมื่อแสดงผล

TextureView จัดการอัลฟ่าและการหมุนได้ดีกว่า SurfaceView แต่ SurfaceView มีข้อได้เปรียบด้านประสิทธิภาพเมื่อคอมโพสองค์ประกอบ UI ที่วางซ้อนกันบนวิดีโอ เมื่อลูกค้าแสดงผลด้วย SurfaceView ทาง SurfaceView จะจัดเตรียมเลเยอร์การคอมโพสแยกต่างหากให้กับลูกค้า SurfaceFlinger จะประกอบเลเยอร์แยกต่างหากเป็นการวางซ้อนฮาร์ดแวร์หากอุปกรณ์รองรับ เมื่อไคลเอ็นต์แสดงผลด้วย TextureView เครื่องมือชุด UI จะคอมโพสเนื้อหาของ TextureView ลงในลําดับชั้นของมุมมองด้วย GPU การอัปเดตเนื้อหาอาจทําให้องค์ประกอบ View อื่นๆ วาดใหม่ เช่น หากวาง View อื่นๆ ไว้ด้านบน TextureView หลังจากแสดงผลมุมมองเสร็จแล้ว SurfaceFlinger จะคอมโพสเลเยอร์ UI ของแอปและเลเยอร์อื่นๆ ทั้งหมดเพื่อให้พิกเซลที่มองเห็นได้ทั้งหมดคอมโพสกัน 2 ครั้ง

กรณีศึกษา: วิดีโอ Play ของ Grafika

Play Video ของ Grafika มีโปรแกรมเล่นวิดีโอ 2 รายการ โดย 1 รายการติดตั้งใช้งานกับ TextureView และอีก 1 รายการติดตั้งใช้งานกับ SurfaceView ส่วนการถอดรหัสวิดีโอของกิจกรรมจะส่งเฟรมจาก MediaCodec ไปยังพื้นผิวสำหรับทั้ง TextureView และ SurfaceView ความแตกต่างที่ใหญ่ที่สุดระหว่างการติดตั้งใช้งานคือขั้นตอนที่จำเป็นในการนำเสนอสัดส่วนภาพที่ถูกต้อง

การปรับขนาด SurfaceView ต้องใช้การติดตั้งใช้งาน FrameLayout ที่กําหนดเอง WindowManager ต้องส่งตำแหน่งหน้าต่างใหม่และค่าขนาดใหม่ไปยัง SurfaceFlinger การปรับขนาด SurfaceTexture ของ TextureView กำหนดให้ต้องกำหนดค่าเมตริกการเปลี่ยนรูปแบบด้วย TextureView#setTransform()

หลังจากแสดงสัดส่วนภาพที่ถูกต้องแล้ว การติดตั้งใช้งานทั้ง 2 รูปแบบจะเป็นไปตามรูปแบบเดียวกัน เมื่อ SurfaceView/TextureView สร้างพื้นผิว โค้ดของแอปจะเปิดใช้การเล่น เมื่อผู้ใช้แตะเล่น ระบบจะเริ่มเธรดการถอดรหัสวิดีโอ โดยมีแพลตฟอร์มเป็นเป้าหมายเอาต์พุต หลังจากนั้น โค้ดแอปจะไม่ทําการใดๆ เลย คอมโพสชันและการแสดงผลจะจัดการโดย SurfaceFlinger (สําหรับ SurfaceView) หรือ TextureView

กรณีศึกษา: การถอดรหัสแบบคู่ของ Grafika

การถอดรหัสแบบคู่ของ Grafika แสดงการจัดการ SurfaceTexture ภายใน TextureView

การถอดรหัสแบบคู่ของ Grafika ใช้ออบเจ็กต์ TextureView 2 รายการเพื่อแสดงวิดีโอ 2 รายการที่เล่นควบคู่กัน ซึ่งจำลองแอปการประชุมทางวิดีโอ เมื่อการวางแนวของหน้าจอเปลี่ยนไปและกิจกรรมเริ่มต้นขึ้นอีกครั้ง ตัวถอดรหัส MediaCodec จะไม่หยุดทำงาน ซึ่งจำลองการเล่นสตรีมวิดีโอแบบเรียลไทม์ เพื่อปรับปรุงประสิทธิภาพ ลูกค้าควรทำให้แพลตฟอร์มทำงานอยู่เสมอ พื้นผิวคือแฮนเดิลสำหรับอินเทอร์เฟซของผู้ผลิตใน BufferQueue ของ SurfaceTexture เนื่องจาก TextureView จัดการ SurfaceTexture ไคลเอ็นต์จึงต้องเก็บ SurfaceTexture ไว้เพื่อให้พื้นผิวทำงานต่อไป

ในการทำให้ SurfaceTexture ทำงานต่อไปอยู่เสมอ การถอดรหัสแบบคู่ของ Grafika จะรับการอ้างอิงถึง SurfaceTexture จากออบเจ็กต์ TextureView และบันทึกไว้ในช่องแบบคงที่ จากนั้นการถอดรหัสแบบคู่ของ Grafika จะแสดงผล false จาก TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed() เพื่อป้องกันการทำลาย SurfaceTexture จากนั้น TextureView จะส่ง SurfaceTexture ไปยัง onSurfaceTextureDestroyed() ซึ่งจะคงอยู่ได้แม้จะมีการเปลี่ยนแปลงการกําหนดค่ากิจกรรม ซึ่งไคลเอ็นต์จะส่งไปยัง TextureView ใหม่ผ่าน setSurfaceTexture()

แต่ละตัวถอดรหัสวิดีโอจะทำงานด้วยเธรดแยกกัน Mediaserver จะส่งบัฟเฟอร์ที่มีเอาต์พุตที่ถอดรหัสแล้วไปยัง SurfaceTextures ซึ่งเป็นผู้บริโภค BufferQueue ออบเจ็กต์ TexturView จะแสดงผลและดำเนินการในเธรด UI

การใช้การถอดรหัสแบบ 2 ขั้นตอนของ Grafika กับ SurfaceView นั้นยากกว่าการใช้กับ TextureView เนื่องจากออบเจ็กต์ SurfaceView จะทำลายพื้นผิวระหว่างการเปลี่ยนแปลงการวางแนว นอกจากนี้ การใช้ออบเจ็กต์ SurfaceView จะเพิ่มเลเยอร์อีก 2 เลเยอร์ ซึ่งไม่เหมาะอย่างยิ่งเนื่องจากข้อจำกัดของจำนวนการวางซ้อนที่ใช้ได้บนฮาร์ดแวร์