Hoạ tiết bề mặt

SurfaceTexture là sự kết hợp giữa một nền tảng và một hoạ tiết OpenGL ES (GLES). Các thực thể SurfaceTexture được dùng để cung cấp các bề mặt xuất ra kết cấu GLES.

SurfaceTexture chứa một thực thể của BufferQueue mà ứng dụng là người dùng. Lệnh gọi lại onFrameAvailable() thông báo cho các ứng dụng khi nhà sản xuất đưa một vùng đệm mới vào hàng đợi. Sau đó, các ứng dụng sẽ gọi updateTexImage() để giải phóng vùng đệm đã giữ trước đó, lấy vùng đệm mới từ hàng đợi và thực hiện các lệnh gọi EGL để cung cấp vùng đệm cho GLES dưới dạng hoạ tiết bên ngoài.

Kết cấu GLES bên ngoài

Kết cấu GLES bên ngoài (GL_TEXTURE_EXTERNAL_OES) khác với kết cấu GLES truyền thống (GL_TEXTURE_2D) ở những điểm sau:

  • Kết cấu bên ngoài kết xuất các đa giác có kết cấu trực tiếp từ dữ liệu nhận được từ BufferQueue.
  • Trình kết xuất hoạ tiết bên ngoài được định cấu hình khác với trình kết xuất hoạ tiết GLES truyền thống.
  • Kết cấu bên ngoài không thể thực hiện tất cả hoạt động kết cấu GLES truyền thống.

Lợi ích chính của hoạ tiết bên ngoài là khả năng kết xuất trực tiếp từ dữ liệu BufferQueue. Các thực thể SurfaceTexture đặt cờ sử dụng của người dùng thành GRALLOC_USAGE_HW_TEXTURE khi tạo các thực thể BufferQueue cho hoạ tiết bên ngoài để đảm bảo rằng GLES có thể nhận dạng được dữ liệu trong vùng đệm.

Vì các thực thể SurfaceTexture tương tác với ngữ cảnh EGL, nên ứng dụng chỉ có thể gọi các phương thức của thực thể đó trong khi ngữ cảnh EGL sở hữu hoạ tiết đang ở trên luồng gọi. Để biết thêm thông tin, hãy xem tài liệu về lớp SurfaceTexture.

Dấu thời gian và phép biến đổi

Các thực thể SurfaceTexture bao gồm phương thức getTimeStamp() (truy xuất dấu thời gian) và phương thức getTransformMatrix() (truy xuất ma trận biến đổi). Việc gọi updateTexImage() sẽ đặt cả dấu thời gian và ma trận biến đổi. Mỗi vùng đệm mà BufferQueue truyền đều bao gồm các tham số biến đổi và dấu thời gian.

Các tham số biến đổi rất hữu ích cho hiệu quả. Trong một số trường hợp, dữ liệu nguồn có thể không đúng hướng cho người dùng. Thay vì xoay dữ liệu trước khi gửi cho người dùng, hãy gửi dữ liệu theo hướng của dữ liệu đó bằng một phép biến đổi giúp sửa dữ liệu. Bạn có thể hợp nhất ma trận biến đổi với các phép biến đổi khác khi sử dụng dữ liệu, giúp giảm thiểu hao tổn.

Dấu thời gian hữu ích cho các nguồn bộ đệm phụ thuộc vào thời gian. Ví dụ: khi setPreviewTexture() kết nối giao diện nhà sản xuất với đầu ra của máy ảnh, các khung hình từ máy ảnh có thể được dùng để tạo video. Mỗi khung cần có dấu thời gian trình bày từ thời điểm chụp khung, chứ không phải từ thời điểm ứng dụng nhận được khung. Mã máy ảnh đặt dấu thời gian được cung cấp cùng với vùng đệm, dẫn đến một loạt dấu thời gian nhất quán hơn.

Nghiên cứu điển hình: Tính năng chụp liên tục của Grafika

Tính năng chụp liên tục của Grafika bao gồm việc ghi lại các khung hình từ máy ảnh của thiết bị và hiển thị các khung hình đó trên màn hình. Để quay khung hình, hãy tạo một nền tảng bằng phương thức createInputSurface() của lớp MediaCodec rồi truyền nền tảng đó đến máy ảnh. Để hiển thị khung, hãy tạo một thực thể của SurfaceView và truyền giao diện đến setPreviewDisplay(). Xin lưu ý rằng việc ghi lại các khung hình và hiển thị các khung hình đó cùng một lúc là một quy trình phức tạp hơn.

Hoạt động quay liên tục hiển thị video từ camera khi video đang được quay. Trong trường hợp này, video đã mã hoá được ghi vào vùng đệm tròn trong bộ nhớ và có thể được lưu vào ổ đĩa bất cứ lúc nào.

Quy trình này liên quan đến 3 hàng đợi bộ đệm:

  • App – Ứng dụng sử dụng một thực thể SurfaceTexture để nhận khung hình từ máy ảnh, chuyển đổi các khung hình đó thành một hoạ tiết GLES bên ngoài.
  • SurfaceFlinger – Ứng dụng khai báo một thực thể SurfaceView để hiển thị các khung.
  • MediaServer – Định cấu hình bộ mã hoá MediaCodec bằng một bề mặt đầu vào để tạo video.

Trong hình dưới đây, các mũi tên cho biết quá trình truyền dữ liệu từ máy ảnh. Các thực thể BufferQueue có màu (thực thể sản xuất có màu xanh lục lam, thực thể tiêu thụ có màu xanh lục).

Hoạt động chụp liên tục của Grafika

Hình 1. Hoạt động chụp liên tục của Grafika

Video H.264 đã mã hoá sẽ chuyển đến vùng đệm tròn trong RAM trong quá trình xử lý ứng dụng. Khi người dùng nhấn nút chụp, lớp MediaMuxer sẽ ghi video đã mã hoá vào tệp MP4 trên ổ đĩa.

Tất cả các thực thể BufferQueue đều được xử lý bằng một ngữ cảnh EGL duy nhất trong ứng dụng, trong khi các thao tác GLES được thực hiện trên luồng giao diện người dùng. Việc xử lý dữ liệu đã mã hoá (quản lý bộ đệm tròn và ghi dữ liệu đó vào ổ đĩa) được thực hiện trên một luồng riêng.

Khi sử dụng lớp SurfaceView, lệnh gọi lại surfaceCreated() sẽ tạo các thực thể EGLContextEGLSurface cho màn hình và bộ mã hoá video. Khi một khung hình mới đến, SurfaceTexture sẽ thực hiện 4 hoạt động:
  1. Thu thập khung hình.
  2. Cung cấp khung dưới dạng kết cấu GLES.
  3. Kết xuất khung bằng các lệnh GLES.
  4. Chuyển tiếp phép biến đổi và dấu thời gian cho mỗi thực thể của EGLSurface.

Sau đó, luồng bộ mã hoá sẽ lấy đầu ra đã mã hoá từ MediaCodec và lưu trữ đầu ra đó trong bộ nhớ.

Phát video kết cấu một cách an toàn

Android hỗ trợ GPU xử lý hậu kỳ nội dung video được bảo vệ. Điều này cho phép các ứng dụng sử dụng GPU cho các hiệu ứng video phức tạp, phi tuyến tính (chẳng hạn như hiệu ứng xoắn), ánh xạ nội dung video được bảo vệ lên kết cấu để sử dụng trong các cảnh đồ hoạ chung (ví dụ: sử dụng GLES) và thực tế ảo (VR).

Phát video kết cấu bảo mật

Hình 2. Phát video kết cấu một cách an toàn

Bạn có thể bật tính năng hỗ trợ bằng hai tiện ích sau:

  • Tiện ích EGL – (EGL_EXT_protected_content) Cho phép tạo các ngữ cảnh và nền tảng GL được bảo vệ, cả hai đều có thể hoạt động trên nội dung được bảo vệ.
  • Tiện ích GLES – (GL_EXT_protected_textures) Cho phép gắn thẻ hoạ tiết là được bảo vệ để có thể dùng làm tệp đính kèm hoạ tiết vùng đệm khung hình.

Android cho phép SurfaceTexture và ACodec (libstagefright.so) gửi nội dung được bảo vệ ngay cả khi nền tảng của cửa sổ không xếp hàng vào SurfaceFlinger và cung cấp nền tảng video được bảo vệ để sử dụng trong ngữ cảnh được bảo vệ. Việc này được thực hiện bằng cách đặt bit người dùng được bảo vệ (GRALLOC_USAGE_PROTECTED) trên các nền tảng được tạo trong ngữ cảnh được bảo vệ (do ACodec xác minh).

Tính năng phát video kết cấu bảo mật đặt nền tảng cho việc triển khai DRM mạnh mẽ trong môi trường OpenGL ES. Nếu không triển khai DRM mạnh mẽ, chẳng hạn như Widevine cấp 1, nhiều nhà cung cấp nội dung sẽ không cho phép kết xuất nội dung có giá trị cao trong môi trường OpenGL ES, ngăn chặn các trường hợp sử dụng quan trọng của VR, chẳng hạn như xem nội dung được bảo vệ bằng DRM trong VR.

AOSP bao gồm mã khung để phát video kết cấu một cách an toàn. Việc hỗ trợ trình điều khiển là tuỳ thuộc vào OEM. Trình triển khai thiết bị phải triển khai EGL_EXT_protected_contentGL_EXT_protected_textures extensions. Khi sử dụng thư viện bộ mã hoá và giải mã của riêng bạn (để thay thế libstagefright), hãy lưu ý các thay đổi trong /frameworks/av/media/libstagefright/SurfaceUtils.cpp cho phép gửi vùng đệm được đánh dấu bằng GRALLOC_USAGE_PROTECTED đến ANativeWindow (ngay cả khi ANativeWindow không xếp hàng trực tiếp vào trình tổng hợp cửa sổ) miễn là các bit sử dụng của người dùng chứa GRALLOC_USAGE_PROTECTED. Để biết tài liệu chi tiết về cách triển khai các tiện ích, hãy tham khảo các sổ đăng ký Khronos (EGL_EXT_protected_contentGL_EXT_protected_textures).