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 поддерживает постобработку защищенного видеоконтента с помощью графического процессора. Это позволяет приложениям использовать GPU для создания сложных нелинейных видеоэффектов (таких как деформации), наложения защищенного видеоконтента на текстуры для использования в обычных графических сценах (например, с использованием 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, в виртуальной реальности.
AOSP включает фреймворк для безопасного воспроизведения видео с текстурами. Поддержка драйверов осуществляется OEM-производителями. Разработчики устройств должны реализовать расширения EGL_EXT_protected_content и GL_EXT_protected_textures extensions . При использовании собственной библиотеки кодеков (для замены libstagefright ) обратите внимание на изменения в /frameworks/av/media/libstagefright/SurfaceUtils.cpp , которые позволяют отправлять буферы, отмеченные GRALLOC_USAGE_PROTECTED , в ANativeWindow (даже если ANativeWindow не ставится в очередь непосредственно в оконный композитор) до тех пор, пока биты использования потребителя содержат GRALLOC_USAGE_PROTECTED . Для получения подробной документации по реализации расширений обратитесь к реестрам Khronos ( EGL_EXT_protected_content и GL_EXT_protected_textures ).