docs(mcap): split legacy single-camera layout reference

Move the legacy /camera/* contract into its own reference page so the main MCAP layout doc can stay focused on current bundled and copy-layout behavior.

Document the compatibility model explicitly: legacy single-camera is operationally equivalent to one-camera copy when the effective camera label is treated as the literal `camera`.

Update the mcap_rgbd_example helper and recipe docs to accept legacy /camera/* inputs under that compatibility rule instead of rejecting them.
This commit is contained in:
2026-03-24 10:55:01 +00:00
parent ffd246e508
commit d0f3dc5cf1
5 changed files with 94 additions and 51 deletions
+6 -8
View File
@@ -149,6 +149,8 @@ def is_present_status(status_name: str) -> bool:
def topic_for(layout: str, camera_label: str, kind: str) -> str:
if layout == "single-camera":
return f"/camera/{kind}"
if layout not in {"copy", "bundled"}:
raise click.ClickException(f"unsupported layout '{layout}'")
return f"/{camera_label}/{kind}"
@@ -164,11 +166,7 @@ def selected_camera_label(base_summary: bundle_validator.McapSummary, camera_lab
def ensure_supported_layout(base_summary: bundle_validator.McapSummary) -> None:
if base_summary.layout == "single-camera":
raise click.ClickException(
"legacy /camera/* MCAP files are not supported by this helper; regenerate them into copy-layout MCAPs"
)
if base_summary.layout not in {"copy", "bundled"}:
if base_summary.layout not in {"single-camera", "copy", "bundled"}:
reason = base_summary.validation_reason or "unsupported MCAP layout"
raise click.ClickException(reason)
@@ -544,7 +542,7 @@ def write_sample_outputs(
@click.group()
def main() -> None:
"""Small MCAP RGBD example helper for bundled and copy-layout MCAP files."""
"""Small MCAP RGBD example helper for bundled, copy, and legacy single-camera MCAP files."""
@main.command("summary")
@@ -558,7 +556,7 @@ def summary_command(mcap_path: Path) -> None:
@main.command("export-sample")
@click.argument("mcap_path", type=click.Path(path_type=Path, exists=True))
@click.option("--camera-label", help="Camera label to export. Defaults to the first sorted namespaced label.")
@click.option("--camera-label", help="Camera label to export. Defaults to `camera` for legacy files or the first sorted namespaced label.")
@click.option("--sample-index", default=0, show_default=True, type=click.IntRange(min=0), help="Zero-based per-camera RGB+depth sample index.")
@click.option("--output-dir", required=True, type=click.Path(path_type=Path), help="Directory to write rgb.png, depth.npy, depth_preview.png, and sample_metadata.json.")
@click.option("--ffmpeg-bin", default="ffmpeg", show_default=True, help="ffmpeg binary used to decode the selected RGB frame.")
@@ -581,7 +579,7 @@ def export_sample_command(
depth_max_m: float,
depth_palette: str,
) -> None:
"""Export one per-camera RGB/depth sample from a bundled or copy-layout MCAP file."""
"""Export one per-camera RGB/depth sample from a bundled, copy, or legacy single-camera MCAP file."""
summary = summarize_mcap(mcap_path.resolve())
ensure_supported_layout(summary.base)
if summary.base.validation_status != "valid":