A API de frame rate permite que os apps informem a Plataforma Android sobre o frame pretendido e está disponível em apps direcionados ao Android 11 (nível 30 da API) ou versões mais recentes. Tradicionalmente, a maioria dos dispositivos oferece suporte a uma única taxa de atualização da tela, normalmente 60 Hz, mas isso está mudando. Muitos dispositivos como 90 Hz ou 120 Hz. Alguns dispositivos oferecem suporte à taxa de atualização contínua interruptores, enquanto outros mostram brevemente uma tela preta, geralmente com duração de um segundo.
O objetivo principal da API é permitir que os aplicativos aproveitem melhor todas
as taxas de atualização de exibição compatíveis. Por exemplo, um app que reproduz um vídeo de 24 Hz
que chama setFrameRate()
pode fazer com que o dispositivo mude a tela
de 60 Hz para 120 Hz. Essa nova taxa de atualização permite uma interface
a reprodução de vídeos a 24 Hz sem trepidação e sem a necessidade do menu suspenso de 3:2, como seria
necessário para reproduzir o mesmo vídeo em uma tela de 60 Hz. Isso resulta em uma melhor experiência
do usuário.
Uso básico
O Android expõe várias maneiras de acessar e controlar superfícies. Portanto, há
várias versões da API setFrameRate()
. Cada versão da API usa
e funciona da mesma forma que os outros:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
O app não precisa considerar as taxas de atualização de tela compatíveis.
que pode ser obtido chamando
Display.getSupportedModes()
,
para chamar setFrameRate()
com segurança. Por exemplo, mesmo que apenas o dispositivo
ofereça suporte a 60 Hz, chame setFrameRate()
com o frame rate de preferência do app.
Os dispositivos que não têm uma correspondência melhor para o frame rate do app continuarão com
a taxa de atualização da tela atual.
Para conferir se uma chamada para setFrameRate()
resulta em uma mudança na atualização da tela
registrar-se para notificações de alteração de exibição chamando
DisplayManager.registerDisplayListener()
ou AChoreographer_registerRefreshRateCallback()
.
Ao chamar setFrameRate()
, recomendamos transmitir o frame rate exato em vez
do que arredondar para um número inteiro. Por exemplo, ao renderizar um vídeo gravado
29,97 Hz, passe 29,97 em vez de arredondar para 30.
Para apps de vídeo, o parâmetro de compatibilidade transmitido para setFrameRate()
precisa ser definido.
para Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
para dar uma dica adicional a
a plataforma Android na qual o aplicativo usará o menu suspenso para se adaptar a um
a taxa de atualização da tela, o que resulta em trepidação.
Em alguns casos, a plataforma de vídeo vai parar de enviar frames, mas vai permanecer
visível na tela por algum tempo. Cenários comuns incluem quando a reprodução
chega ao final do vídeo ou quando o usuário pausa a reprodução. Nesses casos,
Chame setFrameRate()
com o parâmetro de frame rate definido como 0 para limpar
o frame rate para o valor padrão. Como limpar a configuração de frame rate
isso não é necessário ao destruir a superfície ou quando ela estiver
oculta porque o usuário muda para outro app. Limpar o frame rate
configuração apenas quando a superfície permanece visível sem ser usada.
Troca de frame rate não perfeita
Em alguns dispositivos, a mudança da taxa de atualização pode ter interrupções visuais, como um preto
na tela por um ou dois segundos. Isso normalmente ocorre em conversores, painéis de TV
e dispositivos semelhantes. Por padrão, o framework do Android não alterna de modo.
quando o Surface.setFrameRate()
API é chamada, para evitar essas interrupções visuais.
Alguns usuários preferem uma interrupção visual no início e fim de vídeos mais longos. Isso permite que a taxa de atualização da tela corresponda o frame rate do vídeo e evite artefatos de conversão de frame rate como 3:2 trepidação no menu suspenso para a reprodução de filmes.
Por essa razão, as chaves de taxa de atualização não contínuas poderão ser ativadas se as ativação por usuário e apps:
- Usuários: para ativar o recurso, os usuários podem ativar a opção Corresponder ao frame rate do conteúdo. do ambiente.
- Apps: para ativar, os apps podem transmitir
CHANGE_FRAME_RATE_ALWAYS
emsetFrameRate()
.
Recomendamos que você sempre use CHANGE_FRAME_RATE_ALWAYS
para vídeos longos, como filmes. Isso ocorre porque o benefício de corresponder
o frame rate do vídeo supera a interrupção que ocorre ao alterar
e a taxa de atualização.
Recomendações adicionais
Siga estas recomendações para cenários comuns.
Várias superfícies
A plataforma Android foi projetada para lidar corretamente com cenários em que há
várias plataformas com diferentes configurações de frame rate. Quando seu app tem vários
com frame rates diferentes, chame setFrameRate()
com a
o frame rate de cada plataforma. Mesmo que o dispositivo execute vários aplicativos
usando a tela dividida ou o modo picture-in-picture, cada app pode chamar
setFrameRate()
para as próprias plataformas.
A plataforma não muda no frame rate do app
Mesmo que o dispositivo seja compatível com o frame rate especificado pelo app em uma chamada para
setFrameRate()
, há casos em que o dispositivo não muda a tela para
essa taxa de atualização. Por exemplo, uma superfície de prioridade mais alta pode ter um
do frame rate, ou o dispositivo pode estar no modo de economia de bateria (definindo um
restrição na taxa de atualização da tela para economizar bateria). O app ainda precisa
funcionam corretamente quando o dispositivo não muda a taxa de atualização da tela para o
à configuração de frame rate do app, mesmo que o dispositivo mude para um ritmo normal
em cada situação.
Cabe ao app decidir como responder quando a taxa de atualização da tela
não corresponde ao frame rate do app. Para vídeos, o frame rate é o valor do
o vídeo de origem, e o menu suspenso será necessário para mostrar o conteúdo do vídeo. Um
pode optar por executar na taxa de atualização da tela em vez
manter o frame rate preferido. O app não deve mudar o valor
é transmitido para setFrameRate()
com base no que a plataforma faz. Ele deve ficar definido
para o frame rate preferencial do app, independentemente de como ele lida com casos em que
a plataforma não se ajustar para corresponder à solicitação do app. Dessa forma, se o dispositivo
as condições mudam para permitir o uso de taxas de atualização de exibição adicionais, a
plataforma tenha as informações corretas para alternar para o frame preferido do app
e a taxa de conversão.
Nos casos em que o aplicativo não pode ou não pode ser executado com a taxa de atualização da tela, o aplicativo devem especificar carimbos de data/hora da apresentação para cada frame, usando um dos mecanismos da plataforma para definir carimbos de data/hora da apresentação:
O uso desses carimbos de data/hora também impede que a plataforma apresente um frame do app cedo, o que resultaria em trepidação desnecessária. Uso correto do frame os carimbos de data/hora da apresentação é um pouco complicado. Para jogos, consulte nossa guia de ritmo de frames para mais informações sobre como evitar trepidação, e considere usar o Biblioteca Android Frame Pacing.
Em alguns casos, a plataforma pode alternar para um múltiplo do frame rate do app
especificado em setFrameRate()
. Por exemplo, um app pode chamar setFrameRate()
com 60 Hz, e o dispositivo pode mudar a tela para 120 Hz. Uma razão pela qual isso pode
acontecer se outro app tiver uma plataforma com uma configuração de frame rate de 24 Hz. Em
nesse caso, executar a tela a 120 Hz permitirá que a superfície de 60 Hz e
Superfície de 24 Hz para execução sem necessidade de abrir o menu suspenso.
Quando a tela está sendo executada em um múltiplo do frame rate do app, ele deve especificar carimbos de data/hora da apresentação para cada frame para evitar o uso desnecessário trepidação. Para jogos, a biblioteca Android Frame Pacing é útil para corrigir definir carimbos de data/hora da apresentação do frame.
setFrameRate() vs. PreferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
é outra forma de os apps indicarem o frame rate para a plataforma. Algumas
os aplicativos querem apenas alterar a taxa de atualização da tela, em vez de alterar outros
configurações do modo de exibição, como a resolução da tela. Em geral, use
setFrameRate()
em vez de preferredDisplayModeId
. O setFrameRate()
é mais fácil de usar porque o aplicativo não precisa procurar na
lista de modos de exibição para encontrar um modo com um frame rate específico.
setFrameRate()
dá à plataforma mais oportunidades de escolher um
em cenários em que há várias superfícies em execução
frame rates diferentes. Por exemplo, considere um cenário em que dois aplicativos
executados no modo de tela dividida em um Pixel 4, em que um app reproduz um vídeo de 24 Hz
e o outro está mostrando ao usuário uma lista rolável. O Pixel 4 oferece suporte a dois
exibir taxas de atualização: 60 Hz e 90 Hz. Usando a API preferredDisplayModeId
,
a superfície de vídeo for forçada a escolher 60 Hz ou 90 Hz; Ligando para
setFrameRate()
a 24 Hz, a superfície de vídeo oferece à plataforma mais
informações sobre o frame rate do vídeo de origem, permitindo que a plataforma
escolher 90 Hz para a taxa de atualização da tela, que é melhor do que 60 Hz neste
diferente.
No entanto, há cenários em que preferredDisplayModeId
precisa ser usado
em vez de setFrameRate()
, como no exemplo a seguir:
- Se o app quiser alterar a resolução ou outras configurações do modo de exibição,
use
preferredDisplayModeId
. - A plataforma só alternará os modos de exibição em resposta a uma chamada para
setFrameRate()
se a chave de modo for leve e provavelmente não será perceptíveis para o usuário. Se o app preferir alternar a atualização da tela mesmo que exija uma chave de modo grosso (por exemplo, no Android TV dispositivo), usepreferredDisplayModeId
. - Apps que não podem processar a exibição em um múltiplo do frame do app
que requer a definição de carimbos de data/hora da apresentação em cada frame, deve
use
preferredDisplayModeId
.
setFrameRate() vs. PreferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
define um frame rate preferencial na janela do app, e a taxa é aplicável.
a todas as superfícies dentro da janela. O app deve especificar a preferência
independentemente das taxas de atualização compatíveis com o dispositivo, semelhante às
setFrameRate()
, para dar ao programador uma dica melhor sobre a intenção do app
frame rate.
preferredRefreshRate
é ignorado nas plataformas que usam setFrameRate()
. Em
use setFrameRate()
, se possível, de forma geral.
PreferredRefreshRate vs. PreferredDisplayModeId
Se os aplicativos só quiserem alterar a taxa de atualização preferencial, é preferível usar
preferredRefreshRate
, em vez de preferredDisplayModeId
.
Evitar chamar setFrameRate() com muita frequência
Embora a chamada setFrameRate()
não tenha um custo muito elevado em termos de desempenho,
os apps precisam evitar chamar setFrameRate()
a cada frame ou várias vezes por
segundo. As chamadas para setFrameRate()
provavelmente resultarão em uma mudança no
a taxa de atualização da tela, o que pode resultar em uma queda de frames durante a transição.
Descobrir o frame rate correto com antecedência e chamar
setFrameRate()
uma vez.
Uso em jogos ou outros apps que não são de vídeo
Embora o vídeo seja o principal caso de uso da API setFrameRate()
, ele pode ser
usados por outros apps. Por exemplo, um jogo que não pretende executar mais de
60 Hz (para reduzir o uso de energia e ter sessões de reprodução mais longas) pode chamar
Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
: Neste
Dessa forma, um dispositivo que executa a 90 Hz por padrão será executado a 60 Hz, enquanto o
está ativo, o que evita a trepidação que ocorreria se o
foi executado a 60 Hz, e a tela, a 90 Hz.
Uso de FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
O FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
é destinado apenas a apps de vídeo. Para
sem vídeo, use FRAME_RATE_COMPATIBILITY_DEFAULT
.
Como escolher uma estratégia para mudar o frame rate
- É altamente recomendável que os aplicativos, ao exibirem vídeos de longa duração,
filmes, chamada a
setFrameRate(
qps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
em que QPS é o frame rate do vídeo. - Não recomendamos apps que chamem
setFrameRate()
comCHANGE_FRAME_RATE_ALWAYS
. quando você espera que a reprodução do vídeo dure vários minutos ou menos.
Exemplo de integração para apps de reprodução de vídeo
Recomendamos as seguintes etapas para integrar as mudanças de taxa de atualização em apps de reprodução de vídeo:
- Decida a
changeFrameRateStrategy
:- Se estiver assistindo um vídeo de longa duração, como um filme, use
MATCH_CONTENT_FRAMERATE_ALWAYS
- Se estiver assistindo um vídeo curto, como um trailer de movimento, use
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
.
- Se estiver assistindo um vídeo de longa duração, como um filme, use
- Se o
changeFrameRateStrategy
forCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
, vá para a etapa 4. - Detecte se uma mudança de taxa de atualização não contínua está prestes a acontecer verificando
que ambos os fatos são verdadeiros:
- Não é possível mudar para o modo contínuo devido à taxa de atualização atual.
chamá-lo de C) ao frame rate do vídeo (vamos chamá-lo de V). Isso vai
se C e V forem diferentes e
Display.getMode().getAlternativeRefreshRates
não contém um múltiplo de V. - O usuário aceitou mudanças contínuas na taxa de atualização. Você pode detectar
isso verificando se
DisplayManager.getMatchContentFrameRateUserPreference
retornaMATCH_CONTENT_FRAMERATE_ALWAYS
- Não é possível mudar para o modo contínuo devido à taxa de atualização atual.
chamá-lo de C) ao frame rate do vídeo (vamos chamá-lo de V). Isso vai
se C e V forem diferentes e
- Se a migração for simples, faça o seguinte:
- Chamar
setFrameRate
e passarfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, echangeFrameRateStrategy
, em quefps
é o frame rate do vídeo. - Iniciar a reprodução do vídeo
- Chamar
- Se uma mudança de modo não contínua estiver prestes a acontecer, faça o seguinte:
- Mostre a UX para notificar o usuário. Recomendamos que você implemente uma forma que o usuário dispense essa UX e ignore o atraso adicional na etapa 5.d. Isso é porque o atraso recomendado é maior que o necessário em telas que exibir tempos de troca mais rápidos.
- Chamar
setFrameRate
e passarfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, eCHANGE_FRAME_RATE_ALWAYS
,fps
é o frame rate do vídeo. - Aguarde o evento
onDisplayChanged
o retorno de chamada. - Aguarde 2 segundos para que a troca de modo seja concluída.
- Iniciar a reprodução do vídeo
O pseudocódigo para oferecer suporte apenas à alternância perfeita é o seguinte:
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();
O pseudocódigo para oferecer suporte a alternâncias contínuas e não contínuas, conforme descrito acima, é o seguinte:
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();
}