Framerate

Mit der Framerate API können Apps die Android-Plattform über den beabsichtigten Frame informieren. und ist nur für Apps verfügbar, die auf Android 11 (API-Level 30) oder höher ausgerichtet sind. Bisher haben die meisten Geräte nur eine einzige Displayaktualisierungsrate unterstützt, in der Regel 60 Hz. Das ändert sich jedoch. Viele Geräte unterstützen jetzt zusätzliche Bildwiederholraten wie 90 Hz oder 120 Hz. Einige Geräte unterstützen nahtlose Umstellungen der Bildwiederholrate, während bei anderen kurz ein schwarzer Bildschirm angezeigt wird, der in der Regel eine Sekunde lang anhält.

Der Hauptzweck der API besteht darin, Apps die Möglichkeit zu geben, alle unterstützten Displaywiederholraten besser zu nutzen. Wenn beispielsweise eine App ein 24‑Hz-Video wiedergibt, das setFrameRate() aufruft, kann das Gerät die Displayaktualisierungsrate von 60 Hz auf 120 Hz ändern. Diese neue Bildwiederholrate ermöglicht eine flüssige, ruckelfreie Wiedergabe von 24‑Hz-Videos, ohne dass ein 3:2-Pulldown erforderlich ist, wie es für die Wiedergabe desselben Videos auf einem 60‑Hz-Display erforderlich wäre. Dies führt zu einer besseren User Experience Nutzererfahrung.

Grundlegende Nutzung

Android bietet mehrere Möglichkeiten, auf Oberflächen zuzugreifen und sie zu steuern. Daher gibt es mehrere Versionen der setFrameRate() API. Jede Version der API verwendet dieselben Parameter und funktioniert genauso wie die anderen:

Die App berücksichtigt nicht die tatsächlich unterstützten Display-Aktualisierungsraten, Rufen Sie dazu den folgenden Befehl auf: Display.getSupportedModes(), um setFrameRate() sicher anzurufen. Auch wenn das Gerät nur 60 Hz unterstützt, rufe setFrameRate() mit der Framerate auf, die für deine App bevorzugt wird. Auf Geräten, die keine bessere Übereinstimmung mit der Framerate der App haben, bleibt die aktuelle Displayaktualisierungsrate erhalten.

Wenn Sie wissen möchten, ob ein Aufruf von setFrameRate() zu einer Änderung der Bildwiederholrate führt, registrieren Sie sich für Benachrichtigungen zu Displayänderungen. Rufen Sie dazu DisplayManager.registerDisplayListener() oder AChoreographer_registerRefreshRateCallback() auf.

Beim Aufrufen von setFrameRate() ist es am besten, die genaue Framerate zu übergeben, als das Runden auf eine ganze Zahl. Zum Beispiel beim Rendern eines Videos, das 29,97 Hz übergeben und nicht auf 30 gerundet wird, sondern 29,97.

Für Video-Apps sollte der an setFrameRate() übergebene Kompatibilitätsparameter festgelegt werden an Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, um einen zusätzlichen Hinweis für die Android-Plattform, die die App verwendet, um sie an eine nicht übereinstimmende Aktualisierungsrate des Displays. Dies führt zu Ruckeln.

In einigen Fällen sendet die Videooberfläche zwar keine Frames mehr, aber sie bleibt unverändert. einige Zeit auf dem Bildschirm sichtbar sind. Häufige Szenarien sind die Wiedergabe das Ende des Videos erreicht oder der Nutzer die Wiedergabe anhält. In diesen Fällen Rufen Sie setFrameRate() auf und setzen Sie den Framerate-Parameter auf 0, um die Framerate auf den Standardwert zurückgesetzt. Das Löschen der Framerate-Einstellung ist nicht erforderlich, wenn die Oberfläche zerstört oder ausgeblendet wird, weil der Nutzer zu einer anderen App wechselt. Löschen Sie die Framerate-Einstellung nur, wenn die Oberfläche sichtbar bleibt, ohne verwendet zu werden.

Nicht nahtloser Wechsel der Framerate

Auf einigen Geräten kann es beim Umschalten der Aktualisierungsrate zu visuellen Unterbrechungen wie einem schwarzen ein oder zwei Sekunden lang. Dies geschieht in der Regel bei Set-Top-Boxen, TV-Panels und ähnliche Geräte. Standardmäßig wechselt das Android-Framework nicht den Modus wenn der Surface.setFrameRate() API aufgerufen, um solche optischen Unterbrechungen zu vermeiden.

Einige Nutzer bevorzugen eine visuelle Unterbrechung zu Beginn und am Ende längerer Videos. So kann die Bildwiederholrate des Displays an die Framerate des Videos angepasst werden und es werden keine Framerate-Konvertierungsartefakte wie Ruckler bei der 3:2-Pulldown-Filmwiedergabe vermieden.

Aus diesem Grund können nicht nahtlose Wechsel der Bildwiederholrate aktiviert werden, wenn sowohl der Nutzer als auch die Apps dies aktivieren:

Wir empfehlen, für Videos mit langer Laufzeit wie Filme immer CHANGE_FRAME_RATE_ALWAYS zu verwenden. Das liegt daran, dass der Vorteil die Framerate des Videos überwiegt die Unterbrechung, die beim Ändern der Aktualisierungsrate.

Weitere Empfehlungen

Beachten Sie die folgenden Empfehlungen für häufige Szenarien.

Mehrere Oberflächen

Die Android-Plattform ist darauf ausgelegt, auf mehreren Oberflächen mit unterschiedlichen Framerate-Einstellungen. Wenn Ihre App mehrere Oberflächen mit unterschiedlichen Frame-Rates verwenden, rufen Sie setFrameRate() mit dem Frame-Rate für die jeweilige Oberfläche. Auch wenn auf dem Gerät mehrere Apps Mit dem Splitscreen-Modus oder dem Bild-im-Bild-Modus kann jede App setFrameRate() für ihre eigenen Oberflächen.

Die Plattform ändert sich nicht an der Framerate der App.

Auch wenn das Gerät die Framerate unterstützt, die von der App in einem Aufruf von setFrameRate(), es gibt Fälle, in denen das Display das Display nicht wechselt die Aktualisierungsrate erhöhen. So kann beispielsweise eine Oberfläche mit höherer Priorität eine andere Framerate haben oder das Gerät befindet sich im Energiesparmodus, wodurch die Bildwiederholrate des Displays eingeschränkt wird, um den Akku zu schonen. Die App muss immer noch ordnungsgemäß funktioniert, wenn das Gerät die Aktualisierungsrate des Displays nicht auf die der Framerate der App, auch wenn das Gerät im normalen Modus wechselt. Situation.

Die App entscheidet selbst, wie sie reagieren soll, wenn die Aktualisierungsrate des Displays nicht mit der Framerate der App übereinstimmt. Bei Videos ist die Framerate auf die des Quellvideos festgelegt. Für die Wiedergabe des Videoinhalts ist ein Drop-down-Menü erforderlich. Ein Spiel kann stattdessen versuchen, mit der Bildwiederholrate des Displays ausgeführt zu werden, anstatt bei der bevorzugten Framerate zu bleiben. Die App darf den Wert, den sie an setFrameRate() übergibt, nicht basierend auf der Funktionsweise der Plattform ändern. Sie sollte auf die bevorzugte Framerate der App eingestellt bleiben, unabhängig davon, wie die App Fälle behandelt, in denen sich die Plattform nicht an die Anfrage der App anpasst. So hat die Plattform die richtigen Informationen, um bei einer Änderung der Gerätebedingungen zur Verwendung zusätzlicher Displayaktualisierungsraten zur bevorzugten Framerate der App zu wechseln.

Wenn die App nicht oder nicht mit der Bildwiederholrate des Displays ausgeführt wird, sollte sie für jeden Frame Präsentationszeitstempel angeben. Dazu kann einer der Mechanismen der Plattform zum Festlegen von Präsentationszeitstempeln verwendet werden:

Wenn Sie diese Zeitstempel verwenden, kann die Plattform auch keinen App-Frame präsentieren was zu unnötigem Rumpf führen würde. Die korrekte Verwendung von Zeitstempeln für die Frame-Darstellung ist etwas schwierig. Informationen zu Spielen findest du in unserer Leitfaden zur Taktung von Frames findest du weitere Informationen zur Vermeidung von Rauschen. Außerdem kannst du Android Frame Pacing Library.

In einigen Fällen wechselt die Plattform zu einem Vielfachen der Framerate der App. angegeben in setFrameRate(). Eine App ruft beispielsweise setFrameRate() mit 60 Hz auf und das Gerät schaltet das Display auf 120 Hz um. Ein Grund dafür, tritt auf, wenn eine andere App eine Oberfläche mit einer Framerate von 24 Hz hat. In diesem Fall können sowohl die 60‑Hz- als auch die 24‑Hz-Oberfläche ohne Pulldown ausgeführt werden, wenn das Display mit 120 Hz betrieben wird.

Wenn der Bildschirm mit einem Vielfachen der Framerate der App ausgeführt wird, zeigt die App sollten Präsentationszeitstempel für jeden Frame angeben, um unnötige Richtig schlecht. Bei Spielen ist die Android Frame Pacing-Bibliothek hilfreich, um Zeitstempel für die Frame-Darstellung korrekt festzulegen.

setFrameRate() im Vergleich zu preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId ist eine weitere Möglichkeit, wie Apps ihre Framerate an die Plattform senden können. Einige Apps nur die Aktualisierungsrate des Displays ändern, statt andere Einstellungen für den Anzeigemodus wie z. B. die Bildschirmauflösung. Verwenden Sie im Allgemeinen setFrameRate() anstelle von preferredDisplayModeId. Die Funktion setFrameRate() ist einfacher zu verwenden, da die App nicht die Liste der Anzeigemodi durchsuchen muss, um einen Modus mit einer bestimmten Framerate zu finden.

setFrameRate() bietet der Plattform mehr Möglichkeiten, eine kompatible in Szenarien mit mehreren Oberflächen, die auf unterschiedliche Frame-Rates. Stellen Sie sich beispielsweise ein Szenario vor, bei dem zwei Apps auf einem Pixel 4 im Splitscreen-Modus, wobei eine App ein 24-Hz-Video abspielt und eine scrollbare Liste. Pixel 4 unterstützt zwei Display-Aktualisierungsraten: 60 Hz und 90 Hz. Bei Verwendung der preferredDisplayModeId API muss für die Videofläche entweder 60 Hz oder 90 Hz ausgewählt werden. Wenn setFrameRate() mit 24 Hz aufgerufen wird, gibt die Videofläche der Plattform mehr Informationen zur Framerate des Quellvideos. So kann die Plattform 90 Hz für die Displayaktualisierungsrate auswählen, was in diesem Szenario besser ist als 60 Hz.

Es gibt jedoch Szenarien, in denen preferredDisplayModeId verwendet werden sollte statt setFrameRate(). Beispiel:

  • Wenn die App die Auflösung oder andere Einstellungen des Anzeigemodus ändern soll, verwenden Sie preferredDisplayModeId.
  • Die Plattform wechselt nur als Reaktion auf einen Aufruf von setFrameRate(), wenn der Moduswechsel leicht ist, dies jedoch unwahrscheinlich ist für die Nutzenden erkennbar sind. Wenn die App die Displayaktualisierung bevorzugt, auch wenn ein intensiver Moduswechsel erforderlich ist (z. B. auf einem Android TV-Gerät). Gerät), verwenden Sie preferredDisplayModeId.
  • Bei Apps, die das Display nicht mit einer Framerate ausführen können, die ein Vielfaches der Framerate der App ist, müssen für jeden Frame Präsentationszeitstempel festgelegt werden. In diesen Fällen sollte preferredDisplayModeId verwendet werden.

setFrameRate() im Vergleich zu PreferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate legt eine bevorzugte Frame-Rate im App-Fenster fest und die Rate gilt für alle Oberflächen des Fensters. Die App sollte die bevorzugte Framerate unabhängig von den unterstützten Aktualisierungsraten des Geräts angeben, ähnlich wie bei setFrameRate(), um dem Scheduler einen besseren Hinweis auf die beabsichtigte Framerate der App zu geben.

preferredRefreshRate wird für Oberflächen ignoriert, die setFrameRate() verwenden. Verwenden Sie nach Möglichkeit setFrameRate().

preferredRefreshRate im Vergleich zu preferredDisplayModeId

Wenn Apps nur die bevorzugte Aktualisierungsrate ändern möchten, empfiehlt sich die Verwendung von preferredRefreshRate statt preferredDisplayModeId.

Zu häufiges Aufrufen von setFrameRate() vermeiden

Der setFrameRate()-Aufruf ist zwar nicht sehr leistungsintensiv, Apps sollten setFrameRate() jedoch nicht in jedem Frame oder mehrmals pro Sekunde aufrufen. Aufrufe an setFrameRate() führen wahrscheinlich zu einer Änderung des Aktualisierungsrate des Bildschirms, was zu einem Rückgang der Frame während des Übergangs führen kann. Sie sollten die richtige Framerate im Voraus ermitteln und setFrameRate() einmal aufrufen.

Nutzung für Spiele und andere Apps ohne Video

Videos sind der primäre Anwendungsfall für die setFrameRate() API, sie kann aber auch für andere Apps verwendet werden. Ein Spiel, das beispielsweise nicht schneller als 60 Hz laufen soll, um den Stromverbrauch zu senken und längere Spielsitzungen zu ermöglichen, kann Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) aufrufen. In dieser Geräte, die standardmäßig mit 90 Hz laufen, stattdessen mit 60 Hz, während der das Spiel aktiv ist. Dadurch wird verhindert, dass der Nutzer ruckelt, wenn das Spiel das Spiel bei 60 Hz, das Display bei 90 Hz.

Verwendung von FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE ist nur für Video-Apps vorgesehen. Für nicht für Videos: FRAME_RATE_COMPATIBILITY_DEFAULT verwenden.

Strategie zum Ändern der Framerate auswählen

  • Wenn Apps mit langer Laufzeit wie z. B. Filme, setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) anrufen wobei fps für die Frame-Rate des Videos steht.
  • Wir raten dringend davon ab, in Apps setFrameRate() mit CHANGE_FRAME_RATE_ALWAYS aufzurufen, wenn die Videowiedergabe voraussichtlich nur wenige Minuten dauert.

Beispielintegration für Apps zur Videowiedergabe

Wir empfehlen die folgenden Schritte zum Integrieren von Schaltern für die Aktualisierungsrate in Apps zur Videowiedergabe:

  1. Legen Sie die changeFrameRateStrategy fest:
    1. Wenn Sie ein Video mit langer Laufzeit, z. B. einen Film, abspielen möchten, verwenden Sie MATCH_CONTENT_FRAMERATE_ALWAYS.
    2. Wenn ein kurzes Video wie ein Filmtrailer wiedergegeben wird, verwenden Sie CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS.
  2. Wenn changeFrameRateStrategy = CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS ist, fahren Sie mit Schritt 4 fort.
  3. Prüfen Sie, ob ein Wechsel der Aktualisierungsrate bei einer nicht nahtlosen Aktualisierung bevorsteht. dass diese beiden Fakten wahr sind:
    1. Ein nahtloser Moduswechsel von der aktuellen Bildwiederholrate (nennen wir sie C) zur Framerate des Videos (nennen wir sie V) ist nicht möglich. Dadurch wird wenn C und V unterschiedlich sind und Display.getMode().getAlternativeRefreshRates kein Vielfaches von V enthält.
    2. Der Nutzer hat die Option für nicht nahtlose Änderungen der Bildwiederholrate aktiviert. Sie können das prüfen, indem Sie sehen, ob DisplayManager.getMatchContentFrameRateUserPreference MATCH_CONTENT_FRAMERATE_ALWAYS zurückgibt.
  4. Wenn die Umstellung nahtlos erfolgen soll, gehen Sie so vor:
    1. setFrameRate anrufen und übergeben es fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, und changeFrameRateStrategy, wobei fps die Framerate des Videos ist.
    2. Videowiedergabe starten
  5. Wenn eine Änderung des nicht nahtlosen Modus bevorsteht, gehen Sie so vor:
    1. Zeigen Sie die UX, um den Nutzer zu benachrichtigen. Wir empfehlen Ihnen, in Schritt 5.d eine Möglichkeit zu implementieren, mit der Nutzer diese UX schließen und die zusätzliche Verzögerung überspringen können. Das liegt daran, dass die empfohlene Verzögerung bei Displays mit kürzeren Schaltzeiten länger ist als erforderlich.
    2. setFrameRate anrufen und übergeben es fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, und CHANGE_FRAME_RATE_ALWAYS Dabei ist fps die Framerate des Videos.
    3. Warten Sie, bis die onDisplayChanged Callback des Nutzers an.
    4. Warten Sie zwei Sekunden, bis der Moduswechsel abgeschlossen ist.
    5. Videowiedergabe starten

Der Pseudocode, der ausschließlich den nahtlosen Wechsel unterstützt, lautet wie folgt:

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

Der oben beschriebene Pseudocode zur Unterstützung des nahtlosen und nahtlosen Wechsels lautet wie folgt:

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