Tôi là Dale Curtis, trưởng nhóm kỹ thuật phụ trách phát nội dung nghe nhìn trong Chromium. Nhóm của tôi chịu trách nhiệm về các API hướng đến web để phát video như MSE và WebCodecs, cũng như các nội dung nội bộ dành riêng cho nền tảng liên quan đến việc phân tách, giải mã và kết xuất âm thanh và video.
Trong bài viết này, tôi sẽ hướng dẫn bạn về cấu trúc kết xuất video của Chromium. Mặc dù một số chi tiết về khả năng mở rộng có thể dành riêng cho Chromium, nhưng hầu hết các khái niệm và thiết kế được thảo luận ở đây đều áp dụng cho các công cụ kết xuất khác và thậm chí cả các ứng dụng phát gốc.
Cấu trúc phát của Chromium đã thay đổi đáng kể trong những năm qua. Mặc dù chúng tôi không bắt đầu bằng ý tưởng về kim tự tháp thành công như mô tả trong bài đăng đầu tiên của loạt bài này, nhưng cuối cùng, chúng tôi đã làm theo các bước tương tự: độ tin cậy, hiệu suất và sau đó là khả năng mở rộng.
Ở đầu, quá trình kết xuất video khá đơn giản – chỉ là một vòng lặp for chọn phần mềm giải mã khung hình video để gửi đến trình kết hợp. Trong nhiều năm, cách này đã đủ đáng tin cậy, nhưng khi độ phức tạp của web tăng lên, nhu cầu về hiệu suất và hiệu quả cao hơn đã dẫn đến những thay đổi về cấu trúc. Nhiều điểm cải tiến yêu cầu các nguyên hàm dành riêng cho hệ điều hành; do đó, cấu trúc của chúng tôi cũng phải trở nên mở rộng hơn để tiếp cận tất cả nền tảng của Chromium.
Bạn có thể chia quá trình kết xuất video thành hai bước: chọn nội dung cần phân phối và phân phối nội dung đó một cách hiệu quả. Để dễ đọc, trước tiên tôi sẽ trình bày về việc phân phối hiệu quả trước khi đi sâu vào cách Chromium chọn nội dung cần phân phối.
Một số thuật ngữ và bố cục
Vì bài viết này tập trung vào việc kết xuất, nên tôi sẽ chỉ đề cập ngắn gọn đến các khía cạnh giải mã và giải mã của quy trình.
Việc giải mã và giải mã trong thế giới hiện đại ngày nay đòi hỏi bạn phải cẩn thận. Trình phân tích cú pháp nhị phân là môi trường mục tiêu phong phú và việc phát nội dung nghe nhìn chứa đầy hoạt động phân tích cú pháp nhị phân. Do đó, các vấn đề bảo mật trong trình phân tích cú pháp nội dung nghe nhìn là cực kỳ phổ biến.
Chromium áp dụng phương pháp phòng thủ đa lớp để giảm nguy cơ người dùng gặp phải các vấn đề bảo mật. Về mặt thực tế, điều này có nghĩa là quá trình phân tách và giải mã phần mềm luôn diễn ra trong một quy trình có đặc quyền thấp, trong khi quá trình giải mã phần cứng diễn ra trong một quy trình chỉ có đủ đặc quyền để giao tiếp với GPU của hệ thống.
Cơ chế giao tiếp đa quy trình của Chromium được gọi là Mojo. Mặc dù chúng ta sẽ không đi sâu vào chi tiết về Mojo trong bài viết này, nhưng với tư cách là lớp trừu tượng giữa các quy trình, Mojo là nền tảng của quy trình truyền dẫn nội dung đa phương tiện có thể mở rộng của Chromium. Bạn cần lưu ý điều này khi tìm hiểu quy trình phát vì quy trình này cho biết quá trình điều phối phức tạp của các thành phần trên nhiều quy trình tương tác để nhận, giải mã, giải mã và cuối cùng hiển thị nội dung nghe nhìn.
Quá nhiều bit
Để hiểu được quy trình kết xuất video hiện nay, bạn cần biết lý do khiến video trở nên đặc biệt: băng thông. Khi phát ở độ phân giải 3840x2160 (4K) với tốc độ 60 khung hình/giây, bạn sẽ sử dụng băng thông bộ nhớ từ 9 đến 12 gigabit/giây. Mặc dù các hệ thống hiện đại có thể có băng thông đỉnh hàng trăm gigabit mỗi giây, nhưng việc phát video vẫn chiếm một phần đáng kể. Nếu không cẩn thận, tổng băng thông có thể dễ dàng tăng lên do các bản sao hoặc lượt truy cập giữa bộ nhớ GPU và CPU.
Mục tiêu của mọi công cụ phát video hiện đại hướng đến hiệu quả là giảm thiểu băng thông giữa bộ giải mã và bước kết xuất cuối cùng. Vì lý do này, quá trình kết xuất video được tách biệt phần lớn khỏi quy trình kết xuất chính của Chromium. Cụ thể, từ quan điểm của quy trình kết xuất chính, video chỉ là một lỗ có kích thước cố định với độ mờ. Chromium đạt được điều này bằng cách sử dụng một khái niệm có tên là bề mặt (surfaces), trong đó mỗi video sẽ trực tiếp giao tiếp với Viz.
Do sự phổ biến của điện toán di động, sức mạnh và hiệu quả đã trở thành một tiêu điểm quan trọng trong thế hệ hiện tại. Kết quả là quá trình giải mã và kết xuất được ghép nối chặt chẽ hơn bao giờ hết ở cấp phần cứng, khiến video trông giống như một lỗ có độ mờ, ngay cả đối với chính hệ điều hành! Bộ giải mã cấp nền tảng thường chỉ cung cấp vùng đệm mờ mà Chromium chuyển đến hệ thống kết hợp cấp nền tảng dưới dạng lớp phủ.
Mỗi nền tảng đều có một dạng lớp phủ riêng mà API giải mã nền tảng của chúng hoạt động cùng. Windows có Direct Composition (Cấu trúc trực tiếp) và Media Foundation Transforms (Biến đổi nền tảng nội dung nghe nhìn), macOS có CoreAnimation Layers (Lớp CoreAnimation) và VideoToolbox, Android có SurfaceView và MediaCodec, còn Linux có VASurfaces và VA-API. Các khái niệm trừu tượng của Chromium cho các khái niệm này được xử lý tương ứng bởi giao diện OverlayProcessor và mojo::VideoDecoder.
Trong một số trường hợp, các vùng đệm này có thể được liên kết vào bộ nhớ hệ thống, vì vậy, các vùng đệm này thậm chí không cần phải mờ và không tiêu tốn băng thông nào cho đến khi được truy cập. Chromium gọi các vùng đệm này là GpuMemoryBuffers. Trên Windows, các vùng đệm này được hỗ trợ bởi vùng đệm DXGI, trên macOS là IOSurfaces, trên Android là AHardwareBuffers và trên Linux là vùng đệm DMA. Mặc dù việc phát video thường không cần quyền truy cập này, nhưng các vùng đệm này rất quan trọng đối với việc quay video để đảm bảo băng thông tối thiểu giữa thiết bị quay video và bộ mã hoá cuối cùng.
Vì GPU thường chịu trách nhiệm cả việc giải mã và hiển thị, nên việc sử dụng các vùng đệm mờ (cũng thường) này đảm bảo rằng dữ liệu video có băng thông cao không bao giờ thực sự rời khỏi GPU. Như đã thảo luận trước đó, việc lưu giữ dữ liệu trên GPU là vô cùng quan trọng đối với hiệu quả; đặc biệt là ở độ phân giải và tốc độ khung hình cao.
Chúng ta càng có thể tận dụng các thành phần gốc của hệ điều hành như lớp phủ và vùng đệm GPU, thì càng ít băng thông được dùng để xáo trộn các byte video không cần thiết. Việc giữ mọi thứ ở cùng một nơi từ giải mã đến kết xuất có thể giúp tiết kiệm điện năng đáng kể. Ví dụ: khi Chromium bật lớp phủ trên macOS, mức tiêu thụ điện năng trong khi phát video ở chế độ toàn màn hình đã giảm một nửa! Trên các nền tảng khác như Windows, Android và ChromeOS, chúng ta có thể sử dụng lớp phủ ngay cả trong các trường hợp không phải toàn màn hình, tiết kiệm tới 50% ở hầu hết mọi nơi.
Kết xuất
Giờ đây, khi đã tìm hiểu về các cơ chế phân phối tối ưu, chúng ta có thể thảo luận về cách Chromium chọn nội dung cần phân phối. Ngăn xếp phát của Chromium sử dụng cấu trúc dựa trên "kéo", nghĩa là mỗi thành phần trong ngăn xếp yêu cầu dữ liệu đầu vào từ thành phần bên dưới theo thứ tự phân cấp. Ở đầu ngăn xếp là quá trình kết xuất khung hình âm thanh và video, bên dưới là quá trình giải mã, tiếp theo là quá trình giải mã và cuối cùng là I/O. Mỗi khung âm thanh được kết xuất sẽ đẩy nhanh đồng hồ dùng để chọn khung hình video để kết xuất khi kết hợp với khoảng thời gian trình bày.
Trên mỗi khoảng thời gian hiển thị (mỗi lần làm mới màn hình), trình kết xuất video được yêu cầu cung cấp một khung hình video bằng CompositorFrameSink đính kèm vào SurfaceLayer đã đề cập trước đó. Đối với nội dung có tốc độ khung hình thấp hơn tốc độ hiển thị, tức là hiển thị cùng một khung hình nhiều lần, trong khi nếu tốc độ khung hình cao hơn tốc độ hiển thị, thì một số khung hình sẽ không bao giờ xuất hiện.
Có nhiều cách để đồng bộ hoá âm thanh và video theo cách làm hài lòng người xem. Hãy xem Project Butter để thảo luận thêm về cách đạt được độ mượt tối ưu cho video trong Chromium. Bài viết này giải thích cách kết xuất video có thể được chia thành các trình tự lý tưởng thể hiện số lần mỗi khung hình sẽ hiển thị. Ví dụ: "1 khung hình mỗi khoảng hiển thị ([1], 60 khung hình/giây ở 60 Hz)", "1 khung hình mỗi 2 khoảng hiển thị ([2], 30 khung hình/giây ở 60 Hz)" hoặc các mẫu phức tạp hơn như [2:3:2:3:2] (25 khung hình/giây ở 60 Hz) bao gồm nhiều khung hình và khoảng hiển thị riêng biệt. Trình kết xuất video càng tuân theo mẫu lý tưởng này thì người dùng càng có nhiều khả năng nhận thấy quá trình phát diễn ra mượt mà.
Mặc dù hầu hết các nền tảng Chromium đều kết xuất từng khung hình, nhưng không phải nền tảng nào cũng vậy. Kiến trúc có thể mở rộng của chúng tôi cũng cho phép kết xuất hàng loạt. Kết xuất hàng loạt là một kỹ thuật hiệu quả, trong đó trình kết hợp cấp hệ điều hành được thông báo trước về nhiều khung hình và xử lý việc phát hành các khung hình đó theo lịch trình thời gian do ứng dụng cung cấp.
Tương lai là hiện tại?
Chúng tôi đã tập trung vào cách Chromium tận dụng các nguyên hàm của hệ điều hành để mang lại trải nghiệm phát tốt nhất trong lớp. Nhưng còn những trang web muốn phát video ở cấp độ nâng cao thì sao? Chúng ta có thể cung cấp cho họ những nguyên hàm mạnh mẽ mà chính Chromium sử dụng để mở ra thế hệ nội dung web tiếp theo không?
Chúng tôi cho rằng câu trả lời là có! Khả năng mở rộng là yếu tố cốt lõi trong cách chúng ta suy nghĩ về nền tảng web ngày nay. Chúng tôi đã hợp tác với các trình duyệt và nhà phát triển khác để tạo ra các công nghệ mới như WebGPU và WebCodecs để các nhà phát triển web có thể sử dụng chính những nguyên hàm mà Chromium sử dụng khi giao tiếp với hệ điều hành. WebGPU hỗ trợ vùng đệm GPU và WebCodecs mang đến các nguyên hàm giải mã và mã hoá nền tảng tương thích với các hệ thống vùng đệm GPU và lớp phủ nêu trên.
Kết thúc luồng
Cảm ơn bạn đã đọc! Tôi hy vọng bạn đã hiểu rõ hơn về các hệ thống phát hiện đại và cách Chromium hỗ trợ hàng trăm triệu giờ xem mỗi ngày. Nếu bạn muốn tìm hiểu thêm về bộ mã hoá và giải mã cũng như video trên web hiện đại, bạn nên đọc bài viết H.264 là phép màu của Sid Bala, Cách hoạt động của trình phát video hiện đại của Erica Beaves và Đóng gói các chương trình đoạt giải thưởng bằng công nghệ đoạt giải thưởng của Cyril Concolato.
Một hình minh hoạ (rất đẹp!) của Una Kravets.