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

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, в виртуальной реальности.

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