Текстура поверхности

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 выполняет четыре действия:
  1. Приобретает кадр.
  2. Делает рамку доступной в виде текстуры GLES.
  3. Отрисовывает кадр с помощью команд GLES.
  4. Пересылает преобразование и метку времени для каждого экземпляра 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, в виртуальной реальности.

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 ).