Interfejsy API do zarządzania buforem HAL3 kamery

Android 10 wprowadza opcjonalne interfejsy API do zarządzania buforem camera HAL3, które umożliwiają implementację logiki zarządzania buforem w celu uzyskania różnych kompromisów między pamięcią a opóźnieniem w przypadku implementacji interfejsu camera HAL.

Interfejs HAL aparatu wymaga N żądań (gdzie N jest równe głębi potoku) w kole, ale często nie wymaga wszystkich N zestawów buforów wyjściowych w tym samym czasie.

Na przykład HAL może mieć 8 żądań w kole w systemie, ale potrzebuje tylko buforów wyjściowych dla 2 żądań w ostatnich etapach. Na urządzeniach z Androidem 9 lub starszym framework aparatu przydziela bufory, gdy prośba jest umieszczana w kole w interfejsie HAL, więc w interfejsie HAL może być 6 zestawów buforów, które nie są używane. W Androidzie 10 interfejsy API do zarządzania buforami w kamerze HAL3 umożliwiają odłączenie buforów wyjściowych, aby zwolnić 6 zestawów buforów. Może to prowadzić do oszczędności setek megabajtów pamięci na urządzeniach wysokiej klasy, a także przynieść korzyści w przypadku urządzeń o małej ilości pamięci.

Rysunek 1 przedstawia diagram interfejsu HAL aparatu na urządzeniach z Androidem 9 lub starszym. Rysunek 2. przedstawia interfejs HAL aparatu w Androidzie 10 z zaimplementowanymi interfejsami API zarządzania buforem HAL3.

Zarządzanie buforem w Androidzie 9 lub starszym

Rysunek 1. Interfejs Camera HAL w Androidzie 9 i starszych

Zarządzanie buforem w Androidzie 10

Rysunek 2. Interfejs HAL aparatu w Androidzie 10 korzystający z interfejsów API do zarządzania buforem

Wdrażanie interfejsów API do zarządzania buforem

Aby zaimplementować interfejsy API zarządzania buforem, interfejs HAL aparatu musi:

HAL aparatu używa metod requestStreamBuffersreturnStreamBuffersICameraDeviceCallback.hal do żądania i zwracania buforów. Biblioteka HAL musi też implementować metodę signalStreamFlushICameraDeviceSession.hal, aby sygnalizować bibliotece HAL aparatu, że ma zwrócić bufory.

requestStreamBuffers

Aby poprosić o bufory z ramki aparatu, użyj metody requestStreamBuffers. Gdy używasz interfejsów API do zarządzania buforami w ramach aparatu HAL3, żądania rejestrowania z ramy aparatu nie zawierają buforów wyjściowych, czyli pole bufferIdStreamBuffer ma wartość 0. Dlatego HAL aparatu musi używać funkcji requestStreamBuffers, aby żądać buforów z ramy aparatu.

Metoda requestStreamBuffers umożliwia wywołującemu żądanie wielu buforów z wielu strumieni wyjściowych w jednym wywołaniu, co pozwala na ograniczenie wywołań HIDL IPC. Jednak wywołania zajmują więcej czasu, gdy jednocześnie jest wymagana większa liczba buforów, co może negatywnie wpłynąć na łączny czas od żądania do wyniku. Ponadto, ponieważ wywołania do funkcji requestStreamBuffers są serializowane w usłudze aparatu, zalecamy, aby interfejs HAL aparatu używał dedykowanego wątku o wysokim priorytecie do żądania buforów.

Jeśli żądanie bufora nie powiedzie się, interfejs HAL aparatu musi być w stanie prawidłowo obsłużyć błędy niekrytyczne. Poniżej znajdziesz listę najczęstszych przyczyn niepowodzeń żądań buforowania i sposób ich obsługi przez interfejs HAL aparatu.

  • Aplikacja rozłącza się ze strumieniem wyjściowym: to błąd niekrytyczny. Interfejs HAL aparatu powinien wysyłać żądanie ERROR_REQUEST dotyczące każdego żądania rejestrowania, które kieruje do odłączonego strumienia, i być gotowy do przetwarzania kolejnych żądań w normalny sposób.
  • Limit czasu: może się to zdarzyć, gdy aplikacja jest zajęta intensywnym przetwarzaniem, a jednocześnie przechowuje niektóre bufory. Interfejs HAL aparatu powinien ERROR_REQUEST przesyłać żądania rejestrowania, które nie mogą zostać zrealizowane z powodu błędu limitu czasu, i być gotowy do przetwarzania kolejnych żądań w normalny sposób.
  • Framework aparatu przygotowuje nową konfigurację strumienia: HAL aparatu powinien zaczekać, aż zakończy się wywołanie configureStreams, a dopiero potem wywołać ponownie funkcję requestStreamBuffers.
  • HAL aparatu osiągnął limit bufora (pole maxBuffers): HAL aparatu powinien zaczekać, aż zwróci co najmniej 1 bufor strumienia, zanim ponownie wywoła funkcję requestStreamBuffers.

returnStreamBuffers

Aby zwrócić dodatkowe bufory do aparatu, użyj metody returnStreamBuffers. Interfejs HAL aparatu zazwyczaj zwraca do interfejsu aparatu oprogramowania interfejsów (API) bufory za pomocą metody processCaptureResult, ale może uwzględniać tylko żądania rejestrowania, które zostały wysłane do interfejsu HAL aparatu. W przypadku metody requestStreamBuffers implementacja interfejsu HAL aparatu może zachować więcej buforów niż te, których wymaga interfejs aparatu. W takich przypadkach należy użyć metody returnStreamBuffers. Jeśli implementacja HAL nigdy nie przechowuje więcej buforów niż wymagane, implementacja HAL aparatu fotograficznego nie musi wywoływać metody returnStreamBuffers.

signalStreamFlush

Metoda signalStreamFlush jest wywoływana przez framework kamery, aby powiadomić interfejs HAL kamery o konieczności zwrócenia wszystkich dostępnych buforów. Ta metoda jest zwykle wywoływana, gdy framework aparatu ma wywołać metodę configureStreams i musi opróżnić potok przechwytywania aparatu. Podobnie jak w przypadku metody returnStreamBuffers, jeśli implementacja interfejsu HAL aparatu nie przechowuje więcej buforów niż jest to wymagane, można użyć pustej implementacji tej metody.

Po wywołaniu przez framework aparatu funkcji signalStreamFlush framework przestaje wysyłać nowe żądania rejestrowania do interfejsu HAL aparatu, dopóki wszystkie bufory nie zostaną zwrócone do frameworku aparatu. Gdy wszystkie bufory zostaną zwrócone, wywołania metody requestStreamBuffers zakończą się niepowodzeniem, a ramka aparatu może kontynuować pracę w czystym stanie. Następnie framework aparatu wywołuje metodę configureStreams lub processCaptureRequest. Jeśli framework aparatu wywoła metodę configureStreams, po pomyślnym wywołaniu metody configureStreams interfejs HAL aparatu może ponownie zacząć żądać buforów. Jeśli framework aparatu wywołuje metodę processCaptureRequest, HAL aparatu może zacząć żądać buforów podczas wywołania processCaptureRequest.

Metoda signalStreamFlush różni się semantycznie od metody flush. Gdy wywoływana jest metoda flush, HAL może przerwać oczekujące żądania przechwytywania, aby jak najszybciej opróżnić kanał.ERROR_REQUEST Gdy wywoływana jest metoda signalStreamFlush, HAL musi normalnie zakończyć wszystkie oczekujące żądania rejestrowania i zwrócić wszystkie bufory do interfejsu aparatu.

Kolejną różnicą między metodą signalStreamFlush a innymi metodami jest to, że signalStreamFlush to jednokierunkowa metoda HIDL, co oznacza, że framework aparatu może wywoływać inne blokujące interfejsy API, zanim HAL otrzyma wywołanie signalStreamFlush. Oznacza to, że metoda signalStreamFlush i inne metody (w szczególności metoda configureStreams) mogą docierać do aparatu HAL w innej kolejności niż kolejność wywołania w ramach interfejsu aparatu. Aby rozwiązać ten problem asynchroniczności, do metody StreamConfiguration dodano pole streamConfigCounter, a także jako argument dodano je do metody signalStreamFlush. Implementacja HAL aparatu powinna używać argumentu streamConfigCounter do określenia, czy wywołanie signalStreamFlush jest późniejsze niż odpowiadające mu wywołanie configureStreams. Przykład znajdziesz na rysunku 3.

Obsługa połączeń, które docierają z opóźnieniem

Rysunek 3. Jak interfejs HAL kamery powinien wykrywać i obsługiwać wywołania signalStreamFlush, które docierają z opóźnieniem

Zmiany w działaniu po wdrożeniu interfejsów API do zarządzania buforem

Podczas korzystania z interfejsów API do zarządzania buforem w celu implementacji logiki zarządzania buforem należy wziąć pod uwagę te możliwe zmiany w zachowaniu aparatu i implementacji interfejsu HAL aparatu:

  • Żądania dotyczące przechwytywania docierają do interfejsu HAL aparatu szybciej i częściej: bez interfejsów API do zarządzania buforami framework aparatu prosi o bufory wyjściowe dla każdego żądania dotyczącego przechwytywania, zanim prześle to żądanie do interfejsu HAL aparatu. Gdy używasz interfejsów API do zarządzania buforami, framework aparatu nie musi już czekać na bufory, więc może wcześniej wysyłać żądania rejestrowania do interfejsu HAL aparatu.

    Ponadto bez interfejsów API do zarządzania buforami framework aparatu przestaje wysyłać żądania przechwytywania, jeśli jeden z wyjściowych strumieni żądania przechwytywania osiągnął maksymalną liczbę buforów, jaką może pomieścić HAL (ta wartość jest wyznaczana przez HAL aparatu w polu HalStream::maxBuffers w wartości zwracanej wywołania configureStreams). Dzięki interfejsom API do zarządzania buforem nie ma już takiego ograniczania przepustowości, a implementacja interfejsu HAL aparatu nie może akceptować wywołań processCaptureRequest, gdy ma zbyt wiele oczekujących żądań rejestrowania.

  • Czas oczekiwania na połączenie requestStreamBuffers może się znacznie różnić: istnieje wiele powodów, dla których połączenie requestStreamBuffers może trwać dłużej niż przeciętnie. Przykład:

    • W przypadku pierwszych kilku buforów nowo utworzonego strumienia wywołania mogą potrwać dłużej, ponieważ urządzenie musi przydzielić pamięć.
    • Oczekiwany czas oczekiwania zwiększa się proporcjonalnie do liczby buforów zażądanych w każdym wywołaniu.
    • Aplikacja przechowuje bufory i przetwarza dane. Może to spowodować spowolnienie żądań buforowania lub przekroczenie limitu czasu z powodu braku buforów lub zajętego procesora.

Strategie zarządzania buforem

Interfejsy API do zarządzania buforem umożliwiają wdrażanie różnych strategii zarządzania buforem. Przykłady:

  • Wsteczna kompatybilność: HAL prosi o bufory dla żądania zapisu podczas wywołania processCaptureRequest. Ta strategia nie pozwala na oszczędzanie pamięci, ale może służyć jako pierwsza implementacja interfejsów API do zarządzania buforem, wymagająca bardzo niewielkich zmian w kodzie w istniejącym interfejsie HAL aparatu.
  • Maksymalizacja oszczędności pamięci: interfejs HAL aparatu prosi o bufory wyjściowe tylko tuż przed wypełnieniem jednego z nich. Ta strategia pozwala na zmaksymalizowanie oszczędzania pamięci. Potencjalną wadą jest większa liczba żądań dotyczących strumienia kamery, gdy żądania buforowania zajmują nienormalnie dużo czasu.
  • Pamięć podręczna: interfejs HAL aparatu przechowuje w pamięci podręcznej kilka buforów, aby zmniejszyć prawdopodobieństwo wpływu na niego sporadycznie powolnego żądania bufora.

W przypadku niektórych zastosowań interfejs HAL aparatu może stosować różne strategie. Na przykład w przypadku zastosowań, które zużywają dużo pamięci, może stosować strategię maksymalizacji oszczędzania pamięci, a w innych przypadkach – strategię zgodności wstecznej.

Przykładowa implementacja w interfejsie zewnętrznego aparatu HAL

Interfejs HAL aparatu zewnętrznego został wprowadzony w Androidzie 9 i można go znaleźć w drzewie źródłowym na stronie hardware/interfaces/camera/device/3.5/. W Androidzie 10 interfejs ten został zaktualizowany i obsługuje ExternalCameraDeviceSession.cpp, czyli implementację interfejsu API do zarządzania buforem. Ten interfejs HAL dla zewnętrznej kamery korzysta z strategii maksymalizacji oszczędzania pamięci opisanej w artykule Zarządzanie buforem – strategie.