# 機能設計書 49-サムネイルシート生成

## 概要

本ドキュメントは、StaxRipにおけるサムネイルシート生成機能の設計を記述する。この機能は、ビデオから一定間隔でフレームを抽出し、グリッド状に配置したサムネイルシート画像を生成する。

### 本機能の処理概要

サムネイルシート生成機能は、Thumbnailerクラスを通じてビデオ映像から複数フレームを抽出し、タイムスタンプ付きのサムネイルをグリッド配置した画像ファイルを生成する。

**業務上の目的・背景**：映像コンテンツの管理・共有において、サムネイルシートは映像の内容を一目で把握できる重要なアセットである。特にメディアライブラリ管理、配信前の確認、アーカイブ用途で活用される。

**機能の利用シーン**：
- 映像コンテンツの視覚的カタログ作成
- メディアライブラリの管理
- SNS/フォーラムでの映像紹介
- エンコード結果の確認

**主要な処理内容**：
1. VapourSynthスクリプトでソース映像読み込み
2. 指定間隔またはフレーム数でサンプリング
3. 各フレームにタイムスタンプをオーバーレイ
4. グリッド状にサムネイルを配置
5. ヘッダー情報（ファイル名、サイズ、解像度等）追加
6. JPG/PNG/BMP等で画像保存

**関連システム・外部連携**：
- VapourSynthフレームサーバー
- ffms2（フレームインデックス）
- GDI+（画像描画）
- System.Drawing（ビットマップ処理）

**権限による制御**：特になし（全ユーザーが利用可能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | MainForm | 設定画面 | サムネイル生成オプション設定 |
| - | OptionsForm | 設定画面 | ThumbnailerSettings詳細設定 |

## 機能種別

画像生成 / フレーム抽出 / ファイル出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sourcePath | String | Yes | ソース映像ファイルパス | 有効なパス |
| ThumbWidth | Integer | No | サムネイル幅 | 0-1920（デフォルト600） |
| Columns | Integer | No | 列数 | 1-50（デフォルト4） |
| Rows | Integer | No | 行数 | 1-80（デフォルト6） |
| Interval | Integer | No | 間隔（秒） | 1-1800（デフォルト60） |
| RowMode | ThumbnailerRowMode | No | 行数モード | Fixed/TimeInterval |

### 入力データソース

- プロジェクト設定（p.ThumbnailerSettings）
- ソース映像ファイル
- MediaInfo（映像情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| thumbnailSheet | Image | 生成されたサムネイルシート画像 |
| headerInfo | String | ヘッダーに表示する映像情報 |

### 出力先

- 画像ファイル（JPG/PNG/BMP/GIF/TIF）
- デフォルト: `%target_dir%\%target_name%_Thumbnail.{format}`

## 処理フロー

### 処理シーケンス

```
1. 設定読み込み
   └─ ThumbnailerSettingsからパラメータ取得
2. VapourSynthスクリプト準備
   └─ PrepareVapoursynthVideoScriptAsync()
3. ヘッダー情報取得
   └─ GetHeaderInfosAsync()でMediaInfoから情報収集
4. 画像初期化
   └─ Bitmap作成、Graphics初期化
5. サムネイル生成（並列処理）
   └─ Parallel.Forで各フレーム処理
6. タイムスタンプ描画
   └─ GraphicsPathでアウトライン付きテキスト
7. ヘッダー描画
   └─ TextRenderer.DrawText()
8. 画像保存
   └─ image.Save(filePath, encoder, parameters)
```

### フローチャート

```mermaid
flowchart TD
    A[サムネイル生成開始] --> B[ThumbnailerSettings読み込み]
    B --> C[VapourSynthスクリプト準備]
    C --> D[MediaInfoからヘッダー情報取得]
    D --> E[Bitmap/Graphics初期化]
    E --> F[Parallel.For開始]
    F --> G[各フレーム取得]
    G --> H[タイムスタンプ描画]
    H --> I[グリッド位置計算]
    I --> J[サムネイル配置]
    J --> K{全フレーム完了?}
    K -->|No| G
    K -->|Yes| L[ヘッダー描画]
    L --> M[画像保存]
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | HDR対応 | HDR映像は自動的にトーンマッピング | SourceVideoHdrFormat != SDR時 |
| BR-49-02 | サイズ制限 | ThumbWidthは最大1920px | 常時 |
| BR-49-03 | 並列処理 | 最大4スレッドで並列処理 | 常時 |
| BR-49-04 | アスペクト比 | DAR維持でリサイズ | 常時 |

### 計算ロジック

フレームサンプリング位置：
```
serverPos = (frames / thumbCount) * (index + 1) - (frames / thumbCount) / 2
```

グリッド位置計算：
```
rowPos = index \ columns
columnPos = index Mod columns
x = spacer + columnPos * (thumbWidth + spacer)
y = thumbVerticalOffset + rowPos * (thumbHeight + spacer)
```

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

### 操作別データベース影響一覧

本機能はデータベースを使用しない。設定はプロジェクトファイル（.srip）に保存される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| THUMB-001 | スクリプトエラー | VapourSynthスクリプトエラー | エラーメッセージ表示 |
| THUMB-002 | フレーム取得失敗 | GetFrame戻り値が0以外 | スキップして続行 |
| THUMB-003 | 画像保存失敗 | ディスク容量不足等 | IOエラーメッセージ表示 |

### リトライ仕様

エラー発生時は該当フレームをスキップして続行

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

該当なし（ファイルベース処理）

## パフォーマンス要件

- 並列処理: MaxDegreeOfParallelism = 4
- メモリ使用: 大画像生成時注意

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

- 出力パスの検証
- 一時ファイルの適切な削除

## 備考

- ThumbnailerRowMode.TimeIntervalで時間間隔ベースのサンプリング
- libplaceboによるHDRトーンマッピング対応

---

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

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

### 推奨読解順序

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

Thumbnailerクラスと設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Thumbnailer.vb | `Source/General/Thumbnailer.vb` | ThumbnailerRowMode enum（10-13行目） |
| 1-2 | Project.vb | `Source/General/Project.vb` | ThumbnailerSettings ObjectStorage（150-151行目） |

**読解のコツ**:
- **10-13行目**: ThumbnailerRowMode（Fixed/TimeInterval）
- **ThumbnailerSettings**: ObjectStorageでキー/値ペアで設定保存

#### Step 2: メインフローを理解する

RunAsync()メソッドの全体フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Thumbnailer.vb | `Source/General/Thumbnailer.vb` | RunAsync()（56-274行目） |

**主要処理フロー**:
- **67-68行目**: DAR取得
- **72-90行目**: ThumbnailerSettingsからパラメータ読み込み
- **165-166行目**: rows/thumbCount計算
- **181-263行目**: Parallel.Forでサムネイル生成

#### Step 3: VapourSynthスクリプト準備を理解する

PrepareVapoursynthVideoScriptAsync()を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Thumbnailer.vb | `Source/General/Thumbnailer.vb` | PrepareVapoursynthVideoScriptAsync()（278-320行目） |

**主要処理フロー**:
- **293行目**: ffms2.Sourceでソース読み込み
- **295-297行目**: resize.Spline64でリサイズ
- **299-306行目**: HDR映像の場合placebo.Tonemapでトーンマッピング

#### Step 4: ヘッダー情報取得を理解する

GetHeaderInfosAsync()を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Thumbnailer.vb | `Source/General/Thumbnailer.vb` | GetHeaderInfosAsync()（324-420行目） |

**主要処理フロー**:
- **331-376行目**: MediaInfoから映像/音声情報収集
- **378-411行目**: ビデオ/オーディオ/テキストストリーム情報

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

```
Thumbnailer.Run() / RunAsync()
    │
    ├─ GetHeaderInfosAsync()
    │      └─ MediaInfo.GetXxx() → HeaderInfo
    │
    ├─ PrepareVapoursynthVideoScriptAsync()
    │      ├─ VideoScript作成
    │      ├─ ffms2.Source
    │      ├─ resize.Spline64
    │      └─ placebo.Tonemap (HDR時)
    │
    ├─ FrameServerFactory.Create()
    │      └─ IFrameServer
    │
    └─ Parallel.For (サムネイル生成)
           ├─ GetFrame()
           ├─ GraphicsPath.AddString() → タイムスタンプ
           └─ imageGraphics.DrawImage() → グリッド配置
```

### データフロー図

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

ソース映像 ─────────▶ VapourSynthスクリプト ─▶ フレームデータ
    │                      │                         │
ThumbnailerSettings ──▶ パラメータ展開 ────────▶ グリッド設定
    │                      │                         │
MediaInfo ──────────▶ GetHeaderInfosAsync() ──▶ ヘッダーテキスト
    │                      │                         │
    └──────────────────────▶ Parallel.For ──────────▶ サムネイル画像
                               │                         │
                               ▼                         │
                           image.Save() ────────▶ 画像ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Thumbnailer.vb | `Source/General/Thumbnailer.vb` | ソース | サムネイル生成ロジック（全行） |
| Project.vb | `Source/General/Project.vb` | ソース | ThumbnailerSettings（150-151行目） |
| MediaInfo.vb | `Source/General/MediaInfo.vb` | ソース | 映像情報取得 |
| FrameServer.vb | `Source/Video/FrameServer.vb` | ソース | フレームサーバーインターフェース |
| Package.vb | `Source/General/Package.vb` | ソース | VapourSynth/ffms2パッケージ |
