Liczba klatek

Interfejs API liczby klatek umożliwia aplikacjom informowanie platformy Androida o docelowej liczbie klatek. Jest on dostępny w aplikacjach kierowanych na Androida 11 (poziom API 30) lub nowszego. Tradycyjnie większość urządzeń obsługiwała tylko jedną częstotliwość odświeżania wyświetlacza, zwykle 60 Hz, ale to się zmienia. Wiele urządzeń obsługuje teraz dodatkowe częstotliwości odświeżania, np. 90 Hz lub 120 Hz. Niektóre urządzenia obsługują płynną zmianę częstotliwości odświeżania, a inne na chwilę (zwykle na sekundę) wyświetlają czarny ekran.

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 w 24 Hz, która wywołuje funkcję setFrameRate(), może spowodować, że urządzenie zmieni częstotliwość odświeżania wyświetlacza z 60 Hz na 120 Hz. Ta nowa częstotliwość odświeżania umożliwia płynne odtwarzanie filmów w 24 Hz bez zacinania się i bez konieczności stosowania konwersji 3:2, która byłaby wymagana do odtworzenia tego samego filmu na wyświetlaczu 60 Hz. Zwiększa to wygodę użytkowników.

Podstawowe użycie

Android udostępnia kilka sposobów uzyskiwania dostępu do powierzchni i ich kontrolowania, dlatego istnieje kilka wersji interfejsu API setFrameRate(). 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ć metodę setFrameRate(). Na przykład nawet jeśli urządzenie obsługuje tylko 60 Hz, wywołaj setFrameRate() z liczbą klatek preferowaną przez aplikację. Urządzenia, które nie mają lepszego dopasowania do liczby klatek aplikacji, pozostaną przy bieżącej częstotliwości odświeżania wyświetlacza.

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

Podczas wywoływania funkcji setFrameRate() najlepiej jest podać dokładną liczbę klatek, a nie zaokrąglać ją do liczby całkowitej. Na przykład podczas renderowania filmu nagranego z częstotliwością 29,97 Hz podaj wartość 29,97, a nie zaokrągloną do 30.

W przypadku aplikacji wideo parametr zgodności przekazywany do setFrameRate() powinien być ustawiony na Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, aby przekazać platformie Android dodatkową wskazówkę, że aplikacja będzie używać pulldown, aby dostosować się do niezgodnej częstotliwości odświeżania wyświetlacza (co spowoduje drgania).

W niektórych przypadkach powierzchnia wideo przestanie przesyłać klatki, ale przez pewien czas pozostanie widoczna na ekranie. Typowe scenariusze obejmują sytuacje, gdy odtwarzanie dobiega końca lub gdy użytkownik wstrzymuje odtwarzanie. W takich przypadkach wywołaj funkcję setFrameRate() z parametrem liczby klatek ustawionym na 0, aby przywrócić domyślną wartość ustawienia liczby klatek powierzchni. Czyszczenie ustawienia liczby klatek w ten sposób nie jest konieczne, gdy powierzchnia jest niszczona lub ukrywana, ponieważ użytkownik przełącza się na inną aplikację. Wyczyść ustawienie liczby klatek tylko wtedy, gdy powierzchnia pozostaje widoczna, ale nie jest używana.

Niepłynne przełączanie liczby klatek

Na niektórych urządzeniach przełączanie częstotliwości odświeżania może powodować zakłócenia wizualne, np. czarny ekran przez sekundę lub dwie. Zwykle dzieje się tak na dekoderach, panelach telewizyjnych i podobnych urządzeniach. Domyślnie platforma Androida nie przełącza trybów po wywołaniu interfejsu API Surface.setFrameRate(), aby uniknąć takich przerw w wyświetlaniu.

Niektórzy użytkownicy wolą, aby na początku i na końcu dłuższych filmów pojawiały się przerwy wizualne. Dzięki temu częstotliwość odświeżania wyświetlacza będzie odpowiadać liczbie klatek filmu, co pozwoli uniknąć artefaktów konwersji liczby klatek, takich jak szarpanie obrazu podczas odtwarzania filmu.

Z tego powodu przełączanie częstotliwości odświeżania bez płynnego przejścia można włączyć, jeśli zarówno użytkownik, jak i aplikacje wyrażą na to zgodę:

W przypadku długich filmów, takich jak filmy pełnometrażowe, zalecamy zawsze używać CHANGE_FRAME_RATE_ALWAYS. Dzieje się tak, ponieważ korzyści wynikające z dopasowania liczby klatek filmu przewyższają niedogodności związane z przerwą, która występuje podczas zmiany częstotliwości odświeżania.

Dodatkowe zalecenia

Postępuj zgodnie z tymi zaleceniami w typowych scenariuszach.

Wiele platform

Platforma Androida została zaprojektowana tak, aby prawidłowo obsługiwać scenariusze, w których występuje wiele powierzchni z różnymi ustawieniami liczby klatek. Jeśli aplikacja ma wiele platform z różnymi liczbami klatek, wywołaj setFrameRate() z odpowiednią liczbą klatek dla każdej platformy. Nawet jeśli na urządzeniu działa jednocześnie kilka aplikacji w trybie podzielonego ekranu lub obrazu w obrazie, każda z nich może bezpiecznie wywołać metodę setFrameRate() dla swoich powierzchni.

Platforma nie zmienia się na liczbę klatek 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 ustawienie liczby klatek lub urządzenie może być w trybie oszczędzania baterii (ustawienie ograniczenia częstotliwości odświeżania wyświetlacza w celu oszczędzania baterii). Aplikacja musi działać prawidłowo, gdy urządzenie nie przełącza częstotliwości odświeżania wyświetlacza na ustawienie liczby klatek aplikacji, nawet jeśli urządzenie przełącza się w normalnych okolicznościach.

To, jak aplikacja zareaguje, gdy częstotliwość odświeżania wyświetlacza nie będzie odpowiadać liczbie klatek, zależy od aplikacji. W przypadku filmu liczba klatek jest stała i odpowiada liczbie klatek filmu źródłowego. Aby wyświetlić treść filmu, wymagane jest rozciągnięcie. Gra może próbować działać z częstotliwością odświeżania wyświetlacza, zamiast utrzymywać preferowaną liczbę klatek. Aplikacja nie powinna zmieniać wartości przekazywanej do setFrameRate() na podstawie działań platformy. Powinna być ustawiona na preferowaną liczbę klatek aplikacji, 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 zmienią się i będzie można używać dodatkowych częstotliwości odświeżania wyświetlacza, platforma będzie miała prawidłowe informacje, aby przełączyć się na preferowaną liczbę klatek aplikacji.

W przypadkach, gdy aplikacja nie może działać z częstotliwością odświeżania wyświetlacza, powinna określać sygnatury czasowe prezentacji dla każdej klatki, używając jednego z mechanizmów platformy do ustawiania sygnatur czasowych prezentacji:

Użycie tych sygnatur czasowych zapobiega zbyt wczesnemu wyświetlaniu klatki aplikacji przez platformę, co mogłoby powodować niepotrzebne drgania. Prawidłowe używanie sygnatur czasowych prezentacji klatek jest nieco skomplikowane. W przypadku gier zapoznaj się z naszym przewodnikiem po tempie klatek, aby dowiedzieć się, jak unikać efektu judder, i rozważ użycie biblioteki Android Frame Pacing.

W niektórych przypadkach platforma może przełączyć się na wielokrotność liczby klatek określonej przez aplikację w metodzie setFrameRate(). Na przykład aplikacja może wywołać 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 powierzchnię z ustawieniem liczby klatek na sekundę na poziomie 24 Hz. W takim przypadku uruchomienie wyświetlacza z częstotliwością 120 Hz pozwoli na wyświetlanie zarówno powierzchni 60 Hz, jak i 24 Hz bez konieczności stosowania pulldown.

Gdy wyświetlacz działa z częstotliwością będącą wielokrotnością liczby klatek 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 prawidłowo ustawiać sygnatury czasowe prezentacji klatek.

setFrameRate() a preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId to inny sposób, w jaki aplikacje mogą wskazywać platformie liczbę klatek. Niektóre aplikacje chcą tylko zmienić częstotliwość odświeżania wyświetlacza, a nie inne ustawienia trybu wyświetlania, takie jak rozdzielczość. Zasadniczo używaj setFrameRate() zamiast preferredDisplayModeId. Funkcja setFrameRate() jest łatwiejsza w użyciu, ponieważ aplikacja nie musi przeszukiwać listy trybów wyświetlania, aby znaleźć tryb z określoną liczbą klatek.

setFrameRate() daje platformie więcej możliwości wyboru zgodnej liczby klatek w scenariuszach, w których występuje wiele powierzchni działających z różną liczbą klatek. Rozważmy na przykład sytuację, w której na Pixelu 4 w trybie podzielonego ekranu działają 2 aplikacje: jedna odtwarza film z częstotliwością 24 Hz, a druga wyświetla użytkownikowi przewijaną listę. Pixel 4 obsługuje 2 częstotliwości odświeżania wyświetlacza: 60 Hz i 90 Hz. Interfejs API preferredDisplayModeId wymusza na powierzchni wideo wybór częstotliwości 60 Hz lub 90 Hz. Wywołując funkcję setFrameRate() z częstotliwością 24 Hz, powierzchnia wideo dostarcza platformie więcej informacji o liczbie klatek filmu źródłowego, dzięki czemu platforma może wybrać częstotliwość odświeżania wyświetlacza 90 Hz, która w tym przypadku jest lepsza niż 60 Hz.

Są jednak sytuacje, w których należy użyć preferredDisplayModeId zamiast setFrameRate(), na przykład:

  • Jeśli aplikacja chce zmienić rozdzielczość lub inne ustawienia trybu wyświetlania, użyj preferredDisplayModeId.
  • Platforma przełączy tryby wyświetlania w odpowiedzi na wywołanie funkcji setFrameRate() tylko wtedy, gdy przełączenie trybu będzie szybkie i prawdopodobnie niezauważalne dla użytkownika. Jeśli aplikacja ma przełączać częstotliwość odświeżania wyświetlacza, nawet jeśli wymaga to przełączenia trybu (np. na urządzeniu z Androidem TV), użyj preferredDisplayModeId.
  • Aplikacje, które nie obsługują wyświetlacza działającego z częstotliwością będącą wielokrotnością liczby klatek aplikacji, co wymaga ustawienia sygnatur czasowych prezentacji na każdej klatce, powinny używać preferredDisplayModeId.

setFrameRate() a preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate ustawia preferowaną liczbę klatek w oknie aplikacji, która jest stosowana do wszystkich powierzchni w oknie. Aplikacja powinna określać preferowaną liczbę klatek niezależnie od obsługiwanych przez urządzenie częstotliwości odświeżania, podobnie jak w przypadku setFrameRate(), aby harmonogram mógł lepiej określić zamierzoną liczbę klatek aplikacji.

Atrybut preferredRefreshRate jest ignorowany na platformach, które używają atrybutu setFrameRate(). Jeśli to możliwe, używaj setFrameRate().

preferredRefreshRate a preferredDisplayModeId

Jeśli aplikacje chcą zmienić tylko preferowaną częstotliwość odświeżania, lepiej użyć 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 powinny unikać wywoływania setFrameRate() w każdej klatce lub wielokrotnie na sekundę. Wywołania funkcji setFrameRate() prawdopodobnie spowodują zmianę częstotliwości odświeżania wyświetlacza, co może skutkować pominięciem klatki podczas przejścia. Prawidłową liczbę klatek należy określić wcześniej i wywołać funkcję setFrameRate() raz.

używanie w grach lub innych aplikacjach niezwiązanych z filmami;

Chociaż interfejs API setFrameRate() jest przeznaczony głównie do filmów, można go używać w innych aplikacjach. Na przykład gra, która nie ma przekraczać 60 Hz (aby zmniejszyć zużycie energii i wydłużyć sesje rozgrywki), może wywołać funkcję 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, będzie działać z częstotliwością 60 Hz, gdy gra będzie aktywna. Pozwoli to uniknąć drgań, które wystąpiłyby, gdyby gra działała z częstotliwością 60 Hz, a wyświetlacz z częstotliwością 90 Hz.

Użycie FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE jest przeznaczony tylko do aplikacji wideo. W przypadku zastosowań innych niż wideo użyj FRAME_RATE_COMPATIBILITY_DEFAULT.

Wybieranie strategii zmiany liczby klatek

  • Zdecydowanie zalecamy, aby aplikacje podczas wyświetlania długich filmów, takich jak filmy pełnometrażowe, wywoływały setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS), gdzie fps to liczba klatek na sekundę filmu.
  • Zdecydowanie odradzamy wywoływanie przez aplikacje metody setFrameRate() z parametrem CHANGE_FRAME_RATE_ALWAYS, gdy odtwarzanie filmu ma trwać kilka minut lub krócej.

Przykładowa integracja aplikacji do odtwarzania filmów

Zalecamy wykonanie tych czynności, aby zintegrować przełączniki częstotliwości odświeżania w aplikacjach do odtwarzania filmów:

  1. Określ changeFrameRateStrategy:
    1. Jeśli odtwarzasz długi film, np. kinowy, użyj MATCH_CONTENT_FRAMERATE_ALWAYS.
    2. Jeśli odtwarzasz krótki film, np. zwiastun, 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ć, czy nastąpi niepłynne przełączenie częstotliwości odświeżania, sprawdź, czy oba te warunki są spełnione:
    1. Nie można płynnie przełączyć bieżącej częstotliwości odświeżania (nazwijmy ją C) na liczbę klatek filmu (nazwijmy ją V). Będzie tak, jeśli C i V są różne, a Display.getMode().getAlternativeRefreshRates nie zawiera wielokrotności V.
    2. Użytkownik wyraził zgodę na zmiany częstotliwości odświeżania, które nie są płynne. Możesz to wykryć, sprawdzając, czy DisplayManager.getMatchContentFrameRateUserPreference zwraca MATCH_CONTENT_FRAMERATE_ALWAYS.
  4. Jeśli przełączanie ma być płynne, wykonaj te czynności:
    1. Wywołaj funkcję setFrameRate i przekaż jej parametry fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE i changeFrameRateStrategy, gdzie fps to liczba klatek na sekundę filmu.
    2. Rozpocznij odtwarzanie filmu
  5. Jeśli ma nastąpić zmiana trybu, która nie jest płynna, wykonaj te czynności:
    1. Wyświetl interfejs, aby powiadomić użytkownika. Zalecamy wdrożenie sposobu, który pozwoli użytkownikowi odrzucić ten interfejs i pominąć dodatkowe opóźnienie w kroku 5d. Dzieje się tak, ponieważ zalecane przez nas opóźnienie jest większe niż konieczne na wyświetlaczach, które charakteryzują się krótszym czasem przełączania.
    2. Wywołaj setFrameRate i przekaż fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE i CHANGE_FRAME_RATE_ALWAYS, gdzie fps to liczba klatek na sekundę filmu.
    3. Poczekaj na wywołanie zwrotne onDisplayChanged.
    4. Poczekaj 2 sekundy na zakończenie przełączania trybu.
    5. Rozpocznij odtwarzanie filmu

Pseudokod, który obsługuje tylko płynne przełączanie, 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 obsługujący płynne i niepłynne przełączanie, jak opisano powyżej, wygląda tak:

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();
}