フレーム レート

フレームレート API を使用すると、アプリが Android プラットフォームに目的のフレームを通知できる Android 11(API レベル 30)以降をターゲットとするアプリで利用できます。 従来、ほとんどのデバイスが 1 つのディスプレイ リフレッシュ レート(一般に 60 Hz)にのみ対応していましたが、これは変わってきています。現在、多くのデバイスが リフレッシュレートを使用できます一部のデバイスはリフレッシュ レートのシームレスな切り替えをサポートしていますが、他のデバイスでは、通常 1 秒ほど黒い画面が表示されます。

API の主な目的は、サポートされているすべてのディスプレイ リフレッシュ レートをアプリがもっと活用できるようにすることです。たとえば、setFrameRate() を呼び出して 24 Hz の動画を再生するアプリでは、デバイスがディスプレイのリフレッシュ レートを 60 Hz から 120 Hz に変更する可能性があります。この新しいリフレッシュレートにより 24 Hz の動画をジャダーなしで再生でき、3:2 プルダウンの 同じ動画を 60 Hz ディスプレイで再生できます。これは、ユーザー エクスペリエンスの改善に貢献します。

基本的な使用方法

Android では、サーフェスにアクセスして操作する方法がいくつか用意されているため、 setFrameRate() API の複数のバージョン。各バージョンの API は同じパラメータを取り、他の API と同じように動作します。

実際にサポートされているディスプレイのリフレッシュ レートをアプリで考慮する必要はありません。 これは、次の呼び出しによって取得できます。 Display.getSupportedModes() setFrameRate() を安全に呼び出すために必要です。たとえば、デバイスが 60 Hz のみをサポートしている場合でも、アプリが優先するフレームレートで setFrameRate() を呼び出します。アプリのフレームレートに適したデバイスがない場合は、現在のディスプレイのリフレッシュ レートが維持されます。

setFrameRate() の呼び出しによってディスプレイの更新が変更されるかどうかを確認する 表示変更の通知に登録するには、 DisplayManager.registerDisplayListener() または AChoreographer_registerRefreshRateCallback()

setFrameRate() を呼び出すときは、整数に丸めずに正確なフレームレートを渡すことをおすすめします。たとえば、29.97 Hz で録画された動画をレンダリングする場合は、30 に丸めずに 29.97 を渡します。

動画アプリの場合は、setFrameRate() に渡される互換性パラメータを設定する必要があります 追加のヒントを Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE に指定できます。 一致しないものに適応するためにアプリがプルダウンを使用する Android プラットフォーム 表示のリフレッシュ レートを変更することもできます(この場合、揺れが生じます)。

場合によっては、動画サーフェスはフレームの送信を停止しますが、しばらくの間画面に表示されたままになります。一般的なシナリオとしては、再生が動画の最後まで到達したときや、ユーザーが再生を一時停止したときなどがあります。このような場合は、フレームレート パラメータを 0 に設定して setFrameRate() を呼び出し、サーフェスのフレームレート設定をデフォルト値に戻します。サーフェスを破棄する場合や、ユーザーが別のアプリに切り替えたためにサーフェスが非表示になった場合は、このようにフレームレート設定を消去する必要はありません。サーフェスが使用されずに表示されたままになっている場合にのみ、フレームレート設定を消去します。

シームレスでないフレームレートの切り替え

デバイスによっては、リフレッシュ レートの切り替え時に、画面が 1~2 秒黒くなるなどの視覚的な中断が発生することがあります。これは通常、セットトップ ボックス、テレビパネル、 同様のデバイスが含まれますデフォルトでは、このような視覚的な中断を回避するために、Android フレームワークは Surface.setFrameRate() API が呼び出されたときにモードを切り替えません。

ユーザーによっては、ゲームの開始時に視覚的な中断を望み、 長い動画の終わりです。これにより、ディスプレイのリフレッシュ レートが 動画のフレームレートを改善し、3:2 のようなフレームレート変換のアーティファクトを回避します。 ムービー再生用のプルダウン ジャダー。

そのため、非シームレスのリフレッシュ レートの切り替えは、 ユーザーとアプリのオプトイン:

常に CHANGE_FRAME_RATE_ALWAYS を使用することをおすすめします。 長時間の動画視聴に適していますこれは、動画のフレームレートを一致させるメリットが、リフレッシュ レートを変更する際に発生する中断よりも大きいためです。

その他の推奨事項

一般的なシナリオでは、以下の推奨事項に従ってください。

複数のサーフェス

Android プラットフォームは、フレームレート設定が異なる複数のサーフェスがあるシナリオを正しく処理するように設計されています。アプリにフレームレートが異なる複数のサーフェスがある場合は、各サーフェスの正しいフレームレートを指定して setFrameRate() を呼び出します。デバイスで分割画面モードまたはピクチャー イン ピクチャー モードを使用して複数のアプリを同時に実行している場合でも、各アプリは独自のサーフェスに対して setFrameRate() を安全に呼び出すことができます。

プラットフォームがアプリのフレームレートに変更されない

デバイスが setFrameRate() の呼び出しでアプリが指定したフレームレートをサポートしている場合でも、デバイスがディスプレイをその更新レートに切り替えない場合があります。たとえば、優先度の高いサーフェスには異なるフレームレート設定が適用されている場合や、デバイスがバッテリー セーバー モードになっている場合(バッテリーを節約するためにディスプレイの更新レートに制限が設定されている場合)などです。デバイスが通常の状況でディスプレイの更新レートをアプリのフレームレート設定に切り替える場合でも、デバイスがディスプレイの更新レートをアプリのフレームレート設定に切り替えない場合でも、アプリは正しく動作する必要があります。

ディスプレイのリフレッシュ レートがアプリのフレームレートと一致しない場合にどのように応答するかは、アプリによって異なります。動画の場合、フレームレートはソース動画のフレームレートに固定され、動画コンテンツを表示するにはプルダウンが必要になります。 ゲームは代わりにディスプレイのリフレッシュ レートで実行しようとし、 望ましいフレームレートを維持しますアプリはその値を変更してはなりません。 プラットフォームの動作に基づいて setFrameRate() に渡されます。設定されたままになっているはずです。 アプリが優先されるフレームレートで応答します。これは、 アプリのリクエストに一致するようにプラットフォームが調整されることはありません。こうすれば、 追加のディスプレイ リフレッシュ レートを使用できるようにする場合は、 アプリの優先フレームに切り替えるための正しい情報がプラットフォームにあること 。

アプリがディスプレイの更新レートで実行されない、または実行できない場合は、プレゼンテーション タイムスタンプを設定するプラットフォームのメカニズムのいずれかを使用して、フレームごとにプレゼンテーション タイムスタンプを指定する必要があります。

これらのタイムスタンプを使用すると、プラットフォームがアプリフレームを早すぎるタイミングで表示するのを防ぐことができ、不要なジャダーが発生しなくなります。フレームの正しい使用方法 表示タイムスタンプは少し複雑です。ゲームについては、 フレーム ペーシング ガイド をご覧ください。また、 Android Frame Pacing ライブラリ

場合によっては、プラットフォームがアプリが setFrameRate() で指定したフレームレートの倍数に切り替わることがあります。たとえば、アプリが 60 Hz で setFrameRate() を呼び出すと、デバイスはディスプレイを 120 Hz に切り替える場合があります。このことが 別のアプリのサーフェスでフレームレートが 24 Hz に設定されている場合に発生します。その場合、ディスプレイを 120 Hz で実行すると、60 Hz サーフェスと 24 Hz サーフェスの両方をプルダウンなしで実行できます。

ディスプレイがアプリのフレームレートの倍数で動作している場合は、不要なジャダーを回避するために、アプリで各フレームのプレゼンテーション タイムスタンプを指定する必要があります。ゲームの場合、Android Frame Pacing ライブラリを使用すると、 設定しています。

setFrameRate() と preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId は、アプリがフレームレートをプラットフォームに示す別の方法です。ディスプレイ解像度などの他のディスプレイ モードの設定を変更するのではなく、ディスプレイのリフレッシュ レートのみを変更するアプリもあります。通常は、preferredDisplayModeId ではなく setFrameRate() を使用します。setFrameRate() 関数は、テキスト メッセージ全体を検索する必要がないため、簡単に使用できます。 表示モードのリストを使用して、特定のフレームレートのモードを検索できます。

setFrameRate() を使用すると、異なるフレームレートで実行されている複数のサーフェスがあるシナリオで、プラットフォームが互換性のあるフレームレートを選択できる機会が増えます。たとえば、2 つのアプリが Google Pixel 4 の分割画面モードで動作し、一方のアプリが 24 Hz の動画を再生している もう 1 つはスクロール可能なリストですGoogle Pixel 4 は、60 Hz と 90 Hz の 2 つのディスプレイ リフレッシュ レートをサポートしています。preferredDisplayModeId API を使用すると、 動画サーフェスは 60Hz または 90Hz のいずれかを選択します。24 Hz で setFrameRate() を呼び出すと、動画サーフェスはソース動画のフレームレートに関するより多くの情報をプラットフォームに提供します。これにより、プラットフォームはディスプレイのリフレッシュ レートに 90 Hz を選択できます。このシナリオでは 60 Hz よりも優れています。

ただし、次のような場合は setFrameRate() ではなく preferredDisplayModeId を使用する必要があります。

  • アプリで解像度やその他の表示モード設定を変更したい場合は、 preferredDisplayModeId を使用します。
  • プラットフォームは、モード切り替えが軽量でユーザーに気付かれない可能性が高い場合にのみ、setFrameRate() の呼び出しに応答してディスプレイ モードを切り替えます。ヘビーモードの切り替えが必要な場合でも、アプリがディスプレイの更新レートを切り替えることを優先する場合(Android TV デバイスなど)は、preferredDisplayModeId を使用します。
  • アプリの複数のフレームで実行されているディスプレイを処理できないアプリ (フレームごとに表示タイムスタンプを設定する必要がある)レートでは、 preferredDisplayModeId を使用します。

setFrameRate() と preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate は、アプリのウィンドウに優先フレームレートを設定します。このレートは、ウィンドウ内のすべてのサーフェスに適用されます。アプリは、setFrameRate() と同様に、デバイスでサポートされているリフレッシュ レートに関係なく、優先するフレームレートを指定する必要があります。これにより、アプリの目的のフレームレートをスケジューラに適切にヒントとして提供できます。

setFrameRate() を使用するサーフェスでは、preferredRefreshRate は無視されます。イン 可能であれば、通常は setFrameRate() を使用してください。

preferredRefreshRate と preferredDisplayModeId

アプリで優先リフレッシュ レートのみを変更する場合は、preferredDisplayModeId ではなく preferredRefreshRate を使用することをおすすめします。

setFrameRate() を頻繁に呼び出すのを避ける

setFrameRate() 呼び出しはパフォーマンスの面でそれほどコストがかかるものではありませんが、アプリではフレームごとに、または 1 秒間に複数回 setFrameRate() を呼び出さないようにする必要があります。setFrameRate() を呼び出すと、 画面の切り替え時にフレーム落ちが発生する可能性があります。 事前に適切なフレームレートを把握しておき、 setFrameRate() を 1 回。

ゲームやその他の動画以外のアプリでの使用

動画は setFrameRate() API の主なユースケースですが、 使用しないでください。たとえば、(消費電力を抑えて長時間のプレイ セッションを実現するために)60 Hz を超えるレートで実行しないことを意図しているゲームは、Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) を呼び出すことができます。この デフォルトで 90 Hz で動作するデバイスは 60 Hz で稼働し、 ゲームがアクティブになり、 ゲームは 60 Hz で実行し、ディスプレイは 90 Hz で実行していた。

Frame_RATE_COMPATIBILITY_FIXED_SOURCE の使用

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE は動画アプリ専用です。対象 動画以外での使用の場合は、FRAME_RATE_COMPATIBILITY_DEFAULT を使用します。

フレームレートの変更方法を選択する

  • 長時間の動画を表示する場合は、アプリの 映画、呼び出し setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) ここで、fps は動画のフレームレートです。
  • 動画の再生時間が数分以内になると予想される場合は、CHANGE_FRAME_RATE_ALWAYSsetFrameRate() を呼び出すアプリは使用しないことを強くおすすめします。

動画再生アプリの統合例

動画再生アプリに更新レートの切り替えスイッチを統合する場合は、次の手順をおすすめします。

  1. changeFrameRateStrategy を決定します。 <ph type="x-smartling-placeholder">
      </ph>
    1. 映画などの長尺動画を再生する場合は、MATCH_CONTENT_FRAMERATE_ALWAYS を使用します。
    2. 予告編などの短い動画を再生する場合は、CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS を使用します。
  2. changeFrameRateStrategyCHANGE_FRAME_RATE_ONLY_IF_SEAMLESS の場合は、ステップ 4 に進みます。
  3. 次のチェック ボックスをチェックして、非シームレスのリフレッシュ レートの切り替えが行われる直前かどうかを検出する 次の両方の事実が正しいことを確認する必要があります。 <ph type="x-smartling-placeholder">
      </ph>
    1. 現在のリフレッシュ レートからシームレス モードに切り替えることはできません( C)を動画のフレームレート(V と呼ぶ)にマッピングします。これにより、 C と V が異なっていて Display.getMode().getAlternativeRefreshRates V の倍数は含まれません。
    2. ユーザーがシームレスでないリフレッシュ レートの変更を有効にしている。新しい P-MAX キャンペーンを これを確認するには、DisplayManager.getMatchContentFrameRateUserPreference は、MATCH_CONTENT_FRAMERATE_ALWAYS を返します。
  4. 切り替えをシームレスに行う場合は、次の手順を行います。 <ph type="x-smartling-placeholder">
      </ph>
    1. setFrameRate を呼び出して、fpsFRAME_RATE_COMPATIBILITY_FIXED_SOURCEchangeFrameRateStrategy を渡します。ここで、fps は動画のフレームレートです。
    2. 動画の再生を開始
  5. 非シームレス モードの変更が行われる場合は、次の手順を行います。 <ph type="x-smartling-placeholder">
      </ph>
    1. ユーザーに通知する UX を表示します。なお、Terraform でインフラストラクチャを ユーザーにこの UX を閉じて、ステップ 5.d の追加の遅延をスキップするよう促します。これは、切り替え時間が短いディスプレイでは、推奨される遅延時間が必要以上に長くなるためです。
    2. setFrameRate を呼び出す fpsFRAME_RATE_COMPATIBILITY_FIXED_SOURCE、 および CHANGE_FRAME_RATE_ALWAYS、 ここで、fps は動画のフレームレートです。
    3. onDisplayChanged コールバックを待機します。
    4. モードの切り替えが完了するまで 2 秒待ちます。
    5. 動画の再生を開始する

シームレスな切り替えをのみサポートする疑似コードは次のとおりです。

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
    contentFrameRate,
    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();

上記のようなシームレス切り替えと非シームレス切り替えをサポートする擬似コードは次のとおりです。

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();
}