# 機能設計書 71-動画再生

## 概要

プレイ画面の背景にMCI(Media Control Interface)経由で動画ファイルを再生する機能の設計書である。

### 本機能の処理概要

譜面ファイルで指定された動画ファイルをプレイ画面の背景に再生する機能を提供する。Windows標準のMCI(Media Control Interface)を利用してMPEGVideo形式の動画を制御する。

**業務上の目的・背景**：音楽ゲームのプレイ体験を視覚的に強化するため、背景に動画を表示する機能が必要である。譜面制作者が動画ファイルを譜面データに組み込むことで、楽曲と映像を同期させた演出が可能となる。

**機能の利用シーン**：譜面ファイルに動画ファイル(cmovfile)が指定されており、かつスクリーンショット出力モード(output)が無効な場合にプレイ画面の背景として動画が再生される。vmov変数が1の場合にMCI経由での動画再生が実行される。

**主要な処理内容**：
1. 譜面データから動画ファイルパス(cmovfile)を取得し、MCI openコマンドでMPEGVideoとして動画を開く
2. 音声をオフに設定し、時間フォーマットをミリ秒に設定する
3. ウィンドウハンドルを指定し、表示領域(destination)を画面サイズに基づいて計算・設定する
4. 再生タイミング(voffset + T_MOEX_DELAY + globaloffset)に達した時点でMCI playコマンドで再生を開始する
5. 再生開始時点でのオフセット計算により、音楽と動画のタイミングを同期する

**関連システム・外部連携**：Windows MCI(Media Control Interface)によるMPEGVideo再生制御を利用する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | play_video.hspによるMCI経由プレイ画面背景への動画再生 |

## 機能種別

メディア再生処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cmovfile | string | Yes | 動画ファイルパス | 空文字でないこと |
| vmov | int | Yes | 動画再生モード(0:無効, 1:MCI再生) | 0または1 |
| voffset | int | No | 動画再生オフセット(ms) | 整数値 |
| output | int | Yes | スクリーンショット出力モード(0:通常再生) | 0であること |
| t | int | Yes | 現在のゲーム時間(ms) | 整数値 |
| globaloffset | int | No | グローバルオフセット(ms) | 整数値 |

### 入力データソース

譜面ファイル(.ksh)のヘッダ情報(mvol, movie, movieoffset等)から取得される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| vfl | int | 動画再生開始フラグ(0:未再生, 1:再生中) |
| t_vo | int | 動画再生開始基準時間 |

### 出力先

プレイ画面のウィンドウ上にMCI経由で動画がオーバーレイ表示される。

## 処理フロー

### 処理シーケンス

```
1. loadChartVideo (動画読み込み)
   ├─ cmovfileが空文字でなく、outputが0であるか確認
   ├─ vmovが1の場合、MCI openコマンドで動画ファイルを開く
   ├─ MCI set audio all offで音声をオフ
   ├─ MCI set time format msで時間フォーマットをミリ秒に設定
   ├─ MCI window handleでウィンドウハンドルを設定
   └─ MCI put destinationで表示領域を設定

2. playVideoIfTimeReachesOffset (動画再生開始判定)
   ├─ 再生開始時間(-voffset - T_MOEX_DELAY - globaloffset)に達したか判定
   ├─ vflが0(未再生)かつvmov>=1であるか確認
   ├─ cmovfileが空文字でなく、outputが0であるか確認
   ├─ vmovが1の場合:
   │   ├─ tが再生開始時間を超えている場合、MCI seekで位置を移動
   │   └─ MCI playで再生開始
   ├─ t_voを計算(動画と音楽の同期基準)
   └─ vflを1に設定(再生中フラグ)
```

### フローチャート

```mermaid
flowchart TD
    A[loadChartVideo] --> B{cmovfile != 空 AND output == 0?}
    B -->|No| Z1[return]
    B -->|Yes| C{vmov == 1?}
    C -->|No| Z1
    C -->|Yes| D[MCI open - MPEGVideo]
    D --> E[MCI set audio all off]
    E --> F[MCI set time format ms]
    F --> G[MCI window handle設定]
    G --> H[MCI put destination設定]
    H --> Z1

    I[playVideoIfTimeReachesOffset] --> J{再生タイミング到達 AND vfl==0 AND vmov>=1?}
    J -->|No| Z2[return]
    J -->|Yes| K{cmovfile != 空 AND output == 0?}
    K -->|No| Z2
    K -->|Yes| L{vmov == 1?}
    L -->|Yes| M{t > 再生開始時間?}
    M -->|Yes| N[MCI seek to 位置]
    N --> O[MCI play]
    M -->|No| O
    L -->|No| P[t_vo計算]
    O --> P
    P --> Q[vfl = 1]
    Q --> Z2
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | 動画再生条件 | cmovfileが空でなく、outputが0の場合のみ動画を読み込み・再生する | 常時 |
| BR-71-02 | 音声ミュート | 動画自体の音声は常にオフに設定される(楽曲音声と二重にならないようにする) | 動画読み込み時 |
| BR-71-03 | 同期制御 | 再生開始が遅れた場合、MCI seekで適切な位置にシークしてから再生する | 再生開始時にtが開始時間を超えている場合 |
| BR-71-04 | T_MOEX_DELAY定数 | 動画再生遅延の補正値として0ms(定数)が定義されている | 常時 |

### 計算ロジック

- 再生開始時間 = `-voffset - T_MOEX_DELAY - globaloffset`
- シーク位置(ms) = `t - 再生開始時間`

## データベース操作仕様

該当なし（ファイルベースのメディア再生機能のため）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル不在 | cmovfileで指定されたファイルが存在しない | MCI openが失敗するが、明示的なエラー処理はない |
| - | フォーマット非対応 | MCIが対応していない動画フォーマット | MCI openが失敗するが、明示的なエラー処理はない |

### リトライ仕様

リトライ処理は実装されていない。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- 動画再生はMCIに委譲されるため、システム側での追加的なパフォーマンス制御はない
- スクリーンショット出力モード(output!=0)時には動画再生は行わない

## セキュリティ考慮事項

- 動画ファイルパスは譜面ファイルから取得されるため、パストラバーサルのリスクがある
- ローカルファイルのみを対象とする

## 備考

- T_MOEX_DELAY定数は0に定義されており、将来の遅延補正用に予約されている
- vmov変数の値が2以上の場合の挙動はplayVideoIfTimeReachesOffsetの条件(`vmov>=1`)で再生開始判定には含まれるが、実際のMCI操作は`vmov=1`でのみ実行される
- 動画再生外枠の描画はplay_draw_frame.hsp内(1020-1024行目)で`cmov=0 AND vmov=1 AND output=0`の条件で行われる

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

本機能で使用される主要な変数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | kshootmania.hsp | `kshootmania.hsp` | T_MOEX_DELAY定数(79行目: `#const T_MOEX_DELAY 0`)の定義を確認する |

**読解のコツ**: HSP3言語では`#const`でコンパイル時定数、`#define`でマクロ定義を行う。MCI(Media Control Interface)はWindowsのマルチメディア制御APIであり、`mci`命令で文字列コマンドを送信して制御する。

#### Step 2: エントリーポイントを理解する

動画読み込み処理の起点となる関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_video.hsp | `src/scene/play/play_video.hsp` | loadChartVideo関数(1-12行目)で動画ファイルのMCIオープン処理を理解する |

**主要処理フロー**:
1. **1行目**: `#deffunc loadChartVideo` - 動画読み込み関数の定義
2. **2行目**: `if((cmovfile!="")&(output=0))` - 動画ファイルが指定されておりスクリーンショットモードでないことを確認
3. **3行目**: `if(vmov=1)` - MCI再生モードかの判定
4. **4行目**: `mci "open \""+cmovfile+"\" type MPEGVideo alias v"` - MCIでMPEGVideo形式として動画を開く(エイリアス名"v")
5. **5行目**: `mci "set v audio all off"` - 動画の音声を全てオフにする
6. **6行目**: `mci "set v time format ms"` - 時間フォーマットをミリ秒に設定
7. **8行目**: `mci "window v handle "+hwnd` - 表示先ウィンドウハンドルを設定
8. **9行目**: `mci "put v destination at ..."` - 表示領域の座標とサイズを設定

#### Step 3: 再生タイミング制御を理解する

再生開始判定処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_video.hsp | `src/scene/play/play_video.hsp` | playVideoIfTimeReachesOffset関数(14-28行目)で再生タイミング制御を理解する |

**主要処理フロー**:
- **15行目**: `if((-voffset-T_MOEX_DELAY-globaloffset<=t)&(vfl=0)&(vmov>=1))` - 再生開始条件の判定(オフセット考慮の再生開始時間に到達、未再生、動画モード有効)
- **18行目**: `if(vmov=1)` - MCI再生モードの場合の処理分岐
- **19行目**: `if(t>stat1):mci "seek v to "+(t-stat1)` - 遅延発生時のシーク処理
- **20行目**: `mci "play v"` - MCI再生コマンドの実行
- **22-24行目**: t_voの計算(音楽との同期基準時間の設定)
- **25行目**: `vfl=1` - 再生中フラグの設定

#### Step 4: 描画フレームでの関連処理を理解する

動画再生枠の描画処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | drawFrame関数内の動画外枠描画処理(1020-1024行目) |

**主要処理フロー**:
- **1020行目**: `if((cmov=0)&(vmov=1)&(output=0))` - 動画再生外枠の描画条件(MCI再生かつ出力モードでない)
- **1021-1023行目**: 半透明の白色矩形で動画再生領域の外枠を描画

### プログラム呼び出し階層図

```
play_init (プレイ画面初期化)
    │
    ├─ loadChartVideo
    │      ├─ mci "open" (動画ファイルオープン)
    │      ├─ mci "set audio all off" (音声オフ)
    │      ├─ mci "set time format ms" (時間フォーマット設定)
    │      ├─ mci "window handle" (表示ウィンドウ設定)
    │      └─ mci "put destination" (表示領域設定)
    │
play_update (プレイ画面更新)
    │
    ├─ playVideoIfTimeReachesOffset
    │      ├─ mci "seek v to" (再生位置シーク)
    │      └─ mci "play v" (再生開始)
    │
drawFrame (描画フレーム)
    │
    └─ 動画再生外枠描画 (1020-1024行目)
```

### データフロー図

```
[入力]                   [処理]                      [出力]

譜面データ(cmovfile) ──▶ loadChartVideo          ──▶ MCI動画オブジェクト(alias "v")
                          (MCI open/set/window)
                              │
ゲーム時間(t)        ──▶ playVideoIfTimeReaches  ──▶ vfl=1 (再生中フラグ)
voffset, globaloffset      Offset                     t_vo (同期基準時間)
                          (MCI seek/play)
                              │
                         drawFrame               ──▶ 動画外枠の描画
                          (外枠描画)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_video.hsp | `src/scene/play/play_video.hsp` | ソース | 動画読み込み・再生制御の主要ファイル(全28行) |
| play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | ソース | 描画フレーム処理(動画外枠描画: 1020-1024行目) |
| kshootmania.hsp | `kshootmania.hsp` | ソース | T_MOEX_DELAY定数の定義(79行目) |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | 譜面読み込み時にcmovfile, voffset, vmov等の動画関連パラメータを設定 |
