本記事は Splathon のアドベントカレンダー2025、12月25日の記事です。メリークリスマス🎄
はじめに
みなさま。いかがお過ごしですか。
日頃から? Splathon(オフラインの Splatoon コミュニティイベント)で、映像系を担当している みゆっき です。
オフラインイベントで Splatoon のゲームを実況するにあたり、「このキルが〜」「この打開のおかげで〜」などを分かりやすく振り返るために試合のリプレイ映像は欠かせません。今までは Premiere Pro を使用して、キャプチャ、編集、送出を素早くやっていましたが、前回のイベントではそこに割り当てる人材がおらず、リプレイシステムを諦めようかと考えていました。
しかし、世の中に ChatGPT など生成 AI が登場した今、その力を借りて半自動のリプレイシステムができないかと考え、Splatoon のリプレイ(ハイライト)自動生成システムを開発しました。
要件 & アーキテクチャ
シンプルにまとめるとリプレイシステムに求められる機能は、
- 入力映像を録画する
- 入力映像から複数の任意の区間を記録する
- 2 の区間の映像を連続した映像として出力する
といった流れになります。
放送の世界では、EVS と呼ばれる機材を使用して 1 と 3 を実現して、オペレーターが 2 を担当するような形になりますが、もちろんそんな予算はありませんので、全てを自前で揃える必要があります。
幸い、TouchDesigner を使用した映像の入出力に知見があったので、1 と 3 については、TouchDesigner を使用して、2 については OpenAI の API を使用して、オペレーターフリーでリプレイを作成するシステムを作ることにしました。
システムの概念図としては次の図のようになりました。
TouchDesigner
TouchDesigner で、以下のようなシステムを作りました。特別なことはしていないので、ざっくりどのようなことをしているかの概要を列挙します。
- Video Device In TOP で映像を入力
- Movie File Out TOP で映像を録画
- Movie File Out TOP で一定間隔でサムネイルを出力
- Web Client DAT で Go Server に OpenAI の API を呼び出す
- Table DAT に API の結果を格納
- Table DAT のシーンに従って Video Device Out TOP で出力
プロンプトエンジニアリング
OpenAI の API では、Sora などの動画生成の機能はありますが、動画そのものを入力として扱うことができません。そのため、動画を一定間隔で画像にして API を呼び出す必要があります。いくつか試した結果、以下のような構成で API を呼び出すことに決まりました。
- 使用したモデル: GPT-4o(GPT-5-mini が使えそうですね)
- FPS: 1
- 入力画像サイズ: 768x432
今回のリプレイシステムでは、リプレイのシーンを選ぶ部分を LLM が担当するので、プロンプトが一番重要です。プロンプトの作成にも ChatGPT の力を借りながら、最終的に以下のようなプロンプトになりました。
# 概要
あなたは、スポーツ(eスポーツ含む)のビデオハイライトクリエイターです。
Splatoon 3の試合動画において、以下の条件でハイライトを抽出してください。
# ハイライト基準
特に注目される部分は、特定のユーザーが連続でキル(例えば、2キル以上)を獲得した部分、勝利や逆転に大きく貢献した部分(例えば、延長戦中のエリア確保、重要なヤグラ防衛、アサリ獲得の瞬間など)です。
試合が終了した瞬間は、試合終了のシーンとして抽出してください。
# 入力
Splatoon 3 の試合の自動観戦視点で撮影されたビデオフレームです。
ビデオのフレームは %d fps のフレームレート、解像度は %s、0 から %d までのフレームです。
入力は試合途中の場合もあります。
# 出力
与えたビデオのフレームの中で、ハイライトとして選択されるべきシーンのリストを、以下の JSON フォーマットを厳密に守って出力してください。
- 出力する JSON オブジェクトには、ルール(rule)とシーンリスト(scenes)の2つの要素が含まれる
- ルールは「ナワバリバトル」「ガチエリア」「ガチヤグラ」「ガチアサリ」「ガチホコバトル」の5種類のうち、いずれかの文字列です
- シーンリストは配列で、シーンの要素には、開始時間(start)、終了時間(end)、理由(reason)の3つの要素が含まれる
- 開始時間と終了時間は、ゲーム内の残り時間ではなくビデオフレームの経過時間の秒数で、例えば 1 fps の場合、3フレーム目の経過時間は 3 です
- 出力には、改行や空白や ` + "```" + `などの記号を含めない
また、出力に関する以下の注意事項を必ず守ってください。
- ゲームのルールを判別して、そのルールにそぐわない理由(例えば、ホコなのにヤグラに乗る)はつけない
- 理由は、最大20文字までの文字列で、プレイヤーの名前は含めない
- 重要なシーンが切れることを避けるため、開始時間と終了時間の前後に 1秒 ずつ余裕を持たせる
- 一つのシーンの最短は 5秒 で、最長の目安は 30秒 ですが、延長戦中のエリア確保などはそれ以上の長さになっても構わない
- シーンは開始時間の昇順に並べる
- シーンの開始時刻は終了時刻よりも前になるようにする
# 出力例
{
"rule": "ガチエリア",
"scenes": [
{
"start": 0.0,
"end": 10.0,
"reason": "3連続キル達成"
},
{
"start": 50.0,
"end": 69.0,
"reason": "延長戦でエリア奪取成功"
}
]
}
出力やダブルクォートに関する指示もありますが、一応 API の呼び出し時に、response_format を type:"json_object" と指定しています。
実行すると以下のようなレスポンスが返ってきました。(見やすいように整形しています)
| start | end | reason |
|---|---|---|
| 45 | 50 | カウントリード |
| 34 | 48 | バリアを壊した |
| 170 | 179 | 試合終了 |
| 182 | 189 | 連続キル達成 |
| 198 | 209 | ゴールチャンス |
| 207 | 219 | リード奪取 |
reason は画面上に表示しても良かったのですが、結果的にはオペレーターが把握するためのものになりました。
課題
実際にシステムを稼働させてみると、いくつかの課題が出てきましたが、次のように対処しています。
API のレスポンスが遅いことがある
大体1分くらいで結果が生成できるのですが、数分待たされてしまうことがありました。試合が終わった後に「リプレイを使用したいタイミングまでに間に合わない!」ということが起こってしまいそうです。
API の実行時間そのものを短くするには、入力のコンテキスト(画像のサイズや枚数)を小さくするのも一つですが、そこまでしても大きな変化がなかったり、精度が悪くなってしまうため、やや富豪的な解決策ですが、一定間隔で API を呼び出すという手法にしました。
例えば、30秒毎に API を呼び出すようにしておくことで、30秒毎に常に最新のシーンのリストがあるため、流すタイミングに何も流せないということが起こらないようにしました。
ちなみに、API を呼び出す際には、前後関係などを把握してもらうために毎回 0 フレーム目からの画像を与えています。
順序がおかしくなる
前述の通り、すべての画像を使用して一定間隔で API を呼び出すため、前回呼び出したシーンと異なるシーンを抽出してきたり、時間に対して昇順ではないシーンの列挙であったりすることがありました。
対策として、API を処理する Go のバックエンド側で前回のシーンと新しいシーンをマージする仕組みや、過去の時間のシーンを無視するようなフィルター処理を入れるようにしました。
短い区間や連続した区間が含まれることがある
プロンプトには、シーンの時間を指定していますが、それでも稀に短い時間や連続した(10-20..20-30など)シーンを抽出してくることがありました。これについては、細かい制御が難しいため、最終的には人が判断できるよう操作用インターフェースで編集できるようにしました。(といっても TouchDesigner の TableDAT を OP Viewer で直接編集できるようにしただけですが...)
最終的には、シーン全体の時間(画面の Duration)を気にしながらリストを編集していました。
コスト
ここまでくると気になるのは OpenAI に掛かったコストですが、最終的には以下のようになりました。
- Cost: $3.40
- Total tokens: 6,714,183
- Total requests: 129
画像をバンバン投げていた印象ですが、非常に安いコストで驚きです。
まとめ
ChatGPT などの LLM の登場により、複雑なコンテキストを理解して要約するといった用途もある程度こなせるようになりました。当時は GPT-4 でしたが、現在では GPT-5 も登場していてより精度が高くなっていることでしょう。
最終的に回答結果を確認するといった人間の保証は必要ですが、今まで張り付いて時間を割いていた部分をオフロードさせることは可能でしょう。
次にこのシステムを使う時には、さらなるパワーアップができればと思います。(が、そんな時間はないかもしれないです)
それでは、良いお年を!


