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