rendercheck について
rendercheckは、生成された音声・動画・画像の測定可能な欠陥を検査するPythonライブラリとCLIです。メディア生成やビルドのパイプラインに適しており、メディアを生成せず合否レポートを返します。
主な機能
- 01音声のペースとラウドネスのアサーション
- 02長さ・無音・ストリームの検査
- 03字幕タイミングと話者の検査
- 04画像のビジュアル基準チェック
- 05JSONレポートと終了コードを提供
活用シーン
- 01pytestで生成エピソードを検査
- 02CIでレンダリングの切り詰めを検出
- 03公開前に音声と字幕を確認
- 04生成スライドのレイアウト不良を検査
MCP 対応
MCPサーバーは、判定と測定値を返す`check_media`を含むメディア検査ツールをMCPクライアントに提供します。`looks_ok`を除く多くの検査は決定的で、キーを必要としません。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
2掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| path | string | はい | 検査するメディアファイル。ディレクトリを指定すると、その中身を検査します。 |
| preset | enum | いいえ | このファイルの用途に応じたラウドネス目標。apple | atsc | ebu | netflix | podcast | spotify | tiktok | web | youtube |
| rubric | array | いいえ | 静止画が満たすべき条件。例:'the title fits on one line'。ビジョン検査を有効にします。この検査には API key が必要です。 |
| script | string | いいえ | ナレーションのテキスト、またはトランスクリプト/.vtt/.srt のパス。速度検査を有効にします。 |
| strict | boolean | いいえ | 実行できなかった検査を失敗として扱います。 |
| captions | string | いいえ | 音声と照合する .vtt または .srt ファイル。同じ名前でメディアと同じ場所にある場合は自動的に検出されます。 |
| presenter | string | いいえ | ナレーションを担当するはずの人物。話者検査を有効にします。この検査には known_names も必要です。 |
| expect_fps | number | いいえ | レンダリング時に指定したフレームレート。音声と映像がずれる一般的な原因である可変フレームレートも検出します。 |
| known_names | array | いいえ | 実際に起用される可能性のあるプレゼンター全員。presenter と併せて必須です。これがないと、シナリオ内の登場人物が「I'm Rosa」と言うだけで、物語を含むすべてのスクリプトで検査に引っかかります。 |
| expect_width | number | いいえ | レンダリング時に指定した映像の幅(ピクセル)。 |
| expect_height | number | いいえ | レンダリング時に指定した映像の高さ(ピクセル)。 |
| expect_channels | number | いいえ | 納品仕様で指定されたチャンネル数:1 はモノラル、2 はステレオです。 |
| expected_seconds | number | いいえ | レンダリングで想定される長さ。 |
| expect_sample_rate | number | いいえ | 納品仕様で指定された音声サンプルレート(Hz)。 |
詳細
rendercheck
生成メディアで最も厄介なバグは、エラーを出しません。
「音声が最後の文の途中で切れることがよくあります […] それでも API はエラーを示さずに成功を返します」
— OpenAI フォーラムの開発者による投稿、 2026年4月、本番環境の出力について

モデルで音声や動画を生成している場合(TTS、音声エージェント、ポッドキャスト、アバター、AI 動画など)、テストで検出できるのは、決して発生しない例外です。1分あたり300語で読み上げるナレーション、合わせた映像より18 dBも小さい音声トラック、長さが42%でレンダリングされたのに成功としてキャッシュされたクリップ、実際に音声が流れる3秒前の内容を示す字幕、音声トラックがまったくないファイルは検出できません。
こうした問題を検出する2026年現在の最先端の方法は、人が出力を聴くことです。それでうまくいきますが、パイプラインの他のすべてのコストを合わせた額より高くつきます。
rendercheck は、これらの問題でエラーを発生させます。
from rendercheck import assert_pace, assert_loudness, looks_ok
assert_pace("episode-12.mp3", "episode-12.vtt")
assert_loudness("episode-12.mp3")
looks_ok("slide-14.png", ["the title fits on one line"])
シンプルな assert 関数です。フレームワークも、ランナーも、サービスもありません。AssertionError を発生させるため、pytest、CI、あるいは5行のスクリプトですぐに使えます。19個のチェックのうち18個は依存関係がなく、ネットワーク呼び出しもありません。ffmpeg があれば、すぐに使えます。
クイックスタート
PATH に ffmpeg が必要です(brew install ffmpeg、apt-get install ffmpeg、または winget install ffmpeg)。その後、次を実行します。
pip install rendercheck
rendercheck demo
または、ファイルを**プレイグラウンド**にドロップします。同じチェックを WebAssembly にコンパイルされた ffmpeg で実行し、ファイルはアップロードされません。
demo は10個の欠陥のあるファイルを合成し、それらに実際のチェックを実行するため、壊れたレンダリングがなくても動作を確認できます。以下は8個のうち最初の2個をそのまま示したものです。
Narration too fast
A voice picked to match a presenter's face read English at machine-gun speed. Valid audio, correct timing, perfectly in sync.
$ rendercheck check machine-gun.wav --script narration.vtt
FAIL pace narration pace 300 WPM exceeds 245 (300 words in 60.0s) -- this reads as machine-gun delivery and listeners cannot follow it: machine-gun.wav
PASS loudness -16.1 LUFS
PASS dead air 0.0 s silence
PASS truncation 8.9 dB of fall-off at the end
PASS clipping 0 samples at 0 dBFS
Levels that don't match
Synthesised narration landed 18 dB under the footage it was cut against. Nobody noticed until viewers rode the volume knob.
$ rendercheck check too-quiet.wav
SKIP pace no --script given
FAIL loudness -34.2 LUFS is 18.2 dB quieter than the -16 target -- it will sound inaudible next to correctly-levelled audio cut alongside it: too-quiet.wav
PASS dead air 0.0 s silence
PASS truncation 8.8 dB of fall-off at the end
PASS clipping 0 samples at 0 dBFS
そして、0.3.0で追加された2個のうちの1つです。
Captions against the wrong clock
A concatenation added three seconds of pre-roll after the captions were written. Both files are perfectly valid on their own.
$ rendercheck check late-captions.wav
SKIP pace no --script given
PASS loudness -16.0 LUFS
PASS dead air 0.0 s silence
PASS truncation 74.3 dB of fall-off at the end
PASS clipping 0 samples at 0 dBFS
FAIL captions late-captions.vtt runs 3.0s late against late-captions.wav, past the 0.75s limit -- every line arrives at the wrong moment, and both files are individually valid so nothing else catches it
次に、自分の出力を指定します。
rendercheck check episode-12.mp3 --script episode-12.vtt --preset podcast
何かに失敗した場合、または測定できたものが何もない場合は、終了コードが1になります。何も確認していない実行は、問題がなかったとは言えないためです。パスを間違えると、終了コード2になります。--json を使うと、どの言語のパイプラインでも同じレポートを取得できます。また、--strict を指定すると、部分的な実行も拒否されます。
このファイルはどこで使いますか?
「どのくらいの音量にすべきか?」に唯一の答えはありません。ファイルの用途によって異なり、プラットフォームごとに公表されている数値も異なります。--preset を使うと、その一覧をビルドで強制できる設定に変換できます。
$ rendercheck presets
preset target tol peak source
youtube -14L 1.0dB -1.0TP YouTube normalises playback to -14 LUFS
spotify -14L 1.0dB -1.0TP Spotify, including podcasts, at -14 LUFS
tiktok -14L 1.5dB -1.0TP TikTok and Instagram, measured rather than published
podcast -16L 1.0dB -1.0TP AES71 / Apple Podcasts: -16 LUFS stereo, -19 mono
apple -16L 1.0dB -1.0TP Apple Music Sound Check, -16 LUFS
web -16L 2.0dB -- spoken-word web video -- rendercheck's own defaults
ebu -23L 1.0dB -1.0TP EBU R128, European broadcast
atsc -24L 2.0dB -2.0TP ATSC A/85, North American broadcast
netflix -27L 2.0dB -2.0TP Netflix delivery, dialog-gated
どの数値も、私たちが決めたものではありません。貢献したのは、レビュアーが意図を理解できる判断として --preset ebu を指定できることです。一方、--target-lufs -23 は、次の担当者が変更するのをためらうマジックナンバーです。上限を定めるプリセットは、トゥルーピークのチェックも有効にします。これにより、ローカルでは問題なく測定されても、アップロード後に歪むマスターを検出できます。web は組み込みのデフォルト設定に名前を付けるためだけに存在するため、何も指定せずに実行した場合と同じ動作になります。
プロジェクト全体の設定は rendercheck.toml(または pyproject.toml の [tool.rendercheck])に記述できます。これにより、CI のステップにフラグを8個並べる必要がなくなります。
preset = "podcast"
max_silence = 5.0
入力したフラグは設定ファイルより優先され、設定ファイルは組み込みのデフォルト設定より優先されます。
pytest では単に assert を使うだけです。プラグインもフィクスチャも必要ありません。
@pytest.mark.parametrize("episode", EPISODES)
def test_episode_is_shippable(episode):
assert_pace(episode.audio, episode.vtt)
assert_loudness(episode.audio)
assert_no_dead_air(episode.audio)
「pyloudnorm の40行分ではありませんか?」
19項目のチェックのうち、1つについてはおおむねそのとおりです。これらの測定自体に目新しさはなく、そうであるかのように示すのは不誠実です。
| 測定項目 | すでに利用できるもの |
|---|---|
| 統合ラウドネス、トゥルーピーク | pyloudnorm、ffmpeg の loudnorm |
| 無音検出 | pydub.silence、ffmpeg の silencedetect |
| 長さ、ストリーム構成、フレームレート | ffprobe |
| 黒味、フリーズ | ffmpeg の blackdetect、freezedetect |
| 字幕と音声のオフセット | ffsubsync — こちらはオフセットを補正します |
| コンテナとコーデックの準拠性 | MediaConch — ポリシーに基づく合否判定を CLI から実行できます |
| 話者の識別 | resemblyzer |
| 動画品質メトリクス | VMAF、ffmpeg-quality-metrics |
その多くが研究者に数値を渡すものです。すでにゲートとして機能する2つは、別のものをチェックします。MediaConch が確認するのは、ファイルがコンテナポリシーに準拠しているかどうかです。これは知覚上の問題ではなく、保存に関する問題です。MediaConch のすべてのルールに合格しても、300 WPM でナレーションされていることはあります。ffsubsync は、そもそも誤っていなかった字幕でも問題なく再同期します。字幕の再同期が必要だったかどうかを判断しないからです。
本当に不足しているもの、そしてこれが提供するものは次のとおりです。
- 論文ではなく、不具合から導かれたしきい値です。245 WPM は、実際の音声が280 WPMでナレーションされ、そのまま出荷されたことが理由です。−16 LUFS は、ナレーションが−34 LUFS、映像の音声が−13 LUFSになっていたことが理由です。
- 人が気づくことを伝えるメッセージです。「−34.0 LUFS」は測定値です。「−16の目標値より18.0 dB小さいため、適切な音量に調整された音声と並べて編集すると、聞こえなくなります」はバグ報告です。
- インフラの問題はフェイルオープン、不具合はフェイルクローズにすることで、CIに組み込んでも、それ自体が原因でビルドを失敗させることがありません。
- ノートブックではなく、ディレクトリを対象に1つのコマンドで実行でき、終了コードも返します。
LLM 評価ツールとの違いは、対象範囲ではなく構造にあります。promptfoo、 DeepEval、 RAGAS はいずれも優れたツールですが、これを実行することはできません。テストケースが文字列だからです。ファイルを置く場所がないので、追加できるアサーションもありません。スクリプトにはこれらを使い、スクリプトから生成されたものにはこちらを使ってください。
また、Interra BATON、Telestream Vidchecker、QCTools などの放送向け QC をすでに運用しているなら、この機能の大半を20年前から利用できています。ただ、それが git フックにはないだけです。
パイプラインでの利用
GitHub Actions — ffmpeg をインストールし、不具合があればビルドを失敗させます。
- uses: rogermsc/rendercheck@v0
with:
files: out/
preset: podcast
strict: "true"
Node、Remotion、ビルド手順でレンダリングするあらゆるもの:
npx rendercheck check out/
Python のツールチェーンをまったく使いたくない場合は、Docker を利用できます。ffmpeg はすでにイメージに含まれています。
docker run --rm -v "$PWD:/work" ghcr.io/rogermsc/rendercheck check /work/out.mp4
MCP 経由で利用するコーディングエージェント向けです。レンダリングパイプラインを書いて実行したばかりのエージェントには、出力されたファイルの品質を確認する手段がありません。他のメディア MCP サーバーは編集やトランスコードを行うため、答えではなく、さらに多くのメディアを返します。
claude mcp add rendercheck -- rendercheck mcp
MCP レジストリには io.github.rogermsc/rendercheck として登録されているため、レジストリを参照するクライアントは、保存場所を指定しなくてもインストールできます。キーは不要です。looks ok 以外のすべてのチェックは決定論的です。
check_media は各チェックの判定と測定値を返すため、モデルは聞くことのできないファイルではなく、「−34 LUFS、目標値より18 dB低い」という結果に基づいて対応できます。
promptfoo — そのアサーションはすべて文字列を対象としているため、評価でナレーションのスクリプトは確認できても、音声については何も分かりません。examples/promptfoo/ を使えば、その部分を30行で補えます。
assert:
- type: python
value: file://rendercheck_assert.py:get_assert
その他のあらゆる用途 — 標準出力に --json を指定すると、ファイルごとに1つのオブジェクトが出力され、終了コードも返します。
6 つのチェック、6 つのインシデント
各デフォルト値は、実際にリリースされた不具合によって決まったしきい値であり、見た目をそろえるために選んだ数値ではありません。以下はすべて原文のままです。すべてのしきい値は引数です。調整についてはリファレンスをご覧ください。
ナレーションが速すぎる。 プレゼンターの顔に合わせて選んだ音声が、英語を約 280 WPM で読み上げました。音声は有効で、タイミングも正しく、完全に同期していました。ただ、機関銃のように聞こえただけです。
assert_pace("episode-12.mp3", "episode-12.vtt", max_wpm=245)
narration pace 300 WPM exceeds 245 (300 words in 60.0s) -- this reads as
machine-gun delivery and listeners cannot follow it: episode-12.mp3
音量レベルが合わない。 合成されたナレーションは −34 LUFS で、−13 の映像と連結されました。同じファイルの途中で 20 dB の段差が生じました。視聴者が 45 分間、音量つまみを操作するまで誰も気づきませんでした。
assert_loudness("episode-12.mp3", target_lufs=-16, tol=2.0)
-34.0 LUFS is 18.0 dB quieter than the -16 target -- it will sound inaudible
next to correctly-levelled audio cut alongside it: episode-12.mp3
切り詰められたレンダリングが成功としてキャッシュされる。 エンコードの失敗により、意図した長さの一部しかないクリップが生成されましたが、パイプラインはそれを成功としてキャッシュしました。再試行で再実行されたのは、エラーになったものだけでした。これらはエラーになっていませんでした。
assert_duration("segment-07.mp4", expected_seconds=24.0)
segment-07.mp4 is 10.0s -- 42% of the expected 24.0s. A render this short is a
silent encode failure, not a short take; re-render rather than retry
途中に穴がある。 合成処理が一時的に、しかもひそかに失敗し、ファイルの途中に無音区間が残りました。長さは正しく、平均音量も適正でした。穴があったのは途中だけでした。
assert_no_dead_air("episode-12.mp3", max_silence=3.0)
6.2s of silence starting at 0:41 exceeds the 3s limit -- a gap this long
mid-file is a dropped segment, not a pause (2 found in total): episode-12.mp3
別の人物が話している。 スクリプトには「I'm Jordan」と書かれていましたが、システムが割り当てていたのは Alex でした。モジュール全体が、別の顔と別の声でレンダリングされました。ほかのゲートはすべて通過していました。
assert_speaker(script, expected="Alex", known_names=["Alex", "Jordan", "Sam"])
the script introduces the presenter as "Jordan" but Alex is assigned -- the
rendered avatar would introduce itself with someone else's name. Fix whichever
is wrong: the assigned presenter, or the name in the script
known_names の名簿は必須であり、これが肝心な点です。これがないと、シナリオ内の登場人物が "I'm Rosa, a nurse" と言うだけで、物語を伝えるすべてのスクリプトがチェックに引っかかります。実際にキャストされる可能性がある人物の名前だけが、話者についての主張とみなされます。
目でしか確認できない問題。 はみ出したタイトル、重なったロゴ、半分しか埋まっていないキャンバス、キャプションの途中で切れた人物。いずれもエラーなくレンダリングされました。
looks_ok("slide-14.png", ["the title fits on one line", "no text is clipped"])
[major] slide-14.png: the title wraps to three lines and overlaps the logo in
the top-right corner -- failed rubric item: 'the title fits on one line'
キーが必要なチェックはこれだけです:pip install "rendercheck[vision]"。
ほかの人から繰り返し報告される不具合に対応する、さらに 13 のチェック
上記の 6 つは、1 つのパイプラインから生まれました。こちらは、ほかの人たちのバグ報告を読んで生まれたものです。どのプロバイダーに対しても、同じ苦情が寄せられていました:
| チェック | 問題 |
|---|---|
assert_no_truncation | API が成功を返す一方で、音声が文の途中で途切れます。生成音声で最も多く報告される問題で、ファイル自体の平均値を基準に測定するため、音量の大小にかかわらず機能します。 |
assert_has_sound | 無音のクリップが返されます。アップスケール処理で音声トラックが削除された、マルチプレクサーが誤ったストリームを参照している、合成処理がゼロを書き込んだ、といったケースです。 |
assert_no_clipping | ゲイン段階で波形がフルスケールを超えています。子音にノイズが乗り、あとから音量を下げても元には戻りません。 |
assert_true_peak | ローカルでは問題なく測定されても、アップロード後に歪みます。ラウドネスとピークは別の問題です。非可逆コーデックはサンプル間の波形を再構成し、その波形が超過した箇所でクリップします。 |
assert_no_black_frames | 生成動画がエラーを返さずに黒画面で途切れます。長さは正しく、コンテナも有効ですが、最後の 3 分の 1 は何もありません。 |
assert_not_frozen | 映像の動きが止まります。フレームはすべて存在しますが、どれも同じフレームです。 |
assert_captions_aligned | あるクロックに基づいて字幕が作成され、別のクロックに基づいて音声がレンダリングされています。各行がすべて誤ったタイミングで表示されますが、ファイルはどちらも個別には完璧です。 |
assert_streams_aligned | 音声と映像の再生時間が一致しません。片方の入力が途中で尽きたマルチプレクサーや、最初のセグメントのタイミングを誤った連結処理などが原因です。 |
assert_format | レンダリング結果がいつの間にか 720p にフォールバックした、フレームレートが誤っている、または後続のパイプラインが固定フレームレートを前提としているのに可変フレームレートになっています。 |
assert_not_blank | 画像生成ツールが失敗して、空のキャンバスを返しました。DALL·E、Stable Diffusion、Qwen、Gemini、Krita で報告されている問題で、いつも同じ状態です。エラーも警告もなく、寸法は正しいのに、何も描かれていません。黒いキャンバスだけでなく、あらゆる単色のキャンバスを検出します。blackdetect では、黒以外の単色キャンバスは検出できません。 |
assert_loudness_range | 音量を一つの設定に調整しても、実用的にならないファイルです。静かな部分に合わせて音量を上げると、大きな音の部分に驚かされます。中央の音量だけを確認する assert_loudness とは別の問題です。 |
assert_audio_format | ステレオ指定に対してモノラルで出力された、または仕様で 48 kHz とされているのに 44.1 kHz で出力され、チェーン内にたまたま存在するコンバーターによって後続処理でリサンプリングされます。 |
assert_lip_sync | 話者の口の動きと声のタイミングがずれています。コンテナは正しく、ストリームは有効で、再生時間も一致しており、assert_streams_aligned も通ります。これはコンテナのタイミングを読み取るのに対し、このチェックはコンテンツを読み取るためです。既定では無効で、回答するよりも回答を控えることのほうが多くあります。チェック対象外 の下にある注記を参照してください。 |
空白チェックだけはキーが不要です。 これが存在するまでは、画像についてこのツールが何かを返すには、ビジョンティアを通す必要がありました。そのため rendercheck check slide.png は何も測定せず、ゼロ以外の終了コードを返していました。このチェックは最小値と最大値ではなく、輝度分布の下端と上端の差を読み取ります。そのため、安定して機能します。迷光によるアーティファクトが 1 つある空白フレームは、最小値と最大値では全範囲にわたりますが、ここでは空白として判定されます。
字幕チェックには、ほかに同等のものがありません。 ffsubsync などはずれを補正します。オンラインのバリデーターは .srt 自体の形式を検査します。たとえば、キューの重複、読み上げ速度、空の行です。どちらも、この字幕ファイルがこの音声に合っているかどうかは確認しません。ビルドで答える必要があるのは、まさにこの問いだけです。話し声の形状と字幕キューの形状を照合し、一定のオフセットとドリフトを別々に報告します。オフセットは正しい位置からの一律のずれですが、ドリフトは一律のずれだけでは修正できません。
これらはいずれも、測定できない場合は成功とするのではなく、スキップします。動画ストリームがない、照合に使える無音構造がない、コンテナにストリームごとの長さがない、といった場合です。.wav に対する blackdetect は何も報告しません。そうでなければ「確認した結果、すべて問題なし」と読めてしまうところです。これは下記のリグレッションと同じ落とし穴であり、すべてがスキップされた実行がゼロ以外で終了する理由です。
実際のファイルで見つかった問題
合成ベンチマークではありません。ナレーション付き動画を大規模にレンダリングする本番パイプラインの出力に適用しました。
| 結果 | |
|---|---|
| 問題がないと分かっている講座 | クリーン — 162 WPM、−14.1 LUFS、無音区間なし |
| ラウドネス修正の適用後に再レンダリングされたコンテンツ | −14.2 LUFS で合格 |
| その修正前にレンダリングされた4つのエピソード | −19.4〜−21.3 LUFS で不合格 |
このツールは、修正が適用された時点を正確に境界として判定しました。何も知らされていないファイルに対して、人間が数か月前に達していた結論と一致しました。
この表は逸話であり、その旨を明記しています。 メディアは非公開のため、作者を含め、誰も再実行できません。確認できる数値は、bench/bench.py が作成した docs/calibration.md にあります。
python bench/bench.py sync # no network, no corpus, about a minute
このスクリプトは、正解が分かっているメディアに既知の大きさの欠陥を埋め込み、各チェックが実際に何を報告したかを集計します。判定保留も分母に含め、ゼロ件の結果ごとにルール・オブ・スリーによる上限を併記します。このライブラリのしきい値に実測に基づく根拠がある場合、その根拠はここに示されています。
2つの約束
インフラの問題があっても処理を続けます。 ffmpeg がない、キーがない、ネットワークがない、測定できない場合は、警告を出して合格とします。自身の障害が原因でパイプラインをブロックするゲートは、1週間以内に削除され、何も守らなくなります。欠陥はフェイルクローズ、チェッカーはフェイルオープンです。(ファイルがないのはインフラの問題ではなく、入力ミスです。その場合は引き続き例外が発生します。)
無音が成功と誤認されることはありません。 実行できなかったチェックは、rendercheck.Skipped 警告と CLI の出力でその旨を示します。何も実行されなかった実行が、問題のない実行として扱われることはありません。
2つ目の約束を守るには、2度の修正が必要でした。
このライブラリの初期版は、音声トラックがまったくないファイルに対して合格を返していました。解析対象がないと silencedetect は何も報告せず、「無音は見つからなかった」と解釈されていたのです。現在これはテストスイートで最も目立つ失敗として扱われ、リグレッションテストにもその名前が付いています。ここから得た教訓は、ほかのすべてにも適用されるルールです。測定して問題があればフェイルクローズ、測定できなければフェイルオープン。
その後、この名前でリリースする前に、ツールが掲げる原則に照らして監査したところ、さらに7つ見つかりました。いずれも、成功を確認していないのに成功を報告していました。
- すべてスキップされた実行が終了コード
0を返していました。実行環境に ffmpeg がなければ、ビルドが成功扱いになっていました。 - ファイルパスの入力ミスでも終了コード
0を返し、2段落前の約束に反していました。 --scriptのパスを間違えると、ナレーションとして読み込まれてしまいました。1語だけのスクリプトとして処理され、音声について誤った判定を自信ありげに出していました。1 WPM is below 110。--known-namesを指定せずに--presenterを指定すると、出演者リストが割り当てられたプレゼンターだけに設定されていました。その結果、話者チェックは構造上、検出できない状態になっていました。別の人物の名前がスクリプトに記載されていても、PASSと表示していました。looks_okはすべての例外の原因を API キー不足としていました。そのため、SDK の不整合がいつまでも合格扱いになり、Bedrock ユーザーは誤った原因を調べることになっていました。- ffprobe のエラーで、生の Python リストがメッセージに表示されていました。
- ffmpeg がないと、スキップする代わりにテストスイートの収集時にクラッシュしていました。
7つすべてを修正し、それぞれ修正がないと失敗するテストを追加しました。また、終了コードを契約として定めました。0 は測定済みで問題なし、1 は欠陥ありまたは測定なし、2 はパスの参照先が存在しないことを示します。詳細は変更履歴をご覧ください。
見落とされた失敗を検出するツールの価値は、それらについてどれだけ正直であるかにかかっています。
チェック対象外
対象範囲を実際以上に広く見せる QA ツールは、ないよりも悪いため、明確にしておきます。
- 重要な許容範囲でのリップシンク。
assert_lip_syncは映像の動きと音声エンベロープの相関を調べ、顔検出もモデルも使わずに、口の動きが音声と半秒近くずれているケースの大半を検出します。ただし、できないことが2つあります。知覚上本当に重要なずれは判定できません。EBU R37 では、音声が +40 ms 先行、または −60 ms 遅延すると検知可能とされていますが、このチェックが検出するのは 200 ms のずれの3分の1未満です。また、約3分の2のファイルでは相関ピークが十分に明確でなく数値を読み取れないため、判定を返しません。壊れたパイプラインは見つけますが、正常なパイプラインを保証するものではありません。その確認には、依然としてモデル(SyncNet など)が必要です。 - 知覚的な動画品質。 PSNR、SSIM、VMAF はありません。これらには比較対象となる参照エンコードが必要ですが、生成メディアにはありません。
- ナレーションが 正しい かどうか。 チェックするのは読み上げの速さと、字幕のタイミングが合っているかどうかだけです。ここでは音声を文字起こししないため、間違った原稿を適切なペースで読み上げる音声は、すべてのチェックに合格します。この確認には Whisper が必要ですが、ほかの部分に比べて依存関係として重すぎます。根拠との整合性や事実の正確性はまた別の問題で、LLM 評価ツールが十分に対応しています。
- 音声の明瞭度。 音量が適切でも、明瞭とは限りません。適切な音量に調整されたトラックでも、ぼそぼそと聞こえることがあります。
- 音楽、ミキシング、その他の音声以外の要素。 デフォルト設定は話し言葉を想定しています。
- 記述されていない評価基準。
looks_okがチェックするのは、指定した内容だけです。
詳細
- 症状 — 「TTS が最後の文を途中で切った」「クリップが無音で返ってきた」などの症状と、それぞれを検出するチェック
- リファレンスと調整 — すべてのしきい値と、チェックを無効にするタイミング
- 貢献 — 新しいチェックに求められる基準
- 変更履歴
MIT。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。