Webページで再生中の動画の FPS と解像度をリアルタイムで確認したくて、Chrome 拡張機能を作りました。YouTube、ニコニコ動画、その他 HTML5 動画に対応しています。ソースコードは GitHub で公開しています。

manifest.json の構成は次のとおりです。

{
  "manifest_version": 3,
  "name": "Video FPS & Resolution Display",
  "version": "1.0.0",
  "description": "Webページで再生中の動画のFPSと解像度をリアルタイム表示します",
  "permissions": ["storage", "activeTab"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "css": ["content.css"],
    "run_at": "document_idle"
  }],
  "options_page": "options.html"
}

動画再生中、画面上にオーバーレイで FPS・解像度・ドロップフレーム数が表示されます。デフォルトは右上、緑色の文字です。

YouTubeで動画再生中、右上にFPS・解像度・ドロップフレーム数が表示されている様子
動画再生時の表示例(YouTube)

使い方

インストールは、リポジトリをクローンまたは ZIP でダウンロードし、Chrome の chrome://extensions/ で「デベロッパーモード」を ON にして「パッケージ化されていない拡張機能を読み込む」からフォルダを選択します。動画ページを開くと自動で表示され、アイコンクリックで ON/OFF を切り替えられます。「設定を開く」から表示位置(左上/右上/左下/右下)と文字色を変更できます。

ポップアップと設定画面の例です。表示位置は「左上」「右上」「左下」「右下」から選択でき、文字色はカラーピッカーまたは HEX コードで指定できます。

拡張機能のポップアップ。表示のトグルスイッチと「設定を開く」リンクがある
アイコンクリックで表示されるポップアップ
設定画面。表示位置のセレクトボックスと文字色のカラーピッカー、プレビューが表示されている
オプション画面(表示位置・文字色の設定)

仕組み

FPS 計測には requestVideoFrameCallback(Chrome 83+ で利用可能)を優先しています。動画の各フレーム描画時にコールバックが呼ばれ、metadata.presentedFrames から経過フレーム数を取得。1 秒窓で差分を取って FPS を算出します。

function measureFPSWithRVFC(now, metadata) {
  const frames = metadata.presentedFrames;
  const elapsed = (now - tracker.windowStartTime) / 1000;
  if (elapsed >= 1) {
    const deltaFrames = frames - tracker.windowStartFrames;
    tracker.fps = deltaFrames / elapsed;
    tracker.windowStartTime = now;
    tracker.windowStartFrames = frames;
  }
  updateDisplay();
  tracker.callbackId = video.requestVideoFrameCallback(measureFPSWithRVFC);
}

非対応環境では getVideoPlaybackQualitytotalVideoFramesrequestAnimationFrame でサンプリングし、同様に 1 秒窓の差分から FPS を算出してフォールバックしています。

function measureFPSWithRAF() {
  const quality = video.getVideoPlaybackQuality?.();
  const frames = quality?.totalVideoFrames ?? 0;
  const elapsed = (now - tracker.windowStartTime) / 1000;
  if (elapsed >= 1 && frames >= tracker.windowStartFrames) {
    const deltaFrames = frames - tracker.windowStartFrames;
    tracker.fps = deltaFrames / elapsed;
    tracker.windowStartTime = now;
    tracker.windowStartFrames = frames;
  }
  updateDisplay();
  tracker.rafId = requestAnimationFrame(measureFPSWithRAF);
}

起動時に API の有無を判定してどちらを使うか決め、play / pause / ended で計測の開始・停止を制御しています。解像度は videoWidth / videoHeight を参照。ドロップフレームは droppedVideoFrames の 1 秒間の増分を表示。MutationObserver で document.body を監視し、動的に追加される動画(SPA のページ遷移など)にも対応しています。

if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
  tracker.callbackId = video.requestVideoFrameCallback(measureFPSWithRVFC);
} else {
  tracker.rafId = requestAnimationFrame(measureFPSWithRAF);
}
const observer = new MutationObserver(() => scanForVideos());
observer.observe(document.body, { childList: true, subtree: true });

注意点として、動画が一時停止中は FPS 計測を停止し「停止」と表示します。一部のサイトでは動画の実装により正しく計測できない場合があります。Chrome(Chromium 系)での動作を想定しています。