Fréquence d'images

L'API de fréquence d'images permet aux applications d'informer la plate-forme Android de l'image souhaitée. et est disponible sur les applications qui ciblent Android 11 (niveau d'API 30) ou version ultérieure. Traditionnellement, la plupart des appareils n'acceptent qu'une seule fréquence d'actualisation de l'écran, 60 Hz en général, mais cela a changé. De nombreux appareils prennent désormais en charge avec des fréquences d'actualisation telles que 90 Hz ou 120 Hz. Certains appareils sont compatibles avec la fréquence d'actualisation fluide tandis que d'autres affichent brièvement un écran noir, qui dure généralement une seconde.

L'objectif principal de l'API est de permettre aux applications de mieux profiter les fréquences d'actualisation de l'affichage acceptées. Par exemple, une application qui lit une vidéo 24 Hz qui appelle setFrameRate() peut entraîner le changement d'affichage de l'appareil de 60 Hz à 120 Hz. Cette nouvelle fréquence d'actualisation permet Lecture sans saccades des vidéos 24 Hz, pas besoin d'un défilement 3:2 comme ce serait nécessaire pour lire la même vidéo sur un écran 60 Hz. Cela se traduit par une meilleure expérience utilisateur expérience.

Utilisation de base

Android propose plusieurs façons d'accéder aux surfaces et de les contrôler. Il existe donc plusieurs versions de l'API setFrameRate(). Chaque version de l'API utilise les mêmes paramètres et fonctionne de la même manière que les autres:

L'application n'a pas besoin de prendre en compte les fréquences d'actualisation de l'affichage réellement prises en charge. que vous pouvez obtenir en appelant Display.getSupportedModes(), pour appeler setFrameRate() en toute sécurité. Par exemple, même si l'appareil compatible 60 Hz, appelez setFrameRate() avec la fréquence d'images préférée de votre application. Les appareils qui ne correspondent pas à la fréquence d'images de l'application resteront avec la fréquence d'actualisation actuelle de l'affichage.

Pour voir si un appel à setFrameRate() entraîne une modification de l'actualisation de l'affichage enregistrez-vous pour recevoir des notifications de changement d'affichage en appelant DisplayManager.registerDisplayListener() ou AChoreographer_registerRefreshRateCallback().

Lorsque vous appelez setFrameRate(), il est préférable de transmettre la fréquence d'images exacte plutôt que que d'arrondir à un nombre entier. Par exemple, pour le rendu d'une vidéo enregistrée 29,97 Hz, transmettre à 29,97 au lieu d'arrondir à 30.

Pour les applications vidéo, le paramètre de compatibilité transmis à setFrameRate() doit être défini à Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE pour donner un indice supplémentaire à la plate-forme Android que l'application utilisera le menu déroulant pour s'adapter à un élément qui ne correspond pas la fréquence d'actualisation de l'affichage (ce qui peut être saccadé).

Dans certains cas, la surface vidéo cesse d'envoyer des images, mais reste visible à l'écran pendant un certain temps. Voici quelques cas de figure courants : lorsque la vidéo arrive à la fin ou lorsque l'utilisateur met la lecture en pause ; Dans ces cas, appelez setFrameRate() avec le paramètre de fréquence d'images défini sur 0 pour effacer le la fréquence d'images par défaut. Effacer le paramètre de fréquence d'images ce qui n'est pas nécessaire pour détruire la surface, ou lorsque la surface masquées, car l'utilisateur passe à une autre application. Effacer la fréquence d'images uniquement lorsque la surface reste visible sans être utilisée.

Changement dynamique de la fréquence d'images

Sur certains appareils, le changement de la fréquence d'actualisation peut entraîner des interruptions visuelles, comme un écran l'écran pendant une seconde ou deux. Cela se produit généralement sur les boîtiers décodeurs, les dalles TV et appareils similaires. Par défaut, le framework Android ne change pas de mode lorsque Surface.setFrameRate() est appelée afin d'éviter de telles interruptions visuelles.

Certains utilisateurs préfèrent une interruption visuelle au début et à la fin des vidéos plus longues. Cela permet à la fréquence d'actualisation de l'affichage de correspondre la fréquence d'images de la vidéo, et évitez les artefacts de conversion de fréquence d'images tels que le 3:2 faites glisser le sac à dos pour regarder le film.

Il est donc possible d'activer les interrupteurs non fluides de la fréquence d'actualisation activation pour les utilisateurs et les applications:

Nous vous recommandons de toujours utiliser CHANGE_FRAME_RATE_ALWAYS pour les vidéos de longue durée, comme les films. En effet, l'avantage de la mise en correspondance la fréquence d'images de la vidéo l'emporte sur l'interruption qui se produit lorsque vous modifiez la fréquence d'actualisation.

Autres recommandations

Suivez les recommandations ci-dessous pour les scénarios courants.

Plusieurs surfaces

La plate-forme Android est conçue pour gérer correctement les scénarios sur plusieurs surfaces avec différents paramètres de fréquence d'images. Lorsque votre application comporte plusieurs surfaces avec des fréquences d'images différentes, appelez setFrameRate() avec la bonne la fréquence d'images de chaque surface. Même si l'appareil exécute plusieurs applications à en mode Écran partagé ou Picture-in-picture, chaque appli peut appeler en toute sécurité setFrameRate() pour leurs propres surfaces.

La plate-forme ne modifie pas la fréquence d'images de l'application.

Même si l'appareil est compatible avec la fréquence d'images spécifiée par l'application dans un appel à setFrameRate(), il peut arriver que l'appareil ne bascule pas l'écran sur cette fréquence d'actualisation. Par exemple, une surface prioritaire peut avoir une valeur différente de fréquence d'images, ou si l'appareil est en mode Économiseur de batterie (par exemple, sur la fréquence d'actualisation de l'affichage pour préserver l'autonomie de la batterie). L'application doit toujours fonctionne correctement lorsque l'appareil ne règle pas la fréquence d'actualisation de l'affichage sur paramètre de fréquence d'images de l'application, même si l'appareil bascule en mode normal les circonstances.

C'est à l'application de décider comment réagir lorsque la fréquence d'actualisation de l'affichage ne correspond pas à la fréquence d'images de l'application. Pour les vidéos, la fréquence d'images est fixée à celle de la vidéo source, et un menu déroulant sera nécessaire pour afficher le contenu vidéo. A le jeu peut choisir de s'exécuter à la fréquence d'actualisation de l'affichage plutôt que en conservant sa fréquence d'images préférée. L'application ne doit pas modifier la valeur transmet à setFrameRate() en fonction de ce que fait la plate-forme. Elle doit rester définie. à la fréquence d'images préférée de l'application, quelle que soit la façon dont elle gère les cas la plateforme ne s'ajuste pas à la demande de l'application. De cette façon, si l’appareil pour permettre l'utilisation d'autres fréquences d'actualisation de l'affichage, la plate-forme dispose des informations correctes pour passer au cadre préféré de l'application. taux de conversion.

Si l'application ne peut pas ou ne peut pas s'exécuter à la fréquence d'actualisation de l'affichage, doit spécifier les codes temporels de présentation pour chaque image, en utilisant l'une des de la plate-forme pour définir les codes temporels de présentation:

L'utilisation de ces codes temporels empêche également la plate-forme de présenter une image d'application. au début, ce qui entraînerait des saccades inutiles. Utilisation correcte du cadre les horodatages de présentation est un peu délicat. Pour les jeux, consultez notre Guide du frame pacing pour en savoir plus sur la façon d'éviter les saccades, et pensez à utiliser le Bibliothèque Android Frame Pacing.

Dans certains cas, la plate-forme peut passer à un multiple de la fréquence d'images de l'application. spécifié dans setFrameRate(). Par exemple, une application peut appeler setFrameRate() avec une fréquence de 60 Hz et l'appareil peut faire passer l'écran à 120 Hz. L'une des raisons pour lesquelles cela pourrait se produit si une autre application est dotée d'une surface avec un paramètre de fréquence d'images de 24 Hz. Dans Dans ce cas, le fait d'utiliser l'écran avec une fréquence de 120 Hz permettra à la fois d'utiliser la surface 60 Hz et Surface 24 Hz pour une exécution sans défilement nécessaire.

Lorsque l'écran s'exécute à un multiple de la fréquence d'images de l'application, l'application doivent spécifier des codes temporels de présentation pour chaque image afin d'éviter des saccades. Pour les jeux, la bibliothèque Android Frame Pacing est utile pour la définition des codes temporels de présentation des trames.

setFrameRate() et preferenceDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId est un autre moyen pour les applications d'indiquer leur fréquence d'images à la plateforme. Un peu les applications ne veulent modifier que la fréquence d'actualisation de l'affichage au lieu de modifier d'autres les paramètres du mode d'affichage, comme la résolution d'affichage. En général, utilisez setFrameRate() au lieu de preferredDisplayModeId. setFrameRate() est plus facile à utiliser, car l'application n'a pas besoin d'effectuer une recherche dans liste des modes d'affichage pour trouver un mode avec une fréquence d'images spécifique.

setFrameRate() permet à la plate-forme de choisir un appareil compatible de fréquence d'images lorsque plusieurs surfaces sont exécutées différentes fréquences d'images. Prenons l'exemple d'un scénario dans lequel deux applications sont s'exécute en mode Écran partagé sur un Pixel 4, où une application lit une vidéo 24 Hz et l'autre montre à l'utilisateur une liste déroulante. Le Pixel 4 prend en charge fréquences d'actualisation de l'affichage: 60 Hz et 90 Hz. Avec l'API preferredDisplayModeId, la surface vidéo doit choisir entre 60 Hz ou 90 Hz. En appelant setFrameRate() avec une fréquence de 24 Hz, la surface vidéo offre plus de possibilités à la plate-forme des informations sur la fréquence d'images de la vidéo source, ce qui permet à la plate-forme choisir une fréquence d'actualisation de l'écran de 90 Hz, qui est préférable à 60 Hz dans cette dans ce scénario.

Toutefois, il existe des scénarios dans lesquels preferredDisplayModeId doit être utilisé. au lieu de setFrameRate(), comme suit:

  • Si l'application souhaite modifier la résolution ou d'autres paramètres du mode d'affichage, utiliser preferredDisplayModeId.
  • La plate-forme ne changera de mode d'affichage qu'en réponse à un appel à setFrameRate() si le bouton de mode est léger et a peu de chances d'être visible par l'utilisateur. Si l'application préfère actualiser l'affichage même si un changement de mode intensif est nécessaire (par exemple, appareil), utilisez preferredDisplayModeId.
  • Applications qui ne peuvent pas gérer l'affichage de l'écran à un multiple du cadre de l'application qui nécessite de définir des codes temporels pour chaque image, doit utiliser preferredDisplayModeId.

setFrameRate() et preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate définit une fréquence d'images préférée pour la fenêtre de l'application, laquelle s'applique à toutes les surfaces de la fenêtre. L'application doit spécifier quelle que soit la fréquence d'actualisation compatible avec l'appareil. setFrameRate(), pour donner au programmeur un meilleur indice sur l'objectif de l'application ; de la fréquence d'images.

preferredRefreshRate est ignoré pour les surfaces qui utilisent setFrameRate(). Dans Si possible, utilisez setFrameRate().

PreferredRefreshRate et preferenceDisplayModeId

Si les applications ne veulent modifier que la fréquence d'actualisation préférée, il est préférable d'utiliser preferredRefreshRate au lieu de preferredDisplayModeId.

Éviter d'appeler trop souvent setFrameRate()

Bien que l'appel setFrameRate() ne soit pas très coûteux en termes de performances, les applications doivent éviter d'appeler setFrameRate() à chaque image ou plusieurs fois par seconde. Les appels à setFrameRate() sont susceptibles d'entraîner une modification de la la fréquence d'actualisation de l'affichage, ce qui peut entraîner une perte de frames pendant la transition. Vous devez déterminer la fréquence d'images correcte à l'avance et appeler setFrameRate() une fois.

Utilisation pour des jeux ou d'autres applications non vidéo

Bien que la vidéo soit le principal cas d'utilisation de l'API setFrameRate(), elle peut être pour d'autres applications. Par exemple, un jeu destiné à ne pas dépasser La fréquence 60 Hz (pour réduire la consommation d'énergie et prolonger les sessions de jeu) peut appeler Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) Dans ce un appareil fonctionnant à 90 Hz par défaut, le sera à 60 Hz, alors que jeu est actif, ce qui permet d'éviter les saccades qui se produiraient autrement si le avec une fréquence de 60 Hz et une fréquence de 90 Hz.

Utilisation de FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE n'est destiné qu'aux applications vidéo. Pour d'un contenu autre que vidéo, utilisez FRAME_RATE_COMPATIBILITY_DEFAULT.

Choisir une stratégie pour modifier la fréquence d'images

  • Nous vous recommandons vivement d'utiliser les applications pour diffuser des vidéos de longue durée telles que films, appeler setFrameRate(FPS, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) où "FPS" correspond à la fréquence d'images de la vidéo.
  • Nous déconseillons fortement aux applications qui appellent setFrameRate() avec CHANGE_FRAME_RATE_ALWAYS lorsque vous pensez que la lecture de la vidéo durera plusieurs minutes, voire moins.

Exemple d'intégration pour les applications de lecture de vidéos

Nous vous recommandons de procéder comme suit pour intégrer les boutons de fréquence d'actualisation dans les applications de lecture vidéo:

  1. Déterminez le changeFrameRateStrategy: <ph type="x-smartling-placeholder">
      </ph>
    1. Si vous lisez une vidéo de longue durée, telle qu'un film, utilisez MATCH_CONTENT_FRAMERATE_ALWAYS.
    2. Si vous regardez une vidéo courte, telle qu'une bande-annonce animée, utilisez CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS.
  2. Si changeFrameRateStrategy est CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS , passez à l'étape 4.
  3. Détectez si le changement de fréquence d'actualisation est sur le point de se produire en vérifiant que ces deux faits sont vrais: <ph type="x-smartling-placeholder">
      </ph>
    1. Il n'est pas possible de changer de mode fluide à partir de la fréquence d'actualisation actuelle appelez-la "C") à la fréquence d'images de la vidéo (appelons-la "V"). Cela permettra être le cas si C et V sont différents et Display.getMode().getAlternativeRefreshRates ne contient pas de multiple de V.
    2. L'utilisateur a activé les modifications fluides de la fréquence d'actualisation. Vous pouvez détecter en vérifiant si DisplayManager.getMatchContentFrameRateUserPreference renvoie MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Si la transition se fait en douceur, procédez comme suit: <ph type="x-smartling-placeholder">
      </ph>
    1. Appeler setFrameRate et lui transmettre fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, et changeFrameRateStrategy, où fps correspond à la fréquence d'images de la vidéo.
    2. Lancer la lecture de la vidéo
  5. Si un changement de mode fluide est sur le point de se produire, procédez comme suit: <ph type="x-smartling-placeholder">
      </ph>
    1. Afficher l'expérience utilisateur pour avertir l'utilisateur. Notez que nous vous conseillons de mettre en place à l'utilisateur d'ignorer cette expérience utilisateur et d'ignorer le délai supplémentaire de l'étape 5.d. C'est car le délai recommandé est supérieur au délai nécessaire sur les écrans présentent des temps de transition plus rapides.
    2. Appeler setFrameRate et lui transmettre fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, et CHANGE_FRAME_RATE_ALWAYS, où fps correspond à la fréquence d'images de la vidéo.
    3. Attendez l'événement onDisplayChanged. .
    4. Patientez deux secondes, le temps que le changement de mode soit terminé.
    5. Lancer la lecture de la vidéo

Le pseudo-code permettant uniquement de prendre en charge le basculement fluide est le suivant:

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

Le pseudo-code permettant une commutation fluide et fluide, tel que décrit ci-dessus, se présente comme suit:

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