Phát Video Trong Game Engine - nói dối e blog

Phát Video Trong Game Engine

Đoạn video mở đầu game do nhóm họa sĩ thiết kế chuẩn bị tích hợp vào sản phẩm thì phát hiện ra engine của chúng ta居然居然 không hỗ trợ tính năng phát video. Tôi nghĩ việc này hẳn có nhiều thư viện mã nguồn mở sẵn sàng hỗ trợ, việc triển khai chắc sẽ rất đơn giản. Không ngờ mất nguyên một ngày trời mới hoàn thành được.

Điều đầu tiên cần xem xét là giấy phép sử dụng. Thử khảo sát thì thấy ffmpeg - thư viện được sử dụng rộng rãi nhất - lại mang giấy phép GPL, không phù hợp với ứng dụng thương mại. Dù một số thành phần có thể dùng theo giấy phép LGPL, nhưng việc tuân thủ các điều khoản cũng phức tạp không kém. Cân nhắc kỹ, tôi quyết định từ bỏ ý định dùng ffmpeg, không muốn dẫm vào vết xe đổ như các phần mềm như Bão Phong Ảnh hay QQ Player từng vướng vào tai tiếng.

Khảo sát kỹ các lựa chọn khác, cuối cùng Google VP8 nổi bật với giấy phép cực kỳ linh hoạt. Tôi lập tức tải về phiên bản mới nhất của libvpx để thử nghiệm. Trong file README có đề cập cần sử dụng cygwin để biên dịch trên Windows, tôi ngoan ngoãn cài đặt cygwin và build thành công file thư viện libvpx.a. Định mang sang môi trường Mingw sử dụng thì gặp sự cố thiếu thư viện pthread - thứ không có sẵn trong mingw32. Mặc dù tìm được một phiên bản pthread-win32 trên mạng, nhưng khi nhìn thấy đống file dll phức tạp kia tôi đã nản chí không dám tiếp tục.

Quay lại nghiên cứu mã nguồn libvpx, phát hiện ra nó không bắt buộc dùng pthread API. Trên Windows có thể sử dụng các API gốc của Win32, vốn được chuẩn bị sẵn cho Visual Studio. Tôi phán đoán Mingw cũng có thể hỗ trợ, liền cài đặt msys và thử nghiệm thành công.

Để xây dựng một trình phát video đơn giản, cần có file dữ liệu được nén theo định dạng VP8. Thử kiểm tra, libvpx cung cấp công cụ ivfenc để chuyển đổi dữ liệu đầu vào định dạng YUV thành định dạng IVF. Vì trang chủ libvpx không có tài liệu API, tôi phải mày mò đọc mã nguồn ví dụ simple decoder. May mắn là code rất dễ hiểu, việc triển khai không quá phức tạp.

Vấn đề phát sinh ở khâu tạo file test IVF. YUV là định dạng dữ liệu bitmap không nén trong không gian màu YUV, có thể dùng ffmpeg để tạo. Tôi lại biên dịch ffmpeg, chuyển đổi video đầu vào thành file .yuv, rồi dùng ivfenc để tạo file .ivf. Thử tìm phần mềm phát file IVF thì không thấy có sẵn trên mạng, đành gồng mình viết trình phát trước.

Khi chạy thử, kết quả không như mong đợi. Tôi nghi ngờ do quá trình nén IVF bị lỗi, nhờ có kinh nghiệm làm việc với codec JPEG trước đây nên nhanh chóng nhận ra vấn đề nằm ở file YUV. Hóa ra file YUV chỉ là dòng dữ liệu thô, hoàn toàn không chứa thông tin định dạng như kích thước video, tốc độ khung hình. Do đó việc tìm trình phát YUV trên mạng gần như bất khả thi. Hơn nữa khi dùng ivfenc phải chỉ định rõ kích thước video qua dòng lệnh, vì dữ liệu YUV đầu vào không chứa thông tin này. Ban đầu tôi lầm tưởng ivfenc sẽ tự động resize dữ liệu đầu vào theo kích thước chỉ định, nhưng khi tính toán số khung hình thực tế thì phát hiện sự chênh lệch nghiêm trọng.

Tương tự như vậy, định dạng IVF cũng chỉ chứa dòng ảnh nén, không phải định dạng video hoàn chỉnh. Nó thiếu các thông tin mô tả bổ sung và luồng âm thanh. Hiểu rõ điều này, tôi điều chỉnh cách dùng ffmpeg: khi input file YUV, thêm tham số -f yuv4mpegpipe để xác định thông tin định dạng, chỉ định -pix_fmts yuv420p (định dạng YUV được ivfenc hỗ trợ). Khi sử dụng ivfenc, cần nhập chính xác độ rộng/cao để tạo file IVF hợp lệ.

Quá trình phát video thường cần chuyển đổi dữ liệu pixel từ YUV sang RGB. Tôi từng tối ưu hóa quá trình này bằng MMX cách đây 10 năm, hiện tại chỉ cần tái sử dụng. Phiên bản C thuần cũng khá ổn. Hôm nay còn tình cờ tìm thấy một bài báo nghiên cứu chuyên sâu về tối ưu hóa thuật toán này, các bạn quan tâm có thể

Trong engine 3D còn có giải pháp tối ưu hơn: dùng GPU. Chỉ cần tạo 3 texture đơn kênh cho Y, U, V rồi thực hiện chuyển đổi trong pixel shader. Không dùng texture 3 kênh vì dữ liệu VP8 nén theo tỷ lệ 4:1:1. Tất nhiên nếu chỉ phát video đơn giản, có thể dùng overlay surface định dạng YUV - điều dễ thực hiện trên DirectX, nhưng với OpenGL tôi vẫn chưa rõ cách triển khai.

Ban đầu có bạn đề xuất nhúng media player hoặc control Flash Player vào engine. Tôi kiên quyết phản đối phương án này. Thực tế thì việc dùng thư viện mã nguồn mở cũng không tiêu tốn nhiều nhân lực như dự đoán ban đầu.

0%