# Parameter encoding video

Ketika penyimpanan video diaktifkan, LeRobot menyimpan setiap aliran kamera sebagai file **MP4** alih-alih menyimpan satu file gambar per langkah waktu. Pengodean video melakukan kompresi melintasi waktu, yang biasanya mengurangi ukuran dataset dan I/O dibandingkan tumpukan PNG, sambil tetap mempertahankan MP4 — format yang dipahami oleh setiap pemutar dan pemuat.

Encoding frame ke dalam MP4 adalah pipeline FFmpeg lengkap: pilihan encoder, format piksel, GOP/keyframe, kualitas vs. kecepatan, dan flag encoder tambahan opsional. Sebagian besar pengaturan ini dapat disesuaikan oleh pengguna melalui `rgb_encoder`, yaitu `RGBEncoderConfig` bersarang (`lerobot.configs.video.RGBEncoderConfig`) yang diteruskan melalui PyAV.

Anda dapat mengatur parameter ini dari CLI dengan `--dataset.rgb_encoder.<field>` (misalnya dengan `lerobot-record` atau `lerobot-rollout`). Blok yang sama berlaku untuk setiap stream video kamera dalam run tersebut.

> [!TIP]
> Penyimpanan video harus diaktifkan agar `rgb_encoder` memiliki efek — gunakan `use_videos=True` pada API Python, atau `--dataset.video=true` pada CLI (default untuk perekaman). Jika video dimatikan, input tetap berupa gambar dan `rgb_encoder` diabaikan.

Untuk detail mengenai **kapan** frame ditulis vs. di-encode (streaming vs. pasca-episode), antrean, dan sakelar `--dataset.*` tingkat atas lainnya, lihat [Streaming Video Encoding](./streaming_video_encoding). Untuk perbandingan parameter encoding dan eksperimen, lihat [ruang video-benchmark](https://huggingface.co/spaces/lerobot/video-benchmark).

---

## Contoh

```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
```

---

## Menyetel parameter

> [!WARNING]
> Nilai bawaarannya disetel untuk menyeimbangkan **rasio kompresi**, **kualitas visual**, dan **kecepatan decoding/seek** untuk dataset robotika yang umum. Mengubahnya dapat memengaruhi baik perekaman (beban CPU, frame drop) maupun pelatihan (throughput decoding, kualitas gambar).
>
> Hanya timpa parameter ini jika Anda memiliki alasan spesifik, dan ukur dampaknya pada pipeline Anda sebelum mengandalkan pengaturan baru.

Semua flag di bawah ini memiliki awalan `--dataset.rgb_encoder.` pada CLI.

| Parameter       | Tipe             | Default       | Deskripsi                                                                                                                                                                                                             |
| --------------- | ---------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`            | `"libsvtav1"` | Nama codec video. `"auto"` memilih encoder perangkat keras pertama yang tersedia dari daftar preferensi tetap, dengan fallback ke `libsvtav1`.                                                                                        |
| `pix_fmt`       | `str`            | `"yuv420p"`   | Format piksel output. Harus didukung oleh codec yang dipilih dalam build FFmpeg Anda.                                                                                                                                        |
| `g`             | `int`            | `2`           | Ukuran GOP — satu keyframe setiap `g` frame. Dikeluarkan sebagai opsi FFmpeg `g`.                                                                                                                                                   |
| `crf`           | `int` atau `float` | `30`          | Nilai kualitas abstrak, dipetakan per codec (lihat [pemetaan](https://github.com/huggingface/lerobot/blob/main/src/lerobot/configs/video.py#L197)). Semakin rendah → kualitas lebih tinggi / output lebih besar di mana pemetaannya monoton. |
| `preset`        | `int` atau `str`   | `12` \*       | Preset kecepatan encoder; maknanya bergantung pada codec. \* Jika tidak diset dan `vcodec=libsvtav1`, LeRobot secara default menggunakan `12`.                                                                                                |
| `fast_decode`   | `int`            | `0`           | `libsvtav1`: `0–2`, diteruskan melalui `svtav1-params`. `h264` / `hevc` (perangkat lunak): jika `>0`, mengatur `tune=fastdecode`. Codec lain: biasanya tidak digunakan.                                                                    |
| `video_backend` | `str`            | `"pyav"`      | Saat ini, hanya `"pyav"` yang diimplementasikan untuk pengkodean video.                                                                                                                                                              |
| `extra_options` | `dict`           | `{}`          | Opsi spesifik FFmpeg atau codec tambahan yang digabungkan setelah field terstruktur di atas. Tidak dapat menimpa kunci yang sudah diset oleh field tersebut.                                                                                      |

---

## Aliran kedalaman

Peta kedalaman (Intel RealSense, Reachy 2) disimpan sebagai **stream video tersendiri** di samping stream RGB. Kedalaman mentah (`uint16` milimeter atau `float32` meter) tidak dapat bertahan melalui codec 8-bit, sehingga LeRobot **mengkuantisasi** setiap peta menjadi kode 12-bit (`[0, 4095]`) — secara logaritmik secara default, untuk mencocokkan profil kesalahan `1/depth` dari sensor kedalaman — kemudian mengemasnya ke dalam format piksel dengan kedalaman bit tinggi (`gray12le`) dan mengenkodinya dengan codec 12-bit.

  
    
      Kedalaman mentah
      
        uint16 mm
        
        float32 m
      
    
    
      →
    
    
      
        Waktu rekaman
      
      
        Clip
        
          ke [depth_min,
          
          depth_max]
        
      
      
        →
      
      
        Kuantisasi
        
          Kode 12-bit 0–4095
          
          log (default) atau linear
        
      
      
        →
      
      
        Paket
        
          ke gray12le
          
          plane
        
      
      
        →
      
      
        Encode
        
          HEVC
          
          Utama 12
        
      
    
    
      →
    
    
      MP4
      
        disimpan
        
        stream
      
    
    
      →
    
    
      
        Waktu pemuatan
      
      
        Dequantisasi
        
          ke mm / m
        
      
    
  

Konfigurasi pipeline kedalaman melalui blok **`depth_encoder`** paralel (`DepthEncoderConfig`). Blok ini berbagi setiap field `RGBEncoderConfig` (`vcodec`, `pix_fmt`, `crf`, …) dan menambahkan empat knob kuantizer, yang diatur melalui `--dataset.depth_encoder.<field>`:

```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
```

| Parameter       | Tipe    | Default                         | Deskripsi                                                                                                                            |
| --------------- | ------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`   | `"hevc"`                        | HEVC Main 12 (kodek dengan kemampuan 12-bit, kompatibel dengan MP4).                                                                                 |
| `extra_options` | `dict`  | `{"x265-params": "lossless=1"}` | **Depth secara default lossless** (round-trip yang tepat); `crf` diabaikan. Berikan `extra_options={}` dan atur `crf` untuk stream lossy yang lebih kecil. |
| `pix_fmt`       | `str`   | `"gray12le"`                    | Format piksel 12-bit kanal tunggal yang digunakan untuk membawa kode kuantisasi.                                                                  |
| `depth_min`     | `float` | `0.01`                          | Kedalaman dalam meter dipetakan ke kuantum `0`. Nilai di bawah dipotong saat decode.                                                             |
| `depth_max`     | `float` | `10.0`                          | Kedalaman dalam meter dipetakan ke kuantum `4095`. Nilai di atas dipangkas saat decode.                                                          |
| `shift`         | `float` | `3.5`                           | Offset pra-log (meter) yang digunakan dalam kuantisasi logaritmik untuk stabilitas numerik di dekat nol. Harus memenuhi `depth_min + shift > 0`.      |
| `use_log`       | `bool`  | `True`                          | Jika `true`, kuantisasi dilakukan dalam ruang log (disarankan untuk sensor kedalaman tipikal). Atur ke `false` untuk kuantisasi seragam/linier.              |

> [!TIP]
> `depth_min`, `depth_max`, dan `shift` selalu diinterpretasikan dalam **meter**, terlepas dari unit kedalaman input. Input dideteksi secara otomatis: array bilangan bulat (misalnya `uint16` milimeter langsung dari RealSense) diperlakukan sebagai milimeter, sedangkan array bilangan desimal sebagai meter. Pilih `depth_min` / `depth_max` untuk membatasi rentang kerja aktual sensor Anda — kuantum di luar rentang tersebut akan jenuh, yang dapat merusak detail di batas-batasnya.

Fitur kedalaman ditandai dengan `"is_depth_map": true` di `meta/info.json`, dan pengaturan kuantizernya (`video.depth_min`, `video.depth_max`, `video.shift`, `video.use_log`) disimpan — hal inilah yang memungkinkan kedalaman untuk **didekuantisasi kembali ke satuan fisik** saat dimuat.

### Unit output saat pemuatan

`depth_encoder` adalah masalah pada **waktu perekaman**. Unit yang digunakan untuk mendekuantisasi peta kedalaman saat _memuat_ (misalnya selama pelatihan) diatur secara terpisah oleh flag waktu baca `--dataset.depth_output_unit`:

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

| Parameter           | Tipe  | Default | Deskripsi                                                                                  |
| ------------------- | ----- | ------- | -------------------------------------------------------------------------------------------- |
| `depth_output_unit` | `str` | `"mm"`  | Peta kedalaman unit fisik didekuantisasi saat dimuat menjadi: `"mm"` (milimeter) atau `"m"` (meter). |

> [!TIP]
> Ini murni pilihan presentasi pada waktu decode — hal ini **tidak** mengubah video yang disimpan atau metadatanya, sehingga dataset yang sama dapat dibaca sebagai `mm` atau `m` tanpa re-encoding. Hal ini tidak berdampak pada dataset tanpa kamera kedalaman.

---

## Persistensi dalam metadata dataset

Setelah episode pertama dari aliran video dikodekan, konfigurasi encoder **disimpan ke dalam metadata dataset** (`meta/info.json`) di bawah setiap fitur video, berdampingan dengan nilai yang diambil dari file itu sendiri. Untuk fitur video `observation.images.<camera>`, tata letak di `info.json` adalah:

```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 }
      }
    }
  }
}
```

Dua sumber berkontribusi pada blok `info`:

| Sumber              | Asal-usulnya                                   | Bidang                                                                                                                  |
| ------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **Dihasilkan dari stream**  | Baca kembali dari MP4 yang dikodekan dengan PyAV.             | `video.height`, `video.width`, `video.codec`, `video.pix_fmt`, `video.fps`, `video.channels`, `is_depth_map`, `audio.*` |
| **Berdasarkan encoder** | Diambil dari `RGBEncoderConfig` / `DepthEncoderConfig`. | `video.g`, `video.crf`, `video.preset`, `video.fast_decode`, `video.video_backend`, `video.extra_options`               |

> [!IMPORTANT]
> Blok ini diisi **sekali**, dari episode **pertama**. Blok ini mengasumsikan setiap episode dalam dataset dikodekan dengan `rgb_encoder` yang sama. Mengubah pengaturan encoder di tengah perekaman tidak didukung — `info.json` hanya akan mencerminkan parameter yang digunakan untuk episode pertama.

---

## Menggabungkan dataset

Saat mengagregasi dataset dengan `merge_datasets`, file video digabungkan apa adanya (tanpa re-encoding), dan field encoder di `info.json` digabungkan per kunci:

| Aturan penggabungan         | Bidang                                                                             | Perilaku                                                                                                                                                 |
| ------------------ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Harus cocok**     | `video.codec`, `video.pix_fmt`, `video.height`, `video.width`, `video.fps`         | Field yang diturunkan dari stream harus cocok di antara sumber, jika tidak demuxer concat FFmpeg akan gagal.                                                                 |
| **Disatukan secara longgar** | `video.g`, `video.crf`, `video.preset`, `video.fast_decode`, `video.extra_options` | Field penyetelan encoder. Jika semua sumber setuju, nilainya dipertahankan; jika tidak, nilainya diatur ke `null` (atau `{}` untuk `video.extra_options`) dan peringatan dicatat. |

