Tekstura powierzchni

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

SurfaceTexture zawiera instancję BufferQueue , dla której aplikacje są konsumentem. Wywołanie zwrotne onFrameAvailable() powiadamia aplikacje, gdy producent umieści w kolejce nowy bufor. Następnie aplikacje wywołują funkcję updateTexImage() , która zwalnia poprzednio przechowywany bufor, pobiera nowy bufor z kolejki i wykonuje wywołania EGL , aby udostępnić bufor GLES jako teksturę zewnętrzną.

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:

  • Tekstury zewnętrzne renderują teksturowane wielokąty bezpośrednio z danych otrzymanych z BufferQueue .
  • Zewnętrzne moduły renderowania tekstur są konfigurowane inaczej niż tradycyjne moduły renderowania tekstur GLES.
  • Tekstury zewnętrzne nie mogą wykonywać wszystkich tradycyjnych czynności związanych z teksturami GLES.

Główną zaletą tekstur zewnętrznych jest ich możliwość renderowania bezpośrednio z danych BufferQueue . Instancje SurfaceTexture ustawiają flagi użytkowania konsumenckiego na GRALLOC_USAGE_HW_TEXTURE podczas tworzenia instancji BufferQueue dla tekstur zewnętrznych, aby zapewnić rozpoznawalność danych w buforze przez GLES.

Ponieważ instancje SurfaceTexture wchodzą w interakcję z kontekstem EGL, aplikacja może wywoływać swoje metody tylko wtedy, gdy kontekst EGL będący właścicielem tekstury jest bieżący w wątku wywołującym. Więcej informacji można znaleźć w dokumentacji klasy SurfaceTexture .

Znaczniki czasu i transformacje

Instancje SurfaceTexture obejmują metodę getTimeStamp() , która pobiera znacznik czasu, oraz metodę getTransformMatrix() , która pobiera macierz transformacji. Wywołanie updateTexImage() ustawia zarówno znacznik czasu, jak i macierz transformacji. Każdy bufor przekazywany BufferQueue zawiera parametry transformacji i sygnaturę czasową.

Parametry transformacji są przydatne dla wydajności. W niektórych przypadkach dane źródłowe mogą mieć niewłaściwą orientację dla konsumenta. Zamiast obracać dane przed wysłaniem ich do konsumenta, wyślij dane w ich orientacji z transformacją, która je koryguje. Macierz transformacji można połączyć z innymi transformacjami, gdy używane są dane, minimalizując narzut.

Znacznik czasu jest przydatny w przypadku źródeł buforowych zależnych od czasu. Na przykład, gdy setPreviewTexture() łączy interfejs producenta z wyjściem kamery, klatki z kamery mogą zostać wykorzystane do stworzenia wideo. Każda klatka musi mieć sygnaturę czasową prezentacji od momentu jej przechwycenia, a nie od chwili, gdy aplikacja otrzymała ramkę. Kod kamery ustawia znacznik czasu dostarczony z buforem, co skutkuje bardziej spójną serią znaczników czasu.

Studium przypadku: ciągłe przechwytywanie grafiki

Ciągłe przechwytywanie grafiki polega na nagrywaniu klatek z kamery urządzenia i wyświetlaniu tych klatek na ekranie. Aby nagrać klatki, utwórz powierzchnię za pomocą metody createInputSurface() klasy MediaCodec i przekaż powierzchnię do kamery. Aby wyświetlić ramki, utwórz instancję SurfaceView i przekaż powierzchnię do setPreviewDisplay() . Należy pamiętać, że nagrywanie klatek i jednoczesne ich wyświetlanie jest procesem bardziej złożonym.

Funkcja ciągłego przechwytywania wyświetla obraz wideo z kamery w trakcie jego nagrywania. W tym przypadku zakodowany obraz wideo jest zapisywany w buforze kołowym w pamięci, który można w dowolnej chwili zapisać na dysku.

Przepływ ten obejmuje trzy kolejki buforowe:

  • App — aplikacja wykorzystuje instancję SurfaceTexture do odbierania klatek z kamery i konwertowania ich na zewnętrzną teksturę GLES.
  • SurfaceFlinger — aplikacja deklaruje instancję SurfaceView w celu wyświetlania ramek.
  • MediaServer — skonfiguruj koder MediaCodec z powierzchnią wejściową, aby utworzyć wideo.

Na poniższym rysunku strzałki wskazują propagację danych z kamery. Instancje BufferQueue są kolorowe (producenci są w kolorze turkusowym, konsumenci w kolorze zielonym).

Ciągła aktywność przechwytywania grafiki

Rysunek 1. Ciągła aktywność przechwytywania grafiki

Zakodowane wideo w formacie H.264 trafia w procesie aplikacji do bufora cyklicznego w pamięci RAM. Gdy użytkownik naciśnie przycisk przechwytywania, klasa MediaMuxer zapisuje zakodowane wideo w pliku MP4 na dysku.

Wszystkie instancje BufferQueue są obsługiwane w aplikacji w pojedynczym kontekście EGL, podczas gdy operacje GLES są wykonywane w wątku interfejsu użytkownika. Obsługa zakodowanych danych (zarządzanie buforem cyklicznym i zapisywanie ich na dysku) odbywa się w osobnym wątku.

W przypadku korzystania z klasy SurfaceView wywołanie zwrotne surfaceCreated() tworzy instancje EGLContext i EGLSurface dla wyświetlacza i kodera wideo. Kiedy nadchodzi nowa ramka, SurfaceTexture wykonuje cztery działania:
  1. Zdobywa ramę.
  2. Udostępnia ramkę jako teksturę GLES.
  3. Renderuje klatkę za pomocą poleceń GLES.
  4. Przekazuje transformację i sygnaturę czasową dla każdej instancji EGLSurface .

Następnie wątek kodera pobiera zakodowane dane wyjściowe z MediaCodec i przechowuje je w pamięci.

Bezpieczne odtwarzanie wideo z teksturami

Android obsługuje przetwarzanie końcowe chronionej zawartości wideo przez procesor graficzny. Dzięki temu aplikacje mogą używać procesora graficznego do tworzenia złożonych, nieliniowych efektów wideo (takich jak wypaczenia), mapowania chronionej zawartości wideo na tekstury do wykorzystania w ogólnych scenach graficznych (na przykład przy użyciu GLES) i rzeczywistości wirtualnej (VR).

Bezpieczne odtwarzanie wideo z teksturami

Rysunek 2. Bezpieczne odtwarzanie wideo z teksturami

Wsparcie jest włączone przy użyciu następujących dwóch rozszerzeń:

  • Rozszerzenie EGL — ( EGL_EXT_protected_content ) Umożliwia tworzenie chronionych kontekstów i powierzchni GL, które mogą działać na chronionej treści.
  • Rozszerzenie GLES — ( GL_EXT_protected_textures ) Umożliwia oznaczanie tekstur jako chronionych, dzięki czemu można ich używać jako załączników tekstur buforujących ramkę.

Android umożliwia SurfaceTexture i ACodec ( libstagefright.so ) wysyłanie chronionej zawartości, nawet jeśli powierzchnia okna nie kolejkuje do SurfaceFlinger i zapewnia chronioną powierzchnię wideo do użycia w chronionym kontekście. Odbywa się to poprzez ustawienie chronionego bitu konsumenta ( GRALLOC_USAGE_PROTECTED ) na powierzchniach utworzonych w chronionym kontekście (zweryfikowanym przez ACodec).

Bezpieczne odtwarzanie wideo z teksturami stanowi podstawę solidnej implementacji DRM w środowisku OpenGL ES. Bez silnej implementacji DRM, takiej jak Widevine poziom 1, wielu dostawców treści nie pozwala na renderowanie treści o wysokiej wartości w środowisku OpenGL ES, uniemożliwiając ważne przypadki użycia VR, takie jak oglądanie treści chronionych DRM w VR.

AOSP zawiera kod struktury do bezpiecznego odtwarzania wideo z teksturami. Wsparcie dla sterowników zależy od producentów OEM. Osoby wdrażające urządzenia muszą implementować rozszerzenia EGL_EXT_protected_content i GL_EXT_protected_textures extensions . Używając własnej biblioteki kodeków (w celu zastąpienia libstagefright ), zwróć uwagę na zmiany w /frameworks/av/media/libstagefright/SurfaceUtils.cpp , które umożliwiają wysyłanie buforów oznaczonych GRALLOC_USAGE_PROTECTED do ANativeWindow (nawet jeśli ANativeWindow nie kolejkuje się bezpośrednio do kompozytor okna), o ile bity użytkowania konsumenckiego zawierają GRALLOC_USAGE_PROTECTED . Szczegółową dokumentację dotyczącą wdrażania rozszerzeń można znaleźć w rejestrach Khronos ( EGL_EXT_protected_content i GL_EXT_protected_textures ).