fix(record): fall back to millimeter for unknown depth unit

This commit is contained in:
2026-03-12 11:00:25 +08:00
parent 59ff8b79d9
commit a21d4b6769
3 changed files with 81 additions and 26 deletions
+13 -7
View File
@@ -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<record::RawDepthMapView, std::string> make_depth_map_view(const ipc::CoherentSnapshot &snapshot) {
if (!snapshot.depth_info) {
@@ -200,9 +208,6 @@ std::expected<record::RawDepthMapView, std::string> 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<record::RawDepthMapView, std::string> 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<const float>(
reinterpret_cast<const float *>(snapshot.depth.data()),
pixel_count),
@@ -554,10 +559,12 @@ int run_pipeline(const RuntimeConfig &config) {
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");
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(
+14 -7
View File
@@ -39,6 +39,14 @@ struct EncodedDepthPayload {
std::vector<std::uint8_t> 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::vector<std::uint8_t>, 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<EncodedDepthPayload, std::string> encode_depth_payload(const RawDepthMapView &depth_map) {
const auto pixel_count = static_cast<std::size_t>(depth_map.width) * static_cast<std::size_t>(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<std::uint16_t> pixels(pixel_count, 0);
for (std::size_t index = 0; index < pixel_count; ++index) {
const float sample = depth_map.pixels[index];
@@ -281,7 +287,7 @@ std::expected<EncodedDepthPayload, std::string> encode_depth_payload(const RawDe
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)) {
if (source_unit == ipc::DepthUnit::Millimeter && std::isfinite(sample)) {
sample *= 0.001f;
}
if (!std::isfinite(sample) || sample <= 0.0f) {
@@ -443,6 +449,7 @@ std::expected<void, std::string> 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<void, std::string> 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(
+43 -1
View File
@@ -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<float>::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<const std::uint8_t>(
reinterpret_cast<const std::uint8_t *>(unknown_message.data().data()),
unknown_message.data().size()));
const auto unknown_decoded = rvl::decompress_image(std::span<const std::uint8_t>(
reinterpret_cast<const std::uint8_t *>(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());