Kecepatan frame

API kecepatan frame memungkinkan aplikasi memberi tahu platform Android tentang kecepatan frame yang diinginkan dan tersedia di aplikasi yang menargetkan Android 11 (API level 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 rasio refresh tambahan 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 pemutaran video 24 Hz yang lancar tanpa guncangan, tanpa memerlukan pulldown 3:2 seperti yang diperlukan untuk memutar video yang sama di layar 60 Hz. Hal ini menghasilkan pengalaman pengguna yang lebih baik.

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:

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 diinginkan aplikasi Anda. Perangkat yang tidak memiliki kecocokan yang lebih baik untuk kecepatan frame aplikasi akan tetap menggunakan kecepatan refresh layar saat ini.

Untuk melihat apakah panggilan ke setFrameRate() menghasilkan perubahan pada kecepatan refresh layar, daftar untuk notifikasi perubahan layar 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,97 Hz, teruskan 29,97, bukan membulatkan 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 kecepatan refresh layar yang tidak cocok (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 hal ini, panggil setFrameRate() dengan parameter kecepatan frame yang ditetapkan ke 0 untuk menghapus setelan kecepatan frame platform kembali ke nilai default. Menghapus setelan kecepatan frame seperti ini tidak diperlukan saat menghancurkan platform, atau saat platform disembunyikan karena pengguna beralih ke aplikasi lain. Hapus setelan kecepatan frame hanya jika platform 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 API Surface.setFrameRate() dipanggil, untuk menghindari gangguan visual tersebut.

Beberapa pengguna lebih menyukai gangguan visual di awal dan akhir 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, tombol kecepatan refresh yang tidak lancar dapat diaktifkan jika pengguna dan aplikasi memilih ikut serta:

Sebaiknya Anda selalu menggunakan CHANGE_FRAME_RATE_ALWAYS untuk video berdurasi panjang 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 permukaan dengan setelan kecepatan frame yang berbeda. Jika aplikasi Anda memiliki beberapa platform dengan kecepatan frame yang berbeda, panggil setFrameRate() dengan kecepatan frame yang benar untuk setiap platform. Meskipun perangkat menjalankan beberapa aplikasi sekaligus menggunakan mode layar terpisah atau picture-in-picture, setiap aplikasi dapat memanggil setFrameRate() dengan aman 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 berfungsi dengan benar saat perangkat tidak mengalihkan kecepatan refresh layar ke setelan kecepatan frame aplikasi, meskipun perangkat beralih dalam keadaan normal.

Aplikasi dapat menentukan cara merespons saat kecepatan refresh layar tidak cocok dengan kecepatan frame aplikasi. Untuk video, kecepatan frame adalah tetap video sumber, dan pulldown akan diperlukan untuk menampilkan konten video. Game mungkin memilih untuk mencoba berjalan pada kecepatan refresh layar, bukan tetap menggunakan kecepatan frame yang diinginkan. Aplikasi tidak boleh mengubah nilai yang diteruskan ke setFrameRate() berdasarkan tindakan platform. Nilai ini harus tetap ditetapkan ke kecepatan frame pilihan aplikasi, terlepas dari cara aplikasi menangani kasus saat platform tidak menyesuaikan untuk mencocokkan 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:

Penggunaan stempel waktu ini akan menghentikan platform untuk menampilkan frame aplikasi terlalu awal, yang akan menyebabkan guncangan 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.

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 dengan kelipatan kecepatan frame aplikasi, aplikasi harus menentukan stempel waktu presentasi untuk setiap frame guna menghindari judder yang tidak perlu. 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. Fungsi setFrameRate() lebih mudah digunakan karena aplikasi tidak perlu menelusuri daftar mode tampilan untuk menemukan mode dengan kecepatan frame tertentu.

setFrameRate() memberi platform lebih banyak peluang untuk memilih kecepatan frame yang kompatibel dalam skenario saat ada beberapa platform yang berjalan pada kecepatan frame 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 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, platform video akan memberikan informasi selengkapnya tentang kecepatan frame video sumber, sehingga platform dapat memilih 90 Hz untuk kecepatan refresh layar, yang lebih baik daripada 60 Hz dalam skenario ini.

Namun, ada 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), gunakan preferredDisplayModeId.
  • Aplikasi yang tidak dapat menangani tampilan yang berjalan dengan kelipatan kecepatan frame aplikasi, yang memerlukan setelan stempel waktu presentasi di setiap frame, harus menggunakan preferredDisplayModeId.

setFrameRate() vs PreferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate menetapkan kecepatan frame yang diinginkan pada jendela aplikasi, dan kecepatan tersebut berlaku untuk semua platform dalam jendela. Aplikasi harus menentukan rasio frame yang diinginkan, terlepas dari rasio refresh yang didukung perangkat, mirip dengan setFrameRate(), untuk memberi penjadwal petunjuk yang lebih baik tentang rasio frame yang diinginkan aplikasi.

preferredRefreshRate diabaikan untuk Platform yang menggunakan setFrameRate(). Secara umum, gunakan setFrameRate() jika memungkinkan.

preferredRefreshRate vs preferredDisplayModeId

Jika aplikasi hanya ingin mengubah kecepatan refresh yang diinginkan, sebaiknya gunakan preferredRefreshRate, bukan preferredDisplayModeId.

Menghindari terlalu sering memanggil setFrameRate()

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 menyebabkan perubahan pada kecepatan refresh layar, yang dapat menyebabkan penurunan frame selama transisi. Anda harus mengetahui kecepatan frame 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, 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. Untuk penggunaan non-video, gunakan FRAME_RATE_COMPATIBILITY_DEFAULT.

Memilih strategi untuk mengubah kecepatan frame

  • Sebaiknya aplikasi, saat menampilkan video berdurasi panjang seperti film, memanggil setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) dengan fps adalah kecepatan frame video.
  • Sebaiknya jangan gunakan aplikasi yang memanggil setFrameRate() dengan CHANGE_FRAME_RATE_ALWAYS jika Anda ingin pemutaran video berlangsung beberapa menit atau kurang.

Contoh integrasi untuk aplikasi pemutaran video

Sebaiknya lakukan langkah-langkah berikut untuk mengintegrasikan tombol kecepatan refresh di aplikasi pemutaran video:

  1. Tentukan changeFrameRateStrategy:
    1. Jika memutar video berdurasi panjang seperti film, gunakan MATCH_CONTENT_FRAMERATE_ALWAYS
    2. Jika memutar video singkat seperti cuplikan film, gunakan CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
  2. Jika changeFrameRateStrategy adalah CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, lanjutkan ke langkah 4.
  3. Mendeteksi apakah pengalihan kecepatan refresh yang tidak lancar akan terjadi dengan memeriksa bahwa kedua fakta ini benar:
    1. 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.
    2. Pengguna telah memilih untuk mengaktifkan perubahan kecepatan refresh yang tidak lancar. Anda dapat mendeteksi ini dengan memeriksa apakah DisplayManager.getMatchContentFrameRateUserPreference menampilkan MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Agar peralihan berjalan lancar, lakukan hal berikut:
    1. Panggil setFrameRate dan teruskan fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, dan changeFrameRateStrategy, dengan fps adalah kecepatan frame video.
    2. Mulai pemutaran video
  5. Jika perubahan mode yang tidak lancar akan terjadi, lakukan hal berikut:
    1. 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. Hal ini karena penundaan yang kami rekomendasikan lebih besar dari yang diperlukan pada layar yang menampilkan waktu pengalihan yang lebih cepat.
    2. Panggil setFrameRate dan meneruskan fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, dan CHANGE_FRAME_RATE_ALWAYS, dengan fps adalah kecepatan frame video.
    3. Tunggu hingga onDisplayChanged .
    4. Tunggu 2 detik hingga tombol mode selesai.
    5. Mulai pemutaran video

Kode semu untuk hanya mendukung pengalihan 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();
}