Tekstura powierzchni

SurfaceTexture to połączenie powierzchni i tekstury OpenGL ES (GLES). Instancje SurfaceTexture są używane do udostępniania powierzchni, które są wyjściem dla tekstur GLES.

SurfaceTexture zawiera instancję BufferQueue, której aplikacje są konsumentami. Funkcja wywołania zwrotnego onFrameAvailable() powiadamia aplikacje, gdy producent wstawia do kolejki nowy bufor. Następnie aplikacje wywołują funkcję updateTexImage(), która zwalnia wcześniej przechowywany bufor, pobiera nowy bufor z kolejki i wywołuje EGL, aby udostępnić bufor GLES jako zewnętrzną teksturę.

Zewnętrzne tekstury GLES

Zewnętrzne tekstury GLES (GL_TEXTURE_EXTERNAL_OES) różnią się od tradycyjnych tekstur GLES (GL_TEXTURE_2D) w następujący sposób:

  • Zewnętrzne tekstury renderują teksturowane wielokąty bezpośrednio z danych otrzymanych z BufferQueue.
  • Zewnętrzne procesory tekstur są konfigurowane inaczej niż tradycyjne procesory tekstur GLES.
  • Tekstury zewnętrzne nie mogą wykonywać wszystkich tradycyjnych działań związanych z teksturami GLES.

Główną zaletą zewnętrznych tekstur jest możliwość ich renderowania bezpośrednio z danych BufferQueue. SurfaceTexture instancje ustawiają flagi użycia przez konsumenta na GRALLOC_USAGE_HW_TEXTURE podczas tworzenia BufferQueue instancji dla zewnętrznych tekstur, aby dane w buforze były rozpoznawalne przez GLES.

Ponieważ instancje SurfaceTexture współdziałają z kontekstem EGL, aplikacja może wywoływać ich metody tylko wtedy, gdy kontekst EGL, do którego należy tekstura, jest bieżący na wątku wywołania. Więcej informacji znajdziesz w dokumentacji klasy SurfaceTexture.

Sygnatury czasowe i transformacje

SurfaceTexture to m.in. metoda getTimeStamp(), która pobiera sygnaturę czasową, oraz metoda getTransformMatrix(), która pobiera macierz przekształcenia. Wywołanie funkcji updateTexImage() ustawia sygnaturę czasową i macierz przekształcenia. Każdy bufor, który przechodzi przez BufferQueue, zawiera parametry przekształcenia i sygnaturę czasową.

Parametry przekształcania są przydatne ze względu na wydajność. W niektórych przypadkach dane źródłowe mogą być w niewłaściwym układzie dla odbiorcy. Zamiast obracać dane przed ich wysłaniem do odbiorcy, wyślij je w ich orientacji z zastosowaniem transformacji, która ją skoryguje. Podczas używania danych można scalić macierzy przekształceń z innymi przekształceniami, aby zminimalizować nakład.

Sygnatura czasowa jest przydatna w przypadku źródeł bufora, które są zależne od czasu. Na przykład gdy setPreviewTexture() połączy interfejs producenta z wyjściem kamery, można użyć klatek z kamery do utworzenia filmu. Każda klatka musi mieć znacznik czasu przedstawiający moment jej przechwycenia, a nie moment otrzymania przez aplikację. Kod aparatu ustawia sygnaturę czasową podaną w buforze, co powoduje bardziej spójną serię sygnatur czasowych.

Studium przypadku: ciągłe przechwytywanie przez Grafika

Grafika ciągłego przechwytywania polega na rejestrowaniu klatek z aparatu urządzenia i wyświetlaniu ich na ekranie. Aby nagrywać klatki, utwórz powierzchnię za pomocą metody createInputSurface() klasy MediaCodec i przekaż ją do kamery. Aby wyświetlić ramki, utwórz instancję SurfaceView i przenieś powierzchnię do setPreviewDisplay(). Pamiętaj, że nagrywanie klatek i wyświetlanie ich w tym samym czasie jest bardziej skomplikowanym procesem.

Aktywność ciągłego nagrywania wyświetla obraz z kamery w trakcie nagrywania filmu. W takim przypadku zakodowany film jest zapisywany w buforze okrężnym w pamięci, który można w każdej chwili zapisać na dysku.

Ten proces obejmuje 3 koleje buforowe:

  • App – aplikacja używa instancji SurfaceTexture do odbierania ramek z kamery i konwertowania ich na zewnętrzną teksturę GLES.
  • SurfaceFlinger – aplikacja deklaruje wystąpienie SurfaceView, aby wyświetlać ramki.
  • MediaServer – skonfiguruj koder MediaCodec z powierzchnią wejściową, aby utworzyć film.

Na rysunku poniżej strzałki wskazują propagowanie danych z kamery. BufferQueue instancje są kolorowe (producenci są w kolorze turkusowym, a konsumenci w zielonym).

Grafika ciągłego rejestrowania

Rysunek 1. Grafika's ciągłe przechwytywanie aktywności

Zaszyfrowany film H.264 trafia do pętli buforowej w pamięci RAM w procesie aplikacji. Gdy użytkownik naciśnie przycisk rejestracji, klasa MediaMuxer zapisze zakodowany film do pliku MP4 na dysku.

Wszystkie wystąpienia BufferQueue są obsługiwane za pomocą pojedynczego kontekstu EGL w aplikacji, podczas gdy operacje GLES są wykonywane na wątku interfejsu użytkownika. Obsługa zakodowanych danych (zarządzanie pętlą i zapisywanie jej na dysku) odbywa się w oddzielnym wątku.

Gdy używasz klasy SurfaceView, wywołanie zwrotne surfaceCreated() tworzy instancje EGLContextEGLSurface dla wyświetlacza oraz kodera wideo. Gdy otrzymasz nową ramkę, SurfaceTexture wykona 4 działania:
  1. Pobiera ramkę.
  2. Udostępnia ramkę jako teksturę GLES.
  3. Wykonuje renderowanie ramki za pomocą poleceń GLES.
  4. Przekazuje przekształcenie i sygnaturę czasową dla każdego wystąpienia funkcji EGLSurface.

Następnie wątek kodera pobiera zakodowany kod z MediaCodec i przechowuje go w pamięci.

Bezpieczne odtwarzanie filmów z teksturami

Android obsługuje postprocessing chronionych treści wideo za pomocą procesora graficznego. Dzięki temu aplikacje mogą używać GPU do tworzenia złożonych, nieliniowych efektów wideo (np. przekształcania), mapowania chronionych treści wideo na tekstury do użycia w ogólnych scenach graficznych (np. za pomocą GLES) oraz do rzeczywistości wirtualnej (VR).

Bezpieczne odtwarzanie filmów z teksturami

Rysunek 2. Bezpieczne odtwarzanie filmów z teksturami

Obsługa jest włączona za pomocą tych 2 rozszerzeń:

  • Rozszerzenie EGL (EGL_EXT_protected_content) umożliwia tworzenie chronionych kontekstów i powierzchni GL, które mogą działać na chronionych treściach.
  • Rozszerzenie GLES (GL_EXT_protected_textures) umożliwia oznaczanie tekstur jako chronionych, aby można było ich używać jako załączników tekstur framebuffera.

Android umożliwia SurfaceTexture i ACodec (libstagefright.so) wysyłanie treści chronionych, nawet jeśli powierzchnia okna nie jest umieszczana w kole do SurfaceFlinger, oraz zapewnia chronioną powierzchnię wideo do użytku w ramach chronionego kontekstu. Polega to na ustawieniu chronionego bitu klienta (GRALLOC_USAGE_PROTECTED) na powierzchniach utworzonych w chronionym kontekście (potwierdzonych przez ACodec).

Bezpieczne odtwarzanie filmów z teksturami stanowi podstawę solidnej implementacji DRM w środowisku OpenGL ES. Bez solidnego wdrożenia DRM, takiego jak Widevine Level 1, wielu dostawców treści nie zezwala na renderowanie swoich cennych treści w środowisku OpenGL ES, co uniemożliwia ważne przypadki użycia VR, takie jak oglądanie treści chronionych DRM w VR.

AOSP zawiera kod frameworka do bezpiecznego odtwarzania filmów z teksturami. Obsługa sterowników zależy od producenta. Implementatorzy urządzeń muszą zaimplementować EGL_EXT_protected_contentGL_EXT_protected_textures extensions. Jeśli używasz własnej biblioteki kodeków (aby zastąpić libstagefright), zwróć uwagę na zmiany w /frameworks/av/media/libstagefright/SurfaceUtils.cpp, które umożliwiają wysyłanie buforów oznaczonych jako GRALLOC_USAGE_PROTECTED do ANativeWindow (nawet jeśli ANativeWindow nie umieszcza bezpośrednio w kolejce elementów do kompozytora okna), o ile bity dotyczące użycia przez klienta zawierają wartość GRALLOC_USAGE_PROTECTED. Szczegółową dokumentację dotyczącą wdrażania rozszerzeń znajdziesz w rejestrach Khronos (EGL_EXT_protected_content i GL_EXT_protected_textures).