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