# 流式视频编码指南

## 1. 概述

流式视频编码消除了视频数据集录制过程中的传统 PNG 往返操作。而不是：

1. 捕获帧 -> 将 PNG 写入磁盘 -> （回合结束时）读取 PNG -> 编码为 MP4 -> 删除 PNG

帧可以在捕获过程中实时编码：

1. 捕获帧 -> 排队至编码器线程 -> 直接编码为 MP4

这使得 `save_episode()` 几乎可以即时完成（在剧集结束时视频已经编码完毕），并消除了剧集之间先前存在的阻塞等待，尤其是在长剧集中使用多个摄像头时。

## 2. 调整参数

| 参数               | CLI 标志                          | 类型          | 默认       | 描述                                                       |
| ----------------------- | --------------------------------- | ------------- | ------------- | ----------------------------------------------------------------- |
| `streaming_encoding`    | `--dataset.streaming_encoding`    | `bool`        | `False`       | 在捕获期间启用实时编码                          |
| `vcodec`                | `--dataset.rgb_encoder.vcodec`    | `str`         | `"libsvtav1"` | 视频编解码器。`"auto"` 可自动检测最佳硬件编码器                     |
| `encoder_threads`       | `--dataset.encoder_threads`       | `int \| None` | `None`（自动） | 每个编码器实例的线程数。`None` 将交由 vcoded 自行决定 |
| `encoder_queue_maxsize` | `--dataset.encoder_queue_maxsize` | `int`         | `30`          | 每个摄像头的最大缓冲帧数（30fps 下约 1 秒）。会占用内存       |

## 3. 性能考量

流式编码意味着 CPU 在捕获循环**期间**对视频进行编码，而不是在循环结束后进行。这会产生一个 CPU 预算，需要在以下各项之间共享：

- **控制循环**（读取摄像头、控制机器人、写入非视频数据）
- **编码器线程**（每个摄像头一个线程池）
- **重新运行可视化**（如果已启用）
- **操作系统和其他进程**

### 分辨率和摄像头数量的影响

| 设置                     | 吞吐量（像素/秒） | CPU 编码加载 | 备注                          |
| ------------------------- | ------------------- | ----------------- | ------------------------------ |
| 2camsx 640x480x3 @30fps   | 55M                 | 低               | 适用于大多数系统          |
| 2camsx 1280x720x3 @30fps  | 165M                | 中等          | 在现代系统上运行流畅  |
| 2camsx 1920x1080x3 @30fps | 373M                | 高              | 需要强大的高端 CPU |

### `encoder_threads` 调优

此参数控制每个编码器实例内部使用的线程数：

- **较高的值**（例如 4-5）：编码速度更快，但每个摄像头占用的 CPU 核心数更多。适用于拥有大量核心的高端系统。
- **较低的值**（例如 1-2）：每个摄像头占用的 CPU 更少，从而为核心释放资源用于捕获和可视化。适用于低分辨率图像和性能较强的 CPU。
- **`None`（默认值）**：由编解码器自行决定。相关信息可在编解码器日志中查看。

### 背压与帧丢弃

每个相机都有一个有界队列（`encoder_queue_maxsize`，默认 30 帧）。当编码器无法跟上时：

1. 队列填满（消耗 RAM）
2. 新帧会被**丢弃**（而非阻塞）——捕获循环持续不间断地运行
3. 会记录一条警告：`"Encoder queue full for {camera}, dropped N frame(s)"`
4. 在回合结束时，会报告每个相机的总丢帧数

### 编码器落后的症状

- **系统感觉卡顿并冻结**：所有 CPU 均达到 100%
- 日志中出现的 **丢帧警告**，或录制数据集中帧数/FPS 低于预期
- **机器人动作卡顿**：如果 CPU 严重过载，即使是捕获循环也可能受到影响
- **累积重跑延迟**：可视化落后于实时

## 4. 硬件加速编码

### 何时使用

在以下情况下使用硬件编码：

- CPU 是瓶颈（出现丢帧、机器人动作卡顿、rerun 延迟）
- 您拥有兼容的硬件（GPU 或专用编码器）
- 您正在以高吞吐量进行录制（高分辨率或使用多个摄像头）

### 选择编解码器

| 编解码器                 | CPU 使用率 | 文件大小      | 质量 | 备注                                                            |
| --------------------- | --------- | -------------- | ------- | ---------------------------------------------------------------- |
| `libsvtav1`（默认） | 高      | 最小       | 最佳    | 默认。压缩效果最佳，但 CPU 负载最高                 |
| `h264`                | 中等    | ~30-50% 更大 | 好的    | 软件 H.264。更低的 CPU                                        |
| 硬件编码器           | 非常低  | 最大        | 好的    | 卸载到专用硬件。最适合 CPU 受限的系统 |

### 可用的硬件编码器

| 编码器             | 平台      | 硬件                                                                                         | CLI 值                                        |
| ------------------- | ------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
| `h264_videotoolbox` | macOS         | Apple Silicon / Intel                                                                            | `--dataset.rgb_encoder.vcodec=h264_videotoolbox` |
| `hevc_videotoolbox` | macOS         | Apple Silicon / Intel                                                                            | `--dataset.rgb_encoder.vcodec=hevc_videotoolbox` |
| `h264_nvenc`        | Linux/Windows | NVIDIA GPU                                                                                       | `--dataset.rgb_encoder.vcodec=h264_nvenc`        |
| `hevc_nvenc`        | Linux/Windows | NVIDIA GPU                                                                                       | `--dataset.rgb_encoder.vcodec=hevc_nvenc`        |
| `h264_vaapi`        | Linux         | Intel/AMD 显卡                                                                                    | `--dataset.rgb_encoder.vcodec=h264_vaapi`        |
| `h264_qsv`          | Linux/Windows | Intel Quick Sync                                                                                 | `--dataset.rgb_encoder.vcodec=h264_qsv`          |
| `auto`              | 任意           | 探测系统中可用的硬件编码器。如果未找到硬件编码器，则回退到 `libsvtav1` | `--dataset.rgb_encoder.vcodec=auto`              |

> [!NOTE]
> 要使用硬件加速编码器，您可能需要升级 GPU 驱动程序。

> [!NOTE]
> `libsvtav1` 是默认选项，因为它能提供最佳的训练性能；其他 vcodecs 可以降低 CPU 占用并提升速度，但通常会产生更大的文件，并可能影响训练时间。

## 5. 故障排除

| 症状                                                            | 可能的原因                                 | 修复                                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------------ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 系统冻结或机器人动作卡顿或 Rerun 可视化延迟 | CPU 资源不足（负载使用率 100%）                | 关闭其他应用程序，降低编码吞吐量，调低 `encoder_threads`，使用 `h264`，使用 `display_data=False`。如果 CPU 仍然持续处于 100% 状态，则可能无法满足您的配置需求，请考虑使用 `--dataset.streaming_encoding=false` 或硬件编码（`--dataset.rgb_encoder.vcodec=auto`） |
| 数据集中出现“Encoder queue full”警告或丢帧         | 编码器跟不上（队列溢出）       | 如果 CPU 未达到 100%：请增加 `encoder_threads`，增加 `encoder_queue_maxsize`，或使用硬件编码（`--dataset.rgb_encoder.vcodec=auto`）。                                                                                                                                                    |
| 高内存使用                                                     | 队列填充速度超过编码速度           | `encoder_threads` 设置过低或 CPU 资源不足。请降低 `encoder_queue_maxsize` 或改用硬件编码                                                                                                                                                                                                 |
| 大型视频文件                                                  | 使用硬件编码器或 H.264                    | 预期的权衡。如果 CPU 允许，请切换到 `libsvtav1`                                                                                                                                                                                                                                          |
| `save_episode()` 仍然很慢                                        | `streaming_encoding` 为 `False`              | 设置 `--dataset.streaming_encoding=true`                                                                                                                                                                                                                                                          |
| 编码器线程崩溃                                               | 编解码器不可用或设置无效      | 检查 `vcodec` 是否已安装，尝试使用 `--dataset.rgb_encoder.vcodec=auto`                                                                                                                                                                                                                             |
| 记录的 dataset 缺少 frames                                 | CPU/GPU 资源耗尽或偶发的负载峰值 | 如果约 5% 的帧丢失，您的系统很可能已过载——请遵循上述建议。如果丢失的帧较少（约 2%），它们可能是由偶尔的瞬时负载峰值（通常在启动时）引起的，可以视为预期行为。                                               |

## 6. 推荐配置

这些估算较为保守；我们建议您在自己的环境中进行测试——从低负载开始，逐步增加负载。

### 高端系统：现代 12 核及以上（24 线程及以上）

在 CPU 上，约 250-500M px/sec 的吞吐量应该比较舒适。如果可用，尝试使用硬件编码以获得更好的效果。

```bash
# 3camsx 1280x720x3 @30fps: Defaults work well. Optionally increase encoder parallelism.
# 2camsx 1920x1080x3 @30fps: Defaults work well. Optionally increase encoder parallelism.
lerobot-record --dataset.encoder_threads=5 ...

# 3camsx 1920x1080x3 @30fps: Might require some tuning.
```

### 中端系统：现代 8 核及以上（16 线程及以上）或 Apple Silicon

在 CPU 上，吞吐量应可达到约 80-300M px/sec。

```bash
# 3camsx 640x480x3 @30fps: Defaults work well. Optionally decrease encoder parallelism.
# 2camsx 1280x720x3 @30fps: Defaults work well. Optionally decrease encoder parallelism.
lerobot-record --dataset.encoder_threads=2 ...

# 2camsx 1920x1080x3 @30fps: Might require some tuning.
```

### 低资源系统：现代 4 核及以上（8 线程及以上）或 Raspberry Pi 5

在资源非常受限的系统上，流式编码可能会与捕获循环产生过重的竞争。禁用该功能会回退到基于 PNG 的方案，其中编码发生在回合之间（会阻塞，但不会干扰捕获）。或者，以较低的吞吐量进行录制，以降低捕获和编码的负载。还可以考虑将编解码器更改为 `h264` 并使用批量编码。

```bash
# 2camsx 640x480x3 @30fps: Requires some tuning.

# Use H.264, disable streaming, consider batching encoding
lerobot-record --dataset.rgb_encoder.vcodec=h264 --dataset.streaming_encoding=false ...
```

## 7. 结语

性能最终取决于您的具体配置——每秒帧数、分辨率、CPU 核心数及负载、可用内存、回合长度以及您选择的编码器。请务必针对目标工作负载进行测试，注意您的 CPU 及系统能力，并合理调整 `encoder_threads`、`encoder_queue_maxsize` 和 `vcodec`。话虽如此，一种常见的实用配置（适用于许多应用）是三台相机以 640×480x3 @30fps 运行；在现代系统中，这通常可以配合默认的流式视频编码设置正常运行。请始终通过将视频时长与 CLI 回合时长进行比较，并确认行数等于 FPS × CLI 时长，来验证您记录的 dataset 是否健康。

