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 поддерживает постобработку защищенного видеоконтента с помощью графического процессора. Это позволяет приложениям использовать GPU для создания сложных нелинейных видеоэффектов (таких как деформации), наложения защищенного видеоконтента на текстуры для использования в обычных графических сценах (например, с использованием 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-производителями. Разработчики устройств должны реализовать расширения 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
).