# Video encoding parameters

ビデオストレージが有効な場合、LeRobotはタイムステップごとの画像ファイルを保存する代わりに、各カメラストリームを**MP4**ファイルとして保存します。ビデオエンコードは時間軸に沿って圧縮を行うため、PNGの山を扱う場合と比べて、通常はデータセットのサイズとI/Oを削減できます。また、MP4はすべてのプレイヤーやローダーが理解する形式であるため、互換性を保ちます。

MP4へのフレームエンコードは、エンコーダーの選択、ピクセルフォーマット、GOP/キーフレーム、品質と速度のバランス、および任意の追加エンコーダーフラグを含む、完全なFFmpegパイプラインです。これらの設定の多くは、PyAVを介して渡されるネストされた`RGBEncoderConfig`（`lerobot.configs.video.RGBEncoderConfig`）である`rgb_encoder`を通じて、ユーザーが調整できます。

これらのパラメータは、`--dataset.rgb_encoder.<field>`（例：`lerobot-record`または`lerobot-rollout`）を介してCLIから設定できます。このブロックは、その実行のすべてのカメラ映像ストリームに適用されます。

> [!TIP]
> `rgb_encoder` が効果を発揮するには、ビデオの保存を有効にする必要があります — Python API では `use_videos=True`、CLI では `--dataset.video=true`（録画時のデフォルト値）を指定します。ビデオが無効の場合、入力は画像のままとなり、`rgb_encoder` は無視されます。

**いつ**フレームが書き込まれるのか、エンコードされるのか（ストリーミングかエピソード後か）の詳細、キュー、およびその他のトップレベルの`--dataset.*`スイッチについては、[Streaming Video Encoding](./streaming_video_encoding)を参照してください。エンコードパラメータの比較と実験については、[video-benchmark Space](https://huggingface.co/spaces/lerobot/video-benchmark)を参照してください。

---

## 例

```bash
lerobot-record \
    --robot.type=so100_follower \
    --robot.port=/dev/tty.usbmodem58760431541 \
    --robot.cameras="{laptop: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --robot.id=black \
    --teleop.type=so100_leader \
    --teleop.port=/dev/tty.usbmodem58760431551 \
    --teleop.id=blue \
    --dataset.repo_id=<my_username>/<my_dataset_name> \
    --dataset.num_episodes=2 \
    --dataset.single_task="Grab the cube" \
    --dataset.streaming_encoding=true \
    --dataset.encoder_threads=2 \
    --dataset.rgb_encoder.vcodec=h264 \
    --dataset.rgb_encoder.preset=fast \
    --dataset.rgb_encoder.extra_options='{"tune": "film", "profile:v": "high", "bf": 2}' \
    --display_data=true
```

---

## チューニングパラメータ

> [!WARNING]
> デフォルト値は、一般的なロボティクスデータセットにおいて**圧縮率**、**視覚品質**、**デコード/シーク速度**のバランスを取るよう調整されています。これらの値を変更すると、録画（CPU負荷、フレームドロップ）と学習（デコードスループット、画像品質）の両方に影響を与える可能性があります。
>
> これらのパラメータを上書きするのは、明確な理由がある場合のみとし、新しい設定に依存する前に、パイプラインへの影響を測定してください。

以下のすべてのフラグは、CLI では `--dataset.rgb_encoder.` というプレフィックスが付与されます。

| パラメータ       | 型             | デフォルト       | 説明                                                                                                                                                                                                             |
| --------------- | ---------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`            | `"libsvtav1"` | ビデオコーデック名。`"auto"`は、固定の優先度リストから最初の利用可能なハードウェアエンコーダーを選択し、利用できない場合は`libsvtav1`にフォールバックします。                                                                                        |
| `pix_fmt`       | `str`            | `"yuv420p"`   | 出力ピクセル形式。選択したコーデックが、お使いのFFmpegビルドでサポートしている必要があります。                                                                                                                                        |
| `g`             | `int`            | `2`           | GOPサイズ — `g`フレームごとにキーフレームを出力します。FFmpegオプションの`g`として出力されます。                                                                                                                                                   |
| `crf`           | `int`または`float` | `30`          | 抽象的な品質値。コーデックごとにマッピングされます（[マッピング](https://github.com/huggingface/lerobot/blob/main/src/lerobot/configs/video.py#L197)を参照）。マッピングが単調な場合、値が低いほど品質が高く、出力サイズが大きくなります。 |
| `preset`        | `int`または`str`   | `12` \*       | エンコーダーの速度プリセット。意味はコーデックによって異なります。\* 未設定かつ`vcodec=libsvtav1`の場合、LeRobotはデフォルトで`12`を使用します。                                                                                                |
| `fast_decode`   | `int`            | `0`           | `libsvtav1`: `0–2`、`svtav1-params`経由で指定します。`h264` / `hevc`（ソフトウェア）: `>0`の場合、`tune=fastdecode`を設定します。その他のコーデック: 通常は使用されません。                                                                    |
| `video_backend` | `str`            | `"pyav"`      | 現在、動画エンコーディングには`"pyav"`のみが実装されています。                                                                                                                                                              |
| `extra_options` | `dict`           | `{}`          | 上記の構造化フィールドの後にマージされる、FFmpegまたはコーデック固有の追加オプションです。これらのフィールドによって既に設定されているキーは上書きできません。                                                                                      |

---

## 深度ストリーム

深度マップ（Intel RealSense、Reachy 2）は、RGB ストリームと並んで、**独自のビデオストリーム**として保存されます。生深度（`uint16` のミリメートルまたは `float32` のメートル）は 8 ビットコーデックでは保持できないため、LeRobot は各マップを 12 ビットコード（`[0, 4095]`）に**量子化**します。これはデフォルトで対数的に行われ、深度センサーの `1/depth` エラープロファイルに合わせるためです。その後、高ビット深度のピクセルフォーマット（`gray12le`）にパッキングし、12 ビットコーデックでエンコードします。

  
    
      生深度
      
        uint16 mm
        
        float32 m
      
    
    
      →
    
    
      
        記録時間
      
      
        Clip
        
          to [depth_min,
          
          depth_max]
        
      
      
        →
      
      
        量子化
        
          12ビットコード 0–4095
          
          log (default) または linear
        
      
      
        →
      
      
        Pack
        
          gray12le
          
          plane
        
      
      
        →
      
      
        エンコード
        
          HEVC
          
          メイン 12
        
      
    
    
      →
    
    
      MP4
      
        保存
        
        ストリーム
      
    
    
      →
    
    
      
        読み込み時間
      
      
        Dequantize
        
          mm / m へ
        
      
    
  

並列の**`depth_encoder`**ブロック（`DepthEncoderConfig`）を通じて深度パイプラインを設定します。これは`RGBEncoderConfig`のすべてのフィールド（`vcodec`、`pix_fmt`、`crf`、…）を共有し、`--dataset.depth_encoder.<field>`で設定する4つの量子化パラメータを追加します。

```bash
lerobot-record \
    ... \
    --dataset.depth_encoder.vcodec=hevc \
    --dataset.depth_encoder.depth_min=0.05 \
    --dataset.depth_encoder.depth_max=5.0 \
    --dataset.depth_encoder.use_log=true
```

| パラメータ       | 型    | デフォルト                         | 説明                                                                                                                            |
| --------------- | ------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`   | `"hevc"`                        | HEVC Main 12（12ビット対応のコーデック、MP4互換）。                                                                                 |
| `extra_options` | `dict`  | `{"x265-params": "lossless=1"}` | **Depth はデフォルトで lossless（完全なラウンドトリップ）です**。`crf` は無視されます。より小さい有損ストリームにするには、`extra_options={}` を渡し、`crf` を設定してください。 |
| `pix_fmt`       | `str`   | `"gray12le"`                    | 量子化コードを保持するために使用される、単一チャネルの12ビットピクセル形式。                                                                  |
| `depth_min`     | `float` | `0.01`                          | メートル単位の深さを量子化`0`にマッピングします。以下の値はデコード時にクリップされます。                                                             |
| `depth_max`     | `float` | `10.0`                          | メートル単位の深度は量子化値`4095`にマッピングされます。これを超える値はデコード時にクリップされます。                                                          |
| `shift`         | `float` | `3.5`                           | ゼロ付近の数値安定性のために対数量子化で使用するログ前オフセット（メートル）。`depth_min + shift > 0` を満たす必要があります。      |
| `use_log`       | `bool`  | `True`                          | `true`の場合、対数空間で量子化します（一般的な深度センサーには推奨されます）。均一/線形量子化には`false`を設定してください。              |

> [!TIP]
> `depth_min`、`depth_max`、および `shift` は、入力深度の単位に関わらず、常に**メートル**として解釈されます。入力は自動検出されます。整数配列（例: RealSense から直接取得した `uint16` のミリメートル値）はミリメートルとして、浮動小数点配列はメートルとして扱われます。`depth_min` / `depth_max` は、センサーの実際の動作範囲を囲むように設定してください。この範囲外の量子は飽和するため、境界部分のディテールが潰れてしまう可能性があります。

Depth機能は`meta/info.json`内で`"is_depth_map": true`としてフラグ付けされ、その量子化設定（`video.depth_min`、`video.depth_max`、`video.shift`、`video.use_log`）が永続化されます。これにより、読み込み時にdepthを**物理単位に逆量子化**することが可能になります。

### 読み込み時の出力ユニット

`depth_encoder`は**記録時**の関心事です。_読み込み_（例：トレーニング中）時に深度マップがデクアンタイズされる単位は、読み込み時のフラグ`--dataset.depth_output_unit`によって別途設定されます：

```bash
lerobot-train \
    --dataset.repo_id=<my_username>/<my_dataset_name> \
    --dataset.depth_output_unit=m \
    --policy.type=act
```

| パラメータ           | 型  | デフォルト | 説明                                                                                  |
| ------------------- | ----- | ------- | -------------------------------------------------------------------------------------------- |
| `depth_output_unit` | `str` | `"mm"`  | 物理単位深度マップは読み込み時にデクォアンタイズされます: `"mm"` (ミリメートル) または `"m"` (メートル)。 |

> [!TIP]
> これは純粋にデコード時の表示上の選択であり、**変更しない**ため、保存された動画やそのメタデータは変わりません。そのため、同じデータセットを再エンコードせずに`mm`または`m`として読み取ることができます。深度カメラを備えていないデータセットには影響しません。

---

## データセットメタデータへの永続化

ビデオストリームの最初のエピソードがエンコードされると、エンコーダーの設定は、ファイル自体から取得された値とともに、各ビデオ機能の下で**データセットのメタデータに永続化**されます（`meta/info.json`）。ビデオ機能`observation.images.<camera>`の場合、`info.json`内のレイアウトは以下の通りです。

```json
{
  "features": {
    "observation.images.laptop": {
      "dtype": "video",
      "shape": [480, 640, 3],
      "info": {
        "video.height": 480,
        "video.width": 640,
        "video.codec": "h264",
        "video.pix_fmt": "yuv420p",
        "video.fps": 30,
        "video.channels": 3,
        "is_depth_map": false,
        "video.g": 2,
        "video.crf": 30,
        "video.preset": "fast",
        "video.fast_decode": 0,
        "video.video_backend": "pyav",
        "video.extra_options": { "tune": "film", "profile:v": "high", "bf": 2 }
      }
    }
  }
}
```

`info`ブロックには、2つのソースが寄与します:

| ソース              | その由来                                   | フィールド                                                                                                                  |
| ------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **ストリーム由来**  | PyAVを使用して、エンコードされたMP4から読み戻します。             | `video.height`, `video.width`, `video.codec`, `video.pix_fmt`, `video.fps`, `video.channels`, `is_depth_map`, `audio.*` |
| **エンコーダー由来** | `RGBEncoderConfig` / `DepthEncoderConfig` から取得されました。 | `video.g`, `video.crf`, `video.preset`, `video.fast_decode`, `video.video_backend`, `video.extra_options`               |

> [!IMPORTANT]
> このブロックは、**最初の**エピソードから**一度だけ**設定されます。データセット内のすべてのエピソードが同じ`rgb_encoder`でエンコードされていることを前提としています。録画中にエンコーダーの設定を変更することはサポートされていません。`info.json`には、最初のエピソードで使用されたパラメータのみが反映されます。

---

## データセットのマージ

`merge_datasets`でデータセットをアグリゲーションする際、動画ファイルはそのまま連結されます（再エンコードは行われません）。また、`info.json`内のエンコーダーフィールドはキーごとにマージされます。

| マージルール         | フィールド                                                                             | 動作                                                                                                                                                 |
| ------------------ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **一致する必要があります**     | `video.codec`, `video.pix_fmt`, `video.height`, `video.width`, `video.fps`         | ストリーム由来のフィールドはソース間で一致する必要があります。一致しない場合、FFmpegのconcat demuxerは失敗します。                                                                 |
| **ゆるくマージ** | `video.g`, `video.crf`, `video.preset`, `video.fast_decode`, `video.extra_options` | エンコーダーチューニング用のフィールド。すべてのソースが一致する場合、その値は保持されます。一致しない場合は、`null`（`video.extra_options`の場合は`{}`）に設定され、警告がログに記録されます。 |

