Skip to content

fix: v3 の動画位置を data レイアウトではなく meta/episodes から解決する - #286

Merged
rikunosuke merged 2 commits into
mainfrom
fix-lerobot-v3-video-location
Aug 5, 2026
Merged

fix: v3 の動画位置を data レイアウトではなく meta/episodes から解決する#286
rikunosuke merged 2 commits into
mainfrom
fix-lerobot-v3-video-location

Conversation

@rikunosuke

Copy link
Copy Markdown
Contributor

問題

import_lerobot(v3)で、_build_episode_mapdata parquet のレイアウトから各エピソードの動画 chunk/file を導出していました。しかし LeRobot v3 では data と動画ファイルは独立に集約(consolidate)されるため chunk/file 番号が一致する保証がなく、

  • 存在しない mp4 を参照 → video_path.exists() チェックで黙ってスキップされ、ZIP から動画が欠落
  • 同名ファイルが偶然存在する場合 → data parquet の行オフセットを動画フレームオフセットとして使うため、別エピソードの区間を切り出す

という問題がありました。カメラごとに動画位置が異なる点も考慮されていませんでした。

修正内容

  • _build_episode_mapmeta/episodes/chunk-*/file-*.parquet の読み取りに変更(v3 の正式な位置情報ソース)。エピソードメタデータが無い場合は FastLabelInvalidException
  • EpisodeInfo を再設計: data_chunk / data_file_stem / length + カメラキーごとの videos dict(chunk / file_stem / from_timestamp / to_timestamp)
  • _assemble_episode_zip はカメラごとに動画パスを解決し、フレームオフセットを from_timestamp × fps(meta/info.json)で算出
  • 動画ファイル欠落時は黙って落とさず logger.warning を出してスキップ(ZIP にはテレメトリ JSON と他カメラの動画は含まれる)
  • 動画切り出しが必要なのに fps が無い場合は例外(誤区間の切り出しを防ぐため)

補足

chunk/file のパス形式は LeRobot デフォルトの chunk-{i:03d}/file-{i:03d} を前提としています(info.jsondata_path / video_path テンプレートは未参照。既存の detect_version と同じ前提)。

テスト

  • meta/episodes ベースの episode map 構築(data と異なる chunk/file を指す動画位置の読み取り含む)
  • _assemble_episode_zip が正しいファイル・オフセットから切り出すこと(data=file-000 / 動画=file-001、from_timestamp=0.5s → フレーム5開始で4フレーム)
  • 動画欠落時の warning + スキップ、fps 欠落時の例外
  • 全 79 テストパス

🤖 Generated with Claude Code

_build_episode_map は各エピソードの動画 chunk/file を data parquet の
レイアウトから導出していたが、v3 では data と動画が独立に集約されるため、
存在しない mp4 を参照(黙ってスキップ)するか、同名ファイルが偶然存在する
場合は data ファイルの行オフセットを動画フレームオフセットとして使い
誤った区間を切り出していた。

- episode map を meta/episodes/chunk-*/file-*.parquet から構築し、
  カメラごとの動画位置(chunk/file index, from/to_timestamp)を保持
- 動画フレームオフセットを from_timestamp × fps(meta/info.json)で算出
- 動画ファイル欠落時は黙って落とさず warning を出してスキップ。
  切り出しが必要なのに fps が無い場合は例外

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread fastlabel/lerobot/v3.py
Comment on lines +90 to +99
"chunk": _chunk_name(int(row[f"videos/{key}/chunk_index"])),
"file_stem": _file_stem(int(row[f"videos/{key}/file_index"])),
"from_timestamp": float(row[f"videos/{key}/from_timestamp"]),
"to_timestamp": float(row[f"videos/{key}/to_timestamp"]),
}
frame_offset += length
episode_map[int(row["episode_index"])] = {
"data_chunk": _chunk_name(int(row["data/chunk_index"])),
"data_file_stem": _file_stem(int(row["data/file_index"])),
"length": int(row["length"]),
"videos": videos,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

video のチャンク番号と、episode のチャンク番号で同じものを使っていたことが根本原因でした。

Comment thread fastlabel/lerobot/v3.py
Comment on lines +231 to +235
logger.warning(
"Video file not found, skipping camera %s: %s",
camera.key,
video_path,
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

いままで暗黙に continue してしまっていたので、warning を表示するように修正しました。

@rikunosuke rikunosuke self-assigned this Aug 5, 2026
カメラループ内でのチェックだと、ステージング作成や先行カメラの
切り出し後に失敗しうるため、選択カメラに動画セグメントがあるのに
fps が無い場合は処理開始前に例外を出す。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes LeRobot v3 episode video extraction by resolving per-episode/per-camera video locations from meta/episodes (the authoritative source in v3) instead of inferring them from the data/ parquet layout, which can diverge after independent consolidation.

Changes:

  • Reworked _build_episode_map (v3) to read meta/episodes/chunk-*/file-*.parquet and include per-camera video segment metadata.
  • Updated episode ZIP assembly to resolve video paths per camera and convert from_timestamp to a frame offset using fps from meta/info.json, with warnings on missing video files.
  • Added/updated tests to cover meta/episodes-driven mapping, timestamp offset extraction, missing video warnings, and missing-fps errors.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
fastlabel/lerobot/v3.py Switches episode mapping to meta/episodes, redesigns episode/video info, and updates ZIP assembly to use per-camera video metadata + fps.
fastlabel/lerobot/__init__.py Adapts public helpers to the new episode-map shape and passes fps into ZIP assembly.
tests/test_lerobot_v3_parquet.py Updates episode-map expectations and adds coverage for per-camera video metadata + missing episode metadata.
tests/test_lerobot_v3_video.py Adds ZIP-assembly tests validating per-camera location resolution, timestamp offset handling, warnings on missing videos, and missing-fps failures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fastlabel/lerobot/v3.py
Comment thread fastlabel/lerobot/v3.py

@yo-tak yo-tak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一行一行細かくは把握できていないですが、大きな方針は理解しました。LGTM 🚀

@rikunosuke
rikunosuke merged commit a2f80df into main Aug 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants