# 機能設計書 10-タイムスタンプ抽出

## 概要

本ドキュメントは、StaxRipアプリケーションにおけるタイムスタンプ抽出機能の設計仕様を記述する。可変フレームレート（VFR）ファイルからフレームタイムスタンプ情報を抽出し、エンコード後のファイルに適用するための機能である。

### 本機能の処理概要

**業務上の目的・背景**：可変フレームレート（VFR）ビデオは、各フレームの表示タイミングが一定ではない。アニメーションや映画素材では意図的にVFRが使用されることがある。エンコード処理では一般的に固定フレームレート（CFR）に変換されるが、タイムスタンプ情報を保持することで、Mux時に元のVFRタイミングを再現できる。

**機能の利用シーン**：
- VFRのMKVファイルからのタイムスタンプ抽出
- アニメ素材（24fps/30fps混合）の処理
- 映画素材（テレシネ素材）の処理
- タイムスタンプのMux時適用

**主要な処理内容**：
1. VFR判定（MediaInfo FrameRate_Mode確認）
2. mkvextract timestamps_v2でタイムスタンプ抽出
3. 抽出タイムスタンプのMux時適用

**関連システム・外部連携**：
- mkvextract timestamps_v2：タイムスタンプ抽出
- MediaInfo：VFR判定（FrameRate_Mode）
- mkvmerge --timestamps：タイムスタンプMux

**権限による制御**：特になし。ファイルシステムへの読み書きアクセス権が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | MainForm | 主画面 | タイムスタンプ抽出設定 |

## 機能種別

データ抽出 / メタデータ処理 / VFR処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sourceFile | String | Yes | MKVファイルパス | 拡張子チェック（mkv） |
| extractTimestamps | TimestampsMode | Yes | 抽出モード（Never/Always/VFR時） | - |

### 入力データソース

- プロジェクト設定：p.ExtractTimestamps
- ソースファイル情報：proj.SourceFrameRateMode

### 対応入力形式

- MKV

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| タイムスタンプファイル | File | _timestamps.txt（v2形式） |

### 出力先

- プロジェクト一時ディレクトリ（proj.TempDir）

## 処理フロー

### 処理シーケンス

```
1. 抽出モード確認
   └─ p.ExtractTimestamps != TimestampsMode.Never
2. VFR判定
   └─ ExtractTimestamps == Always または FrameRate_Mode == "VFR"
3. ストリーム順序取得
   └─ MediaInfo.GetVideo("StreamOrder")
4. タイムスタンプ抽出
   └─ mkvextract timestamps_v2 streamOrder:_timestamps.txt
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ExtractTimestamps?}
    B -->|Never| C[終了]
    B -->|Always/VFR| D{ソースがMKV?}
    D -->|No| C
    D -->|Yes| E{Always または VFR?}
    E -->|No| C
    E -->|Yes| F[StreamOrder取得]
    F --> G[mkvextract timestamps_v2]
    G --> H[_timestamps.txt出力]
    H --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | MKV限定 | MKVファイルのみ対応 | 常時 |
| BR-002 | Neverモード | Never設定時は抽出しない | p.ExtractTimestamps == Never |
| BR-003 | Alwaysモード | 常にタイムスタンプ抽出 | p.ExtractTimestamps == Always |
| BR-004 | VFRモード | VFRファイルの場合のみ抽出 | FrameRate_Mode == "VFR" |

### 計算ロジック

- VFR判定：MediaInfo.GetVideo("FrameRate_Mode") == "VFR"
- ストリーム順序：MediaInfo.GetVideo("StreamOrder").ToInt

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-001 | NotMKV | MKV以外のファイル | スキップ |
| E-002 | ExtractError | mkvextract失敗 | ログ出力（終了コード1,2は許容） |

### リトライ仕様

リトライ処理は行わない。

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

本機能はトランザクション管理を行わない。

## パフォーマンス要件

- タイムスタンプ抽出：瞬時（メタデータのみ）

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

- ファイルパスのエスケープ処理

## 備考

- mkvextract終了コード0,1,2を許容
- タイムスタンプv2形式：各フレームのタイムスタンプをミリ秒で記録
- CommandLineDemuxerとmkvDemuxerの両方でタイムスタンプ抽出を実装

---

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

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

### 推奨読解順序

#### Step 1: タイムスタンプ抽出モードを理解する

TimestampsMode列挙型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Project.vb | `Source/General/Project.vb` | ExtractTimestampsプロパティ |

**TimestampsMode値**:
- **Never**: タイムスタンプ抽出しない
- **Always**: 常にタイムスタンプ抽出
- **VFR時のみ**: FrameRate_Mode="VFR"の場合のみ抽出

#### Step 2: mkvDemuxerでの実装を理解する

mkvDemuxerでのタイムスタンプ抽出処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Demux.vb | `Source/General/Demux.vb` | mkvDemuxer.Runのタイムスタンプ処理（782-797行目） |

**主要処理フロー**:
- **782行目**: p.ExtractTimestamps != TimestampsMode.Neverで有効化確認
- **783行目**: Always または FrameRate_Mode="VFR"で抽出判定
- **784行目**: StreamOrder取得
- **786-795行目**: mkvextract timestamps_v2実行

#### Step 3: CommandLineDemuxerでの実装を理解する

CommandLineDemuxerでのタイムスタンプ抽出処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Demux.vb | `Source/General/Demux.vb` | CommandLineDemuxer.Runのタイムスタンプ処理（154-169行目） |

**主要処理フロー**:
- **154行目**: p.ExtractTimestamps != TimestampsMode.Neverで有効化確認
- **154行目**: ソースファイルがMKV拡張子で終わる場合のみ
- **155行目**: Always または SourceFrameRateMode="VFR"で抽出判定
- **156行目**: StreamOrder取得
- **158-167行目**: mkvextract timestamps_v2実行

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

```
[mkvDemuxer]
mkvDemuxer.Run(proj)
    │
    ├─ p.ExtractTimestamps != TimestampsMode.Never
    │
    ├─ proj.SourceFile.EndsWithEx(".mkv")
    │
    ├─ p.ExtractTimestamps == Always || FrameRate_Mode == "VFR"
    │
    ├─ MediaInfo.GetVideo("StreamOrder")
    │
    └─ mkvextract timestamps_v2 streamOrder:_timestamps.txt

[CommandLineDemuxer]
CommandLineDemuxer.Run(proj)
    │
    ├─ p.ExtractTimestamps != TimestampsMode.Never
    │
    ├─ proj.SourceFile.EndsWithEx(".mkv")
    │
    ├─ p.ExtractTimestamps == Always || proj.SourceFrameRateMode == "VFR"
    │
    ├─ MediaInfo.GetVideo("StreamOrder")
    │
    └─ mkvextract timestamps_v2 streamOrder:_timestamps.txt
```

### データフロー図

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

MKVファイル ────────▶ ExtractTimestamps判定
                              │
                              ▼
                     VFR/Always判定
                              │
                              ▼
                     MediaInfo.GetVideo("StreamOrder")
                              │
                              ▼
                     mkvextract timestamps_v2
                              │
                              └───────────────────▶ _timestamps.txt
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Demux.vb | `Source/General/Demux.vb` | ソース | mkvDemuxer/CommandLineDemuxerタイムスタンプ処理 |
| Project.vb | `Source/General/Project.vb` | ソース | ExtractTimestampsプロパティ |
| Misc.vb | `Source/General/Misc.vb` | ソース | MediaInfo.GetVideoメソッド |
| Package.vb | `Source/General/Package.vb` | ソース | mkvextractパッケージ定義 |
