API frame rate memungkinkan aplikasi memberi tahu platform Android tentang frame rate yang diinginkan dan tersedia di aplikasi yang menargetkan Android 11 (API level 30) atau yang lebih tinggi. Biasanya, sebagian besar perangkat hanya mendukung satu rasio pembaruan tampilan, umumnya 60 Hz, tetapi hal ini telah berubah. Sekarang banyak perangkat mendukung rasio pembaruan lain, seperti 90 Hz atau 120 Hz. Beberapa perangkat mendukung peralihan rasio pembaruan yang lancar, sementara perangkat lain menampilkan layar hitam sebentar, biasanya berlangsung selama satu detik.
Tujuan utama API ini adalah agar aplikasi dapat memanfaatkan semua rasio pembaruan tampilan yang didukung dengan lebih baik. Misalnya, aplikasi yang memutar video 24 Hz yang memanggil setFrameRate() dapat menyebabkan perangkat mengubah rasio pembaruan tampilan dari 60 Hz menjadi 120 Hz. Rasio pembaruan baru ini memungkinkan pemutaran video 24 Hz yang lancar dan tanpa judder, tanpa memerlukan pulldown 3:2 seperti yang diperlukan untuk memutar video yang sama pada tampilan 60 Hz. Ini menghasilkan pengalaman pengguna yang lebih baik.
Penggunaan dasar
Android mengungkapkan beberapa cara untuk mengakses dan mengontrol permukaan, sehingga terdapat beberapa versi setFrameRate() API. Setiap versi API menggunakan parameter yang sama dan berfungsi sama seperti yang lain:
Surface.setFrameRate()SurfaceControl.Transaction.setFrameRate()ANativeWindow_setFrameRate()ASurfaceTransaction_setFrameRate()
Aplikasi tidak perlu mempertimbangkan rasio pembaruan tampilan yang sebenarnya didukung,
yang dapat diperoleh dengan memanggil
Display.getSupportedModes(),
untuk memanggil setFrameRate() dengan aman. Misalnya, meskipun perangkat hanya mendukung 60 Hz, panggil setFrameRate() dengan frame rate yang disukai aplikasi Anda.
Perangkat yang tidak memiliki kecocokan yang lebih baik untuk frame rate aplikasi akan tetap menggunakan rasio pembaruan tampilan saat ini.
Untuk melihat apakah panggilan ke setFrameRate() menghasilkan perubahan pada rasio pembaruan tampilan, daftarkan notifikasi perubahan tampilan dengan memanggilDisplayManager.registerDisplayListener()atau AChoreographer_registerRefreshRateCallback().
Saat memanggil setFrameRate(), sebaiknya teruskan frame rate yang tepat, bukan pembulatan ke bilangan bulat. Misalnya, saat merender video yang direkam pada 29,97 Hz, teruskan 29,97, bukan pembulatan ke 30.
Untuk aplikasi video, parameter kompatibilitas yang diteruskan ke setFrameRate() harus ditetapkan ke Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE untuk memberikan petunjuk tambahan ke platform Android bahwa aplikasi akan menggunakan pulldown untuk beradaptasi dengan rasio pembaruan tampilan yang tidak cocok (yang akan menghasilkan judder).
Dalam beberapa skenario, permukaan video akan berhenti mengirimkan frame, tetapi akan tetap terlihat di layar selama beberapa waktu. Skenario umum mencakup saat pemutaran mencapai akhir video atau saat pengguna menjeda pemutaran. Dalam kasus ini, panggil setFrameRate() dengan parameter frame rate yang ditetapkan ke 0 untuk menghapus setelan frame rate permukaan kembali ke nilai default. Menghapus setelan frame rate seperti ini tidak diperlukan saat menghancurkan permukaan, atau saat permukaan disembunyikan karena pengguna beralih ke aplikasi lain. Hapus setelan frame rate hanya jika permukaan tetap terlihat tanpa digunakan.
Peralihan frame rate yang tidak lancar
Di beberapa perangkat, peralihan rasio pembaruan mungkin mengalami gangguan visual seperti layar hitam selama satu atau dua detik. Hal ini biasanya terjadi pada set top box, panel TV, dan perangkat serupa. Secara default, framework Android tidak beralih mode
saat Surface.setFrameRate()
API dipanggil, untuk menghindari gangguan visual tersebut.
Beberapa pengguna lebih menyukai gangguan visual di awal dan akhir video yang lebih panjang. Hal ini memungkinkan rasio pembaruan tampilan cocok dengan frame rate video, dan menghindari artefak konversi frame rate seperti judder pulldown 3:2 untuk pemutaran film.
Oleh karena itu, peralihan rasio pembaruan yang tidak lancar dapat diaktifkan jika pengguna dan aplikasi memilih untuk ikut:
- Pengguna: Untuk memilih ikut, pengguna dapat mengaktifkan setelan pengguna Cocokkan frame rate konten.
- Aplikasi: Untuk memilih ikut, aplikasi dapat meneruskan
CHANGE_FRAME_RATE_ALWAYSkesetFrameRate().
Sebaiknya Anda selalu menggunakan CHANGE_FRAME_RATE_ALWAYS
untuk video yang berjalan lama seperti film. Hal ini karena manfaat mencocokkan frame rate video lebih besar daripada gangguan yang terjadi saat mengubah rasio pembaruan.
Rekomendasi tambahan
Ikuti rekomendasi ini untuk skenario umum.
Beberapa permukaan
Platform Android didesain untuk menangani skenario dengan benar jika ada beberapa permukaan dengan setelan frame rate yang berbeda. Jika aplikasi Anda memiliki beberapa permukaan dengan frame rate yang berbeda, panggil setFrameRate() dengan frame rate yang benar untuk setiap permukaan. Meskipun perangkat menjalankan beberapa aplikasi sekaligus, menggunakan mode layar terpisah atau picture-in-picture, setiap aplikasi dapat memanggil setFrameRate() dengan aman untuk permukaannya sendiri.
Platform tidak berubah ke frame rate aplikasi
Meskipun perangkat mendukung frame rate yang ditentukan aplikasi dalam panggilan ke setFrameRate(), ada kasus ketika perangkat tidak akan mengalihkan tampilan ke rasio pembaruan tersebut. Misalnya, permukaan prioritas yang lebih tinggi mungkin memiliki setelan frame rate yang berbeda, atau perangkat mungkin dalam mode hemat baterai (menetapkan batasan pada rasio pembaruan tampilan untuk menghemat baterai). Aplikasi harus tetap berfungsi dengan benar saat perangkat tidak mengalihkan rasio pembaruan tampilan ke setelan frame rate aplikasi, meskipun perangkat beralih dalam keadaan normal.
Aplikasi harus memutuskan cara merespons saat rasio pembaruan tampilan tidak cocok dengan frame rate aplikasi. Untuk video, frame rate ditetapkan ke video sumber, dan pulldown akan diperlukan untuk menampilkan konten video. Game mungkin memilih untuk mencoba berjalan pada rasio pembaruan tampilan, bukan tetap menggunakan frame rate yang disukainya. Aplikasi tidak boleh mengubah nilai yang diteruskannya ke setFrameRate() berdasarkan tindakan platform. Aplikasi harus tetap ditetapkan ke frame rate yang disukai, terlepas dari cara aplikasi menangani kasus saat platform tidak menyesuaikan untuk mencocokkan permintaan aplikasi. Dengan begitu, jika kondisi perangkat berubah untuk memungkinkan penggunaan rasio pembaruan tampilan tambahan, platform akan memiliki informasi yang benar untuk beralih ke frame rate yang disukai aplikasi.
Jika aplikasi tidak akan atau tidak dapat berjalan pada rasio pembaruan tampilan, aplikasi harus menentukan stempel waktu presentasi untuk setiap frame, menggunakan salah satu mekanisme platform untuk menetapkan stempel waktu presentasi:
Penggunaan stempel waktu ini akan menghentikan platform menampilkan frame aplikasi terlalu awal, yang akan menghasilkan judder yang tidak perlu. Penggunaan stempel waktu presentasi frame yang benar agak rumit. Untuk game, lihat panduan kecepatan frame kami untuk mengetahui info selengkapnya tentang cara menghindari judder, dan pertimbangkan untuk menggunakan library Android Frame Pacing.
Dalam beberapa kasus, platform dapat beralih ke kelipatan frame rate yang ditentukan aplikasi di setFrameRate(). Misalnya, aplikasi dapat memanggil setFrameRate() dengan 60 Hz dan perangkat dapat mengalihkan tampilan ke 120 Hz. Salah satu alasan hal ini dapat terjadi adalah jika aplikasi lain memiliki permukaan dengan setelan frame rate 24 Hz. Dalam hal ini, menjalankan tampilan pada 120 Hz akan memungkinkan permukaan 60 Hz dan permukaan 24 Hz berjalan tanpa memerlukan pulldown.
Saat tampilan berjalan pada kelipatan frame rate aplikasi, aplikasi harus menentukan stempel waktu presentasi untuk setiap frame guna menghindari judder yang tidak perlu. Untuk game, library Android Frame Pacing berguna untuk menetapkan stempel waktu presentasi frame dengan benar.
setFrameRate() vs preferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
adalah cara lain yang dapat digunakan aplikasi untuk menunjukkan frame rate ke platform. Beberapa aplikasi hanya ingin mengubah rasio pembaruan tampilan, bukan mengubah setelan mode tampilan lainnya, seperti resolusi tampilan. Secara umum, gunakan setFrameRate() dan bukan preferredDisplayModeId. Fungsi setFrameRate() lebih mudah digunakan karena aplikasi tidak perlu menelusuri daftar mode tampilan untuk menemukan mode dengan frame rate tertentu.
setFrameRate() memberi platform lebih banyak peluang untuk memilih frame rate yang kompatibel dalam skenario ketika ada beberapa permukaan yang berjalan pada frame rate yang berbeda. Misalnya, pertimbangkan skenario saat dua aplikasi berjalan dalam mode layar terpisah di Pixel 4, dengan satu aplikasi memutar video 24 Hz dan aplikasi lainnya menampilkan daftar yang dapat di-scroll kepada pengguna. Pixel 4 mendukung dua rasio pembaruan tampilan: 60 Hz dan 90 Hz. Dengan menggunakan preferredDisplayModeId API, permukaan video dipaksa untuk memilih 60 Hz atau 90 Hz. Dengan memanggil setFrameRate() dengan 24 Hz, permukaan video memberi platform lebih banyak informasi tentang frame rate video sumber, sehingga platform dapat memilih 90 Hz untuk rasio pembaruan tampilan, yang lebih baik daripada 60 Hz dalam skenario ini.
Namun, ada skenario ketika preferredDisplayModeId harus digunakan, bukan setFrameRate(), seperti berikut:
- Jika aplikasi ingin mengubah resolusi atau setelan mode tampilan lainnya, gunakan
preferredDisplayModeId. - Platform hanya akan mengalihkan mode tampilan sebagai respons terhadap panggilan ke
setFrameRate()jika peralihan mode ringan dan kemungkinan tidak akan terlihat oleh pengguna. Jika aplikasi lebih suka mengalihkan rasio pembaruan tampilan meskipun memerlukan peralihan mode yang berat (misalnya, di perangkat Android TV), gunakanpreferredDisplayModeId. - Aplikasi yang tidak dapat menangani tampilan yang berjalan pada kelipatan frame rate aplikasi, yang memerlukan penetapan stempel waktu presentasi pada setiap frame, harus menggunakan
preferredDisplayModeId.
setFrameRate() vs preferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
menetapkan frame rate pilihan di jendela aplikasi, dan kecepatan berlaku untuk semua permukaan dalam jendela. Aplikasi harus menentukan frame rate yang disukainya, terlepas dari rasio pembaruan yang didukung perangkat, mirip dengan setFrameRate(), untuk memberikan petunjuk yang lebih baik kepada penjadwal tentang frame rate yang diinginkan aplikasi.
preferredRefreshRate diabaikan untuk Surface yang menggunakan setFrameRate(). Secara umum, gunakan setFrameRate() jika memungkinkan.
preferredRefreshRate vs preferredDisplayModeId
Jika aplikasi hanya ingin mengubah rasio pembaruan pilihan, sebaiknya gunakan preferredRefreshRate, bukan preferredDisplayModeId.
Menghindari panggilan setFrameRate() terlalu sering
Meskipun panggilan setFrameRate() tidak terlalu mahal dalam hal performa, aplikasi harus menghindari panggilan setFrameRate() setiap frame atau beberapa kali per detik. Panggilan ke setFrameRate() kemungkinan akan menghasilkan perubahan pada rasio pembaruan tampilan, yang dapat mengakibatkan frame drop selama transisi.
Anda harus mengetahui frame rate yang benar terlebih dahulu dan memanggil setFrameRate() sekali.
Penggunaan untuk game atau aplikasi non-video lainnya
Meskipun video adalah kasus penggunaan utama untuk setFrameRate() API, API ini dapat digunakan untuk aplikasi lain. Misalnya, game yang tidak ingin berjalan lebih tinggi dari 60 Hz (untuk mengurangi penggunaan daya dan mencapai sesi bermain yang lebih lama) dapat memanggil Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). Dengan cara ini, perangkat yang berjalan pada 90 Hz secara default akan berjalan pada 60 Hz saat game aktif, yang akan menghindari judder yang akan terjadi jika game berjalan pada 60 Hz saat tampilan berjalan pada 90 Hz.
Penggunaan FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE hanya ditujukan untuk aplikasi video. Untuk penggunaan non-video, gunakan FRAME_RATE_COMPATIBILITY_DEFAULT.
Memilih strategi untuk mengubah frame rate
- Sebaiknya aplikasi, saat menampilkan video yang berjalan lama seperti film, memanggil
setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)dengan fps adalah frame rate video. - Sebaiknya aplikasi tidak memanggil
setFrameRate()denganCHANGE_FRAME_RATE_ALWAYSjika Anda memperkirakan pemutaran video akan berlangsung selama beberapa menit atau kurang.
Contoh integrasi untuk aplikasi pemutaran video
Sebaiknya ikuti langkah-langkah berikut untuk mengintegrasikan peralihan rasio pembaruan di aplikasi pemutaran video:
- Tentukan
changeFrameRateStrategy:- Jika memutar video yang berjalan lama seperti film, gunakan
MATCH_CONTENT_FRAMERATE_ALWAYS - Jika memutar video pendek seperti trailer film, gunakan
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
- Jika memutar video yang berjalan lama seperti film, gunakan
- Jika
changeFrameRateStrategyadalahCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, lanjutkan ke langkah 4. - Deteksi apakah peralihan rasio pembaruan yang tidak lancar akan terjadi dengan memeriksa apakah kedua fakta ini benar:
- Peralihan mode yang lancar tidak mungkin dilakukan dari rasio pembaruan saat ini (sebut saja C) ke frame rate video (sebut saja V). Hal ini akan
terjadi jika C dan V berbeda dan
Display.getMode().getAlternativeRefreshRatestidak berisi kelipatan V. - Pengguna telah memilih untuk ikut perubahan rasio pembaruan yang tidak lancar. Anda dapat mendeteksi
ini dengan memeriksa apakah
DisplayManager.getMatchContentFrameRateUserPreferencemenampilkanMATCH_CONTENT_FRAMERATE_ALWAYS
- Peralihan mode yang lancar tidak mungkin dilakukan dari rasio pembaruan saat ini (sebut saja C) ke frame rate video (sebut saja V). Hal ini akan
terjadi jika C dan V berbeda dan
- Jika peralihan akan lancar, lakukan hal berikut:
- Panggil
setFrameRatedan teruskanfps,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, danchangeFrameRateStrategy, denganfpsadalah frame rate video. - Mulai pemutaran video
- Panggil
- Jika perubahan mode yang tidak lancar akan terjadi, lakukan hal berikut:
- Tampilkan UX untuk memberi tahu pengguna. Perhatikan bahwa sebaiknya Anda menerapkan cara agar pengguna dapat menutup UX ini dan melewati penundaan tambahan di langkah 5.d. Hal ini karena penundaan yang kami rekomendasikan lebih besar dari yang diperlukan pada tampilan yang menunjukkan waktu peralihan yang lebih cepat.
- Panggil
setFrameRatedan teruskanfps,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, danCHANGE_FRAME_RATE_ALWAYS, denganfpsadalah frame rate video. - Tunggu
onDisplayChangedcallback. - Tunggu 2 detik hingga peralihan mode selesai.
- Mulai pemutaran video
Kode semu untuk hanya mendukung peralihan yang lancar adalah sebagai berikut:
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
contentFrameRate,
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();
Kode semu untuk mendukung peralihan yang lancar dan tidak lancar seperti yang dijelaskan di atas adalah sebagai berikut:
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();
}