Frequenza fotogrammi

L'API Frame Rate consente alle app di comunicare alla piattaforma Android il frame previsto ed è disponibile su app destinate ad Android 11 (livello API 30) o versioni successive. In genere, la maggior parte dei dispositivi supporta una sola frequenza di aggiornamento del display, tipicamente a 60 Hz, ma la situazione è cambiata. Molti dispositivi ora supportano di aggiornamento, come 90 Hz o 120 Hz. Alcuni dispositivi supportano una frequenza di aggiornamento continua mentre altri mostrano brevemente uno schermo nero, che in genere dura un secondo.

Lo scopo principale dell'API è consentire alle app di sfruttare al meglio tutti le frequenze di aggiornamento del display supportate. Ad esempio, un'app che riproduce un video a 24 Hz la chiamata a setFrameRate() potrebbe comportare la modifica del display del dispositivo frequenza di aggiornamento da 60 Hz a 120 Hz. Questa nuova frequenza di aggiornamento consente Riproduzione senza sbalzi di video a 24 Hz, senza necessità di pulldown 3:2, come si farebbe necessaria per riprodurre lo stesso video su un display a 60 Hz. Ciò si traduce in un miglioramento dell'esperienza utente un'esperienza senza intervento manuale.

Utilizzo di base

Android presenta diversi modi per accedere alle piattaforme e controllarle, quindi ci sono diverse versioni dell'API setFrameRate(). Ogni versione dell'API utilizza ha gli stessi parametri e funziona esattamente come gli altri:

L'app non deve considerare le effettive frequenze di aggiornamento del display supportate, che puoi ottenere chiamando Display.getSupportedModes(), per chiamare in sicurezza setFrameRate(). Ad esempio, anche se il dispositivo supporta 60 Hz, chiama setFrameRate() con la frequenza fotogrammi preferita dalla tua app. I dispositivi che non corrispondono meglio alla frequenza frame dell'app rimarranno su l'attuale frequenza di aggiornamento.

Per verificare se una chiamata a setFrameRate() determina una modifica dell'aggiornamento della visualizzazione , registrati per ricevere le notifiche di modifica del display chiamando DisplayManager.registerDisplayListener() o AChoreographer_registerRefreshRateCallback().

Quando chiami il numero setFrameRate(), è meglio passare la frequenza fotogrammi esatta anziché rispetto all'arrotondamento a un numero intero. Ad esempio, quando esegui il rendering di un video registrato 29,97 Hz, passa a 29,97 anziché arrotondare a 30.

Per le app video, è necessario impostare il parametro di compatibilità trasmesso a setFrameRate() a Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE per fornire un ulteriore suggerimento la piattaforma Android che l'app utilizzerà il menu a discesa per adattarsi a una frequenza di aggiornamento del display (che comporterà sbalzi).

In alcuni scenari, la piattaforma video interromperà l'invio dei frame, ma rimarrà visibile sullo schermo per un po' di tempo. Gli scenari più comuni sono la riproduzione raggiunge la fine del video o quando l'utente mette in pausa la riproduzione. In questi casi, chiama setFrameRate() con il parametro della frequenza fotogrammi impostato su 0 per cancellare il ripristinare la frequenza fotogrammi al valore predefinito. Annullare l'impostazione della frequenza fotogrammi come questa non è necessaria quando si distrugge la superficie o quando la superficie nascosto perché l'utente passa a un'altra app. Cancella la frequenza fotogrammi solo quando la superficie rimane visibile senza essere utilizzata.

Cambio di frequenza fotogrammi senza interruzioni

Su alcuni dispositivi, il cambio di frequenza di aggiornamento potrebbe presentare interruzioni visive, ad esempio il colore nero schermo per un secondo o due. Questo solitamente si verifica su decoder, pannelli TV, e dispositivi simili. Per impostazione predefinita, il framework Android non cambia modalità quando Surface.setFrameRate() viene chiamata l'API per evitare queste interruzioni visive.

Alcuni utenti preferiscono un'interruzione visiva all'inizio alla fine dei video più lunghi. In questo modo la frequenza di aggiornamento del display corrisponde la frequenza fotogrammi del video ed evitare artefatti di conversione da frequenza fotogrammi, come 3:2 menu a discesa per la riproduzione di film.

Per questo motivo, è possibile attivare i sensori della frequenza di aggiornamento non continui se sono attivazione di utenti e app:

Ti consigliamo di utilizzare sempre CHANGE_FRAME_RATE_ALWAYS per i video di lunga durata come i film. Questo perché il vantaggio della corrispondenza la frequenza fotogrammi del video supera l'interruzione che si verifica quando si cambia il e la frequenza di aggiornamento.

Altri consigli

Segui questi consigli per gli scenari più comuni.

Più piattaforme

La piattaforma Android è progettata per gestire correttamente scenari in cui più piattaforme con impostazioni di frequenza fotogrammi diverse. Se l'app include più piattaforme con frequenze fotogrammi diverse, chiama setFrameRate() con il corretto per ogni superficie. Anche se il dispositivo esegue più app in una volta sola, usando la modalità schermo diviso o Picture in picture, ogni app può chiamare setFrameRate() per le proprie piattaforme.

La piattaforma non cambia la frequenza fotogrammi dell'app

Anche se il dispositivo supporta la frequenza fotogrammi specificata dall'app in una chiamata setFrameRate(), ci sono casi in cui il dispositivo non esegue il passaggio del display a che la frequenza di aggiornamento. Ad esempio, una piattaforma con priorità più elevata potrebbe avere un frequenza fotogrammi oppure il dispositivo potrebbe essere in modalità di risparmio energetico (l'impostazione di limitazione della frequenza di aggiornamento del display per risparmiare batteria). L'app deve comunque funzionano correttamente quando il dispositivo non passa la frequenza di aggiornamento del display all'impostazione della frequenza frame dell'app, anche se il dispositivo passa al livello normale circostanze.

Sta all'app decidere come rispondere al momento della frequenza di aggiornamento del display. non corrisponde alla frequenza fotogrammi dell'app. Per i video, la frequenza fotogrammi è fissata su quella il video sorgente e il menu a discesa sarà necessario per mostrare i contenuti del video. R potrebbe invece scegliere di eseguire un test alla frequenza di aggiornamento del display anziché con la sua frequenza fotogrammi preferita. L'app non deve modificarne il valore trasmette a setFrameRate() in base alle azioni compiute dalla piattaforma. Dovrebbe rimanere impostato alla frequenza fotogrammi preferita dell'app, indipendentemente dal modo in cui l'app gestisce i casi in cui la piattaforma non si adatta alla richiesta dell'app. In questo modo, se il dispositivo cambiano le condizioni per consentire l'utilizzo di altre frequenze di aggiornamento del display, piattaforma abbia le informazioni corrette per passare al frame preferito dell'app di conversione.

Nei casi in cui l'app non può essere eseguita o non può essere eseguita con la frequenza di aggiornamento del display, devi specificare i timestamp della presentazione per ogni frame, utilizzando uno dei dei meccanismi della piattaforma per impostare timestamp delle presentazioni:

L'uso di questi timestamp impedisce alla piattaforma di presentare anche un frame dell'app in anticipo, il che provocherebbe urti inutili. Uso corretto del frame i timestamp della presentazione sono un po' difficili. Per i giochi, consulta le nostre guida al pacing del frame per ulteriori informazioni su come evitare i colpi di scena e considera l'utilizzo del Libreria di pacing frame Android.

In alcuni casi, la piattaforma può passare a un multiplo della frequenza fotogrammi dell'app specificato in setFrameRate(). Ad esempio, un'app potrebbe chiamare setFrameRate() a 60 Hz e il dispositivo può impostare il display a 120 Hz. Uno dei motivi per cui succede se un'altra app ha una piattaforma con una frequenza fotogrammi di 24 Hz. Nella in questo caso, l'esecuzione del display a 120 Hz consentirà sia alla superficie a 60 Hz che Superficie a 24 Hz per l'esecuzione senza pulldown.

Quando il display è a un multiplo della frequenza fotogrammi dell'app, l'app devi specificare i timestamp della presentazione per ogni frame per evitare sbalorditivi. Per i giochi, la libreria del pacing del frame Android è utile per impostare i timestamp di presentazione del frame.

setFrameRate() e preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId è un altro modo con cui le app possono indicare la frequenza fotogrammi alla piattaforma. Alcune le app vogliono modificare solo la frequenza di aggiornamento del display anziché cambiare altre impostazioni della modalità di visualizzazione, come la risoluzione. In generale, usa setFrameRate() anziché preferredDisplayModeId. setFrameRate() è più facile da usare perché l'app non ha bisogno di eseguire ricerche nella elenco di modalità di visualizzazione per trovare una modalità con una frequenza fotogrammi specifica.

setFrameRate() offre alla piattaforma più opportunità di scegliere un modello compatibile frame rate in scenari in cui sono presenti più piattaforme diverse frequenze fotogrammi. Ad esempio, considera uno scenario in cui due app vengono in modalità schermo diviso su Pixel 4, su cui un'app riproduce un video a 24 Hz e l'altra mostra all'utente un elenco scorrevole. Pixel 4 supporta due frequenza di aggiornamento del display: 60 Hz e 90 Hz. Utilizzando l'API preferredDisplayModeId, la superficie video deve selezionare 60 Hz o 90 Hz. Chiamando setFrameRate() a 24 Hz, la superficie video offre alla piattaforma più informazioni sulla frequenza fotogrammi del video sorgente, consentendo alla piattaforma scegliere 90 Hz per la frequenza di aggiornamento del display, migliore di 60 Hz in questo scenario.

Tuttavia, esistono casi in cui è necessario utilizzare preferredDisplayModeId anziché setFrameRate(), come ad esempio:

  • Se l'app vuole modificare la risoluzione o altre impostazioni della modalità di visualizzazione, usa preferredDisplayModeId.
  • La piattaforma cambia modalità di visualizzazione solo in risposta a una chiamata a setFrameRate() se il cambio di modalità è leggero e probabilmente non lo è evidente per l'utente. Se l'app preferisce cambiare l'aggiornamento del display anche se richiede un'opzione di modalità Intensa (ad esempio, su un dispositivo Android TV) dispositivo), usa preferredDisplayModeId.
  • App che non possono gestire il display in esecuzione in più frame dell'app rapida, che richiede l'impostazione dei timestamp della presentazione su ogni frame, usa preferredDisplayModeId.

setFrameRate() e preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate imposta una frequenza fotogrammi preferita nella finestra dell'app e la frequenza è applicabile a tutte le superfici all'interno della finestra. L'app deve specificare la sua frequenza fotogrammi indipendentemente dalle frequenze di aggiornamento supportate dal dispositivo, simile a setFrameRate(), per dare allo scheduler un suggerimento migliore sulle esigenze dell'app frequenza fotogrammi.

preferredRefreshRate viene ignorato per le piattaforme che utilizzano setFrameRate(). Nella uso generico di setFrameRate(), se possibile.

preferredRefreshRate e preferredDisplayModeId

Se le app vogliono modificare solo la frequenza di aggiornamento preferita, è preferibile usare preferredRefreshRate anziché preferredDisplayModeId.

Evitare di chiamare setFrameRate() troppo spesso

Anche se la chiamata a setFrameRate() non è molto costosa in termini di prestazioni, le app dovrebbero evitare di chiamare setFrameRate() a ogni frame o più volte secondo. È probabile che le chiamate a setFrameRate() comportino una modifica al frequenza di aggiornamento del display, che potrebbe causare un calo dei frame durante la transizione. Dovresti capire in anticipo la frequenza fotogrammi corretta e chiamare setFrameRate() una volta.

Utilizzo di giochi e altre app non video

Sebbene i video siano il caso d'uso principale per l'API setFrameRate(), è possibile usata per altre app. Ad esempio, un gioco che non intende essere eseguito più in alto di 60 Hz (per ridurre il consumo di energia e ottenere sessioni di riproduzione più lunghe) può chiamare Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). In questo un dispositivo che funziona a 90 Hz per impostazione predefinita userà invece a 60 Hz mentre che il gioco sia attivo, per evitare sbalzi che altrimenti si verificherebbero se del gioco funzionava a 60 Hz, mentre il display a 90 Hz.

Utilizzo di FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE è destinato solo alle app video. Per per utilizzo non video, usa FRAME_RATE_COMPATIBILITY_DEFAULT.

Scelta di una strategia per modificare la frequenza fotogrammi

  • Consigliamo vivamente alle app, quando mostrano video di lunga durata come film, chiamata a setFrameRate(f/s, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) dove f/s è la frequenza fotogrammi del video.
  • Sconsigliamo vivamente di app che chiamano setFrameRate() con CHANGE_FRAME_RATE_ALWAYS quando si prevede che la riproduzione del video duri diversi minuti o anche meno.

Integrazione di esempio per le app di riproduzione video

Consigliamo di seguire questi passaggi per integrare le opzioni della frequenza di aggiornamento nelle app di riproduzione video:

  1. Decidi i changeFrameRateStrategy:
    1. Se riproduci un video di lunga durata, ad esempio un film, utilizza MATCH_CONTENT_FRAMERATE_ALWAYS
    2. Se riproduci un breve video, ad esempio il trailer di un movimento, utilizza CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
  2. Se changeFrameRateStrategy è CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS , vai al passaggio 4.
  3. Rileva se sta per verificarsi un cambio di frequenza di aggiornamento non continuo controllando che entrambe le cose sono vere:
    1. Con la frequenza di aggiornamento corrente non è possibile cambiare modalità senza interruzioni C) alla frequenza fotogrammi del video (che chiameremo V). In questo modo anche se C e V sono diversi Display.getMode().getAlternativeRefreshRates non contiene un multiplo di V.
    2. L'utente ha attivato le modifiche alla frequenza di aggiornamento non continue. Puoi rilevare questo controllando se DisplayManager.getMatchContentFrameRateUserPreference resi MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Se il passaggio non avverrà senza problemi:
    1. Chiama il numero setFrameRate e lo superi fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, e changeFrameRateStrategy, dove fps è la frequenza fotogrammi del video.
    2. Avvia riproduzione video
  5. Se sta per essere effettuato un cambio di modalità senza soluzione di continuità:
    1. Mostra UX per inviare una notifica all'utente. Ti consigliamo di implementare un metodo all'utente di ignorare questa UX e saltare l'ulteriore ritardo nel passaggio 5.d. Questo è perché il ritardo consigliato è maggiore del necessario sui display che tempi di passaggio più rapidi.
    2. Chiama il numero setFrameRate e lo superi fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, e CHANGE_FRAME_RATE_ALWAYS, dove fps è la frequenza fotogrammi del video.
    3. Attendi onDisplayChanged di Google.
    4. Attendi 2 secondi per il completamento del passaggio alla modalità.
    5. Avvia riproduzione video

Lo pseudo-codice per supportare solo il passaggio senza interruzioni è il seguente:

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

Lo pseudo-codice per supportare il passaggio fluido e fluido come descritto sopra:

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