Kare hızı

Kare hızı API'si, uygulamaların Android platformunu amaçlanan kare hızları hakkında bilgilendirmesine olanak tanır ve Android 11 (API düzeyi 30) veya sonraki sürümleri hedefleyen uygulamalarda kullanılabilir. Önceden çoğu cihaz yalnızca tek bir ekran yenileme hızını destekliyordu. ancak bu değer değişti. Birçok cihaz artık 90 Hz veya 120 Hz gibi yenileme hızları. Bazı cihazlar yenileme hızı geçişlerini kesintisiz şekilde desteklerken bazıları genellikle bir saniye süren kısa bir süreliğine siyah ekran gösterir.

API'nin birincil amacı, uygulamaların tüm Android platformlarından daha iyi desteklenen ekran yenileme hızlarını ayarlar. Örneğin, setFrameRate() çağrısı yapan ve 24 Hz video oynatan bir uygulama, cihazın ekran yenileme hızını 60 Hz'den 120 Hz'ye değiştirmesine neden olabilir. Bu yeni yenileme hızı, 24 Hz videonun 60 Hz ekranda oynatılması için gereken 3:2 kaydırma işlemine gerek kalmadan sorunsuz ve takılma olmadan oynatılmasını sağlar. Bu, daha iyi bir kullanıcı deneyimi sağlar.

Temel kullanım

Android, yüzeylere erişmek ve bunları kontrol etmek için çeşitli yöntemler sunar. Bu nedenle, setFrameRate() API'nin birkaç sürümü vardır. API'nin her sürümü ve diğerleriyle aynı şekilde çalışır:

Uygulamanın, setFrameRate()'ı güvenli bir şekilde çağırmak için desteklenen gerçek ekran yenileme hızlarını dikkate alması gerekmez. Bu hızları Display.getSupportedModes() çağrısı yaparak elde edebilirsiniz. Örneğin, cihaz yalnızca 60 Hz'i destekliyorsa setFrameRate() uygulamasını uygulamanızın tercih ettiği kare hızıyla arayın. Uygulamanın kare hızı için daha iyi bir eşleşmeye sahip olmayan cihazlar yenileme hızına ayarlanır.

setFrameRate() çağrısının ekran yenileme hızında bir değişikliğe yol açıp açmadığını görmek için DisplayManager.registerDisplayListener() veya AChoreographer_registerRefreshRateCallback() numaralı telefondan arayarak ekran değişikliği bildirimlerine kaydolun.

setFrameRate() işlevini çağırırken, tam kare hızını bir tam sayıya yuvarlamak yerine tam olarak iletmek en iyisidir. Örneğin, 29,97 Hz'de kaydedilen bir videoyu oluştururken 30'a yuvarlamak yerine 29,97 değerini iletin.

Video uygulamaları için setFrameRate() parametresine iletilen uyumluluk parametresi, Android platformuna uygulamanın eşleşmeyen bir ekran yenileme hızına uyum sağlamak için açılır menüyü kullanacağıyla ilgili ek bir ipucu vermek üzere Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE olarak ayarlanmalıdır (bu da titremeye neden olur).

Bazı senaryolarda video yüzeyi, kare göndermeyi durdurur ancak bu şekilde kalır. ekranda bir süre görünür. Oynatma işleminin videonun sonuna ulaşması veya kullanıcının oynatmayı duraklatması gibi durumlar yaygın senaryolardır. Bu durumlarda, yüzeyin kare hızı ayarını varsayılan değere döndürmek için kare hızı parametresi 0 olarak ayarlanmış şekilde setFrameRate()'ü çağırın. Kare hızı ayarı temizleniyor Örneğin, yüzeyleri yok ederken veya yüzey düzlemi çalışırken kullanıcı farklı bir uygulamaya geçtiği için gizlidir. Kare hızını temizle yalnızca yüzey kullanılmadan görünür kaldığında ayarlanır.

Kesintisiz olmayan kare hızı anahtarı

Bazı cihazlarda, yenileme hızı geçişinde siyah gibi görsel kesintiler olabilir bir iki saniyeliğine ekranda kalır. Bu durum genellikle set üstü kutularda, TV panellerinde ve benzer cihazlarda görülür. Android çerçevesi, bu tür görsel kesintileri önlemek için varsayılan olarak Surface.setFrameRate() API'si çağrıldığında mod değiştirmez.

Bazı kullanıcılar başlangıçta görsel bir kesintiyi uzun videoların sonu gelir. Bu, ekranın yenileme hızının eşleşmesini sağlar Video kare hızını değiştirmeyin ve 3:2 gibi kare hızı dönüştürme eserlerinden kaçının. titremesini kullanabilirsiniz.

Bu nedenle, kesintisiz olmayan yenileme hızı anahtarları hem kullanıcı ve uygulama etkinleştirmesi:

Her zaman CHANGE_FRAME_RATE_ALWAYS kullanmanızı öneririz. filmler gibi uzun süreli videolar için. Bunun nedeni, video kare hızını eşleştirmenin avantajının, yenileme hızını değiştirirken oluşan kesintinin ağır basmasıdır.

Ek öneriler

Sık karşılaşılan senaryolarda aşağıdaki önerileri uygulayın.

Birden fazla yüzey

Android platformu, mobil cihazlarda bir sürü Farklı kare hızı ayarlarına sahip birden fazla yüzey Uygulamanızda birden fazla farklı kare hızlarına sahip yüzeyler için setFrameRate() çağırarak doğru her yüzeyin kare hızını artırabilirsiniz. Cihaz bölünmüş ekran veya pencere içinde pencere modunu kullanarak birden fazla uygulamayı çalıştırsa bile her uygulama kendi yüzeyleri için setFrameRate()'ü güvenli bir şekilde çağırabilir.

Platform, uygulamanın kare hızına göre değişmez.

Cihaz, uygulamanın bir çağrıda belirttiği kare hızını desteklese bile setFrameRate(), cihazın ekranı yenileme hızında gösterilir. Örneğin, daha yüksek öncelikli bir yüzeyin farklı bir kare hızı ayarı olabilir veya cihaz pil tasarrufu modunda olabilir (pil tasarrufu için ekran yenileme hızında kısıtlama ayarlanır). Cihaz normal şartlarda ekran yenileme hızını uygulamanın kare hızı ayarına geçirse bile uygulama, cihaz ekran yenileme hızını uygulamanın kare hızı ayarına geçirmediğinde de düzgün şekilde çalışmaya devam etmelidir.

Ekran yenileme hızına ne zaman yanıt verileceğine uygulama karar verir. uygulamanın kare hızıyla eşleşmiyor. Video için kare hızı, kaynak videonun kare hızına sabitlenir ve video içeriğini göstermek için açılır menü gerekir. CEVAP Bunun yerine oyun, yerine ekranın yenileme hızında tercih ettiği kare hızında kalmaya devam eder. Uygulama, değeri değiştirmemelidir. platformun ne yaptığına bağlı olarak setFrameRate() için geçilir. Ayarlanmış durumda kalmalıdır uygulamanın tercih edilen kare hızına platform, uygulamanın isteğiyle eşleşecek şekilde ayarlanmaz. Bu şekilde cihazın ek ekran yenileme hızlarının kullanılmasına izin verecek şekilde değişirse, platform, uygulamanın tercih edilen çerçevesine geçmek için doğru bilgilere sahip oranıdır.

Uygulama, ekran yenileme hızında çalışmadığı veya çalışamadığı durumlarda, platformun sunum zaman damgalarını ayarlamak için kullandığı mekanizmalar:

Bu zaman damgalarını kullanmak, platformun uygulama çerçevesini çok erken sunmasını engeller. Bu da gereksiz sarsıntılara neden olur. Çerçeve sunma zaman damgalarının doğru kullanımı biraz karmaşıktır. Oyunlarda titremeden kaçınma hakkında daha fazla bilgi için kare hızı kılavuzumuza göz atın ve Android Frame Pacing kitaplığını kullanmayı düşünün.

Bazı durumlarda platform, uygulamanın kare hızının katlarından birine geçiş yapabilir setFrameRate() içinde belirtilir. Örneğin, bir uygulama setFrameRate() çağırabilir 60 Hz'e çevirebilir ve cihaz ekranı 120 Hz'e geçirebilir. Bunun nedenlerinden biri, başka bir uygulamanın yüzeyi 24 Hz kare hızı ayarına sahip olduğunda görülür. Bu durumda, ekranı 120 Hz'de çalıştırmak hem 60 Hz yüzeyin hem de 24 Hz yüzeyin, kaydırma gerekmeden çalışmasına olanak tanır.

Ekran, uygulamanın kare hızının bir katı hızda çalışırken uygulama, gereksiz titremeyi önlemek için her kare için sunma zaman damgalarını belirtmelidir. Oyunlarda Android Frame Pacing kitaplığını doğru çerçeve sunumu zaman damgalarını ayarlayabilirsiniz.

setFrameRate() ve preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId uygulamaların kare hızlarını platforma bildirmelerinin başka bir yoludur. Bazı uygulamalar, ekran çözünürlüğü gibi diğer ekran modu ayarlarını değiştirmek yerine yalnızca ekran yenileme hızını değiştirmek ister. Genel olarak, preferredDisplayModeId yerine setFrameRate(). setFrameRate() işlevinin kullanılması daha kolaydır, çünkü uygulamanın belirli bir kare hızına sahip modu bulmak için görüntü modları listesinden yararlanın.

setFrameRate(), uyumlu bir seçim yapması için platforma daha fazla fırsat sunar birden fazla yüzeyin olduğu senaryolarda kare hızı farklı kare hızlarında görüntülenebilir. Örneğin, iki uygulamanın aynı olduğu bir senaryoyu Pixel 4'te bölünmüş ekran modunda çalışan (bir uygulamanın 24 Hz video oynattığı) diğeri ise kullanıcıya kaydırılabilir bir liste gösteriyor. Pixel 4 iki cihazı destekler görüntü yenileme hızları: 60 Hz ve 90 Hz. preferredDisplayModeId API'yi kullanarak, video yüzeyi 60 Hz veya 90 Hz seçilmeye zorlanır. Video yüzeyi, setFrameRate() işlevini 24 Hz ile çağırarak platforma kaynak videonun kare hızı hakkında daha fazla bilgi verir. Bu sayede platform, görüntü yenileme hızı için 90 Hz'i seçebilir. Bu, söz konusu senaryoda 60 Hz'den daha iyidir.

Bununla birlikte, preferredDisplayModeId işlevinin kullanılması gereken senaryolar da vardır. yerine setFrameRate() kullanabilirsiniz. Örneğin:

  • Uygulama, çözünürlüğü veya diğer ekran modu ayarlarını değiştirmek istiyorsa preferredDisplayModeId değerini kullanın.
  • Platform yalnızca şu çağrıya yanıt olarak görüntü modlarını değiştirir: Mod anahtarı hafifse ve çok düşük değilse setFrameRate() fark edebilirsiniz. Uygulama, ekranı yenilemeyi tercih ederse yoğun mod anahtarı gerektirse bile (örneğin, Android TV'de cihaz) preferredDisplayModeId kullanın.
  • Görüntünün, uygulamanın kare hızının bir katı hızda çalışmasını kaldıramayan uygulamalar (bu durumda her karede zaman damgası ayarlaması gerekir) preferredDisplayModeId değerini kullanmalıdır.

setFrameRate() ve preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate, uygulamanın penceresinde tercih edilen bir kare hızı belirler. Bu hız, penceredeki tüm yüzeyler için geçerlidir. Uygulama, planlayıcıya uygulamanın amaçlanan kare hızıyla ilgili daha iyi bir ipucu vermek için setFrameRate()'e benzer şekilde, cihazın desteklediği yenileme hızlarından bağımsız olarak tercih ettiği kare hızını belirtmelidir.

preferredRefreshRate, setFrameRate() kullanan yüzeyler için yoksayılır. İçinde genel kullanım için setFrameRate() kullanın.

preferredRefreshRate ve preferredDisplayModeId

Uygulamalar yalnızca tercih edilen yenileme hızını değiştirmek istiyorsa preferredDisplayModeId yerine preferredRefreshRate kullanılması tercih edilir.

setFrameRate() işlevini çok sık çağırmaktan kaçınma

setFrameRate() çağrısı performans açısından çok maliyetli olmasa da uygulamaların setFrameRate() çağrısını her karede veya saniyede birden çok kez çağırmaktan kaçınması gerekir. setFrameRate() numaralı telefona yapılan aramaların, yenileme hızında gösterilir. Bu da geçiş sırasında kare düşüşüne neden olabilir. Doğru kare hızını önceden belirlemeniz ve Bir kez setFrameRate().

Oyunlar veya video dışı diğer uygulamalar için kullanım

setFrameRate() API'nin başlıca kullanım alanı video olsa da diğer uygulamalar için kullanılır. Örneğin, 60 Hz'den daha yüksek bir hızda çalışmayı amaçlayan (güç kullanımını azaltmak ve daha uzun oyun oturumları elde etmek için) bir oyun Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) işlevini çağırabilir. Bu sayede, varsayılan olarak 90 Hz'de çalışan bir cihaz, oyun etkinken 60 Hz'de çalışır. Böylece, oyun 60 Hz'de çalışırken ekran 90 Hz'de çalışıyorsa oluşabilecek takılmalar önlenir.

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE kullanımı

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE yalnızca video uygulamaları için tasarlanmıştır. Örneğin, video dışı kullanım için FRAME_RATE_COMPATIBILITY_DEFAULT kullanın.

Kare hızını değiştirmek için strateji seçme

  • Aşağıdaki gibi uzun süreli videoları görüntülerken uygulamaların filmler, setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)'yi ara Burada fps, videonun kare hızıdır.
  • CHANGE_FRAME_RATE_ALWAYS ile setFrameRate() çağıran uygulamaları kesinlikle önermeyiz Video oynatmanın birkaç dakika veya daha kısa sürmesini beklediğiniz durumlarda.

Video oynatma uygulamaları için örnek entegrasyon

Video oynatma uygulamalarına yenileme hızı anahtarlarını entegre etmek için aşağıdaki adımları uygulamanız önerilir:

  1. changeFrameRateStrategy değerine karar verin:
    1. Film gibi uzun bir videoyu oynatıyorsanız MATCH_CONTENT_FRAMERATE_ALWAYS simgesini kullanın.
    2. Film fragmanı gibi kısa bir video oynatıyorsanız CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS düğmesini kullanın.
  2. changeFrameRateStrategy CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS ise 4. adıma geçin.
  3. Kesintisiz olmayan yenileme hızı değişiminin gerçekleşip gerçekleşmediğini kontrol ederek iki gerçeğin de doğru olduğunu
    1. Mevcut yenileme hızından (C olarak adlandıralım) videonun kare hızına (V olarak adlandıralım) sorunsuz geçiş yapılamaz. C ve V farklıysa ve Display.getMode().getAlternativeRefreshRates, V'nin bir katını içermiyorsa bu durum söz konusudur.
    2. Kullanıcı, yenileme hızı değişikliklerinin sorunsuz olmayan sürümünü etkinleştirmişse Google'da DisplayManager.getMatchContentFrameRateUserPreference MATCH_CONTENT_FRAMERATE_ALWAYS değerini döndürür
  4. Geçiş sorunsuz olacaksa aşağıdakileri yapın:
    1. setFrameRate numaralı telefonu arayın ve fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, ve changeFrameRateStrategy (burada fps, videonun kare hızıdır).
    2. Video oynatmayı başlat
  5. Sorunsuz olmayan bir mod değişikliği gerçekleşmek üzereyse aşağıdakileri yapın:
    1. Kullanıcıyı bilgilendirmek için kullanıcı deneyimini gösterin. Kullanıcının bu kullanıcı deneyimini kapatıp 5.d adımında ek gecikmeyi atlayabileceği bir yöntem uygulamanızı öneririz. Bunun nedeni, önerilen gecikmenin daha hızlı geçiş süreleri gösteren ekranlarda gerekenden daha uzun olmasıdır.
    2. setFrameRate numaralı telefonu arayın ve fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, ve CHANGE_FRAME_RATE_ALWAYS Burada fps videonun kare hızıdır.
    3. onDisplayChanged geri aramasını bekleyin.
    4. Mod geçişinin tamamlanması için 2 saniye bekleyin.
    5. Video oynatmayı başlat

Sorunsuz geçişi yalnızca destekleyen sözde kod şu şekildedir:

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

Yukarıda açıklandığı gibi sorunsuz ve sorunsuz olmayan geçişleri destekleyen sözde kod şu şekildedir:

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