# معلمات ترميز الفيديو

عند تمكين تخزين الفيديو، يخزّن LeRobot كل تدفق كاميرا كملف **MP4** بدلاً من حفظ ملف صورة واحد لكل خطوة زمنية. يعمل ترميز الفيديو على الضغط عبر الزمن، مما يقلل عادةً من حجم مجموعة البيانات ومدخلات/مخرجات الإدخال/الإخراج مقارنةً بكمية كبيرة من ملفات PNG، مع الحفاظ على MP4 — وهو صيغة تفهمها كل مشغّل وكل محمّل.

تحويل الإطارات إلى ملف MP4 هو خط أنابيب كامل لـ FFmpeg: اختيار المُشفِّر، وصيغة البكسل، ومجموعات GOP/الإطارات المفتاحية، والجودة مقابل السرعة، وأعلام المُشفِّر الإضافية الاختيارية. معظم هذه الإعدادات قابلة للضبط من قِبل المستخدم عبر `rgb_encoder`، وهو `RGBEncoderConfig` متداخل (`lerobot.configs.video.RGBEncoderConfig`) يُمرَّر عبر PyAV.

يمكنك ضبط هذه المعلمات من سطر الأوامر باستخدام `--dataset.rgb_encoder.<field>` (على سبيل المثال باستخدام `lerobot-record` أو `lerobot-rollout`). ينطبق نفس الكتلة على كل تدفق فيديو كاميرا في تلك الجولة.

> [!TIP]
> يجب أن يكون تخزين الفيديو مفعّلًا حتى يكون لـ `rgb_encoder` أي تأثير — وذلك عن طريق `use_videos=True` في واجهات برمجة التطبيقات بلغة بايثون، أو `--dataset.video=true` في سطر الأوامر (وهو الافتراضي عند التسجيل). عند إيقاف الفيديو، تبقى المدخلات على شكل صور ويُتجاهل `rgb_encoder`.

لتفاصيل **متى** تُكتب الإطارات مقابل ترميزها (بث مباشر مقابل ما بعد الحلقة)، والطوابير، ومفاتيح `--dataset.*` الأخرى على المستوى الأعلى، راجع [ترميز الفيديو البثي](./streaming_video_encoding). لمقارنة معاملات الترميز والتجارب، راجع [مساحة video-benchmark](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]
> تم ضبط القيم الافتراضية لتحقيق التوازن بين **نسبة الضغط** و**الجودة البصرية** و**سرعة فك الترميز/البحث** لمجموعات بيانات الروبوتات النموذجية. قد يؤثر تغييرها على كل من التسجيل (حمولة المعالج المركزي، فقدان الإطارات) والتدريب (معدل فك الترميز، جودة الصور).
>
> لا تتجاوز هذه المعلمات إلا إذا كان لديك سبب محدد لذلك، وقِس الأثر على خط أنابيبك قبل الاعتماد على الإعدادات الجديدة.

جميع الأعلام أدناه مُسبوقة بـ `--dataset.rgb_encoder.` في سطر الأوامر.

| معامل       | النوع             | افتراضي       | الوصف                                                                                                                                                                                                             |
| --------------- | ---------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`            | `"libsvtav1"` | اسم مشفّر الفيديو. `"auto"` يختار أول مشفّر عتادي متاح من قائمة تفضيلات ثابتة، مع الرجوع إلى `libsvtav1` عند عدم التوفر.                                                                                        |
| `pix_fmt`       | `str`            | `"yuv420p"`   | صيغة البكسلات للمخرجات. يجب أن تكون مدعومة من قِبل مُرمِّز (codec) المُختار في نسخة 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 مم
        
        float32 m
      
    
    
      →
    
    
      
        تسجيل الوقت
      
      
        مقطع
        
          إلى [depth_min,
          
          depth_max]
        
      
      
        →
      
      
        تكميم
        
          رموز 12-بت 0–4095
          
          log (افتراضي) أو خطي
        
      
      
        →
      
      
        حزمة
        
          إلى gray12le
          
          plane
        
      
      
        →
      
      
        ترميز
        
          HEVC
          
          Main 12
        
      
    
    
      →
    
    
      MP4
      
        محفوظ
        
        بث
      
    
    
      →
    
    
      
        وقت التحميل
      
      
        إلغاء التكميم
        
          إلى مم / م
        
      
    
  

قم بإعداد خط أنابيب العمق عبر كتلة **`depth_encoder`** متوازية (`DepthEncoderConfig`). تشارك جميع حقول `RGBEncoderConfig` (`vcodec`، `pix_fmt`، `crf`، …) وتضيف أربعة مقابض كمّية، تُضبط عبر `--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
```

| معامل       | النوع    | افتراضي                         | الوصف                                                                                                                            |
| --------------- | ------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `vcodec`        | `str`   | `"hevc"`                        | HEVC Main 12 (ترميز يدعم 12 بت، متوافق مع MP4).                                                                                 |
| `extra_options` | `dict`  | `{"x265-params": "lossless=1"}` | **العمق الافتراضي هو خالٍ من الفقد** (دورة ذهاب وإياب دقيقة)؛ يتم تجاهل `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` تُفسَّر دائمًا بوحدة **المتر**، بغض النظر عن وحدة عمق الإدخال. يتم اكتشاف المدخلات تلقائيًا: تُعامل المصفوفات الصحيحة (مثل `uint16` بالمليمتر مباشرة من RealSense) كمليمتر، والمصفوفات العائمة كمتر. اختر `depth_min` / `depth_max` بحيث يحصران النطاق الفعلي للعمل لجهاز الاستشعار لديك — فالقيم خارج هذا النطاق تصل إلى حد التشبع، مما قد يؤدي إلى فقدان التفاصيل عند الحدود.

تُوسم ميزات العمق بـ `"is_depth_map": true` في `meta/info.json`، وتُحفظ إعدادات مُكمِّمها (`video.depth_min`، `video.depth_max`، `video.shift`، `video.use_log`) — وهذا ما يتيح **إلغاء تكميم العمق وإعادته إلى الوحدات الفيزيائية** عند التحميل.

### وحدة الإخراج عند التحميل

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

| المصدر              | من أين يأتي                                   | الحقول                                                                                                                  |
| ------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **مشتق من البث**  | اقرأ مرة أخرى من ملف MP4 المُرمّز باستخدام PyAV.             | `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`         | يجب أن تتطابق الحقول المشتقة من البث عبر المصادر، وإلا فشل مُفكك concat الخاص بـ FFmpeg.                                                                 |
| **مدمجة بشكل فضفاض** | `video.g`, `video.crf`, `video.preset`, `video.fast_decode`, `video.extra_options` | حقول ضبط المُشفِّر. إذا اتفقت جميع المصادر، يُحفظ القيمة؛ وإذا لم تتفق، تُضبط على `null` (أو `{}` لـ `video.extra_options`) ويُسجَّل تحذير. |

