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).

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.
SurfaceView
, lệnh gọi lại surfaceCreated()
sẽ tạo các thực thể EGLContext
và EGLSurface
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:
- Thu thập khung hình.
- Cung cấp khung dưới dạng kết cấu GLES.
- Kết xuất khung bằng các lệnh GLES.
- 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).

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_content
và GL_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_content
và GL_EXT_protected_textures
).