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. Geleneksel olarak çoğu cihaz yalnızca tek bir ekran yenileme hızını (genellikle 60 Hz) destekler. Ancak bu durum değişiyor. Birçok cihaz artık 90 Hz veya 120 Hz gibi ek yenileme hızlarını destekliyor. Bazı cihazlar yenileme hızı geçişlerini kesintisiz olarak desteklerken bazıları genellikle bir saniye süren kısa bir süreliğine siyah ekran gösterir.
API'nin birincil amacı, uygulamaların desteklenen tüm ekran yenileme hızlarından daha iyi yararlanmasını sağlamaktır. Ö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ü aynı parametreleri alır ve diğerleriyle aynı şekilde çalışır:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
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()
işlevini uygulamanızın tercih ettiği kare hızıyla çağırın.
Uygulamanın kare hızıyla daha iyi eşleşmeyen cihazlar mevcut ekran yenileme hızını kullanmaya devam eder.
setFrameRate()
adresine yapılan bir çağrı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()
numarasını 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ğı (bu da titremeye neden olur) konusunda ek bir ipucu vermek üzere Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
olarak ayarlanmalıdır.
Bazı durumlarda video yüzeyi kare göndermeyi durdurur ancak ekranda bir süre görünür kalı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ış setFrameRate()
işlevini çağırın. Yüzey yok edildiğinde veya kullanıcı farklı bir uygulamaya geçtiği için yüzey gizlendiğinde kare hızı ayarının bu şekilde temizlenmesi gerekmez. Kare hızı ayarını yalnızca yüzey kullanılmadan görünür durumda kaldığında temizleyin.
Sorunlu kare hızı geçişi
Bazı cihazlarda, yenileme hızı geçişi sırasında bir veya iki saniye boyunca siyah ekran gibi görsel kesintiler yaşanabilir. 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, uzun videoların başında ve sonunda görsel kesinti olmasını tercih eder. Bu sayede ekranın yenileme hızı video kare hızıyla eşleşebilir ve film oynatma sırasında 3:2 aşağı kaydırma sarsıntısı gibi kare hızı dönüşümü kusurları önlenebilir.
Bu nedenle, hem kullanıcı hem de uygulamalar etkinleştirirse kesintisiz olmayan yenileme hızı geçişleri etkinleştirilebilir:
- Kullanıcılar: Kullanıcılar, bu özelliği etkinleştirmek için İçerik kare hızını eşle kullanıcı ayarını etkinleştirebilir.
- Uygulamalar: Uygulamalar, etkinleştirmek için
CHANGE_FRAME_RATE_ALWAYS
ilesetFrameRate()
arasında geçiş yapabilir.
Film gibi uzun videolar için her zaman CHANGE_FRAME_RATE_ALWAYS
kullanmanızı öneririz. 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, farklı kare hızı ayarlarına sahip birden fazla yüzeyin bulunduğu senaryoları doğru şekilde işlemek için tasarlanmıştır. Uygulamanızda farklı kare hızlarına sahip birden fazla yüzey varsa her yüzey için doğru kare hızıyla setFrameRate()
işlevini çağırın. Cihaz aynı anda birden fazla uygulamayı çalıştırsa bile bölünmüş ekran veya pencere içinde pencere modu kullanılarak 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 setFrameRate()
çağrısında belirttiği kare hızını desteklese bile ekranı bu yenileme hızına geçirmeyebilir. Ö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, cihaz ekran yenileme hızını uygulamanın kare hızı ayarına geçirmediğinde uygulama düzgün çalışmaya devam etmelidir.
Ekran yenileme hızı, uygulama kare hızıyla eşleşmediğinde nasıl yanıt verileceğine uygulama karar verir. 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. Bir oyun, tercih edilen kare hızında kalmak yerine ekran yenileme hızında çalışmayı deneyebilir. Uygulama, platformun yaptığı işleme bağlı olarak setFrameRate()
'e ilettiği değeri değiştirmemelidir. Platformun, uygulamanın isteğine uygun şekilde ayarlanmadığı durumlarda uygulamanın nasıl davrandığına bakılmaksızın, uygulamanın tercih ettiği kare hızında ayarlanmalıdır. Böylece, cihaz koşulları ek ekran yenileme hızlarının kullanılmasına izin verecek şekilde değişirse platform, uygulamanın tercih ettiği kare hızına geçmek için doğru bilgilere sahip olur.
Uygulamanın ekran yenileme hızında çalışmadığı veya çalışamadığı durumlarda, uygulama, platformun zaman damgası ayarlama mekanizmalarından birini kullanarak her kare için zaman damgası belirtmelidir:
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 setFrameRate()
içinde belirttiği kare hızının bir katına geçebilir. Örneğin, bir uygulama setFrameRate()
60 Hz ile çağırabilir ve cihaz ekranı 120 Hz'e geçirebilir. Bunun nedeni, başka bir uygulamanın 24 Hz kare hızı ayarı olan bir yüzeye sahip olması olabilir. 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. Android Frame Pacing kitaplığı, oyunlarda kare sunma zaman damgalarını doğru şekilde ayarlamak için faydalıdır.
setFrameRate() ve preferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
uygulamaların, kare hızlarını platforma belirtmesinin bir başka 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()
kullanın. Uygulamanın belirli bir kare hızına sahip bir mod bulmak için görüntü modu listesinde arama yapması gerekmediğinden setFrameRate()
işlevi daha kolay kullanılır.
setFrameRate()
, farklı kare hızlarında çalışan birden fazla yüzeyin bulunduğu senaryolarda platforma uyumlu bir kare hızı seçme konusunda daha fazla fırsat sunar. Örneğin, Pixel 4'te iki uygulamanın bölünmüş ekran modunda çalıştığı bir senaryo düşünün. Bu senaryodaki uygulamalardan biri 24 Hz video oynatırken diğeri kullanıcıya kaydırılabilir bir liste gösteriyor. Pixel 4, iki ekran yenileme hızını destekler: 60 Hz ve 90 Hz. preferredDisplayModeId
API'si kullanılarak video yüzeyi 60 Hz veya 90 Hz'i seçmeye 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, bu senaryoda 60 Hz'den daha iyidir.
Bununla birlikte, setFrameRate()
yerine preferredDisplayModeId
kullanılması gereken senaryolar da vardır. Ö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 mod geçişi hafif ve kullanıcının fark etmesi olası değilse
setFrameRate()
çağrısına yanıt olarak ekran modlarını değiştirir. Uygulama, ağır mod geçişi gerektirse bile ekran yenileme hızını değiştirmeyi tercih ediyorsa (ör. Android TV cihazında)preferredDisplayModeId
değerini 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 Surface'ler için yoksayılır. Mümkünse genel olarak 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çının
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()
çağrıları, ekran yenileme hızında bir değişikliğe neden olabilir. Bu da geçiş sırasında kare atlamasına yol açabilir.
Doğru kare hızını önceden belirlemeniz ve setFrameRate()
işlevini bir kez çağırmanız gerekir.
Oyunlar veya video dışı diğer uygulamalar için kullanım
setFrameRate()
API'nin birincil kullanım alanı video olsa da diğer uygulamalarda da kullanılabilir. Ö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. Video dışındaki kullanımlar için FRAME_RATE_COMPATIBILITY_DEFAULT
değerini kullanın.
Kare hızını değiştirmek için strateji seçme
- Uygulamaların, film gibi uzun videolar gösterirken
setFrameRate(
fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
değerini çağırmasını önemle tavsiye ederiz. Burada fps, videonun kare hızıdır. - Video oynatma işleminin birkaç dakika veya daha kısa sürmesini beklediğiniz durumlarda
setFrameRate()
işleviniCHANGE_FRAME_RATE_ALWAYS
ile çağıran uygulamaları kullanmamanızı önemle tavsiye ederiz.
Video oynatma uygulamaları için örnek entegrasyon
Yenileme hızı anahtarlarını video oynatma uygulamalarına entegre etmek için aşağıdaki adımları uygulamanızı öneririz:
changeFrameRateStrategy
'ye karar verin:- Film gibi uzun bir videoyu oynatıyorsanız
MATCH_CONTENT_FRAMERATE_ALWAYS
simgesini kullanın. - Film fragmanı gibi kısa bir videoyu oynatıyorsanız
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
simgesini kullanın.
- Film gibi uzun bir videoyu oynatıyorsanız
changeFrameRateStrategy
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
ise 4. adıma geçin.- Aşağıdakilerin her ikisinin de doğru olup olmadığını kontrol ederek sorunsuz olmayan bir yenileme hızı geçişinin gerçekleşip gerçekleşmeyeceğini algılayın:
- 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. - Kullanıcı, yenileme hızı değişikliklerinin sorunsuz olmayan sürümünü etkinleştirmişse.
DisplayManager.getMatchContentFrameRateUserPreference
işlevininMATCH_CONTENT_FRAMERATE_ALWAYS
değerini döndürüp döndürmediğini kontrol ederek bunu tespit edebilirsiniz.
- 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
- Geçiş sorunsuz olacaksa aşağıdakileri yapın:
setFrameRate
işlevini çağırın vefps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
vechangeFrameRateStrategy
parametrelerini iletin.fps
, videonun kare hızıdır.- Video oynatmayı başlatma
- Sorunsuz olmayan bir mod değişikliği gerçekleşmek üzereyse aşağıdakileri yapın:
- 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.
setFrameRate
işlevini çağırın vefps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
veCHANGE_FRAME_RATE_ALWAYS
parametrelerini iletin.fps
, videonun kare hızıdır.onDisplayChanged
geri aramasını bekleyin.- Mod geçişinin tamamlanması için 2 saniye bekleyin.
- Video oynatmayı başlatma
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();
}