Texture de surface

SurfaceTexture est une combinaison d'une surface et d'une texture OpenGL ES (GLES) . Les instances SurfaceTexture sont utilisées pour fournir des surfaces qui génèrent des textures GLES.

SurfaceTexture contient une instance de BufferQueue dont les applications sont les consommateurs. Le rappel onFrameAvailable() avertit les applications lorsque le producteur met en file d'attente un nouveau tampon. Ensuite, les applications appellent updateTexImage() , qui libère le tampon précédemment détenu, acquiert le nouveau tampon de la file d'attente et effectue des appels EGL pour rendre le tampon disponible à GLES en tant que texture externe.

Textures GLES externes

Les textures GLES externes ( GL_TEXTURE_EXTERNAL_OES ) diffèrent des textures GLES traditionnelles ( GL_TEXTURE_2D ) des manières suivantes :

  • Les textures externes restituent les polygones texturés directement à partir des données reçues de BufferQueue .
  • Les rendus de texture externes sont configurés différemment des rendus de texture GLES traditionnels.
  • Les textures externes ne peuvent pas effectuer toutes les activités de texture GLES traditionnelles.

Le principal avantage des textures externes est leur capacité à être restituées directement à partir des données BufferQueue . Les instances SurfaceTexture définissent les indicateurs d'utilisation du consommateur sur GRALLOC_USAGE_HW_TEXTURE lorsqu'elles créent des instances BufferQueue pour les textures externes afin de garantir que les données dans le tampon sont reconnaissables par GLES.

Étant donné que les instances SurfaceTexture interagissent avec un contexte EGL, une application ne peut appeler ses méthodes que lorsque le contexte EGL propriétaire de la texture est actuel sur le thread appelant. Pour plus d’informations, consultez la documentation de la classe SurfaceTexture .

Horodatages et transformations

Les instances SurfaceTexture incluent la méthode getTimeStamp() , qui récupère un horodatage, et la méthode getTransformMatrix() , qui récupère une matrice de transformation. L'appel de updateTexImage() définit à la fois l'horodatage et la matrice de transformation. Chaque tampon transmis par BufferQueue comprend des paramètres de transformation et un horodatage.

Les paramètres de transformation sont utiles pour l’efficacité. Dans certains cas, les données sources peuvent être mal orientées pour le consommateur. Au lieu de faire pivoter les données avant de les envoyer au consommateur, envoyez les données dans leur orientation avec une transformation qui les corrige. La matrice de transformation peut être fusionnée avec d'autres transformations lorsque les données sont utilisées, minimisant ainsi les frais généraux.

L'horodatage est utile pour les sources tampon qui dépendent du temps. Par exemple, lorsque setPreviewTexture() connecte l'interface du producteur à la sortie de la caméra, les images de la caméra peuvent être utilisées pour créer une vidéo. Chaque image doit avoir un horodatage de présentation à partir du moment où l'image a été capturée, et non à partir du moment où l'application a reçu l'image. Le code de la caméra définit l'horodatage fourni avec le tampon, ce qui donne lieu à une série d'horodatages plus cohérente.

Étude de cas : la capture continue de Grafika

La capture continue de Grafika consiste à enregistrer des images à partir de la caméra d'un appareil et à afficher ces images à l'écran. Pour enregistrer des images, créez une surface avec la méthode createInputSurface() de la classe MediaCodec et transmettez la surface à la caméra. Pour afficher des images, créez une instance de SurfaceView et transmettez la surface à setPreviewDisplay() . Notez que l'enregistrement d'images et leur affichage en même temps est un processus plus complexe.

L'activité de capture continue affiche la vidéo de la caméra pendant l'enregistrement de la vidéo. Dans ce cas, la vidéo codée est écrite dans un tampon circulaire en mémoire qui peut être enregistrée sur le disque à tout moment.

Ce flux implique trois files d'attente tampon :

  • App — L'application utilise une instance SurfaceTexture pour recevoir des images de la caméra, les convertissant en une texture GLES externe.
  • SurfaceFlinger — L'application déclare une instance SurfaceView pour afficher les images.
  • MediaServer — Configurez un encodeur MediaCodec avec une surface d'entrée pour créer la vidéo.

Dans la figure ci-dessous, les flèches indiquent la propagation des données depuis la caméra. Les instances BufferQueue sont en couleur (les producteurs sont bleu sarcelle, les consommateurs sont verts).

Activité de capture continue Grafika

Figure 1. Activité de capture continue de Grafika

La vidéo codée H.264 est envoyée dans un tampon circulaire dans la RAM au cours du processus d'application. Lorsqu'un utilisateur appuie sur le bouton de capture, la classe MediaMuxer écrit la vidéo encodée dans un fichier MP4 sur le disque.

Toutes les instances BufferQueue sont gérées avec un seul contexte EGL dans l'application tandis que les opérations GLES sont effectuées sur le thread de l'interface utilisateur. La gestion des données codées (gestion d'un tampon circulaire et écriture sur le disque) se fait sur un thread séparé.

Lors de l'utilisation de la classe SurfaceView , le rappel surfaceCreated() crée les instances EGLContext et EGLSurface pour l'affichage et l'encodeur vidéo. Lorsqu'une nouvelle image arrive, SurfaceTexture effectue quatre activités :
  1. Acquiert le cadre.
  2. Rend le cadre disponible sous forme de texture GLES.
  3. Rend le cadre avec les commandes GLES.
  4. Transfère la transformation et l'horodatage pour chaque instance de EGLSurface .

Le thread de l'encodeur extrait ensuite la sortie codée de MediaCodec et la stocke en mémoire.

Lecture vidéo de texture sécurisée

Android prend en charge le post-traitement GPU du contenu vidéo protégé. Cela permet aux applications d'utiliser le GPU pour des effets vidéo complexes et non linéaires (tels que des déformations), en mappant le contenu vidéo protégé sur des textures à utiliser dans des scènes graphiques générales (par exemple, en utilisant GLES) et en réalité virtuelle (VR).

Lecture vidéo sécurisée avec texture

Figure 2. Lecture vidéo de texture sécurisée

La prise en charge est activée à l'aide des deux extensions suivantes :

  • Extension EGL — ( EGL_EXT_protected_content ) Permet la création de contextes et de surfaces GL protégés, qui peuvent tous deux fonctionner sur du contenu protégé.
  • Extension GLES — ( GL_EXT_protected_textures ) Permet de marquer les textures comme protégées afin qu'elles puissent être utilisées comme pièces jointes de texture de framebuffer.

Android permet à SurfaceTexture et ACodec ( libstagefright.so ) d'envoyer du contenu protégé même si la surface de la fenêtre ne fait pas la queue vers SurfaceFlinger et fournit une surface vidéo protégée à utiliser dans un contexte protégé. Cela se fait en définissant le bit consommateur protégé ( GRALLOC_USAGE_PROTECTED ) sur les surfaces créées dans un contexte protégé (vérifié par ACodec).

La lecture vidéo à texture sécurisée constitue la base d'une mise en œuvre solide de DRM dans l'environnement OpenGL ES. Sans une implémentation DRM solide, telle que Widevine Level 1, de nombreux fournisseurs de contenu n'autorisent pas le rendu de leur contenu de grande valeur dans l'environnement OpenGL ES, empêchant ainsi des cas d'utilisation importants de la VR, tels que le visionnage de contenu protégé par DRM en VR.

AOSP inclut un code-cadre pour la lecture vidéo de texture sécurisée. La prise en charge des pilotes appartient aux OEM. Les implémenteurs de périphériques doivent implémenter les extensions EGL_EXT_protected_content et GL_EXT_protected_textures extensions . Lorsque vous utilisez votre propre bibliothèque de codecs (pour remplacer libstagefright ), notez les changements dans /frameworks/av/media/libstagefright/SurfaceUtils.cpp qui permettent aux tampons marqués avec GRALLOC_USAGE_PROTECTED d'être envoyés à ANativeWindow (même si ANativeWindow ne fait pas la queue directement vers le window composer) tant que les bits d'utilisation du consommateur contiennent GRALLOC_USAGE_PROTECTED . Pour une documentation détaillée sur la mise en œuvre des extensions, reportez-vous aux registres Khronos ( EGL_EXT_protected_content et GL_EXT_protected_textures ).