# 帳票設計書 13-動画PNG連番+WAV

## 概要

本ドキュメントは、Godot Engineにおける動画出力機能のうち、PNG連番画像とWAVオーディオファイルによる出力に関する設計書である。ゲームプレイ録画をロスレス形式で出力し、高品質な動画制作のソース素材として利用可能にする。

### 本帳票の処理概要

本機能は、Godot Engineの MovieWriter システムを使用して、ゲーム画面をフレームごとにPNG連番画像として出力し、同時にオーディオデータをWAVファイルとして保存する。これにより、外部の動画編集ソフトウェアで高品質な動画制作が可能となる。

**業務上の目的・背景**：ゲーム開発において、プロモーション動画の制作、トレーラー作成、チュートリアル動画の作成、ゲームプレイのアーカイブなど、高品質な動画出力が必要となる場面が多い。PNG連番+WAV形式は完全にロスレスであるため、後処理での品質劣化がなく、プロフェッショナルな動画制作ワークフローに適している。FFmpegなどのツールで簡単に他の動画形式に変換できる。

**帳票の利用シーン**：ゲームトレーラーの制作、プロモーション動画の撮影、チュートリアル動画の収録、デモプレイの記録、品質検証用のゲームプレイ録画、バグ再現動画の作成など。

**主要な出力内容**：
1. PNG連番画像ファイル（basename00000000.png 〜）
2. WAVオーディオファイル（basename.wav）
3. フレームレートに同期した映像・音声データ
4. 32ビットPCMオーディオ（ステレオ〜7.1chサラウンド対応）

**帳票の出力タイミング**：エディタのムービー録画機能を有効にしてゲームを実行した際、またはコマンドラインから `--write-movie` オプションを指定して実行した際に出力される。

**帳票の利用者**：ゲーム開発者、マーケティング担当者、動画制作者、QAエンジニア

## 帳票種別

動画出力 / 連番画像・オーディオファイル出力

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | エディタ | Project > Movie Maker | ムービー録画設定・実行 |
| - | コマンドライン | --write-movie path.png | コマンドライン引数指定 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PNG（連番）+ WAV |
| 用紙サイズ | N/A（動画出力） |
| 向き | N/A |
| ファイル名 | {basename}{8桁連番}.png / {basename}.wav |
| 出力方法 | ファイル保存 |
| 文字コード | N/A（バイナリ） |

### PNG固有設定

| 項目 | 内容 |
|-----|------|
| 圧縮形式 | ロスレス（PNG標準） |
| 連番桁数 | 8桁（MAX_TRAILING_ZEROS = 8） |
| 最大フレーム数 | 99,999,999フレーム（60fpsで約19日間） |

### WAV固有設定

| 項目 | 内容 |
|-----|------|
| サンプリングレート | project設定 editor/movie_writer/mix_rate |
| ビット深度 | 32ビット（固定） |
| チャンネル数 | 2〜8（スピーカーモード依存） |
| フォーマット | PCM（非圧縮） |

## 帳票レイアウト

### レイアウト概要

PNG連番ファイルと1つのWAVファイルで構成される。

```
出力ディレクトリ/
├── basename00000000.png    (フレーム0)
├── basename00000001.png    (フレーム1)
├── basename00000002.png    (フレーム2)
│   ...
├── basename{nnnnnnnn}.png  (最終フレーム)
└── basename.wav            (オーディオ全体)
```

### PNGファイル構成

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | PNGシグネチャ | PNG識別子 | 固定値 | 8バイト |
| 2 | IHDRチャンク | 画像ヘッダー | movie_size | バイナリ |
| 3 | IDATチャンク | 圧縮画像データ | フレームバッファ | DEFLATE圧縮 |
| 4 | IENDチャンク | 終端マーカー | 固定値 | バイナリ |

### WAVファイル構成

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | RIFFヘッダー | ファイル形式識別 | 固定値 | "RIFF" + サイズ + "WAVE" |
| 2 | fmtチャンク | フォーマット情報 | project設定 | 24バイト |
| 3 | dataチャンク | オーディオデータ | AudioServer | PCM 32bit |

### WAV fmtチャンク詳細

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 圧縮コード | PCM形式 | 固定値 | 1 (16bit LE) |
| 2 | チャンネル数 | スピーカーモード | speaker_mode | 2/4/6/8 |
| 3 | サンプルレート | 混合レート | mix_rate | 32bit LE |
| 4 | バイト/秒 | mix_rate * blockalign | 計算値 | 32bit LE |
| 5 | ブロックアライン | bits/8 * channels | 計算値 | 16bit LE |
| 6 | ビット深度 | サンプル精度 | 固定値 | 32 (16bit LE) |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 出力パス | .png 拡張子で終わるパス | Yes |
| 映像サイズ | movie_size が有効な値 | Yes |
| FPS | 0より大きい値 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | フレーム番号 | 昇順（連番） |

### 改ページ条件

N/A（動画出力）

## データベース参照仕様

### 参照テーブル一覧

N/A（リアルタイムレンダリング出力）

### プロジェクト設定参照

| 設定キー | 用途 | デフォルト値 |
|---------|------|-------------|
| editor/movie_writer/mix_rate | オーディオサンプルレート | 48000 |
| editor/movie_writer/speaker_mode | スピーカーモード | STEREO |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ブロックアライン | bits_per_sample / 8 * channels | - | WAV用 |
| バイト/秒 | mix_rate * blockalign | - | WAV用 |
| オーディオブロックサイズ | (mix_rate / fps) * blockalign | - | 1フレームあたりのバイト数 |
| ファイル名連番 | zeros_str(frame_count) | 8桁ゼロ埋め | PNG用 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[write_begin 呼び出し] --> B[出力パス設定]
    B --> C[既存ファイル削除]
    C --> D[WAVファイル作成]
    D --> E[WAVヘッダー書き込み]
    E --> F[fmtチャンク書き込み]
    F --> G[dataチャンクヘッダー書き込み]
    G --> H{フレームループ}
    H --> I[write_frame 呼び出し]
    I --> J[PNG バッファ生成]
    J --> K[PNGファイル保存]
    K --> L[WAVオーディオデータ追記]
    L --> M{次フレーム?}
    M -->|Yes| H
    M -->|No| N[write_end 呼び出し]
    N --> O[WAVサイズフィールド更新]
    O --> P[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ディレクトリアクセス失敗 | DirAccess::open 失敗 | ERR_FAIL_COND_V(d.is_null(), FAILED) | パスを確認 |
| WAVファイル作成失敗 | FileAccess::open 失敗 | ERR_FAIL_COND_V(f_wav.is_null(), ERR_CANT_OPEN) | 書き込み権限を確認 |
| PNGファイル作成失敗 | FileAccess::open 失敗 | 暗黙的エラー | パスを確認 |
| 未設定状態での呼び出し | f_wav が null | ERR_FAIL_COND_V(f_wav.is_null(), ERR_UNCONFIGURED) | write_begin を先に呼ぶ |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定フレーム数 | 最大99,999,999フレーム |
| 目標出力時間 | リアルタイム以下（フレームドロップなし） |
| 同時出力数上限 | 1（シングルインスタンス） |
| ディスク容量 | 1920x1080, 60fps で約 2-5 MB/フレーム |

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

- 出力パスはユーザー指定のため、パストラバーサル攻撃に注意が必要
- 大量のファイル生成によるディスク枯渇攻撃の可能性
- 既存ファイルの上書きが発生するため、重要ファイルの保護が必要

## 備考

- PNG連番は8桁固定で、約19日間（60fps）の録画が可能
- WAVファイルは録画終了時にサイズフィールドが更新される
- 録画開始時に既存の連番ファイルは自動削除される
- base_path が相対パスの場合は "res://" が自動付加される

---

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

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

### 推奨読解順序

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

まず、MovieWriter 基底クラスとPNGWAV実装の関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | movie_writer.h | `servers/movie_writer/movie_writer.h` | MovieWriter 抽象クラスの仮想関数定義 |
| 1-2 | movie_writer_pngwav.h | `servers/movie_writer/movie_writer_pngwav.h` | MovieWriterPNGWAV クラスのメンバ変数定義 |

**読解のコツ**: MovieWriter は抽象基底クラスで、PNGWAV と MJPEG が具象実装。write_begin/write_frame/write_end の3段階処理パターン。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | handles_file による .png 拡張子マッチング（行47-48） |
| 2-2 | movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | コンストラクタでのproject設定読み込み（行168-171） |

**主要処理フロー**:
1. **行168-171**: コンストラクタで mix_rate と speaker_mode を取得
2. **行47-48**: handles_file で .png 拡張子をチェック
3. **行62-141**: write_begin でWAVファイル初期化
4. **行143-155**: write_frame でPNG/WAV書き込み
5. **行157-166**: write_end でWAVサイズ更新

#### Step 3: 初期化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | write_begin の実装（行62-141） |

**主要処理フロー**:
- **行65-68**: base_path の設定と正規化
- **行70-83**: 既存PNG連番ファイルの削除処理
- **行85-86**: WAVファイルのオープン
- **行90-137**: WAVヘッダーの書き込み

#### Step 4: フレーム書き込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | write_frame の実装（行143-155） |
| 4-2 | movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | zeros_str ヘルパー関数（行51-60） |

**主要処理フロー**:
- **行146**: Image::save_png_to_buffer() でPNGデータ生成
- **行148-149**: 連番ファイル名生成とPNG保存
- **行150**: WAVへのオーディオデータ追記

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

```
MovieWriter::begin(movie_size, fps, base_path)
    │
    └─ MovieWriterPNGWAV::write_begin(movie_size, fps, base_path)
           │
           ├─ DirAccess::open() - 既存ファイル削除
           │
           └─ FileAccess::open() - WAVファイル作成
                  │
                  └─ WAVヘッダー書き込み

MovieWriter::add_frame()
    │
    └─ MovieWriterPNGWAV::write_frame(image, audio_data)
           │
           ├─ image->save_png_to_buffer()
           │       │
           │       └─ PNG圧縮処理
           │
           ├─ FileAccess::open() - PNGファイル作成
           │       │
           │       └─ store_buffer(png_data)
           │
           └─ f_wav->store_buffer(audio_data)

MovieWriter::end()
    │
    └─ MovieWriterPNGWAV::write_end()
           │
           └─ WAVサイズフィールド更新
                  │
                  ├─ f_wav->seek(4)
                  │
                  └─ f_wav->store_32(total_size)
```

### データフロー図

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

フレームバッファ
    │
    └─ Ref<Image> ──────▶ save_png_to_buffer() ───▶ {basename}{n}.png
                                │
                                ▼
                          PNG圧縮 (DEFLATE)

AudioServer出力
    │
    └─ int32_t[] ───────▶ store_buffer() ─────────▶ {basename}.wav
                                │
                                ▼
                          PCM 32bit 書き込み

project設定
    │
    ├─ mix_rate ─────▶ WAV fmtチャンク
    │
    └─ speaker_mode ──▶ チャンネル数決定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| movie_writer_pngwav.cpp | `servers/movie_writer/movie_writer_pngwav.cpp` | ソース | PNGWAV出力の主実装 |
| movie_writer_pngwav.h | `servers/movie_writer/movie_writer_pngwav.h` | ヘッダー | クラス宣言 |
| movie_writer.h | `servers/movie_writer/movie_writer.h` | ヘッダー | MovieWriter基底クラス |
| movie_writer.cpp | `servers/movie_writer/movie_writer.cpp` | ソース | MovieWriter基底実装 |
| image.h | `core/io/image.h` | ヘッダー | Image::save_png_to_buffer |
| file_access.h | `core/io/file_access.h` | ヘッダー | ファイル書き込みAPI |
| dir_access.h | `core/io/dir_access.h` | ヘッダー | ディレクトリ操作API |
| project_settings.h | `core/config/project_settings.h` | ヘッダー | project設定取得 |
