Liczba klatek

Interfejs API częstotliwości klatek pozwala aplikacjom informować platformę Androida o zamierzonej częstotliwości klatek. Jest dostępny w aplikacjach kierowanych na Androida 11 (poziom API 30) lub nowszego. Zazwyczaj większość urządzeń obsługuje tylko jedną częstotliwość odświeżania zwykle 60 Hz, ale to się zmieniło. Wiele urządzeń obsługuje teraz dodatkowe częstotliwości odświeżania, takie jak 90 Hz lub 120 Hz. Niektóre urządzenia obsługują płynną częstotliwość odświeżania przełączniki, podczas gdy inne na chwilę pokazują czarny ekran, zwykle trwający sekundę.

Głównym celem interfejsu API jest umożliwienie aplikacjom lepszego korzystania ze wszystkich obsługiwanych częstotliwości odświeżania wyświetlacza. Na przykład aplikacja odtwarzająca film w standardzie 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 standardzie 24 Hz bez efektu trzęsienia obrazu. Nie trzeba już stosować funkcji pulldown 3:2, która jest wymagana do odtwarzania tego samego filmu na wyświetlaczu 60 Hz. W efekcie użytkownicy będą mieli lepsze wrażenia.

Podstawowe wykorzystanie

Android udostępnia kilka sposobów dostępu do platform i sterowania nimi, dlatego kilka wersji interfejsu API setFrameRate(). Każda wersja interfejsu API przyjmuje te same parametry i działa w ten sam sposób:

Aplikacja nie musi uwzględniać rzeczywistych obsługiwanych częstotliwości odświeżania wyświetlacza, których można użyć, wywołując funkcję Display.getSupportedModes(), aby bezpiecznie wywołać funkcję setFrameRate(). Na przykład nawet wtedy, gdy urządzenie obsługuje tylko 60 Hz, wywołanie setFrameRate() może mieć liczbę klatek na sekundę preferowaną przez Twoją aplikację. Urządzenia, które nie mają lepszego dopasowania do częstotliwości wyświetlania aplikacji, pozostaną przy bieżącej częstotliwości odświeżania wyświetlacza.

Aby sprawdzić, czy wywołanie funkcji setFrameRate() powoduje zmianę częstotliwości odświeżania wyświetlacza, zarejestruj się, aby otrzymywać powiadomienia o zmianach wyświetlacza. Aby to zrobić, wywołaj funkcję DisplayManager.registerDisplayListener() lub AChoreographer_registerRefreshRateCallback().

Gdy wywołujesz funkcję setFrameRate(), najlepiej przekazać dokładną liczbę klatek na sekundę zamiast zaokrąglenia 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 należy ustawić parametr zgodności przekazywany do funkcji setFrameRate() do: Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, aby uzyskać dodatkową wskazówkę dla platformy Android, której aplikacja będzie używać menu rozwijanego, aby dostosować częstotliwość odświeżania wyświetlacza (co będzie powodować szum).

W niektórych przypadkach powierzchnia wideo przestanie przesyłać klatki, ale przez jakiś czas będzie widoczna na ekranie. Typowe scenariusze to m.in. odtwarzanie dotrze do końca filmu lub gdy użytkownik wstrzyma odtwarzanie. W takich przypadkach wywołaj funkcję setFrameRate() z parametrem częstotliwości klatek ustawionym na 0, aby przywrócić ustawienie częstotliwości klatek na powierzchni do wartości domyślnej. Czyszczenie ustawienia liczby klatek nie jest konieczne przy niszczeniu powierzchni lub gdy jest ona jest ukryta, ponieważ użytkownik przełączył się na inną aplikację. Wyczyść liczbę klatek można ustawić tylko wtedy, gdy powierzchnia pozostaje widoczna, ale nie jest używana.

Niepłynny przełącznik liczby klatek

Na niektórych urządzeniach przełączanie częstotliwości odświeżania może powodować przerwy w wyświetlaniu obrazu, np. przez sekundę może być czarny ekran. Zwykle dzieje się tak na dekoderach, panelach TV, i podobnych urządzeniach. Domyślnie platforma Androida nie przełącza trybów. gdy Surface.setFrameRate() Interfejs API jest wywoływany, aby uniknąć takich przerw w działaniu usługi.

Niektórzy użytkownicy wolą na początku wizualną przerwę, na końcu dłuższych filmów. Dzięki temu częstotliwość odświeżania wyświetlacza jest taka sama liczbę klatek na sekundę i unikać zakłóceń związanych z liczbą klatek na sekundę, takich jak 3:2. suwak odtwarzania filmu.

Dlatego niepłynne przełączniki częstotliwości odświeżania można włączyć, jeśli zgody użytkownika i aplikacji:

Zalecamy zawsze używać CHANGE_FRAME_RATE_ALWAYS w przypadku długotrwałych filmów, takich jak filmy. Dzieje się tak, ponieważ korzyści z dopasowania liczby klatek na sekundę filmu przeważają przerwę, która występuje podczas zmiany częstotliwości odświeżania.

Dodatkowe zalecenia

W przypadku typowych scenariuszy postępuj zgodnie z tymi zaleceniami.

Wiele powierzchni

Platforma Android została zaprojektowana tak, aby poprawnie obsługiwać sytuacje, na wielu platformach z różnymi ustawieniami liczby klatek. Gdy aplikacja ma wiele na platformach o różnych liczbach klatek na sekundę, wywołaj funkcję setFrameRate() z właściwym z liczbą klatek na sekundę przez poszczególne powierzchnie. Nawet jeśli na urządzeniu działa kilka aplikacji jednocześnie, korzystając z podziału ekranu lub trybu obrazu w obrazie, każda aplikacja może bezpiecznie wywoływać setFrameRate() dla swoich powierzchni.

Platforma nie zmienia liczby klatek w aplikacji.

Nawet jeśli urządzenie obsługuje liczbę klatek określoną przez aplikację w wywołaniu. setFrameRate(), w niektórych przypadkach urządzenie nie przełącza się na z taką częstotliwością odświeżania. Na przykład platforma o wyższym priorytecie może mieć inny liczby klatek lub urządzenie może być w trybie oszczędzania baterii (ustawienie ograniczenie częstotliwości odświeżania ekranu w celu oszczędzania baterii). Aplikacja musi nadal działa poprawnie, gdy urządzenie nie przełącza częstotliwości odświeżania ekranu ustawienia liczby klatek w aplikacji, nawet jeśli urządzenie przełączy się w normalny sposób. okoliczności.

Gdy częstotliwość odświeżania wyświetlacza nie pasuje do częstotliwości klatek aplikacji, to aplikacja decyduje, jak zareagować. W filmach liczba klatek jest stała Film źródłowy i trzeba rozwijana musi być lista rozwijana. O może zamiast tego spróbować uruchomić ją z częstotliwością odświeżania ekranu z preferowaną liczbą klatek. Aplikacja nie powinna zmieniać wartości, którą otrzymuje przekazuje do setFrameRate() na podstawie tego, co robi platforma. Należy ustawić go na preferowaną przez aplikację liczbę klatek na sekundę, niezależnie od tego, jak aplikacja radzi sobie w przypadkach, gdy platforma nie dostosowuje się do jej żądania. Dzięki temu, jeśli urządzenie warunki zmieniają się, aby umożliwić zastosowanie dodatkowych częstotliwości odświeżania, platforma ma prawidłowe informacje umożliwiające przełączenie się na preferowaną ramkę aplikacji stawki.

Jeśli aplikacja nie działa lub nie może działać z częstotliwością odświeżania ekranu, powinny określić sygnatury czasowe prezentacji dla każdej klatki, korzystając z jednego z mechanizmy platformy służące do ustawiania sygnatur czasowych prezentacji:

Użycie tych sygnatur czasowych uniemożliwia platformie wyświetlanie ramki aplikacji co wydawało się niepotrzebnym osądem. Prawidłowe używanie sygnatur czasowych wyświetlania klatek jest nieco kłopotliwe. W przypadku gier: przewodnik po tempie kadru znajdziesz więcej informacji o tym, jak unikać osądzania, i rozważ korzystanie z bibliotekę Android Frame Pacing,

W niektórych przypadkach platforma może przełączyć się na wielokrotność liczby klatek na sekundę przez aplikację określono w funkcji setFrameRate(). Aplikacja może na przykład dzwonić pod setFrameRate() z częstotliwością 60 Hz, a urządzenie może przełączyć wyświetlacz na 120 Hz. Jedną z przyczyn dzieje się, gdy inna aplikacja ma powierzchnię z częstotliwością klatek 24 Hz. W w tym przypadku wybór częstotliwości 120 Hz umożliwi korzystanie z 60 Hz Powierzchnia 24 Hz działająca bez konieczności opuszczania ekranu.

Gdy wyświetlacz działa z wielokrotnością częstotliwości wyświetlania klatek aplikacji, aplikacja powinna określać sygnatury czasowe wyświetlania dla każdej klatki, aby uniknąć niepotrzebnego zacinania. W przypadku gier biblioteka Android Frame Pacing ułatwia prawidłowe ustawianie sygnatur czasowych prezentacji klatek.

setFrameRate() a PreferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId to kolejny sposób, w jaki aplikacje mogą określać na platformie liczbę klatek. Niektóre Aplikacje chcą zmienić tylko częstotliwość odświeżania wyświetlacza, ustawieniach trybu wyświetlania, takich jak rozdzielczość wyświetlacza. Zwykle zamiast preferredDisplayModeId używaj setFrameRate(). Funkcja setFrameRate() jest łatwiejsza w użyciu, ponieważ aplikacja nie musi przeszukiwać listy trybów wyświetlania w celu znalezienia trybu o określonej liczbie klatek na sekundę.

setFrameRate() daje platformie więcej możliwości wyboru zgodnej częstotliwości klatek w sytuacjach, gdy występuje wiele powierzchni z różnymi częstotliwościami klatek. Rozważmy na przykład scenariusz, w którym 2 aplikacje działają w trybie podzielonego ekranu na Pixelu 4. Jedna z nich odtwarza film w standardzie 24 Hz, a druga wyświetla użytkownikowi listę, którą można przewijać. Pixel 4 obsługuje 2 częstotliwości odświeżania: 60 Hz i 90 Hz. Za pomocą interfejsu API preferredDisplayModeId platforma wideo jest zmuszona do wybrania częstotliwości 60 Hz lub 90 Hz. Przez telefon setFrameRate() przy częstotliwości 24 Hz umożliwia platformie wideo jeszcze więcej informacji o liczbie klatek filmu źródłowego, dzięki czemu platforma może wybierz 90 Hz dla częstotliwości odświeżania ekranu, która jest lepsza niż 60 Hz w tym przypadku.

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

  • Jeśli aplikacja chce zmienić rozdzielczość lub inne ustawienia trybu wyświetlania, użyj preferredDisplayModeId.
  • Platforma przełącza tryby wyświetlania tylko w odpowiedzi na wywołanie setFrameRate(), jeśli przełącznik trybu jest niewielki i prawdopodobnie nie będzie widoczna dla użytkownika. Jeśli aplikacja woli zmienić odświeżanie ekranu nawet wtedy, gdy wymagane jest włączenie dużego przełącznika trybu (na przykład na Androidzie TV urządzenia), użyj funkcji preferredDisplayModeId.
  • Aplikacje, które nie obsługują wyświetlacza działającego z wielokrotnością częstotliwości odświeżania, co wymaga ustawiania sygnatur czasowych dla każdego klatki, powinny używać preferredDisplayModeId.

setFrameRate() a preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate ustawia preferowaną liczbę klatek w oknie aplikacji i zostanie ona zastosowana. na wszystkich powierzchniach okna. Aplikacja powinna określić preferowane ustawienie. liczby klatek niezależnie od obsługiwanych częstotliwości odświeżania, podobnie jak setFrameRate(), aby dać algorytmowi szeregowania lepszą wskazówkę dotyczącą zamierzonego działania aplikacji liczby klatek na sekundę.

Pole preferredRefreshRate jest ignorowane w przypadku platform, które używają setFrameRate(). W ogóle, jeśli to możliwe, używaj setFrameRate().

preferredRefreshRate vs preferredDisplayModeId

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

unikanie zbyt częstego wywoływania funkcji setFrameRate();

Mimo że 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ę. Połączenia z numerem setFrameRate() prawdopodobnie mogą spowodować zmianę w częstotliwość odświeżania wyświetlacza, co może spowodować spadek liczby klatek podczas przejścia. Należy wcześniej określić prawidłową liczbę klatek na sekundę i raz wywołać funkcję setFrameRate().

Używanie w przypadku gier lub innych aplikacji nieobejmujących filmów

Chociaż filmy są głównym przypadkiem użycia interfejsu API setFrameRate(), może być ono używane w innych aplikacjach. Na przykład gra, która nie chce uruchomić więcej niż 60 Hz (aby zmniejszyć zużycie energii i zapewnić dłuższe sesje gry) może wywołać Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) W tym urządzenia, które domyślnie działają z częstotliwością 90 Hz, będą działać z częstotliwością 60 Hz, gra jest aktywna, co pozwoli uniknąć efektu żołądka występującego w innym przypadku, jeśli gra działała z częstotliwością 60 Hz, a wyświetlacz – z 90 Hz.

Wykorzystanie FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE jest przeznaczona tylko do aplikacji wideo. Dla: inne niż wideo, użyj FRAME_RATE_COMPATIBILITY_DEFAULT.

Wybieranie strategii zmiany liczby klatek

  • Zdecydowanie zalecamy, aby do wyświetlania długich filmów, takich jak filmy, połączenie setFrameRate( kl./s, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) gdzie kl./s to liczba klatek w filmie.
  • Zdecydowanie odradzamy wywoływanie przez aplikacje funkcji setFrameRate() z argumentem CHANGE_FRAME_RATE_ALWAYS, jeśli odtwarzanie filmu ma trwać kilka minut lub krócej.

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. Wybierz changeFrameRateStrategy:
    1. W przypadku odtwarzania długotrwałego filmu, na przykład filmu, użyj funkcji MATCH_CONTENT_FRAMERATE_ALWAYS.
    2. Jeśli odtwarzasz krótki film, np. zwiastun z przenoszeniem, użyj aplikacji CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
  2. Jeśli changeFrameRateStrategy to CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, przejdź do kroku 4.
  3. Sprawdź, czy nastąpi niepłynna zmiana częstotliwości odświeżania. że oba te fakty są prawdziwe:
    1. Nie można płynnie przełączyć się z bieżącej częstotliwości odświeżania (nazwijmy ją C) na częstotliwość klatek filmu (nazwijmy ją V). Dzięki temu niezależnie od tego, czy C i V są różne, Display.getMode().getAlternativeRefreshRates nie zawiera wielokrotności V.
    2. Użytkownik zgodził się na zmiany częstotliwości odświeżania, które nie są płynne. Możesz wykryć, to, sprawdzając, czy DisplayManager.getMatchContentFrameRateUserPreference zwraca MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Jeśli przejście będzie działać bezproblemowo, wykonaj te czynności:
    1. Zadzwoń pod numer setFrameRate i przekazać fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, i changeFrameRateStrategy, gdzie fps to liczba klatek filmu.
    2. Rozpocznij odtwarzanie filmu
  5. Jeśli ma nastąpić zmiana trybu bez płynnego przejścia, wykonaj te czynności:
    1. Wyświetl interfejs użytkownika, aby go powiadomić. Pamiętaj, że zalecamy wdrożenie sposobu zamknięcia tego UX i pominięcia dodatkowego opóźnienia w kroku 5.d. To jest bo zalecane opóźnienie jest większe niż konieczne w przypadku wyświetlaczy, są szybsze.
    2. Wywołaj funkcję setFrameRate i przekaż jej argumenty fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCECHANGE_FRAME_RATE_ALWAYS, gdzie fps to liczba klatek na sekundę w filmie.
    3. Poczekaj na onDisplayChanged. oddzwanianie.
    4. Poczekaj 2 sekundy na zakończenie przełączania trybu.
    5. Rozpocznij odtwarzanie filmu

Pseudokod służący do obsługi płynnego przełączania tylko 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:

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