เจาะลึก: VideoNG

Dale Curtis
Dale Curtis

ผมชื่อ Dale Curtis เป็นหัวหน้าทีมวิศวกรด้านการเล่นสื่อใน Chromium ทีมของฉันรับผิดชอบ API ที่แสดงในเว็บสำหรับการเล่นวิดีโอ เช่น MSE และ WebCodecs รวมถึงส่วนภายในเฉพาะแพลตฟอร์มที่เกี่ยวข้องกับการแยกข้อมูล ถอดรหัส และแสดงผลเสียงและวิดีโอ

ในบทความนี้ เราจะอธิบายสถาปัตยกรรมการแสดงผลวิดีโอของ Chromium แม้ว่ารายละเอียดบางอย่างเกี่ยวกับการขยายความสามารถอาจใช้กับ Chromium โดยเฉพาะ แต่แนวคิดและการออกแบบส่วนใหญ่ที่กล่าวถึงที่นี่จะใช้กับเครื่องมือแสดงผลอื่นๆ และแม้แต่แอปการเล่นแบบเนทีฟได้

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

ในช่วงแรก การแสดงผลวิดีโอนั้นค่อนข้างง่าย เพียงแค่ใช้ลูป for เพื่อเลือกซอฟต์แวร์ที่จะถอดรหัสเฟรมวิดีโอเพื่อส่งไปยังโปรแกรมคอมโพสิชัน วิธีการนี้มีความน่าเชื่อถือมากพอมาหลายปีแล้ว แต่ความซับซ้อนของเว็บที่เพิ่มขึ้นทำให้จำเป็นต้องเพิ่มประสิทธิภาพและประสิทธิผล จึงทำให้เกิดการเปลี่ยนแปลงสถาปัตยกรรม การปรับปรุงหลายอย่างต้องใช้องค์ประกอบพื้นฐานเฉพาะระบบปฏิบัติการ ดังนั้นสถาปัตยกรรมของเราจึงต้องขยายได้มากขึ้นเพื่อเข้าถึงแพลตฟอร์มทั้งหมดของ Chromium

แผนภาพขั้นตอนการแสดงผลไปยังแพลตฟอร์ม Chromium ต่างๆ

การแสดงผลวิดีโอแบ่งออกเป็น 2 ขั้นตอน ได้แก่ การเลือกใช้ข้อมูลที่จะแสดงและการแสดงข้อมูลดังกล่าวอย่างมีประสิทธิภาพ เราจะอธิบายการส่งอย่างมีประสิทธิภาพก่อนเจาะลึกวิธีที่ Chromium เลือกสิ่งที่จะแสดงเพื่อช่วยให้อ่านง่าย

ข้อความและเลย์เอาต์บางส่วน

เนื่องจากบทความนี้เน้นที่การแสดงผล เราจะพูดถึงการแยกข้อมูลและการถอดรหัสของไปป์ไลน์เพียงสั้นๆ

ไบต์ที่ไหลเข้าและแพ็กเก็ตที่มีโครงสร้างที่ไหลออก

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

Chromium ใช้แนวทางการป้องกันแบบหลายชั้นเพื่อลดความเสี่ยงที่ผู้ใช้จะพบปัญหาด้านความปลอดภัย กล่าวโดยละเอียดคือ หมายความว่าการแยกข้อมูลและซอฟต์แวร์ถอดรหัสจะเกิดขึ้นในกระบวนการที่มีสิทธิ์ต่ำเสมอ ในขณะที่การถอดรหัสฮาร์ดแวร์จะเกิดขึ้นในกระบวนการที่มีสิทธิ์เพียงพอที่จะสื่อสารกับ GPU ของระบบ

แซนด์บ็อกซ์ของ Chromium สำหรับโปรแกรมแสดงผล, GPU และกระบวนการของเสียง

กลไกการสื่อสารข้ามกระบวนการของ Chromium เรียกว่า Mojo แม้ว่าเราจะไม่ลงรายละเอียดเกี่ยวกับ Mojo ในบทความนี้ แต่ Mojo เป็นเลเยอร์การแยกแยะระหว่างกระบวนการต่างๆ และเป็นรากฐานสำคัญของไปป์ไลน์สื่อแบบขยายได้ของ Chromium คุณควรทราบข้อมูลนี้เมื่อเราอธิบายไปทีละขั้นตอนในไปป์ไลน์การเล่น เนื่องจากข้อมูลนี้จะช่วยให้ทราบการประสานงานที่ซับซ้อนของคอมโพเนนต์ข้ามกระบวนการที่โต้ตอบกันเพื่อรับ แยกข้อมูล ถอดรหัส และแสดงสื่อ

ข้อมูลจำนวนมาก

การทำความเข้าใจไปป์ไลน์การแสดงผลวิดีโอในปัจจุบันจำเป็นต้องมีความรู้เกี่ยวกับเหตุผลที่วิดีโอมีความพิเศษ นั่นก็คือแบนด์วิดท์ การเล่นความละเอียด 3840x2160 (4K) ที่ 60 เฟรมต่อวินาทีจะใช้แบนด์วิดท์หน่วยความจำประมาณ 9-12 กิกะบิตต่อวินาที แม้ว่าระบบสมัยใหม่อาจมีแบนด์วิดท์สูงสุดหลายร้อยกิกะบิตต่อวินาที แต่การเล่นวิดีโอก็ยังคงใช้แบนด์วิดท์เป็นจำนวนมาก หากไม่ระมัดระวัง แบนด์วิดท์ทั้งหมดอาจเพิ่มขึ้นหลายเท่าเนื่องจากมีการทำสำเนาหรือการเดินทางระหว่างหน่วยความจำของ GPU กับ CPU

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

หน้าเว็บที่มีรูและลูกศรที่ระบุว่า "วิดีโอไปไว้ที่นี่"

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

หน้าเว็บที่มีรูและลูกศรที่ระบุว่า "วิดีโอไปอยู่ตรงนี้" ล้อมรอบด้วยกล่องที่แสดงถึงระบบปฏิบัติการ

แพลตฟอร์มแต่ละแพลตฟอร์มจะมีรูปแบบการวางซ้อนของตัวเองที่ API การถอดรหัสแพลตฟอร์มทำงานร่วมกัน Windows มี Direct Composition และ Media Foundation Transforms, macOS มี CoreAnimation Layers และ VideoToolbox, Android มี SurfaceView และ MediaCodec และ Linux มี VASurfaces และ VA-API อินเทอร์เฟซ OverlayProcessor และ mojo::VideoDecoder จะจัดการข้อมูลทั่วไปของ Chromium สำหรับแนวคิดเหล่านี้ตามลำดับ

ในบางกรณี บัฟเฟอร์เหล่านี้อาจแมปกับหน่วยความจำระบบได้ ดังนั้นจึงไม่จำเป็นต้องทึบแสงและไม่กินแบนด์วิดท์จนกว่าจะมีคนเข้าถึง ซึ่ง Chromium จะเรียกบัฟเฟอร์เหล่านี้ว่า GpuMemoryBuffers ใน Windows ข้อมูลเหล่านี้จะสำรองข้อมูลโดยบัฟเฟอร์ DXGI, ใน macOS จะใช้IOSurfaces, ใน Android จะใช้ AHardwareBuffers และใน Linux จะใช้บัฟเฟอร์ DMA แม้ว่าโดยทั่วไปการเล่นวิดีโอจะไม่จำเป็นต้องเข้าถึงนี้ แต่บัฟเฟอร์เหล่านี้มีความสำคัญต่อการจับภาพวิดีโอเพื่อให้แบนด์วิดท์ระหว่างอุปกรณ์จับภาพกับโปรแกรมเปลี่ยนไฟล์เป็นรูปแบบสุดท้ายมีน้อยที่สุด

แผนภาพบัฟเฟอร์ที่กล่าวถึงในข้อความก่อนหน้า

เนื่องจาก GPU มักจะมีหน้าที่รับผิดชอบทั้งการถอดรหัสและการแสดงผล การใช้บัฟเฟอร์ทึบแสง (ซึ่งมักจะเป็นเช่นนั้น) เหล่านี้จึงช่วยให้มั่นใจได้ว่าข้อมูลวิดีโอที่มีแบนด์วิดท์สูงจะไม่ออกจาก GPU จริงๆ ดังที่ได้กล่าวไปก่อนหน้านี้ การคงข้อมูลไว้ใน GPU มีความสำคัญอย่างยิ่งต่อประสิทธิภาพ โดยเฉพาะที่ความละเอียดและอัตราเฟรมสูง

ยิ่งเราใช้ประโยชน์จากองค์ประกอบพื้นฐานของระบบปฏิบัติการ เช่น การซ้อนทับและบัฟเฟอร์ GPU ได้มากเท่าใด ก็จะยิ่งใช้แบนด์วิดท์น้อยลงในการย้ายข้อมูลไบต์วิดีโอไปมาโดยไม่จำเป็น การเก็บทุกอย่างไว้ในที่เดียวตั้งแต่การถอดรหัสไปจนถึงการแสดงผลอาจทำให้ประหยัดพลังงานได้อย่างน่าทึ่ง ตัวอย่างเช่น เมื่อ Chromium เปิดใช้การวางซ้อนใน macOS การใช้พลังงานระหว่างการเล่นวิดีโอแบบเต็มหน้าจอลดลงครึ่งหนึ่ง ในแพลตฟอร์มอื่นๆ เช่น Windows, Android และ ChromeOS เราสามารถใช้การวางซ้อนได้แม้ในกรณีที่ไม่ได้แสดงแบบเต็มหน้าจอ ซึ่งจะช่วยประหยัดพื้นที่โฆษณาได้สูงสุด 50% เกือบทุกที่

การแสดงผล

เมื่อพูดถึงกลไกการแสดงผลที่ดีที่สุดแล้ว เรามาพูดถึงวิธีที่ Chromium เลือกสิ่งที่จะแสดงกัน สแต็กการเล่นของ Chromium ใช้สถาปัตยกรรมแบบ "ดึง" ซึ่งหมายความว่าคอมโพเนนต์แต่ละรายการในสแต็กจะขออินพุตจากคอมโพเนนต์ที่อยู่ด้านล่างตามลําดับชั้น ด้านบนสุดคือการแสดงผลเฟรมเสียงและวิดีโอ ถัดไปคือการถอดรหัส ตามด้วยการนำข้อมูลออกจากมัลติเพลเยอร์ และสุดท้ายคือ I/O เฟรมเสียงที่แสดงผลแต่ละเฟรมจะเดินหน้านาฬิกาที่ใช้เลือกเฟรมวิดีโอสำหรับการแสดงผลเมื่อรวมกับช่วงเวลาของการแสดง

ในแต่ละช่วงเวลาของการแสดงผล (การรีเฟรชจอแสดงผลแต่ละครั้ง) ระบบจะขอให้โปรแกรมแสดงผลวิดีโอแสดงเฟรมวิดีโอโดย CompositorFrameSink ที่แนบอยู่กับ SurfaceLayer ที่กล่าวถึงก่อนหน้านี้ สำหรับเนื้อหาที่มีอัตราเฟรมน้อยกว่าอัตราการแสดงผล หมายความว่าระบบจะแสดงเฟรมเดิมมากกว่า 1 ครั้ง ในขณะที่หากอัตราเฟรมมากกว่าอัตราการแสดงผล ระบบจะไม่แสดงเฟรมบางเฟรมเลย

การซิงค์เสียงและวิดีโอในลักษณะที่ผู้ชมพึงพอใจนั้นยังมีรายละเอียดอีกมากมาย ดูการพูดคุยเพิ่มเติมเกี่ยวกับวิธีทำให้วิดีโอเล่นได้อย่างราบรื่นที่สุดใน Chromium ได้ที่ Project Butter ซึ่งจะอธิบายวิธีแบ่งการแสดงผลวิดีโอออกเป็นลำดับที่เหมาะสมซึ่งแสดงจำนวนครั้งที่ควรแสดงแต่ละเฟรม เช่น "1 เฟรมทุกๆ ช่วงเวลาการแสดงผล ([1], 60 fps ใน 60 Hz)", "1 เฟรมทุกๆ 2 ช่วงเวลา ([2], 30 fps ใน 60 Hz)" หรือรูปแบบที่ซับซ้อนมากขึ้น เช่น [2:3:2:3:2] (25 fps ใน 60 Hz) ซึ่งครอบคลุมเฟรมและช่วงเวลาการแสดงผลที่แตกต่างกันหลายรายการ ยิ่งโปรแกรมแสดงผลวิดีโอทำงานตามรูปแบบที่เหมาะเจาะมากเท่าใด ผู้ใช้ก็ยิ่งรู้สึกว่าการเล่นราบรื่นมากขึ้นเท่านั้น

ลำดับของการแยกข้อมูล ถอดรหัส และการแสดงผล

แม้ว่าแพลตฟอร์ม Chromium ส่วนใหญ่จะแสดงผลทีละเฟรม แต่ก็มีบางแพลตฟอร์มที่ไม่ทำเช่นนั้น สถาปัตยกรรมแบบขยายได้ของเรายังรองรับการแสดงผลแบบเป็นกลุ่มด้วย การแสดงผลแบบเป็นกลุ่มเป็นเทคนิคที่มีประสิทธิภาพซึ่งคอมโพสิตระดับระบบปฏิบัติการจะได้รับการบอกล่วงหน้าเกี่ยวกับเฟรมหลายเฟรมและจัดการการเผยแพร่เฟรมตามกำหนดเวลาที่แอปพลิเคชันระบุ

อนาคตมาถึงแล้วใช่ไหม

เรามุ่งเน้นที่วิธีที่ Chromium ใช้ประโยชน์จากองค์ประกอบพื้นฐานของระบบปฏิบัติการเพื่อมอบประสบการณ์การเล่นที่ดีที่สุด แต่เว็บไซต์ที่ต้องการทำมากกว่าการเล่นวิดีโอพื้นฐานล่ะ เรานำเสนอองค์ประกอบพื้นฐานที่มีประสิทธิภาพแบบเดียวกับที่ Chromium ใช้เพื่อเปิดศักราชใหม่ของเนื้อหาเว็บได้ไหม

เราคิดว่าคำตอบคือใช่ ความสามารถในการขยายการทำงานเป็นหัวใจสําคัญของมุมมองที่เรามีต่อแพลตฟอร์มเว็บในปัจจุบัน เราทำงานร่วมกับเบราว์เซอร์และนักพัฒนาซอฟต์แวร์รายอื่นๆ เพื่อสร้างเทคโนโลยีใหม่ๆ เช่น WebGPU และ WebCodecs เพื่อให้นักพัฒนาเว็บใช้องค์ประกอบพื้นฐานแบบเดียวกับที่ Chromium ใช้เมื่อสื่อสารกับระบบปฏิบัติการได้ WebGPU รองรับบัฟเฟอร์ GPU และ WebCodecs รองรับรูปแบบพื้นฐานในการถอดรหัสและการเข้ารหัสของแพลตฟอร์ม ซึ่งเข้ากันได้กับระบบการวางซ้อนและบัฟเฟอร์ GPU ที่กล่าวถึงข้างต้น

ความสัมพันธ์ระหว่าง WebCodecs กับ WebGPU

สิ้นสุดสตรีม

ขอขอบคุณที่อ่าน เราหวังว่าคุณจะเข้าใจระบบการเล่นสมัยใหม่และวิธีที่ Chromium ช่วยให้ผู้ใช้รับชมวิดีโอได้หลายร้อยล้านชั่วโมงทุกวันมากขึ้น หากต้องการอ่านเพิ่มเติมเกี่ยวกับโค้ดและวิดีโอบนเว็บสมัยใหม่ เราขอแนะนําบทความH.264 คือเวทมนตร์โดย Sid Bala, วิธีการทํางานของโปรแกรมเล่นวิดีโอสมัยใหม่โดย Erica Beaves และการบรรจุรายการที่ได้รับรางวัลด้วยเทคโนโลยีที่ได้รับรางวัลโดย Cyril Concolato

ภาพ 1 ภาพ (ภาพสวยๆ) โดย Una Kravets