Skip to content

Feat/depth compression filter#50

Merged
05F3759DF merged 21 commits intomainfrom
feat/depth-compression-filter
Feb 3, 2026
Merged

Feat/depth compression filter#50
05F3759DF merged 21 commits intomainfrom
feat/depth-compression-filter

Conversation

@05F3759DF
Copy link
Contributor

Pull Request Checklist

Please ensure your PR meets the following requirements:

  • Code follows the style guidelines
  • Tests pass locally (make test or make docker-test)
  • Code is formatted (make format)
  • Documentation updated if needed
  • Commit messages follow conventional commits
  • PR description is complete and clear

Summary

This PR adds depth image compression filter using DepthLiteZ algorithm for ROS1 and ROS2 plugins, achieving 5-10x compression ratio on 16-bit depth images.


Motivation

Depth images consume significant storage space in robotics recordings. A specialized compression filter is needed to reduce storage costs and improve upload performance without losing depth precision.


Changes

Modified Files

Added Files

Deleted Files

  • None

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update (documentation changes only)
  • Refactoring (code improvement without functional changes)
  • Performance improvement (code changes that improve performance)
  • Test changes (adding, modifying, or removing tests)

Impact Analysis

Breaking Changes

None

Backward Compatibility

Fully backward compatible. Depth compression is opt-in via CMake option AXON_ENABLE_DEPTH_COMPRESSION=ON. Default behavior unchanged when option is disabled.


Testing

Test Environment

  • ROS Distribution: ROS 2 Humble / ROS 1 Noetic
  • OS: Ubuntu 22.04
  • Build Type: Release / Debug

Test Cases

  • Unit tests pass locally
  • Integration tests pass locally
  • E2E tests pass (if applicable)
  • Manual testing completed

Manual Testing Steps

  1. Build with depth compression enabled: cmake -DAXON_ENABLE_DEPTH_COMPRESSION=ON ..
  2. Run recorder with depth topics: ./axon_recorder --config config/default_config_ros2.yaml
  3. Verified compressed depth channels are registered with _compressed suffix
  4. Verified MCAP file contains compressed depth messages

Test Coverage

  • New tests added
  • Existing tests updated
  • Coverage maintained or improved

Screenshots / Recordings

N/A


Performance Impact

  • Memory usage: Increased (compression buffers)
  • CPU usage: Increased during compression (depends on mode: fast/medium/max)
  • Recording throughput: Improved for depth images (5-10x size reduction)
  • Lock contention: No change

Documentation


Related Issues

  • Fixes #
  • Related to #
  • Refers to #

Additional Notes

  • DepthLiteZ library is added as a git submodule in middlewares/filters/depthlitez
  • When cloning this repository, use git clone --recursive or run git submodule update --init --recursive
  • The compression mode can be configured via YAML: depth_compression.mode: fast|medium|max
  • Default mode is medium for balanced compression ratio and performance

Reviewers

@zhexuany


Notes for Reviewers

  • Please review the subscription wrapper pattern in both ROS1 and ROS2 plugins
  • Verify the plugin ABI changes are backward compatible (wrapper enums to avoid dlz.hpp namespace pollution)
  • Focus on the thread safety of the depth compression filter implementation

Checklist for Reviewers

  • Code changes are correct and well-implemented
  • Tests are adequate and pass
  • Documentation is updated and accurate
  • No unintended side effects
  • Performance impact is acceptable
  • Backward compatibility maintained (if applicable)

@05F3759DF 05F3759DF requested a review from zhexuany February 3, 2026 05:02
@greptile-apps
Copy link

greptile-apps bot commented Feb 3, 2026

Greptile Overview

Greptile Summary

This PR adds depth image compression using DepthLiteZ algorithm to reduce storage requirements for 16-bit depth images by 5-10x. The implementation includes a new filters library, ROS1/ROS2 plugin integration, and conditional compilation support.

Major Changes:

  • Added middlewares/filters/ library with DepthCompressor class wrapping DepthLiteZ
  • Modified channel registration to support topic+message_type composite keys for dynamic type conversion
  • Extended plugin ABI (v1.0 → v1.1) to pass depth compression options via JSON
  • Added subscription wrapper with conditional depth compression filter pipeline
  • Implemented auto-registration for CompressedImage schema when compression is enabled

Critical Issues Found:

  • Broken backward compatibility in RecordingSession: The topic_channel_ids_ map now uses composite keys (topic + "\n" + message_type), but get_channel_id(topic) still searches by topic alone, causing lookups to always fail
  • Race condition in SubscriptionManager: Callback accesses subscriptions_ map without holding the mutex, creating potential crashes when subscriptions are modified
  • Unsafe const_cast: DepthCompressor::compress() uses const_cast to pass const input data to dlz::CompressEx(), which may modify the buffer

Style Issues:

  • Uses deprecated ament_target_dependencies() in ROS2 CMake instead of modern target_link_libraries() with explicit targets (contradicts style guide)

Testing Impact:

  • Unit tests in test_recording_session.cpp will fail due to broken get_channel_id() implementation

Confidence Score: 1/5

  • Not safe to merge - contains critical bugs that will break existing functionality and tests
  • Multiple critical logic errors were found: (1) get_channel_id() is broken and will fail all lookups after the composite key change, (2) race condition in subscription callback that could cause crashes, (3) unsafe const_cast that violates const-correctness. The test suite will fail due to the broken get_channel_id() implementation. These issues must be fixed before merging.
  • Pay close attention to apps/axon_recorder/recording_session.cpp (broken channel lookup), middlewares/ros2/src/ros2_subscription_wrapper.cpp (race condition), and middlewares/filters/src/depth_compressor.cpp (unsafe const_cast)

Important Files Changed

Filename Overview
apps/axon_recorder/recording_session.cpp Added composite key for channel registration, but breaks backward compatibility with get_channel_id()
middlewares/ros2/src/ros2_subscription_wrapper.cpp Race condition in callback accessing subscriptions map without lock
middlewares/filters/src/depth_compressor.cpp Unsafe const_cast on input data passed to dlz library
middlewares/ros2/CMakeLists.txt Uses deprecated ament_target_dependencies instead of modern target_link_libraries
apps/axon_recorder/test/unit/test_recording_session.cpp Tests will fail due to broken get_channel_id implementation

Sequence Diagram

sequenceDiagram
    participant App as Axon Recorder
    participant Plugin as ROS2 Plugin
    participant SubMgr as SubscriptionManager
    participant Filter as DepthCompressionFilter
    participant Compressor as DepthCompressor
    participant Session as RecordingSession
    participant MCAP as MCAP Writer

    Note over App,Plugin: Initialization Phase
    App->>Plugin: init() with config
    App->>Plugin: subscribe(topic, type, options_json)
    Plugin->>Plugin: Parse depth_compression from options_json
    Plugin->>SubMgr: subscribe(topic, type, options)
    
    alt Depth Compression Enabled
        SubMgr->>Filter: Create DepthCompressionFilter(config)
        Filter->>Compressor: Configure compression level
    end
    
    SubMgr->>SubMgr: Create GenericSubscription
    SubMgr->>SubMgr: Store filter in subscriptions map

    Note over App,MCAP: Recording Phase - Message Flow
    Plugin->>SubMgr: ROS message arrives
    SubMgr->>SubMgr: Extract serialized bytes
    
    alt Depth Compression Enabled
        SubMgr->>Filter: filter_and_process(topic, type, data)
        Filter->>Filter: Deserialize to sensor_msgs::Image
        Filter->>Filter: Check if 16UC1 encoding
        
        alt Is 16UC1 Depth Image
            Filter->>Compressor: compress(depth_data, width, height)
            Compressor->>Compressor: Cast to int16_t and call dlz::CompressEx
            Compressor-->>Filter: compressed_data
            Filter->>Filter: Build CompressedImage message
            Filter->>Filter: Change type to sensor_msgs/msg/CompressedImage
        end
        
        Filter-->>SubMgr: Processed message (original or compressed)
    end
    
    SubMgr->>App: Callback with processed message
    App->>Session: get_or_create_channel(topic, message_type)
    
    alt Channel Not Exists
        Session->>Session: Auto-register schema for message_type
        Session->>Session: Create composite key (topic + "\\n" + message_type)
        Session->>MCAP: register_channel()
        Session->>Session: Store in topic_channel_ids map
    end
    
    Session-->>App: channel_id
    App->>Session: write(channel_id, data, timestamp)
    Session->>MCAP: Write message to MCAP file
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 3, 2026

Additional Comments (1)

apps/axon_recorder/recording_session.cpp
Potential broken behavior: get_channel_id now searches by topic only but map uses composite keys

After the changes, topic_channel_ids_ uses composite keys (topic + "\n" + message_type), but get_channel_id(topic) still searches by topic alone. This will fail to find any channels registered after the change, always returning 0.

This breaks backward compatibility for any code that registers a channel with register_channel() and then looks it up with get_channel_id().

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/axon_recorder/recording_session.cpp
Line: 210:214

Comment:
Potential broken behavior: `get_channel_id` now searches by topic only but map uses composite keys

After the changes, `topic_channel_ids_` uses composite keys (`topic + "\n" + message_type`), but `get_channel_id(topic)` still searches by topic alone. This will fail to find any channels registered after the change, always returning 0.

This breaks backward compatibility for any code that registers a channel with `register_channel()` and then looks it up with `get_channel_id()`.

How can I resolve this? If you propose a fix, please make it concise.

@05F3759DF 05F3759DF force-pushed the feat/depth-compression-filter branch from f85da47 to 42e9b54 Compare February 3, 2026 06:18
@05F3759DF 05F3759DF merged commit 3e0891b into main Feb 3, 2026
23 checks passed
@05F3759DF 05F3759DF deleted the feat/depth-compression-filter branch February 3, 2026 13:42
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.

1 participant