SurfaceTexture

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(), который извлекает матрицу преобразования. Вызов функции "Звонок" (Calling) updateTexImage() задает временную метку и матрицу преобразования. Каждый буфер, который передает BufferQueue, включает параметры преобразования и временную метку.

Параметры преобразования полезны для повышения эффективности. В некоторых случаях исходные данные могут быть ориентированы неправильно. Вместо того чтобы поворачивать данные перед отправкой потребителю, отправьте их в исходной ориентации с преобразованием, которое исправляет ее. Матрицу преобразования можно объединить с другими преобразованиями при использовании данных, что позволяет снизить нагрузку.

Временная метка полезна для источников буфера, которые зависят от времени. Например, когда setPreviewTexture() подключает интерфейс производителя к выходу камеры, кадры с камеры можно использовать для создания видео. У каждого кадра должна быть временная метка, указывающая, когда он был снят, а не когда приложение его получило. Код камеры задает временную метку, которая предоставляется вместе с буфером, что обеспечивает более согласованную серию временных меток.

Пример использования: непрерывная съемка Grafika

Непрерывная съемка Grafika подразумевает запись кадров с камеры устройства и их отображение на экране. Чтобы записать кадры, создайте поверхность с помощью метода MediaCodec класса createInputSurface() и передайте ее камере. Чтобы отобразить кадры, создайте экземпляр SurfaceView и передайте поверхность в setPreviewDisplay(). Обратите внимание, что запись кадров и их одновременное отображение – более сложный процесс.

Непрерывная запись – видео с камеры во время записи. В этом случае закодированное видео записывается в кольцевой буфер в памяти, который можно сохранить на диск в любое время.

В этом процессе используются три буфера:

  • App – приложение использует экземпляр SurfaceTexture для получения кадров с камеры и преобразования их во внешнюю текстуру GLES.
  • SurfaceFlinger – приложение объявляет экземпляр SurfaceView для показа кадров.
  • MediaServer – настройте кодировщик MediaCodec с входной поверхностью, чтобы создать видео.

На рисунке ниже стрелки указывают на распространение данных от камеры. Показано BufferQueue экземпляров с визуальными индикаторами, которые позволяют отличить производителей (бирюзовый цвет) от потребителей (зеленый цвет).

Непрерывная запись в Grafika

Рисунок 1. Непрерывная запись действий Grafika

Закодированное видео H.264 поступает в кольцевой буфер в ОЗУ в процессе приложения. Когда пользователь нажимает кнопку съемки, класс MediaMuxer записывает закодированное видео в файл MP4 на диске.

Все экземпляры BufferQueue обрабатываются в одном контексте EGL в приложении, а операции GLES выполняются в потоке UI. Обработка закодированных данных (управление кольцевым буфером и запись на диск) выполняется в отдельном потоке.

При использовании класса 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 и предоставляет защищенную видеоповерхность для использования в защищенном контексте. Для этого на поверхностях, созданных в защищенном контексте (проверенном ACodec), устанавливается бит защищенного потребителя (GRALLOC_USAGE_PROTECTED).

Безопасное воспроизведение видео с текстурами закладывает основу для надежного управления цифровыми правами (DRM) в среде OpenGL ES. Без надежной реализации DRM, например Widevine Level 1, многие поставщики контента не разрешают воспроизводить свой ценный контент в среде OpenGL ES, что препятствует важным вариантам использования VR, таким как просмотр контента с защитой DRM в VR.

Android Open Source Project (AOSP) включает код фреймворка для безопасного воспроизведения видео с текстурами. Поддержку драйверов обеспечивают производители оригинального оборудования. Производители устройств должны реализовать расширения 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).