Klasa StructureView jest obiektem widoku, który łączy widok z obiektem SurfaceTexture.
Renderowanie za pomocą OpenGL ES
Obiekt StructureView otacza SurfaceTexture, odpowiadając na wywołania zwrotne i pozyskując nowe bufory. Gdy obiekt StructureView pozyskuje nowe bufory, obiekt StructureView wysyła żądanie unieważnienia widoku i rysuje, używając zawartości najnowszego bufora jako źródła danych, renderując tam, gdzie i jak wskazuje stan widoku.
OpenGL ES (GLES) może renderować na StructureView, przekazując SurfaceTexture do wywołania tworzenia EGL, ale stwarza to problem. Kiedy GLES renderuje na StructureView, producenci i konsumenci BufferQueue znajdują się w tym samym wątku, co może spowodować zatrzymanie lub niepowodzenie wywołania wymiany bufora. Na przykład, jeśli producent przesyła kilka buforów w krótkich odstępach czasu z wątku interfejsu użytkownika, wywołanie wymiany buforów EGL musi usunąć bufor z kolejki BufferQueue. Ponieważ jednak konsument i producent korzystają z tego samego wątku, nie będą dostępne żadne bufory i wywołanie wymiany zawiesza się lub kończy się niepowodzeniem.
Aby mieć pewność, że wymiana buforów nie zostanie zatrzymana, BufferQueue zawsze potrzebuje bufora dostępnego do usunięcia z kolejki. Aby to zaimplementować, BufferQueue odrzuca zawartość poprzednio uzyskanego bufora, gdy nowy bufor jest umieszczany w kolejce i nakłada ograniczenia na minimalną i maksymalną liczbę buforów, aby uniemożliwić konsumentowi wykorzystanie wszystkich buforów na raz.
Wybór SurfaceView lub StructureView
SurfaceView i StructureView pełnią podobne role i oba są obywatelami hierarchii widoków. Jednak SurfaceView i StructureView mają różne implementacje. SurfaceView przyjmuje te same parametry, co inne widoki, ale zawartość SurfaceView jest przezroczysta po renderowaniu.
Teksturowany widok ma lepszą obsługę alfa i rotacji niż SurfaceView, ale SurfaceView ma lepszą wydajność podczas komponowania elementów interfejsu użytkownika nałożonych na filmy. Gdy klient renderuje za pomocą SurfaceView, SurfaceView zapewnia klientowi oddzielną warstwę kompozycji. SurfaceFlinger tworzy oddzielną warstwę jako nakładkę sprzętową, jeśli jest obsługiwana przez urządzenie. Gdy klient renderuje za pomocą tekstury, zestaw narzędzi interfejsu użytkownika łączy zawartość tekstury w hierarchię widoków za pomocą procesora graficznego. Aktualizacje zawartości mogą spowodować przerysowanie innych elementów widoku, na przykład, jeśli inne widoki są umieszczone na wierzchu tekstury. Po zakończeniu renderowania widoku SurfaceFlinger łączy warstwę interfejsu aplikacji i wszystkie pozostałe warstwy, tak aby każdy widoczny piksel był złożony dwukrotnie.
Studium przypadku: film wideo firmy Grafika
Play Video firmy Grafika zawiera parę odtwarzaczy wideo, jeden zaimplementowany za pomocą StructureView i jeden zaimplementowany w SurfaceView. Część działania polegająca na dekodowaniu wideo wysyła klatki z MediaCodec na powierzchnię zarówno dla StructureView, jak i SurfaceView. Największą różnicą pomiędzy implementacjami są kroki wymagane do przedstawienia prawidłowego współczynnika kształtu.
Skalowanie SurfaceView wymaga niestandardowej implementacji FrameLayout. WindowManager musi wysłać nową pozycję okna i nowe wartości rozmiaru do SurfaceFlinger. Skalowanie SurfaceTexture StructureView wymaga skonfigurowania macierzy transformacji za pomocą TextureView#setTransform()
.
Po przedstawieniu prawidłowych proporcji obie implementacje zachowują się według tego samego schematu. Gdy SurfaceView/TextureView tworzy powierzchnię, kod aplikacji umożliwia odtwarzanie. Gdy użytkownik kliknie przycisk odtwarzania , rozpoczyna się wątek dekodowania wideo, którego celem wyjściowym jest powierzchnia. Następnie kod aplikacji nie robi nic — kompozycją i wyświetlaniem zajmuje się SurfaceFlinger (w przypadku SurfaceView) lub teksturaView.
Studium przypadku: Podwójne dekodowanie grafiki
Podwójne dekodowanie grafiki demonstruje manipulację SurfaceTexture wewnątrz tekstury.
Double Decode grafiki wykorzystuje parę obiektów StructureView, aby pokazać dwa filmy odtwarzane obok siebie, symulując aplikację do wideokonferencji. Kiedy zmienia się orientacja ekranu i działanie zostaje wznowione, dekodery MediaCodec nie zatrzymują się, symulując odtwarzanie strumienia wideo w czasie rzeczywistym. Aby poprawić wydajność, klient powinien utrzymać powierzchnię przy życiu. Powierzchnia jest uchwytem interfejsu producenta w kolejce BufferQueue SurfaceTexture. Ponieważ StructureView zarządza SurfaceTexture, klient musi utrzymywać SurfaceTexture przy życiu, aby utrzymać powierzchnię przy życiu.
Aby utrzymać SurfaceTexture przy życiu, Double Decode grafiki uzyskuje odniesienia do SurfaceTexture z obiektów StructureView i zapisuje je w polu statycznym. Następnie funkcja Double Decode grafiki zwraca false
z TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed()
, aby zapobiec zniszczeniu SurfaceTexture. Następnie StructureView przekazuje SurfaceTexture do onSurfaceTextureDestroyed()
, który można zachować po zmianie konfiguracji działania, a którą klient przekazuje do nowego StructureView za pomocą setSurfaceTexture()
.
Oddzielne wątki obsługują każdy dekoder wideo. Serwer multimediów wysyła bufory z zdekodowanym wyjściem do SurfaceTextures, konsumentów BufferQueue. Obiekty StructureView wykonują renderowanie i wykonywanie w wątku interfejsu użytkownika.
Implementacja podwójnego dekodowania grafiki za pomocą SurfaceView jest trudniejsza niż implementacja za pomocą StructureView, ponieważ obiekty SurfaceView niszczą powierzchnie podczas zmian orientacji. Dodatkowo użycie obiektów SurfaceView powoduje dodanie dwóch warstw, co nie jest rozwiązaniem idealnym ze względu na ograniczenia liczby nakładek dostępnych na sprzęcie.