API kecepatan frame memungkinkan aplikasi memberi tahu platform Android tentang frame yang diinginkan dan tersedia di aplikasi yang menargetkan Android 11 (level API 30) atau yang lebih tinggi. Biasanya, sebagian besar perangkat hanya mendukung kecepatan refresh layar tunggal, biasanya 60 Hz, tetapi ini telah berubah. Sekarang banyak perangkat mendukung kecepatan refresh, seperti 90 Hz atau 120 Hz. Beberapa perangkat mendukung kecepatan refresh yang lancar {i>switch<i}, sementara yang lain menampilkan layar hitam sebentar, biasanya berlangsung beberapa detik.
Tujuan utama API ini adalah agar aplikasi dapat memanfaatkan semuanya dengan lebih baik
kecepatan refresh tampilan yang didukung. Misalnya, aplikasi yang memutar video 24 Hz
yang memanggil setFrameRate()
dapat menyebabkan perangkat mengubah tampilan
kecepatan refresh dari 60 Hz hingga 120 Hz. Kecepatan refresh baru ini memungkinkan
kelancaran dan
Pemutaran bebas judder untuk video 24Hz, tanpa perlu pulldown 3:2 seperti yang
yang diperlukan untuk memutar video yang sama pada layar 60 Hz. Ini menghasilkan pengguna
yang lebih baik
pengalaman yang lancar bagi developer.
Penggunaan dasar
Android mengekspos beberapa cara untuk mengakses dan mengontrol platform, sehingga ada
beberapa versi setFrameRate()
API. Setiap versi API menggunakan
parameter yang sama dan bekerja
sama dengan yang lain:
Surface.setFrameRate()
SurfaceControl.Transaction.setFrameRate()
ANativeWindow_setFrameRate()
ASurfaceTransaction_setFrameRate()
Aplikasi tidak perlu mempertimbangkan kecepatan refresh layar aktual yang didukung,
yang dapat diperoleh
dengan memanggil
Display.getSupportedModes()
,
untuk memanggil setFrameRate()
dengan aman. Misalnya, meskipun
perangkat hanya
mendukung 60 Hz, panggil setFrameRate()
dengan kecepatan frame yang disukai aplikasi Anda.
Perangkat yang tidak memiliki kecocokan yang lebih baik untuk kecepatan frame aplikasi akan tetap digunakan
kecepatan refresh tampilan saat ini.
Untuk melihat apakah panggilan ke setFrameRate()
menyebabkan perubahan pada pemuatan ulang tampilan
memberi rating, mendaftar notifikasi perubahan tampilan dengan memanggil
DisplayManager.registerDisplayListener()
atau AChoreographer_registerRefreshRateCallback()
.
Saat memanggil setFrameRate()
, sebaiknya teruskan kecepatan frame yang tepat, bukan
pembulatan ke bilangan bulat. Misalnya, saat merender video yang direkam pada
29,97Hz, teruskan 29,97, bukan dibulatkan ke 30.
Untuk aplikasi video, parameter kompatibilitas yang diteruskan ke setFrameRate()
harus disetel
kepada Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
guna memberikan petunjuk tambahan untuk
platform Android tempat aplikasi akan menggunakan pulldown untuk beradaptasi dengan
menampilkan kecepatan refresh (yang akan menyebabkan judder).
Dalam beberapa skenario, platform video akan berhenti mengirimkan frame, tetapi akan tetap ada
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 kecepatan frame yang disetel ke 0 untuk menghapus
pengaturan kecepatan frame kembali ke nilai default. Menghapus setelan kecepatan frame
seperti ini tidak diperlukan saat menghancurkan permukaan, atau ketika permukaan
disembunyikan karena pengguna beralih ke aplikasi lain. Hapus kecepatan frame
setelan hanya saat permukaannya tetap terlihat tanpa digunakan.
Tombol kecepatan frame tidak mulus
Di beberapa perangkat, pengalihan kecepatan refresh dapat menyebabkan gangguan visual seperti warna hitam
layar selama satu atau dua detik. Hal ini biasanya terjadi pada
dekoder, 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 video yang lebih panjang. Ini memungkinkan kecepatan refresh layar untuk mencocokkan kecepatan frame video, dan menghindari artefak konversi kecepatan frame seperti 3:2 judder pulldown untuk pemutaran film.
Karena alasan ini, pengalihan kecepatan refresh yang tidak mulus dapat diaktifkan jika keikutsertaan pengguna dan aplikasi:
- Pengguna: Untuk memilih ikut serta, pengguna dapat mengaktifkan pengguna Cocok dengan kecepatan frame konten deskripsi tempat.
- Aplikasi: Untuk ikut serta, aplikasi dapat melewati
CHANGE_FRAME_RATE_ALWAYS
kesetFrameRate()
.
Sebaiknya selalu gunakan CHANGE_FRAME_RATE_ALWAYS
untuk video berdurasi
lama seperti film. Hal ini karena manfaat pencocokan
kecepatan frame video lebih besar daripada gangguan yang terjadi saat mengubah
kecepatan refresh.
Rekomendasi tambahan
Ikuti rekomendasi berikut untuk skenario umum.
Beberapa platform
Platform Android dirancang untuk menangani skenario dengan benar ketika
beberapa platform dengan setelan kecepatan frame yang berbeda. Jika aplikasi memiliki beberapa
dengan kecepatan frame berbeda, panggil setFrameRate()
dengan
kecepatan frame untuk setiap permukaan. Meskipun perangkat menjalankan beberapa aplikasi pada
sekali, menggunakan layar terpisah atau mode gambar-dalam-gambar, setiap aplikasi dapat memanggil
setFrameRate()
untuk platformnya sendiri.
Platform tidak berubah ke kecepatan frame aplikasi
Bahkan jika perangkat mendukung kecepatan frame yang ditentukan aplikasi dalam panggilan untuk
setFrameRate()
, ada kasus saat perangkat tidak dapat mengalihkan layar ke
kecepatan refresh tersebut. Misalnya, platform dengan prioritas yang lebih tinggi mungkin memiliki
pengaturan kecepatan frame, atau perangkat mungkin dalam mode penghemat baterai (menyetel
pembatasan kecepatan refresh layar untuk menghemat baterai). Aplikasi harus tetap
bekerja dengan benar ketika perangkat tidak mengalihkan kecepatan refresh layar ke
pengaturan kecepatan bingkai aplikasi, meskipun perangkat beralih dalam kondisi normal
situasi.
Aplikasi dapat menentukan cara merespons saat kecepatan refresh tampilan
tidak sesuai dengan
kecepatan frame aplikasi. Untuk video, kecepatan frame adalah tetap
video sumber, dan pulldown akan diperlukan untuk menampilkan konten video. J
game dapat memilih untuk mencoba berjalan pada kecepatan refresh tampilan,
tetap dengan kecepatan frame
yang diinginkan. Aplikasi tidak boleh mengubah nilai
diteruskan ke setFrameRate()
berdasarkan fungsi platform. Nilainya harus tetap disetel
ke kecepatan frame pilihan aplikasi, terlepas dari cara aplikasi menangani kasus saat
platform tidak menyesuaikan dengan
permintaan aplikasi. Dengan begitu, jika perangkat
perubahan kondisi untuk memungkinkan kecepatan refresh tampilan tambahan digunakan,
memiliki informasi yang benar untuk beralih ke {i>frame<i} pilihan aplikasi
besar.
Jika aplikasi tidak atau tidak dapat berjalan pada kecepatan refresh layar, aplikasi harus menentukan stempel waktu presentasi untuk setiap {i>frame<i}, menggunakan salah satu mekanisme platform ini untuk menyetel stempel waktu presentasi:
Menggunakan stempel waktu ini juga akan menghentikan platform untuk menampilkan bingkai aplikasi lebih awal, yang akan menyebabkan Anda tidak perlu bertele-tele. Penggunaan frame yang benar stempel waktu presentasi sedikit rumit. Untuk game, lihat panduan kecepatan frame untuk info selengkapnya tentang menghindari goyang, dan pertimbangkan untuk menggunakan Library Android Frame Pacing.
Pada beberapa kasus, platform dapat beralih ke beberapa kecepatan frame aplikasi
yang ditentukan dalam setFrameRate()
. Misalnya, aplikasi dapat memanggil setFrameRate()
dengan 60 Hz dan perangkat dapat mengalihkan layar ke 120 Hz. Salah satu alasan
ini mungkin
adalah jika aplikasi lain memiliki permukaan dengan pengaturan kecepatan frame 24 Hz. Di beberapa
dalam hal ini, menjalankan layar pada 120Hz akan
memungkinkan permukaan 60Hz dan
24 Hz untuk dijalankan tanpa perlu pulldown.
Saat layar berjalan pada beberapa kecepatan frame aplikasi, aplikasi harus menentukan stempel waktu presentasi untuk setiap {i>frame<i} untuk menghindari judder. Untuk game, library Android Frame Pacing berguna untuk pengaturan waktu presentasi {i>frame<i}.
setFrameRate() vs PreferredDisplayModeId
WindowManager.LayoutParams.preferredDisplayModeId
adalah cara lain bagi aplikasi untuk
menunjukkan kecepatan {i>frame<i} mereka ke platform. Agak besar
aplikasi hanya ingin mengubah kecepatan refresh tampilan, bukan mengubah
pengaturan mode tampilan, seperti resolusi tampilan. Secara umum, gunakan
setFrameRate()
, bukan preferredDisplayModeId
. setFrameRate()
lebih mudah digunakan karena aplikasi tidak perlu mencari melalui
daftar mode tampilan untuk menemukan mode
dengan kecepatan frame tertentu.
setFrameRate()
memberi platform lebih banyak peluang untuk memilih aplikasi yang kompatibel
kecepatan frame dalam skenario di mana ada beberapa platform yang berjalan pada
kecepatan frame yang berbeda. Misalnya, perhatikan skenario di mana dua aplikasi
berjalan dalam mode layar terpisah di Pixel 4, dengan satu aplikasi memutar video 24 Hz
dan tampilan lainnya menampilkan
daftar yang dapat di-scroll kepada pengguna. Pixel 4 mendukung dua
kecepatan refresh layar: 60 Hz dan 90 Hz. Dengan menggunakan preferredDisplayModeId
API,
permukaan video dipaksa untuk memilih 60Hz atau 90Hz. Dengan memanggil
setFrameRate()
dengan 24 Hz, permukaan video memberikan lebih banyak hal kepada platform
informasi tentang kecepatan frame video sumber, sehingga platform dapat
pilih 90Hz untuk kecepatan refresh layar, yang lebih baik dari 60Hz
yang lebih besar.
Namun, ada beberapa skenario saat preferredDisplayModeId
harus digunakan
bukan setFrameRate()
, seperti berikut:
- Jika aplikasi ingin mengubah resolusi atau pengaturan mode tampilan lainnya,
gunakan
preferredDisplayModeId
. - Platform hanya akan beralih mode tampilan sebagai respons terhadap panggilan ke
setFrameRate()
jika tombol mode ringan dan kecil kemungkinannya terlihat jelas oleh pengguna. Jika aplikasi memilih untuk mengalihkan refresh layar tetap kecepatannya meskipun memerlukan tombol mode berat (misalnya, di Android TV perangkat), gunakanpreferredDisplayModeId
. - Aplikasi yang tidak dapat menangani tampilan yang berjalan pada beberapa frame aplikasi
kecepatan, yang memerlukan pengaturan stempel waktu presentasi pada setiap {i>frame<i}, harus
gunakan
preferredDisplayModeId
.
setFrameRate() vs PreferredRefreshRate
WindowManager.LayoutParams#preferredRefreshRate
menyetel kecepatan frame yang diinginkan di jendela aplikasi, dan kecepatan tersebut berlaku
ke semua permukaan di dalam jendela. Aplikasi harus menentukan preferensinya
kecepatan frame tanpa memperhatikan kecepatan refresh yang didukung perangkat, mirip dengan
setFrameRate()
, untuk memberikan penjadwal petunjuk yang lebih baik tentang tujuan aplikasi
kecepatan frame.
preferredRefreshRate
diabaikan untuk Platform yang menggunakan setFrameRate()
. Di beberapa
gunakan setFrameRate()
secara umum jika memungkinkan.
PreferredRefreshRate vs PreferredDisplayModeId
Jika aplikasi hanya ingin mengubah kecepatan refresh pilihan, sebaiknya gunakan
preferredRefreshRate
, bukan preferredDisplayModeId
.
Menghindari terlalu sering memanggil setFrameRate()
Meskipun performa panggilan setFrameRate()
tidak terlalu mahal,
aplikasi harus menghindari memanggil setFrameRate()
setiap frame atau beberapa kali per
kedua. Panggilan ke setFrameRate()
kemungkinan akan mengakibatkan perubahan pada
kecepatan refresh tampilan, yang dapat mengakibatkan penurunan frame selama transisi.
Anda harus mencari tahu kecepatan frame
yang benar sebelumnya dan
setFrameRate()
sekali.
Penggunaan untuk game atau aplikasi non-video lainnya
Meskipun video adalah kasus penggunaan utama untuk setFrameRate()
API, video dapat
digunakan untuk aplikasi lain. Misalnya, game yang tidak dimaksudkan untuk 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)
. Di sini
cara, perangkat yang berjalan pada 90 Hz secara {i>default<i}
akan berjalan pada 60 Hz sementara
game aktif, yang akan menghindari judder yang akan terjadi jika
game berlari pada 60 Hz sementara layar berjalan pada 90 Hz.
Penggunaan FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
hanya ditujukan untuk aplikasi video. Sebagai
penggunaan non-video, gunakan FRAME_RATE_COMPATIBILITY_DEFAULT
.
Memilih strategi untuk mengubah kecepatan frame
- Kami sangat merekomendasikan agar aplikasi, saat menampilkan video berdurasi panjang seperti
film, panggil
setFrameRate(
fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
di mana fps adalah kecepatan frame video. - Sebaiknya jangan aplikasi yang memanggil
setFrameRate()
denganCHANGE_FRAME_RATE_ALWAYS
saat pemutaran video diperkirakan akan berlangsung selama beberapa menit atau kurang.
Contoh integrasi untuk aplikasi pemutaran video
Sebaiknya lakukan langkah-langkah berikut untuk mengintegrasikan tombol kecepatan refresh di aplikasi pemutaran video:
- Tentukan
changeFrameRateStrategy
:- Jika memutar video berdurasi panjang seperti film, gunakan
MATCH_CONTENT_FRAMERATE_ALWAYS
- Jika memutar video singkat seperti cuplikan gerak, gunakan
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
- Jika memutar video berdurasi panjang seperti film, gunakan
- Jika
changeFrameRateStrategy
adalahCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
, lanjutkan ke langkah 4. - Mendeteksi apakah pengalihan kecepatan refresh yang tidak lancar akan terjadi dengan memeriksa
bahwa kedua fakta ini benar:
- Peralihan mode yang mulus tidak dimungkinkan dari kecepatan refresh saat ini (mari kita
sebut saja C) dengan kecepatan frame video (sebut V). Hal ini akan
akan terjadi jika C dan V berbeda dan
Display.getMode().getAlternativeRefreshRates
tidak berisi kelipatan V. - Pengguna telah memilih untuk ikut serta dalam perubahan kecepatan refresh yang tidak lancar. Anda dapat mendeteksi
ini dengan memeriksa apakah
DisplayManager.getMatchContentFrameRateUserPreference
menampilkanMATCH_CONTENT_FRAMERATE_ALWAYS
- Peralihan mode yang mulus tidak dimungkinkan dari kecepatan refresh saat ini (mari kita
sebut saja C) dengan kecepatan frame video (sebut V). Hal ini akan
akan terjadi jika C dan V berbeda dan
- Jika peralihan lancar, lakukan hal berikut:
- Panggil
setFrameRate
dan meneruskanfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, danchangeFrameRateStrategy
, denganfps
adalah kecepatan frame video. - Mulai pemutaran video
- Panggil
- Jika perubahan mode yang tidak lancar akan terjadi, lakukan hal berikut:
- Tampilkan UX untuk memberi tahu pengguna. Perhatikan bahwa kami sarankan Anda menerapkan cara untuk pengguna untuk menutup UX ini dan melewati penundaan tambahan di langkah 5.d. Ini adalah karena penundaan yang kami rekomendasikan lebih besar dari yang diperlukan pada layar yang menunjukkan waktu peralihan yang lebih cepat.
- Panggil
setFrameRate
dan meneruskanfps
,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
, danCHANGE_FRAME_RATE_ALWAYS
, denganfps
adalah kecepatan frame video. - Tunggu hingga
onDisplayChanged
. - Tunggu 2 detik sampai 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();
}