SurfaceTexture
— это комбинация поверхности и текстуры OpenGL ES (GLES) . Экземпляры SurfaceTexture
используются для создания поверхностей, выводимых в текстуры GLES.
SurfaceTexture
содержит экземпляр BufferQueue
, для которого приложения являются потребителями. Обратный вызов onFrameAvailable()
уведомляет приложения, когда производитель помещает новый буфер в очередь. Затем приложения вызывают updateTexImage()
, который освобождает ранее удерживаемый буфер, получает новый буфер из очереди и выполняет вызовы EGL , чтобы сделать буфер доступным для GLES как внешнюю текстуру.
Внешние текстуры GLES
Внешние текстуры GLES ( GL_TEXTURE_EXTERNAL_OES
) отличаются от стандартных текстур GLES ( GL_TEXTURE_2D
) следующим:
- Внешние текстуры визуализируют текстурированные полигоны непосредственно из данных, полученных от
BufferQueue
. - Внешние рендереры текстур настраиваются иначе, чем стандартные рендереры текстур GLES.
- Внешние текстуры не могут выполнять все стандартные действия текстур GLES.
Главное преимущество внешних текстур — возможность рендеринга непосредственно из данных BufferQueue
. Экземпляры SurfaceTexture
устанавливают флаги использования потребителя в GRALLOC_USAGE_HW_TEXTURE
при создании экземпляров BufferQueue
для внешних текстур, чтобы убедиться, что данные в буфере распознаются GLES.
Поскольку экземпляры SurfaceTexture
взаимодействуют с контекстом EGL, приложение может вызывать его методы только пока контекст EGL, владеющий текстурой, активен в вызывающем потоке. Подробнее см. в документации по классу SurfaceTexture
.
Временные метки и преобразования
Экземпляры SurfaceTexture
включают метод getTimeStamp()
, который извлекает временную метку, и метод getTransformMatrix()
, который извлекает матрицу преобразования. Вызов updateTexImage()
устанавливает как временную метку, так и матрицу преобразования. Каждый буфер, передаваемый BufferQueue
, включает параметры преобразования и временную метку.
Параметры преобразования полезны для повышения эффективности. В некоторых случаях исходные данные могут иметь неверную для потребителя ориентацию. Вместо того, чтобы поворачивать данные перед отправкой потребителю, отправьте их в исходной ориентации с преобразованием, которое исправит её. Матрицу преобразования можно объединить с другими преобразованиями при использовании данных, что минимизирует накладные расходы.
Временная метка полезна для источников буфера, зависящих от времени. Например, когда setPreviewTexture()
подключает интерфейс производителя к выходу камеры, кадры с камеры можно использовать для создания видео. Каждый кадр должен иметь временную метку представления с момента захвата кадра, а не с момента получения кадра приложением. Код камеры устанавливает временную метку, предоставляемую буфером, что обеспечивает более согласованную последовательность временных меток.
Пример: непрерывный захват Grafika
Непрерывный захват в Grafika включает запись кадров с камеры устройства и их отображение на экране. Для записи кадров создайте поверхность с помощью метода createInputSurface()
класса MediaCodec
и передайте её камере. Для отображения кадров создайте экземпляр SurfaceView
и передайте поверхность методу setPreviewDisplay()
. Обратите внимание, что одновременная запись кадров и их отображение — более сложный процесс.
В режиме непрерывной записи видео с камеры отображается по мере его записи. В этом случае закодированное видео записывается в кольцевой буфер памяти, который можно сохранить на диск в любой момент.
Этот поток включает три очереди буферов:
-
App
— приложение использует экземплярSurfaceTexture
для получения кадров с камеры и преобразования их во внешнюю текстуру GLES. -
SurfaceFlinger
— приложение объявляет экземплярSurfaceView
для отображения кадров. -
MediaServer
— настройте кодерMediaCodec
с входной поверхностью для создания видео.
На следующем рисунке стрелки указывают на распространение данных от камеры. Показаны экземпляры BufferQueue
с визуальными индикаторами, отличающими производителей (бирюзовый) от потребителей (зелёный).

Рисунок 1. Непрерывная активность захвата Grafika
Закодированное видео H.264 помещается в кольцевой буфер в оперативной памяти процесса приложения. Когда пользователь нажимает кнопку захвата, класс MediaMuxer
записывает закодированное видео в файл MP4 на диск.
Все экземпляры BufferQueue
обрабатываются в приложении в едином контексте EGL, в то время как операции GLES выполняются в потоке пользовательского интерфейса. Обработка закодированных данных (управление кольцевым буфером и запись его на диск) выполняется в отдельном потоке.
При использовании класса SurfaceView
функция обратного вызова surfaceCreated()
создаёт экземпляры EGLContext
и EGLSurface
для дисплея и видеокодера. При поступлении нового кадра SurfaceTexture
выполняет четыре действия:
- Приобретает рамку.
- Делает рамку доступной как GLES-текстура.
- Визуализирует кадр с помощью команд GLES.
- Пересылает преобразование и временную метку для каждого экземпляра
EGLSurface
.
Затем поток кодировщика извлекает закодированный вывод из MediaCodec
и сохраняет его в памяти.
Безопасное воспроизведение видео текстур
Android поддерживает постобработку защищённого видеоконтента на графическом процессоре. Это позволяет приложениям использовать графический процессор для создания сложных нелинейных видеоэффектов (например, деформации), наложения защищённого видеоконтента на текстуры для использования в обычных графических сценах (например, с использованием GLES) и виртуальной реальности (VR).

Рисунок 2. Безопасное воспроизведение видео с текстурами
Поддержка включается с помощью следующих двух расширений:
- Расширение EGL — (
EGL_EXT_protected_content
) позволяет создавать защищенные контексты и поверхности GL, которые могут работать с защищенным содержимым. - Расширение GLES — (
GL_EXT_protected_textures
) позволяет помечать текстуры как защищенные, чтобы их можно было использовать в качестве вложений текстур буфера кадра.
Android позволяет SurfaceTexture
и ACodec ( libstagefright.so
) отправлять защищённое содержимое, даже если поверхность окна не находится в очереди SurfaceFlinger
, и предоставляет защищённую видеоповерхность для использования в защищённом контексте. Это достигается установкой защищённого бита потребителя ( GRALLOC_USAGE_PROTECTED
) на поверхностях, созданных в защищённом контексте (проверено ACodec).
Безопасное воспроизведение видео с текстурами закладывает основу для надежной реализации управления цифровыми правами (DRM) в среде OpenGL ES. Без надежной реализации DRM, такой как Widevine Level 1, многие поставщики контента не разрешают рендеринг своего ценного контента в среде OpenGL ES, что препятствует реализации важных сценариев использования виртуальной реальности, таких как просмотр контента, защищенного DRM, в виртуальной реальности.
Android Open Source Project (AOSP) включает код фреймворка для безопасного воспроизведения видео с текстурами. Поддержка драйверов осуществляется OEM-производителями. Разработчики устройств должны реализовать расширения EGL_EXT_protected_content
и GL_EXT_protected_textures
. При использовании собственной библиотеки кодеков (для замены libstagefright
) обратите внимание на изменения в /frameworks/av/media/libstagefright/SurfaceUtils.cpp
, которые позволяют отправлять буферы, помеченные GRALLOC_USAGE_PROTECTED
в ANativeWindow
(даже если ANativeWindow
не ставится в очередь напрямую к компоновщику окна), при условии, что биты использования потребителя содержат GRALLOC_USAGE_PROTECTED
. Подробную документацию по реализации расширений см. в реестрах Khronos ( EGL_EXT_protected_content
) и ( GL_EXT_protected_textures
).