Liczba klatek

Interfejs API liczby klatek dostarcza aplikacjom informacji o planowanej liczbie klatek. Jest on dostępny w aplikacjach na Androida 11 (poziom API 30) lub nowszego. Tradycyjnie większość urządzeń obsługuje tylko jedną częstotliwość odświeżania wyświetlacza, zwykle 60 Hz, ale ta sytuacja się zmienia. Wiele urządzeń obsługuje teraz dodatkowe częstotliwości odświeżania, np. 90 Hz i 120 Hz. Niektóre urządzenia obsługują płynne przełączanie częstotliwości odświeżania, a inne na krótko wyświetlają czarny ekran, co zwykle trwa sekundę.

Głównym celem interfejsu API jest umożliwienie aplikacjom lepszego wykorzystania wszystkich obsługiwanych częstotliwości odświeżania wyświetlacza. Na przykład aplikacja odtwarzająca film z częstotliwością 24 Hz wywołującą setFrameRate() może spowodować zmianę częstotliwości odświeżania wyświetlacza z 60 Hz na 120 Hz. Ta nowa częstotliwość odświeżania umożliwia płynne i bez zakłóceń odtwarzanie filmów 24 Hz bez konieczności użycia metody 3:2, co byłoby wymagane do odtwarzania tego samego filmu na wyświetlaczu 60 Hz. Zwiększa to wygodę użytkowników.

Podstawowe użycie

Android zapewnia kilka sposobów na dostęp do platform i zarządzanie nimi, dlatego istnieje kilka wersji interfejsu setFrameRate() API. Każda wersja interfejsu API przyjmuje te same parametry i działa tak samo jak pozostałe:

Aplikacja nie musi uwzględniać rzeczywistych obsługiwanych częstotliwości odświeżania wyświetlacza, które można uzyskać, wywołując metodę Display.getSupportedModes(), aby bezpiecznie wywołać setFrameRate(). Na przykład nawet jeśli urządzenie obsługuje tylko 60 Hz, wywołaj funkcję setFrameRate() z liczbą klatek preferowaną przez aplikację. W przypadku urządzeń, których liczba klatek nie jest w pełni dopasowana, liczba klatek w aplikacji pozostanie z bieżącą częstotliwością odświeżania wyświetlacza.

Aby sprawdzić, czy wywołanie funkcji setFrameRate() spowoduje zmianę częstotliwości odświeżania wyświetlacza, zarejestruj się, aby otrzymywać powiadomienia o zmianie wyświetlania, wywołując metodę DisplayManager.registerDisplayListener() lub AChoreographer_registerRefreshRateCallback().

W przypadku wywołania funkcji setFrameRate() najlepiej jest podawać dokładną liczbę klatek niż zaokrąglać do liczby całkowitej. Na przykład podczas renderowania filmu nagranego z częstotliwością 29,97 Hz podaj wartość 29,97, zamiast zaokrąglać do 30.

W przypadku aplikacji wideo parametr zgodności przekazany do setFrameRate() powinien mieć wartość Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, aby stanowić dodatkową wskazówkę dla platformy Androida, że aplikacja będzie używać menu rozwijanego, aby dostosować się do niedopasowanej częstotliwości odświeżania wyświetlacza (co spowoduje drgania).

W niektórych przypadkach interfejs wideo przestanie przesyłać klatki, ale będzie widoczny na ekranie przez jakiś czas. Typowe sytuacje to sytuacje, gdy odtwarzanie dotrze do końca filmu lub gdy użytkownik wstrzyma odtwarzanie. W takich przypadkach wywołaj setFrameRate() z parametrem liczby klatek ustawionym na 0, aby przywrócić domyślną wartość ustawienia liczby klatek na platformie. Takie ustawienie liczby klatek nie jest konieczne w przypadku niszczenia powierzchni ani gdy jest ona ukryta, ponieważ użytkownik przełącza się na inną aplikację. Ustawienia liczby klatek należy usunąć tylko wtedy, gdy powierzchnia pozostaje widoczna i nie jest używana.

Przełącznik niepłynnej liczby klatek

Na niektórych urządzeniach podczas przełączania częstotliwości odświeżania mogą występować wizualne zakłócenia, np. wyświetlanie czarnego ekranu przez sekundę lub dwie. Zwykle dzieje się tak w przypadku dekoderów, paneli telewizyjnych i podobnych urządzeń. Domyślnie platforma Androida nie przełącza trybów po wywołaniu interfejsu API Surface.setFrameRate(), aby uniknąć takich zakłóceń wizualnych.

Niektórzy użytkownicy wolą, aby w dłuższych filmach przerwała się wizualna. Dzięki temu częstotliwość odświeżania wyświetlacza będzie pasowała do liczby klatek w filmie, a jednocześnie unikniesz zakłóceń związanych z liczbą klatek, takich jak przeciąganie 3:2 przy odtwarzaniu filmu.

Dlatego płynne przełączniki częstotliwości odświeżania można włączyć, jeśli wyrażą na to zgodę zarówno użytkownik, jak i aplikacje:

W przypadku dłuższych filmów, takich jak filmy, zawsze zalecamy używanie CHANGE_FRAME_RATE_ALWAYS. Dzieje się tak, ponieważ korzyści wynikające z dopasowania liczby klatek w filmie przeważają nad przerwą po zmianie częstotliwości odświeżania.

Dodatkowe zalecenia

Postępuj zgodnie z tymi zaleceniami dotyczącymi typowych scenariuszy.

Wiele platform

Platforma Android została zaprojektowana tak, aby prawidłowo obsługiwać sytuacje na wielu platformach z różnymi ustawieniami liczby klatek. Jeśli aplikacja ma wiele powierzchni o różnych liczbach klatek, wywołaj funkcję setFrameRate() z prawidłową liczbą klatek dla każdej z nich. Nawet jeśli na urządzeniu działa wiele aplikacji jednocześnie, w trybie podzielonego ekranu lub obrazu w obrazie, każda z nich może bezpiecznie wywołać usługę setFrameRate(), używając swoich platform.

Platforma nie zmienia liczby klatek na sekundę w aplikacji.

Nawet jeśli urządzenie obsługuje liczbę klatek określoną przez aplikację w wywołaniu funkcji setFrameRate(), w niektórych przypadkach urządzenie nie przełączy wyświetlacza na tę częstotliwość odświeżania. Na przykład powierzchnia o wyższym priorytecie może mieć inne ustawienia liczby klatek lub urządzenie może działać w trybie oszczędzania baterii (ustawić ograniczenie częstotliwości odświeżania wyświetlacza w celu oszczędzania baterii). Aplikacja musi działać prawidłowo, gdy urządzenie nie przełączy częstotliwości odświeżania wyświetlacza na wartość ustawioną w aplikacji, nawet jeśli urządzenie działa w normalnych okolicznościach.

Aplikacja decyduje, jak zareagować, gdy częstotliwość odświeżania wyświetlacza nie jest zgodna z liczbą klatek w aplikacji. W przypadku filmów liczba klatek jest stała i niezbędna do wyświetlenia treści wideo. Gra może natomiast uruchamiać się z częstotliwością odświeżania wyświetlacza, a nie pozostawać z preferowaną liczbą klatek. Aplikacja nie powinna zmieniać wartości przekazywanej do setFrameRate() w zależności od działań platformy. Wartość powinna być ustawiona na preferowaną przez aplikację liczbę klatek niezależnie od tego, jak aplikacja obsługuje przypadki, w których platforma nie dostosowuje się do żądania aplikacji. Dzięki temu, jeśli warunki urządzenia ulegną zmianie i umożliwią korzystanie z dodatkowych częstotliwości odświeżania wyświetlacza, platforma ma odpowiednie informacje, aby przełączyć się na preferowaną przez aplikację liczbę klatek.

Jeśli aplikacja nie działa lub nie działa z częstotliwością odświeżania ekranu, powinna określić sygnatury czasowe prezentacji dla każdej klatki, korzystając z jednego z platformowych mechanizmów ustawiania sygnatur czasowych prezentacji:

Użycie tych sygnatur czasowych sprawia, że platforma zbyt wcześnie prezentuje ramkę aplikacji, co prowadzi do niepotrzebnych zwrócenia uwagi. Prawidłowe użycie sygnatur czasowych prezentacji klatek nie jest łatwe. W przypadku gier zapoznaj się z naszym przewodnikiem po tempie klatek, aby dowiedzieć się, jak unikać zakłóceń. Możesz też skorzystać z biblioteki Android Frame Pacing.

W niektórych przypadkach platforma może przełączyć się na wielokrotność liczby klatek określonej w zasadzie setFrameRate(). Na przykład aplikacja może wywoływać setFrameRate() z częstotliwością 60 Hz, a urządzenie może przełączyć wyświetlacz na 120 Hz. Może się tak zdarzyć, jeśli inna aplikacja ma platformę z ustawioną liczbą klatek 24 Hz. W takim przypadku uruchomienie wyświetlacza z częstotliwością 120 Hz umożliwi wyświetlanie zarówno platformy 60 Hz, jak i powierzchni 24 Hz bez konieczności ściągania.

Gdy ekran wyświetla się z wieloma liczbami klatek w aplikacji, aplikacja powinna określać sygnatury czasowe prezentacji dla każdej klatki, aby uniknąć niepotrzebnych zakłóceń. W przypadku gier biblioteka Android Frame Pacing pomaga w prawidłowym ustawianiu sygnatur czasowych prezentacji ramek.

setFrameRate() a preferencjeDisplayModeId;

WindowManager.LayoutParams.preferredDisplayModeId to kolejny sposób, w jaki aplikacje mogą określać liczbę klatek na platformie. Niektóre aplikacje chcą tylko zmieniać częstotliwość odświeżania wyświetlacza, a nie inne ustawienia trybu wyświetlania, np. rozdzielczość. Ogólnie używaj właściwości setFrameRate() zamiast preferredDisplayModeId. Funkcja setFrameRate() jest łatwiejsza w użyciu, ponieważ aplikacja nie musi przeszukiwać listy trybów wyświetlania w poszukiwaniu trybu z konkretną liczbą klatek.

setFrameRate() daje platformie więcej możliwości wyboru zgodnej liczby klatek w sytuacjach, gdy na wielu platformach działają z różnymi liczbami klatek. Rozważmy na przykład scenariusz, w którym 2 aplikacje na Pixelu 4 działają w trybie podzielonego ekranu, gdy jedna z nich odtwarza film w częstotliwości 24 Hz, a druga pokazuje użytkownikowi listę przewijaną. Pixel 4 obsługuje 2 częstotliwości odświeżania wyświetlacza: 60 Hz i 90 Hz. Za pomocą interfejsu API preferredDisplayModeId powierzchnia wideo jest wymuszana do wyboru częstotliwości 60 Hz lub 90 Hz. Wywołanie setFrameRate() z częstotliwością 24 Hz daje platformie więcej informacji o liczbie klatek w filmie źródłowym. Platforma może wybrać 90 Hz jako częstotliwość odświeżania wyświetlacza, co w tym przypadku jest lepsze niż 60 Hz.

Są jednak sytuacje, w których zamiast setFrameRate() należy używać właściwości preferredDisplayModeId, np.:

  • Jeśli aplikacja chce zmienić rozdzielczość lub inne ustawienia trybu wyświetlania, użyj preferredDisplayModeId.
  • Platforma przełącza tryby wyświetlania w odpowiedzi na wywołanie funkcji setFrameRate() tylko wtedy, gdy przełącznik trybu jest niewielki i jest mało zauważalny dla użytkownika. Jeśli aplikacja woli zmieniać częstotliwość odświeżania wyświetlacza, nawet jeśli wymaga to przełącznika trybu intensywnego (np. na urządzeniu z Androidem TV), użyj preferredDisplayModeId.
  • Aplikacje, które nie są w stanie obsłużyć wyświetlacza działającego z wieloma szybkością klatek, co wymaga ustawienia sygnatur czasowych prezentacji dla każdej klatki, powinny używać parametru preferredDisplayModeId.

setFrameRate() a preferowana częstotliwość odświeżania

WindowManager.LayoutParams#preferredRefreshRate ustawia preferowaną liczbę klatek w oknie aplikacji, która ma zastosowanie do wszystkich platform w oknie. Aplikacja powinna określać preferowaną liczbę klatek niezależnie od obsługiwanych częstotliwości odświeżania przez urządzenie (podobnie do setFrameRate()), aby algorytm szeregowania lepiej dał algorytmowi zamierzoną liczbę klatek w aplikacji.

Funkcja preferredRefreshRate jest ignorowana w przypadku platform, które korzystają z metody setFrameRate(). Ogólnie w miarę możliwości używaj pola setFrameRate().

preferowana częstotliwość odświeżania a preferowany formatDisplayModeId

Jeśli aplikacje chcą tylko zmienić preferowaną częstotliwość odświeżania, preferowane jest użycie preferredRefreshRate zamiast preferredDisplayModeId.

Unikanie zbyt częstego wywoływania funkcji setFrameRate()

Chociaż wywołanie setFrameRate() nie jest bardzo kosztowne pod względem wydajności, aplikacje nie powinny wywoływać metody setFrameRate() przy każdej klatce lub wiele razy na sekundę. Wywołania setFrameRate() mogą spowodować zmianę częstotliwości odświeżania wyświetlacza, co może skutkować spadkiem liczby klatek w trakcie przenoszenia. Z wyprzedzeniem ustal prawidłową liczbę klatek i wywołaj metodę setFrameRate() raz.

Użycie w grach i aplikacjach innych niż wideo

Chociaż interfejs setFrameRate() API jest głównym przypadkiem użycia, może być używany w innych aplikacjach. Na przykład gra, która nie powinna działać wyżej niż 60 Hz (aby zmniejszyć zużycie energii i osiągnąć dłuższe sesje gry), może wywoływać metodę Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). W ten sposób urządzenie, które domyślnie działa z częstotliwością 90 Hz, w trakcie gry będzie działać z częstotliwością 60 Hz. Pozwoli to uniknąć niespodziewanych wyników, które w innym przypadku miałyby miejsce, gdyby gra działała z częstotliwością 60 Hz, a ekran działał z prędkością 90 Hz.

Wykorzystanie: FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

Parametr FRAME_RATE_COMPATIBILITY_FIXED_SOURCE jest przeznaczony tylko do aplikacji wideo. Jeśli chcesz korzystać z innych funkcji niż wideo, użyj FRAME_RATE_COMPATIBILITY_DEFAULT.

Wybór strategii zmiany liczby klatek

  • W przypadku wyświetlania długich filmów, takich jak filmy, zdecydowanie zalecamy, aby aplikacje ustawiały setFrameRate(FPS, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS), gdzie liczba klatek na sekundę oznacza liczbę klatek filmu.
  • Zdecydowanie odradzamy aplikacje wywołujące setFrameRate() z parametrem CHANGE_FRAME_RATE_ALWAYS, jeśli odtwarzanie filmu powinno trwać maksymalnie kilka minut.

Przykładowa integracja z aplikacjami do odtwarzania filmów

Aby zintegrować przełączniki częstotliwości odświeżania z aplikacjami do odtwarzania filmów, zalecamy wykonanie tych czynności:

  1. Określ changeFrameRateStrategy:
    1. Jeśli odtwarzasz długotrwały film, np. film, użyj MATCH_CONTENT_FRAMERATE_ALWAYS.
    2. Jeśli odtwarzasz krótki film, np. zwiastun z uruchomieniami, użyj CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS.
  2. Jeśli changeFrameRateStrategy to CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, przejdź do kroku 4.
  3. Aby wykryć niesprawną zmianę częstotliwości odświeżania, sprawdź, czy oba te fakty są prawdziwe:
    1. Płynne przełączenie trybu nie jest możliwe w przypadku obecnej częstotliwości odświeżania (na przykład C) do liczby klatek w filmie (nazwijmy ją V). Tak będzie w przypadku, gdy C i V są różne, a Display.getMode().getAlternativeRefreshRates nie zawiera wielokrotności V.
    2. Użytkownik zgodził się na niepłynne zmiany częstotliwości odświeżania. Możesz to wykryć, sprawdzając, czy DisplayManager.getMatchContentFrameRateUserPreference zwraca MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Jeśli chcesz, aby przejście odbyło się bezproblemowo, wykonaj te czynności:
    1. Wywołaj metodę setFrameRate i przekaż je fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE oraz changeFrameRateStrategy, gdzie fps to liczba klatek filmu.
    2. Rozpocznij odtwarzanie filmu
  5. Jeśli wkrótce nastąpi zmiana trybu, który nie jest płynny, wykonaj te czynności:
    1. Pokaż UX, aby powiadomić użytkownika. Zalecamy wdrożenie sposobu pozwalającego użytkownikowi odrzucić ten interfejs i pominąć dodatkowe opóźnienie w kroku 5.d. Dzieje się tak, ponieważ zalecane opóźnienie jest większe niż konieczne w przypadku wyświetlaczy z krótszym czasem przełączania.
    2. Wywołaj metodę setFrameRate i prześlij ją: fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE oraz CHANGE_FRAME_RATE_ALWAYS, gdzie fps to liczba klatek filmu.
    3. Poczekaj na wywołanie zwrotne onDisplayChanged.
    4. Poczekaj 2 sekundy, aż tryb zostanie przełączony na inny tryb.
    5. Rozpocznij odtwarzanie filmu

Pseudokod obsługujący tylko bezproblemowe przełączanie się wygląda tak:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
    contentFrameRate,
    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();

Pseudokod zapewniający płynne i niezakłócone przełączanie się, jak opisano powyżej:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (isSeamlessSwitch(contentFrameRate)) {
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
  transaction.apply();
  beginPlayback();
} else if (displayManager.getMatchContentFrameRateUserPreference()
      == MATCH_CONTENT_FRAMERATE_ALWAYS) {
  showRefreshRateSwitchUI();
  sleep(shortDelaySoUserSeesUi);
  displayManager.registerDisplayListener(…);
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ALWAYS);
  transaction.apply();
  waitForOnDisplayChanged();
  sleep(twoSeconds);
  hideRefreshRateSwitchUI();
  beginPlayback();
}