Kare hızı API'si, uygulamaların Android platformuna hedeflenen kare hızları hakkında bilgi vermesine 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 24 Hz'lik bir video oynatan bir uygulama, cihazın ekran yenileme hızını 60 Hz'den 120 Hz'e 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. Böylece daha iyi bir kullanıcı deneyimi sağlanır.
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()
ç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()
çağrılırken, bir tam sayıya yuvarlamak yerine tam kare hızını geçirmek en iyi seçenektir. Örneğin, 29,97 Hz'de kaydedilen bir videoyu oluştururken 30'a yuvarlamak yerine 29,97 değerini iletin.
Video uygulamalarında, setFrameRate()
öğesine iletilen uyumluluk parametresi Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
olarak ayarlanmalıdır. Bu sayede, Android platformuna, uygulamanın eşleşmeyen bir ekran yenileme hızına uyum sağlamak için açılır menüyü kullanacağına dair ek bir ipucu verilir (bu durum titremeye neden olur).
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 gibi durumlarda yüzeyin kare hızı ayarını varsayılan değere sıfırlamak için kare hızı parametresi 0'a ayarlanmış setFrameRate()
komutunu çağırın. Yüzeyi ortadan kaldırırken veya kullanıcı farklı bir uygulamaya geçtiği için yüzey gizlenirken 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 kaldığında temizleyin.
Kesintisiz olmayan kare hızı anahtarı
Bazı cihazlarda, yenileme hızı geçişinde bir veya iki saniye 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, ekranın yenileme hızının videonun kare hızıyla eşleşmesini sağlar ve film oynatımı için 3:2'lik aşağı çekme titremesi gibi kare hızı dönüştürme eserlerini önler.
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ştir kullanıcı ayarını etkinleştirebilir.
- Uygulamalar: Uygulamalar, etkinleştirmek için
CHANGE_FRAME_RATE_ALWAYS
ilesetFrameRate()
arasında geçiş yapabilir.
Filmler gibi uzun süreli videolar için her zaman CHANGE_FRAME_RATE_ALWAYS
kullanmanızı öneririz. Bunun nedeni, videonun kare hızını eşleştirmenin avantajının, yenileme hızı değiştirilirken oluşan kesintiden daha ağır bastığıdır.
Ek öneriler
Sık karşılaşılan senaryolar için bu önerileri uygulayın.
Birden fazla yüzey
Android platformu, farklı kare hızı ayarlarına sahip birden fazla yüzeyin olduğu senaryoları doğru şekilde yönetecek şekilde tasarlanmıştır. Uygulamanız farklı kare hızlarına sahip birden fazla yüzeye sahipse her yüzey için doğru kare hızıyla setFrameRate()
çağırın. 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, setFrameRate()
çağrısında belirtilen kare hızını desteklese bile bazı durumlarda 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 (pili korumak için ekranın yenileme hızıyla ilgili bir kısıtlama ayarlanır). Cihaz, ekran yenileme hızını uygulamanın kare hızı ayarına geçirmediğinde, cihaz normal koşullar altında değiştirilse bile uygulama doğru şekilde çalışmalıdır.
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 liste 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()
öğesine aktardığı 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. Bu şekilde, cihaz koşulları ek ekran yenileme hızlarının kullanılmasına izin verecek şekilde değişirse platform, uygulamanın tercih edilen 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 iki katı kadar hızda çalışıyorsa uygulama, gereksiz titremeyi önlemek amacıyla her kare için sunum zaman damgaları belirtmelidir. Android Frame Pacing kitaplığı, oyunlarda kare sunma zaman damgalarını doğru şekilde ayarlamak için faydalıdır.
setFrameRate() ve PreferredDisplayModeId karşılaştırması
WindowManager.LayoutParams.preferredDisplayModeId
, uygulamaların kare hızlarını platforma belirtmelerinin bir başka yoludur. Bazı uygulamalar, ekran çözünürlüğü gibi diğer görüntüleme modu ayarlarını değiştirmek yerine yalnızca ekranın 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 uygulamanın bir 24 Hz video oynattığı, diğerinin ise kullanıcıya kaydırılabilir bir liste gösterdiği bir senaryoyu düşünün. 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, söz konusu senaryoda 60 Hz'den daha iyidir.
Ancak aşağıdaki gibi durumlarda setFrameRate()
yerine preferredDisplayModeId
kullanılması gerekir:
- Uygulama, çözünürlüğü veya diğer ekran modu ayarlarını değiştirmek istiyorsa
preferredDisplayModeId
değerini kullanın. - Platform,
setFrameRate()
çağrısına yanıt olarak görüntü modlarını yalnızca mod anahtarı hafifse ve kullanıcı tarafından fark edilmeyecekse değiştirir. Uygulama, yoğun bir mod anahtarı gerektirse bile (örneğin, Android TV cihazında) ekran yenileme hızını değiştirmeyi tercih edersepreferredDisplayModeId
kullanın. - Uygulamanın kare hızının birden fazlasında ekranı işleyemeyen ve her kareye sunum zaman damgalarının ayarlanmasını gerektiren uygulamalar
preferredDisplayModeId
kullanmalıdır.
setFrameRate() ve preferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
, uygulamanın penceresinde tercih edilen kare hızı belirler ve bu hız pencere içindeki tüm yüzeyler için geçerli olur. Uygulama, planlayıcıya uygulamanın amaçlanan kare hızı hakkında daha iyi bir ipucu vermek için setFrameRate()
benzeri, cihazın desteklenen yenileme hızına bakılmaksızın 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 karşılaştırması
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, setFrameRate()
çağrısını her karede veya saniyede birden fazla kez yapmaktan kaçınmalıdır. setFrameRate()
için yapılan çağrıların, ekranın yenileme hızının değişmesine neden olabilir. Bu da geçiş sırasında karenin düşmesine neden olabilir.
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 yüksek çalışmaması (güç kullanımını azaltmak ve daha uzun oynama oturumları sağlamak için) bir oyun Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
çağırabilir. Bu şekilde, varsayılan olarak 90 Hz'de çalışan bir cihaz oyun aktifken 60 Hz'de çalışır. Bu da, ekran 90 Hz'de çalışırken oyunun 60 Hz'de çalışması halinde oluşabilecek titremelerden kaçınır.
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE kullanımı
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
yalnızca video uygulamaları için tasarlanmıştır. Video dışı kullanım 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 oynatmanın birkaç dakika veya daha kısa sürmesini beklediğiniz durumlarda,
CHANGE_FRAME_RATE_ALWAYS
ilesetFrameRate()
çağıran uygulamaları kesinlikle önermeyiz.
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
ile ilgili karar verin:- Film gibi uzun bir videoyu oynatıyorsanız
MATCH_CONTENT_FRAMERATE_ALWAYS
simgesini kullanın. - Film fragmanı gibi kısa bir video oynatıyorsanız
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
düğmesini kullanın.
- Film gibi uzun bir videoyu oynatıyorsanız
changeFrameRateStrategy
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
ise 4. adıma gidin.- Aşağıdakilerin her ikisinin de doğru olup olmadığını kontrol ederek sorunsuz olmayan bir yenileme hızı değişiminin gerçekleşip gerçekleşmediğini belirleyin:
- 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ı içermiyorsa bu durum söz konusudur. - Kullanıcı, kesintisiz olmayan yenileme hızı değişikliklerini etkinleştirdi.
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şlat
- 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 kapatmasını ve adım 5.d'deki ek gecikmeyi atlamasını sağlayacak bir yöntem uygulamanızı öneririz. Bunun nedeni, daha hızlı geçiş süreleri sunan ekranlarda önerilen gecikmenin gereğinden uzun olmasıdır.
setFrameRate
numaralı telefonu arayıpfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
veCHANGE_FRAME_RATE_ALWAYS
değerlerini iletin. Buradafps
, videonun kare hızıdır.onDisplayChanged
geri çağırmasını bekleyin.- Mod geçişinin tamamlanması için 2 saniye bekleyin.
- Video oynatmayı başlatma
Yalnızca sorunsuz geçişi destekleyen sözde kod aşağıdaki gibidir:
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 kesintisiz olmayan geçişi destekleyen sözde kod aşağıdaki gibidir:
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();
}