Kare hızı API'si, uygulamaların Android platformunu amaçlanan kare hızları hakkında bilgilendirmesine olanak tanır ve Android 11'i (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) desteklerdi 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 kesintisiz yenileme hızı geçişlerini desteklerken diğerleri genellikle bir saniye süren kısa bir siyah ekran gösterir.
API'nin asıl amacı, uygulamaların desteklenen tüm ekran yenileme hızlarından daha iyi yararlanmasını sağlamaktır. Örneğin, setFrameRate()
işlevini çağıran 24 Hz'lik bir video oynatan 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 videoların 60 Hz ekranda oynatılması için gerekli olan 3:2 aşağı çekme işlemi olmadan sorunsuz ve titremesiz oynatılmasını sağlar. Bu sayede daha iyi bir kullanıcı deneyimi elde edilir.
Temel kullanım
Android, yüzeylere erişmek ve bunları kontrol etmek için çeşitli yöntemler sunar. Bu nedenle, setFrameRate()
API'nin çeşitli sürümleri 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()
işlevini güvenli bir şekilde çağırmak için Display.getSupportedModes()
işlevi çağrılarak elde edilebilen, desteklenen gerçek ekran yenileme hızlarını dikkate alması gerekmez. Örneğin, cihaz yalnızca 60 Hz'i desteklese bile uygulamanızın tercih ettiği kare hızıyla setFrameRate()
işlevini ç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()
numarasına yapılan bir aramanın ekran yenileme hızında değişikliğe neden olup olmadığını görmek için DisplayManager.registerDisplayListener()
veya AChoreographer_registerRefreshRateCallback()
numaralarını arayarak ekran değişikliği bildirimlerine kaydolun.
setFrameRate()
işlevini çağırırken tamsayıya yuvarlamak yerine tam kare hızını iletmek en iyisidir. Örneğin, 29,97 Hz'de kaydedilen bir video oluşturulurken 30'a yuvarlamak yerine 29,97 değerini iletin.
Video uygulamalarında, setFrameRate()
öğesine iletilen uyumluluk parametresi, uygulamanın eşleşmeyen bir ekran yenileme hızına uyum sağlamak için açılır menü kullanacağını Android platformuna bildirmek ü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 bir süre boyunca ekranda görünmeye devam eder. Oynatma, videonun sonuna ulaştığında veya kullanıcı oynatmayı duraklattığında bu durum yaygın olarak görülür. Bu durumlarda, yüzeyin kare hızı ayarını varsayılan değere geri döndürmek için kare hızı parametresi 0 olarak ayarlanmış şekilde setFrameRate()
işlevini çağırın. Yüzey yok edilirken 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 kalırsa temizleyin.
Kare hızı geçişi sorunsuz değil
Bazı cihazlarda yenileme hızı değiştirilirken bir veya iki saniye boyunca siyah ekran gibi görsel kesintiler yaşanabilir. Bu durum genellikle set üstü kutularda, TV panellerinde ve benzeri cihazlarda görülür. Android çerçevesi, bu tür görsel kesintileri önlemek için Surface.setFrameRate()
API'si çağrıldığında varsayılan olarak mod değiştirmez.
Bazı kullanıcılar, uzun videoların başında ve sonunda görsel kesintileri tercih eder. Bu sayede ekranın yenileme hızı, video kare hızıyla eşleşir ve film oynatma sırasında 3:2 pulldown judder gibi kare hızı dönüştürme yapaylıkları önlenir.
Bu nedenle, hem kullanıcı hem de uygulamalar kabul ederse sorunsuz olmayan yenileme hızı geçişleri etkinleştirilebilir:
- Kullanıcılar: Kullanıcılar, İçerik kare hızını eşleştir kullanıcı ayarını etkinleştirerek bu özelliği kullanabilir.
- Uygulamalar: Uygulamalar, etkinleştirmek için
CHANGE_FRAME_RATE_ALWAYS
değerinisetFrameRate()
içine iletebilir.
Filmler gibi uzun süren 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ı değiştirilirken oluşan kesintiden daha fazla olmasıdır.
Ek öneriler
Sık karşılaşılan senaryolar için 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şleyecek şekilde tasarlanmıştır. Uygulamanızın farklı kare hızlarına sahip birden fazla yüzeyi varsa her yüzey için doğru kare hızıyla setFrameRate()
işlevini çağırın. Cihaz aynı anda birden fazla uygulama çalıştırıyor olsa bile (bölünmüş ekran veya pencere içinde pencere modu kullanılıyorsa) her uygulama kendi yüzeyleri için setFrameRate()
'ı güvenli bir şekilde çağırabilir.
Platform, uygulamanın kare hızına geçmiyor
Cihaz, setFrameRate()
çağrısında uygulamanın belirttiği kare hızını desteklese bile ekranı bu yenileme hızına geçirmeyebilir. Örneğin, daha yüksek önceliğe sahip bir yüzeyin farklı bir kare hızı ayarı olabilir veya cihaz pil tasarrufu modunda olabilir (pili korumak için ekran yenileme hızına kısıtlama getirilmiş olabilir). Cihaz normal şartlarda geçiş yapsa bile ekran yenileme hızı, uygulamanın kare hızı ayarına geçmediğinde uygulama yine de 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. Videoda kare hızı, kaynak videonun kare hızına sabitlenir ve video içeriğini göstermek için pulldown işlemi gerekir. Bir oyun, tercih ettiği kare hızında kalmak yerine ekran yenileme hızında çalışmayı deneyebilir. Uygulama, platformun yaptıklarına bağlı olarak setFrameRate()
öğesine ilettiği değeri değiştirmemelidir. Uygulamanın, platformun uygulamadan gelen isteğe göre ayarlanmadığı durumları nasıl ele aldığına bakılmaksızın, uygulamanın tercih ettiği kare hızına ayarlanmış olarak kalmalıdır. Bu sayede, cihaz koşulları değişerek ek ekran yenileme hızlarının kullanılmasına izin verilirse 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, uygulamanın her kare için sunum zaman damgalarını belirtmesi gerekir. Bunun için platformun sunum zaman damgalarını ayarlamaya yönelik mekanizmalarından biri kullanılmalıdır:
Bu zaman damgalarının kullanılması, platformun uygulama çerçevesini çok erken sunmasını engeller. Bu durum, gereksiz titremeye neden olur. Çerçeve sunumu zaman damgalarının doğru kullanımı biraz karmaşıktır. Oyunlarda titremeyi önleme hakkında daha fazla bilgi için Frame Pacing Kılavuzumuza göz atın ve Android Frame Pacing kitaplığını kullanmayı deneyin.
Bazı durumlarda platform, uygulamanın setFrameRate()
içinde belirttiği kare hızının katlarına geçebilir. Örneğin, bir uygulama setFrameRate()
ile 60 Hz'de arama yapabilir ve cihaz, ekranı 120 Hz'e geçirebilir. Bunun nedeni, başka bir uygulamanın 24 Hz kare hızı ayarına sahip 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, pulldown işlemi gerektirmeden çalışmasına olanak tanır.
Ekran, uygulamanın kare hızının katı bir hızda çalışırken gereksiz titremeyi önlemek için uygulama her kareye sunum zaman damgaları belirtmelidir. Android Frame Pacing kitaplığı, oyunlarda kare sunumu zaman damgalarını doğru şekilde ayarlamak için faydalıdır.
setFrameRate() ve preferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
uygulamaların platforma kare hızlarını bildirmesinin 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 modu bulmak için görüntüleme modları listesinde arama yapması gerekmediğinden setFrameRate()
işlevinin kullanımı daha kolaydır.
setFrameRate()
, farklı kare hızlarında çalışan birden fazla yüzeyin olduğu senaryolarda platforma uyumlu bir kare hızı seçme konusunda daha fazla fırsat sunar. Örneğin, Pixel 4'te bölünmüş ekran modunda iki uygulamanın çalıştığı bir senaryoyu ele alalım. Bu uygulamalardan biri 24 Hz'lik bir video oynatırken diğeri kullanıcıya kaydırılabilir bir liste gösteriyor. Pixel 4'te iki ekran yenileme hızı desteklenir: 60 Hz ve 90 Hz. preferredDisplayModeId
API'si kullanıldığında video yüzeyi 60 Hz veya 90 Hz'i seçmek zorunda kalır. 24 Hz ile setFrameRate()
çağrısı yapıldığında video yüzeyi, platforma kaynak videonun kare hızı hakkında daha fazla bilgi verir. Bu sayede platform, ekran yenileme hızı için bu senaryoda 60 Hz'den daha iyi olan 90 Hz'i seçebilir.
Ancak aşağıdaki gibi durumlarda preferredDisplayModeId
yerine setFrameRate()
kullanılmalıdır:
- Uygulama çözünürlüğü veya diğer ekran modu ayarlarını değiştirmek isterse
preferredDisplayModeId
simgesini kullanın. - Platform, yalnızca
setFrameRate()
çağrısına yanıt olarak görüntüleme modlarını değiştirir. Bu değişiklik, hafifse ve kullanıcı tarafından fark edilme olasılığı düşükse. Uygulama, ağır mod geçişi gerektirse bile (ör. Android TV cihazında) ekran yenileme hızını değiştirmeyi tercih ediyorsapreferredDisplayModeId
kullanın. - Uygulamanın kare hızının katı olarak çalışan ekranı işleyemeyen ve her karede 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ını ayarlar ve bu hız, penceredeki tüm yüzeyler için geçerlidir. Uygulama, planlayıcıya uygulamanın amaçlanan kare hızı hakkında daha iyi bir ipucu vermek için cihazın desteklenen yenileme hızlarından bağımsız olarak tercih ettiği kare hızını belirtmelidir. Bu, setFrameRate()
ile benzerdir.
preferredRefreshRate
, setFrameRate()
kullanan yüzeylerde yoksayılır. Genel olarak mümkünse 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 her karede veya saniyede birden çok kez setFrameRate()
çağrısı yapmaktan kaçınmalıdır. setFrameRate()
'a yapılan aramalar, ekran yenileme hızında değişikliğe neden olabilir. Bu da geçiş sırasında kare düşmesine yol açabilir.
Doğru kare hızını önceden belirlemeli ve setFrameRate()
işlevini bir kez çağırmalısınız.
Oyunlar veya video olmayan diğer uygulamalarda kullanım
setFrameRate()
API'nin birincil kullanım alanı video olsa da diğer uygulamalar için de kullanılabilir. Örneğin, güç kullanımını azaltmak ve daha uzun oyun oturumları elde etmek için 60 Hz'den daha yüksek bir hızda çalışmaması amaçlanan 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 etkin durumdayken 60 Hz'de çalışır. Bu da, oyun 60 Hz'de çalışırken ekran 90 Hz'de çalışırsa oluşacak titremeyi önler.
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
kullanın.
Kare hızını değiştirme stratejisi seçme
- Uygulamaların, filmler gibi uzun süren 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,
setFrameRate()
ileCHANGE_FRAME_RATE_ALWAYS
işlevini çağıran uygulamaları kesinlikle önermiyoruz.
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ı öneririz:
changeFrameRateStrategy
karar verin:- Film gibi uzun süren bir video oynatıyorsanız
MATCH_CONTENT_FRAMERATE_ALWAYS
simgesini kullanın. - Film fragmanı gibi kısa bir video oynatılıyorsa
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
kullanılmalıdır.
- Film gibi uzun süren bir video oynatıyorsanız
changeFrameRateStrategy
simgesiCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
ise 4. adıma gidin.- Aşağıdaki iki koşulun da doğru olup olmadığını kontrol ederek sorunsuz olmayan bir yenileme hızı geçişinin gerçekleşmek üzere olup olmadığını tespit edin:
- Mevcut yenileme hızından (buna C diyelim) videonun kare hızına (buna V diyelim) sorunsuz mod geçişi mümkün değildir. C ve V farklıysa ve
Display.getMode().getAlternativeRefreshRates
, V'nin katlarını içermiyorsa bu durum geçerlidir. - Kullanıcı, sorunsuz olmayan yenileme hızı değişikliklerini etkinleştirmişse.
DisplayManager.getMatchContentFrameRateUserPreference
değerininMATCH_CONTENT_FRAMERATE_ALWAYS
döndürüp döndürmediğini kontrol ederek bunu tespit edebilirsiniz.
- Mevcut yenileme hızından (buna C diyelim) videonun kare hızına (buna V diyelim) sorunsuz mod geçişi mümkün değildir. 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
değerlerini iletin. Buradafps
, 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 kapatmasına ve 5.d adımındaki ek gecikmeyi atlamasına olanak tanıyan bir yöntem uygulamanızı öneririz. Bunun nedeni, daha hızlı geçiş süreleri gösteren ekranlarda önerdiğimiz gecikmenin gerekenden daha uzun olmasıdır.
setFrameRate
işlevini çağırın vefps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
veCHANGE_FRAME_RATE_ALWAYS
değerlerini iletin. Buradafps
, 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
Kesintisiz geçişi yalnızca 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 sorunsuz olmayan geçişi destekleyen sözde kod aşağıda verilmiştir:
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();
}