L'API de fréquence d'images permet aux applications d'informer la plate-forme Android de leur fréquence d'images prévue. Elle est disponible sur les applications qui ciblent Android 11 (niveau d'API 30) ou version ultérieure. Traditionnellement, la plupart des appareils n'acceptaient qu'une seule fréquence d'actualisation de l'écran, généralement 60 Hz, 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 acceptent les changements de fréquence d'actualisation fluides, tandis que d'autres affichent brièvement un écran noir, généralement pendant une seconde.
L'objectif principal de l'API est de permettre aux applications de mieux exploiter toutes les fréquences d'actualisation d'écran compatibles. 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 améliore l'expérience utilisateur.
Utilisation de base
Android propose plusieurs façons d'accéder et de contrôler les surfaces. 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:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
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 n'est compatible qu'avec 60 Hz, appelez setFrameRate()
avec la fréquence d'images préférée de votre application.
Les appareils qui ne correspondent pas mieux à la fréquence d'images de l'application conserveront la fréquence d'actualisation de l'écran actuelle.
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 sur Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
afin d'indiquer à la plate-forme Android que l'application utilisera le pulldown pour s'adapter à un taux de rafraîchissement d'affichage non correspondant (ce qui entraînera un scintillement).
Dans certains cas, la surface vidéo cesse d'envoyer des images, mais reste
visible à l'écran pendant
un certain temps. Il peut s'agir, par exemple, lorsque la lecture arrive à la fin de la vidéo 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 écrans de télévision et les 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 de faire correspondre la fréquence d'actualisation de l'écran à la fréquence d'images vidéo et d'éviter les artefacts de conversion de fréquence d'images tels que le tremblement de la pulldown 3:2 pour la lecture de films.
Il est donc possible d'activer les interrupteurs non fluides de la fréquence d'actualisation activation pour les utilisateurs et les applications:
- Utilisateurs : pour activer cette fonctionnalité, les utilisateurs peuvent activer le paramètre Adapter la fréquence d'images au contenu.
- Applications: pour activer cette option, les applications peuvent transmettre
CHANGE_FRAME_RATE_ALWAYS
danssetFrameRate()
.
Nous vous recommandons de toujours utiliser CHANGE_FRAME_RATE_ALWAYS
pour les vidéos longues, 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 fréquence d'images appropriée pour 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. Un défilement vers le bas est 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. Ainsi, si les conditions de l'appareil changent pour permettre l'utilisation de fréquences d'actualisation d'écran supplémentaires, la plate-forme dispose des informations correctes pour passer à la fréquence d'images préférée de l'application.
Si l'application ne s'exécute pas ou ne peut pas s'exécuter à la fréquence d'actualisation de l'écran, elle doit spécifier des codes temporels de présentation pour chaque frame, à l'aide de l'un des mécanismes de la plate-forme pour définir des codes temporels de présentation :
L'utilisation de ces codes temporels empêche la plate-forme de présenter un frame d'application trop tôt, ce qui entraînerait un à-coup inutile. 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 spécifiée par l'application dans setFrameRate()
. Par exemple, une application peut appeler setFrameRate()
avec 60 Hz, et l'appareil peut passer l'affichage à 120 Hz. Cela peut se produire si une autre application dispose d'une surface avec un paramètre de fréquence d'images de 24 Hz. Dans ce cas, l'exécution de l'écran à 120 Hz permet d'exécuter à la fois la surface 60 Hz et la surface 24 Hz sans avoir à effectuer de pulldown.
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 définir correctement les codes temporels de présentation des frames.
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
. La fonction setFrameRate()
est plus facile à utiliser, car l'application n'a pas besoin de parcourir la 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 est compatible avec deux fréquences d'actualisation de l'écran : 60 Hz et 90 Hz. À l'aide de l'API preferredDisplayModeId
, la surface vidéo est forcée de choisir 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, utilisez
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), utilisezpreferredDisplayModeId
. - 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 un taux de rafraîchissement préféré sur la fenêtre de l'application. Ce taux s'applique à toutes les surfaces de la fenêtre. L'application doit spécifier sa fréquence d'images préférée, quelle que soit la fréquence d'actualisation prise en charge par l'appareil, comme pour setFrameRate()
, afin de donner au planificateur une meilleure indication de la fréquence d'images prévue de l'application.
preferredRefreshRate
est ignoré pour les surfaces qui utilisent setFrameRate()
. Dans
Utilisez setFrameRate()
si possible.
PreferredRefreshRate et preferenceDisplayModeId
Si les applications ne souhaitent modifier que la fréquence d'actualisation préférée, il est préférable d'utiliser preferredRefreshRate
plutôt que 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 cas d'utilisation principal de l'API setFrameRate()
, elle peut être utilisée pour d'autres applications. Par exemple, un jeu qui ne doit pas fonctionner à plus de 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)
. Ainsi, un appareil qui fonctionne à 90 Hz par défaut fonctionnera à 60 Hz lorsque le jeu est actif, ce qui évitera les à-coups qui se produiraient si le jeu fonctionnait à 60 Hz alors que l'écran fonctionnait à 90 Hz.
Utilisation de FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
est destiné uniquement aux applications vidéo. Pour une utilisation autre que vidéo, utilisez FRAME_RATE_COMPATIBILITY_DEFAULT
.
Choisir une stratégie pour modifier la fréquence d'images
- Lorsque des applications affichent des vidéos longues, telles que des films, nous vous recommandons vivement d'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 vous déconseillons vivement d'appeler
setFrameRate()
avecCHANGE_FRAME_RATE_ALWAYS
dans les applications lorsque la lecture vidéo dure plusieurs minutes ou moins.
Exemple d'intégration pour les applications de lecture vidéo
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:
- Déterminez le
changeFrameRateStrategy
:- Si vous lisez une vidéo longue, comme un film, utilisez
MATCH_CONTENT_FRAMERATE_ALWAYS
. - Si vous lisez une courte vidéo, comme une bande-annonce de film, utilisez
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
.
- Si vous lisez une vidéo longue, comme un film, utilisez
- Si
changeFrameRateStrategy
estCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
, passez à l'étape 4. - 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>
- 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. - L'utilisateur a activé les modifications fluides de la fréquence d'actualisation. Vous pouvez détecter
en vérifiant si
DisplayManager.getMatchContentFrameRateUserPreference
renvoieMATCH_CONTENT_FRAMERATE_ALWAYS
- 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
- Si la transition se fait en douceur, procédez comme suit:
<ph type="x-smartling-placeholder">
- </ph>
- Appeler
setFrameRate
et lui transmettrefps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, etchangeFrameRateStrategy
, oùfps
correspond à la fréquence d'images de la vidéo. - Lancer la lecture de la vidéo
- Appeler
- Si un changement de mode fluide est sur le point de se produire, procédez comme suit:
<ph type="x-smartling-placeholder">
- </ph>
- Affichez l'interface utilisateur pour avertir l'utilisateur. Notez que nous vous recommandons 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. En effet, le délai recommandé est plus long que nécessaire sur les écrans qui affichent des temps de commutation plus rapides.
- Appelez
setFrameRate
et transmettez-luifps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
etCHANGE_FRAME_RATE_ALWAYS
, oùfps
correspond à la fréquence d'images de la vidéo. - Attendez l'événement
onDisplayChanged
. . - Patientez deux secondes, le temps que le changement de mode soit terminé.
- Lancer la lecture de la vidéo
Le pseudo-code permettant de n'autoriser que le changement de profil en douceur 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 de prendre en charge la commutation transparente et non transparente, comme décrit ci-dessus, est le suivant :
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();
}