From a21d4b67697e2d6589eb2884dde450758474e881 Mon Sep 17 00:00:00 2001 From: crosstyan Date: Thu, 12 Mar 2026 11:00:25 +0800 Subject: [PATCH] fix(record): fall back to millimeter for unknown depth unit --- src/pipeline/pipeline_runtime.cpp | 28 +++++++++------ src/record/mcap_record_sink.cpp | 35 +++++++++++-------- src/testers/mcap_depth_record_tester.cpp | 44 +++++++++++++++++++++++- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/pipeline/pipeline_runtime.cpp b/src/pipeline/pipeline_runtime.cpp index b999d5d..46469e4 100644 --- a/src/pipeline/pipeline_runtime.cpp +++ b/src/pipeline/pipeline_runtime.cpp @@ -192,6 +192,14 @@ bool frame_info_equal(const ipc::FrameInfo &lhs, const ipc::FrameInfo &rhs) { lhs.buffer_size == rhs.buffer_size; } +[[nodiscard]] +ipc::DepthUnit normalize_depth_unit_for_recording(ipc::DepthUnit unit) { + if (unit == ipc::DepthUnit::Unknown) { + return ipc::DepthUnit::Millimeter; + } + return unit; +} + [[nodiscard]] std::expected make_depth_map_view(const ipc::CoherentSnapshot &snapshot) { if (!snapshot.depth_info) { @@ -200,9 +208,6 @@ std::expected make_depth_map_view(const ip if (snapshot.depth.empty()) { return std::unexpected("depth plane bytes are missing"); } - if (snapshot.depth_unit == ipc::DepthUnit::Unknown) { - return std::unexpected("depth plane unit is unknown"); - } const auto &depth_info = *snapshot.depth_info; if (depth_info.depth != ipc::Depth::F32 || depth_info.pixel_format != ipc::PixelFormat::GRAY) { @@ -223,7 +228,7 @@ std::expected make_depth_map_view(const ip .timestamp_ns = snapshot.metadata.timestamp_ns, .width = depth_info.width, .height = depth_info.height, - .source_unit = snapshot.depth_unit, + .source_unit = normalize_depth_unit_for_recording(snapshot.depth_unit), .pixels = std::span( reinterpret_cast(snapshot.depth.data()), pixel_count), @@ -551,13 +556,15 @@ int run_pipeline(const RuntimeConfig &config) { continue; } - if (mcap_sink.has_value() && !snapshot->depth.empty()) { - if (snapshot->depth_unit == ipc::DepthUnit::Unknown) { - if (!warned_unknown_depth_unit) { - spdlog::warn("pipeline depth plane present but depth_unit is unknown; skipping depth MCAP recording"); - warned_unknown_depth_unit = true; + if (mcap_sink.has_value() && !snapshot->depth.empty()) { + if (snapshot->depth_unit == ipc::DepthUnit::Unknown) { + if (!warned_unknown_depth_unit) { + spdlog::warn( + "pipeline depth plane present but depth_unit is unknown; assuming millimeters for MCAP recording, producer should upgrade to the ABI with explicit depth_unit metadata"); + warned_unknown_depth_unit = true; + } } - } else { + auto depth_map = make_depth_map_view(*snapshot); if (!depth_map) { const auto reason = "pipeline depth snapshot invalid: " + depth_map.error(); @@ -572,7 +579,6 @@ int run_pipeline(const RuntimeConfig &config) { continue; } } - } stats.pushed_frames += 1; auto drain = drain_encoder( diff --git a/src/record/mcap_record_sink.cpp b/src/record/mcap_record_sink.cpp index 016ac09..2779ee4 100644 --- a/src/record/mcap_record_sink.cpp +++ b/src/record/mcap_record_sink.cpp @@ -39,6 +39,14 @@ struct EncodedDepthPayload { std::vector bytes{}; }; +[[nodiscard]] +ipc::DepthUnit normalize_depth_source_unit(ipc::DepthUnit unit) { + if (unit == ipc::DepthUnit::Unknown) { + return ipc::DepthUnit::Millimeter; + } + return unit; +} + [[nodiscard]] mcap::Compression to_mcap_compression(McapCompression compression) { switch (compression) { @@ -227,7 +235,7 @@ std::expected, std::string> decoder_config_to_annexb( [[nodiscard]] bool can_encode_lossless_u16_mm(const RawDepthMapView &depth_map) { - if (depth_map.source_unit != ipc::DepthUnit::Millimeter) { + if (normalize_depth_source_unit(depth_map.source_unit) != ipc::DepthUnit::Millimeter) { return false; } @@ -249,18 +257,16 @@ bool can_encode_lossless_u16_mm(const RawDepthMapView &depth_map) { [[nodiscard]] std::expected encode_depth_payload(const RawDepthMapView &depth_map) { const auto pixel_count = static_cast(depth_map.width) * static_cast(depth_map.height); + const auto source_unit = normalize_depth_source_unit(depth_map.source_unit); if (depth_map.width == 0 || depth_map.height == 0) { return std::unexpected("depth map dimensions must be non-zero"); } if (pixel_count != depth_map.pixels.size()) { return std::unexpected("depth map dimensions do not match the pixel buffer"); } - if (depth_map.source_unit == ipc::DepthUnit::Unknown) { - return std::unexpected("depth source unit is unknown"); - } try { - if (can_encode_lossless_u16_mm(depth_map)) { + if (source_unit == ipc::DepthUnit::Millimeter && can_encode_lossless_u16_mm(depth_map)) { std::vector pixels(pixel_count, 0); for (std::size_t index = 0; index < pixel_count; ++index) { const float sample = depth_map.pixels[index]; @@ -277,14 +283,14 @@ std::expected encode_depth_payload(const RawDe }; } - std::vector depth_m(pixel_count, std::numeric_limits::quiet_NaN()); - float finite_max_m = 0.0f; - for (std::size_t index = 0; index < pixel_count; ++index) { - float sample = depth_map.pixels[index]; - if (depth_map.source_unit == ipc::DepthUnit::Millimeter && std::isfinite(sample)) { - sample *= 0.001f; - } - if (!std::isfinite(sample) || sample <= 0.0f) { + std::vector depth_m(pixel_count, std::numeric_limits::quiet_NaN()); + float finite_max_m = 0.0f; + for (std::size_t index = 0; index < pixel_count; ++index) { + float sample = depth_map.pixels[index]; + if (source_unit == ipc::DepthUnit::Millimeter && std::isfinite(sample)) { + sample *= 0.001f; + } + if (!std::isfinite(sample) || sample <= 0.0f) { continue; } @@ -443,6 +449,7 @@ std::expected McapRecordSink::write_depth_map(const RawDepthM if (state_ == nullptr) { return std::unexpected("MCAP sink is not open"); } + const auto source_unit = normalize_depth_source_unit(depth_map.source_unit); auto encoded = encode_depth_payload(depth_map); if (!encoded) { @@ -454,7 +461,7 @@ std::expected McapRecordSink::write_depth_map(const RawDepthM message.set_frame_id(state_->frame_id); message.set_width(depth_map.width); message.set_height(depth_map.height); - message.set_source_unit(to_proto_depth_unit(depth_map.source_unit)); + message.set_source_unit(to_proto_depth_unit(source_unit)); message.set_storage_unit(to_proto_storage_unit(encoded->storage_unit)); message.set_encoding(to_proto_depth_encoding(encoded->encoding)); message.set_data( diff --git a/src/testers/mcap_depth_record_tester.cpp b/src/testers/mcap_depth_record_tester.cpp index ae2be32..6059ba5 100644 --- a/src/testers/mcap_depth_record_tester.cpp +++ b/src/testers/mcap_depth_record_tester.cpp @@ -114,6 +114,23 @@ int main(int argc, char **argv) { return exit_code(TesterExitCode::WriteError); } + const float depth_unknown_pixels[4] = { + 1500.0f, + 2500.0f, + std::numeric_limits::quiet_NaN(), + 0.0f, + }; + cvmmap_streamer::record::RawDepthMapView depth_unknown{}; + depth_unknown.timestamp_ns = 13; + depth_unknown.width = 2; + depth_unknown.height = 2; + depth_unknown.source_unit = cvmmap_streamer::ipc::DepthUnit::Unknown; + depth_unknown.pixels = depth_unknown_pixels; + if (auto write = sink->write_depth_map(depth_unknown); !write) { + spdlog::error("failed to write unknown-unit depth map: {}", write.error()); + return exit_code(TesterExitCode::WriteError); + } + sink->close(); mcap::McapReader reader{}; @@ -173,7 +190,7 @@ int main(int argc, char **argv) { reader.close(); - if (video_messages != 1 || depth_messages.size() != 2) { + if (video_messages != 1 || depth_messages.size() != 3) { spdlog::error( "unexpected message counts: video={} depth={}", video_messages, @@ -231,6 +248,31 @@ int main(int argc, char **argv) { return exit_code(TesterExitCode::VerificationError); } + const auto &unknown_message = depth_messages[2]; + if (unknown_message.source_unit() != cvmmap_streamer::DepthMap::DEPTH_UNIT_MILLIMETER || + unknown_message.storage_unit() != cvmmap_streamer::DepthMap::STORAGE_UNIT_MILLIMETER || + unknown_message.encoding() != cvmmap_streamer::DepthMap::RVL_U16_LOSSLESS) { + spdlog::error("unknown-unit fallback metadata verification failed"); + return exit_code(TesterExitCode::VerificationError); + } + const auto unknown_info = rvl::inspect_image(std::span( + reinterpret_cast(unknown_message.data().data()), + unknown_message.data().size())); + const auto unknown_decoded = rvl::decompress_image(std::span( + reinterpret_cast(unknown_message.data().data()), + unknown_message.data().size())); + if (unknown_info.format != rvl::ImageFormat::UInt16Lossless || + unknown_info.rows != 2 || + unknown_info.cols != 2 || + unknown_decoded.pixels.size() != 4 || + unknown_decoded.pixels[0] != 1500 || + unknown_decoded.pixels[1] != 2500 || + unknown_decoded.pixels[2] != 0 || + unknown_decoded.pixels[3] != 0) { + spdlog::error("unknown-unit fallback RVL round-trip verification failed"); + return exit_code(TesterExitCode::VerificationError); + } + spdlog::info( "validated same-file MCAP video+depth recording at '{}'", output_path.string());