SurfaceTexture
là sự kết hợp giữa một nền tảng và một kết cấu OpenGL ES (GLES).
Các thực thể SurfaceTexture
được dùng để cung cấp các vùng hiển thị xuất ra kết cấu GLES.
SurfaceTexture
chứa một thực thể của BufferQueue
mà ứng dụng là đối tượng sử dụng. Lệnh gọi lại onFrameAvailable()
sẽ 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()
, thao tác này sẽ giải phóng bộ đệm đã giữ trước đó, lấy bộ đệm mới từ hàng đợi và thực hiện các lệnh gọi EGL để cung cấp bộ đệm cho GLES dưới dạng một 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 tiêu chuẩn (GL_TEXTURE_2D
) ở những điểm sau:
- Các hoạ tiết bên ngoài kết xuất các đa giác có hoạ tiết trực tiếp từ dữ liệu nhận được từ
BufferQueue
. - Trình kết xuất kết cấu bên ngoài được định cấu hình khác với trình kết xuất kết cấu GLES tiêu chuẩn.
- Các hoạ tiết bên ngoài không thể thực hiện tất cả các hoạt động hoạ tiết GLES tiêu chuẩn.
Lợi ích chính của các 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 phiên bản SurfaceTexture
đặt cờ sử dụng của người dùng thành GRALLOC_USAGE_HW_TEXTURE
khi tạo các phiên bản BufferQueue
cho các hoạ tiết bên ngoài để xác minh rằng GLES có thể nhận dạng dữ liệu trong vùng đệm.
Vì các thực thể SurfaceTexture
tương tác với một 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ể này trong khi ngữ cảnh EGL sở hữu hoạ tiết hiện tại 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à các 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). Khi gọi updateTexImage()
, bạn sẽ đặt cả dấu thời gian và ma trận biến đổi. Mỗi vùng đệm mà BufferQueue
truyền sẽ bao gồm các tham số biến đổi và dấu thời gian.
Các thông số biến đổi rất hữu ích để tăng hiệu quả. Trong một số trường hợp, dữ liệu nguồn có thể có hướng không phù hợp với người tiêu 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 để điều chỉnh. Ma trận biến đổi có thể được hợp nhất với các phép biến đổi khác khi dữ liệu được sử dụng, giúp giảm thiểu chi phí phát sinh.
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 của nhà sản xuất với đầu ra của camera, các khung hình từ camera có thể được dùng để tạo video. Mỗi khung hình cần có dấu thời gian trình chiếu kể từ thời điểm khung hình được ghi lại, chứ không phải kể từ thời điểm ứng dụng nhận được khung hình. 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 chuỗi 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 liên quan đến việc ghi lại các khung hình từ camera của thiết bị và hiển thị các khung hình đó trên màn hình. Để ghi lại 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 chuyển nền tảng đó đến camera. Để hiển thị khung hình, hãy tạo một thực thể của SurfaceView
và truyền nền tảng đó đến setPreviewDisplay()
.
Xin lưu ý rằng việc ghi lại khung hình và hiển thị chúng cùng một lúc là một quy trình phức tạp hơn.
Hoạt động chụp liên tục hiển thị video từ camera trong khi video đang được quay. Trong trường hợp này, video được mã hoá sẽ được ghi vào một vùng đệm vòng trong bộ nhớ và có thể được lưu vào ổ đĩa bất cứ lúc nào.
Quy trình này bao gồm 3 hàng đợi đệm:
App
– Ứng dụng dùng một thực thểSurfaceTexture
để nhận các khung hình từ camera, 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 hình.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 sau, các mũi tên cho biết quá trình truyền dữ liệu từ camera. Các phiên bản BufferQueue
sẽ xuất hiện, với các chỉ báo trực quan phân biệt nhà sản xuất (màu xanh mòng két) với người tiêu dùng (màu xanh lục).

Hình 1. Hoạt động chụp liên tục của Grafika
Video được mã hoá H.264 sẽ chuyển đến một vùng đệm vòng trong RAM trong quy trình ứng dụng.
Khi người dùng nhấn nút chụp, lớp MediaMuxer
sẽ ghi video đã mã hoá vào một 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 được mã hoá (quản lý bộ đệm vòng và ghi dữ liệu đó vào ổ đĩa) được thực hiện trên một luồng riêng biệt.
Khi sử dụng lớp 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 nhận khung hình.
- Cung cấp khung hình dưới dạng cấu trúc bề mặt GLES.
- Kết xuất khung hình bằng các lệnh GLES.
- Chuyển tiếp phép biến đổi và dấu thời gian cho từng phiên bản của
EGLSurface
.
Sau đó, luồng bộ mã hoá sẽ kéo đầu ra đã mã hoá từ MediaCodec
và lưu trữ đầu ra đó trong bộ nhớ.
Phát video có kết cấu bảo mật
Android hỗ trợ hoạt động xử lý hậu kỳ GPU đối với 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 biến dạng), ánh xạ nội dung video được bảo vệ lên các hoạ tiết để 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 có kết cấu bảo mật
Tính năng hỗ trợ được bật bằng cách sử dụng 2 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ẻ các hoạ tiết là được bảo vệ để có thể dùng làm tệp đính kèm hoạ tiết bộ đệm khung.
Android cho phép SurfaceTexture
và ACodec (libstagefright.so
) gửi nội dung được bảo vệ ngay cả khi bề mặt của cửa sổ không xếp hàng vào SurfaceFlinger
và cung cấp một bề mặt video được bảo vệ để sử dụng trong một bối 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 vùng hiển thị được tạo trong một ngữ cảnh được bảo vệ (được ACodec xác minh).
Tính năng phát video kết cấu an toàn đặt nền tảng cho việc triển khai tính năng Quản lý quyền kỹ thuật số (DRM) mạnh mẽ trong môi trường OpenGL ES. Nếu không có một chế độ 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 của họ trong môi trường OpenGL ES, ngăn chặn các trường hợp sử dụng VR quan trọng như xem nội dung được bảo vệ bằng DRM trong VR.
Dự án nguồn mở Android (AOSP) bao gồm mã khung để phát video có kết cấu bảo mật. Việc hỗ trợ trình điều khiển là tuỳ thuộc vào các nhà sản xuất thiết bị gốc (OEM). Người triển khai thiết bị phải triển khai các tiện ích EGL_EXT_protected_content
và GL_EXT_protected_textures
. Khi sử dụng thư viện codec của riêng bạn (để thay thế libstagefright
), hãy lưu ý những thay đổi trong /frameworks/av/media/libstagefright/SurfaceUtils.cpp
cho phép gửi các 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 kết 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
).