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 koderMediaCodec
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).
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.
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:- Zdobywa ramę.
- Udostępnia ramkę jako teksturę GLES.
- Renderuje klatkę za pomocą poleceń GLES.
- 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).
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
).