Skip to content

Commit fd51363

Browse files
authored
Support zero-copy intra-process publishing (#306)
1 parent 74d9e8e commit fd51363

File tree

7 files changed

+188
-8
lines changed

7 files changed

+188
-8
lines changed

image_transport/include/image_transport/camera_publisher.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ class CameraPublisher
111111
const sensor_msgs::msg::Image::ConstSharedPtr & image,
112112
const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info) const;
113113

114+
/*!
115+
* \brief Publish an (image, info) pair on the topics associated with this CameraPublisher.
116+
*/
117+
IMAGE_TRANSPORT_PUBLIC
118+
void publish(
119+
sensor_msgs::msg::Image::UniquePtr image,
120+
sensor_msgs::msg::CameraInfo::UniquePtr info) const;
121+
114122
/*!
115123
* \brief Publish an (image, info) pair with given timestamp on the topics associated with
116124
* this CameraPublisher.
@@ -123,6 +131,19 @@ class CameraPublisher
123131
sensor_msgs::msg::Image & image, sensor_msgs::msg::CameraInfo & info,
124132
rclcpp::Time stamp) const;
125133

134+
/*!
135+
* \brief Publish an (image, info) pair with given timestamp on the topics associated with
136+
* this CameraPublisher.
137+
*
138+
* Convenience version, which sets the timestamps of both image and info to stamp before
139+
* publishing.
140+
*/
141+
IMAGE_TRANSPORT_PUBLIC
142+
void publish(
143+
sensor_msgs::msg::Image::UniquePtr image,
144+
sensor_msgs::msg::CameraInfo::UniquePtr info,
145+
rclcpp::Time stamp) const;
146+
126147
/*!
127148
* \brief Shutdown the advertisements associated with this Publisher.
128149
*/

image_transport/include/image_transport/publisher.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ class Publisher
103103
IMAGE_TRANSPORT_PUBLIC
104104
void publish(const sensor_msgs::msg::Image::ConstSharedPtr & message) const;
105105

106+
/*!
107+
* \brief Publish an image on the topics associated with this Publisher.
108+
*/
109+
IMAGE_TRANSPORT_PUBLIC
110+
void publish(sensor_msgs::msg::Image::UniquePtr message) const;
111+
106112
/*!
107113
* \brief Shutdown the advertisements associated with this Publisher.
108114
*/

image_transport/include/image_transport/publisher_plugin.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#ifndef IMAGE_TRANSPORT__PUBLISHER_PLUGIN_HPP_
3030
#define IMAGE_TRANSPORT__PUBLISHER_PLUGIN_HPP_
3131

32+
#include <stdexcept>
3233
#include <string>
3334
#include <vector>
3435

@@ -59,6 +60,14 @@ class PublisherPlugin
5960
*/
6061
virtual std::string getTransportName() const = 0;
6162

63+
/**
64+
* \brief Check whether this plugin supports publishing using UniquePtr.
65+
*/
66+
virtual bool supportsUniquePtrPub() const
67+
{
68+
return false;
69+
}
70+
6271
/**
6372
* \brief Advertise a topic, simple version.
6473
*/
@@ -95,6 +104,18 @@ class PublisherPlugin
95104
publish(*message);
96105
}
97106

107+
/**
108+
* \brief Publish an image using the transport associated with this PublisherPlugin.
109+
* This version of the function can be used to optimize cases where the Plugin can
110+
* avoid doing copies of the data when having the ownership to the image message.
111+
* Plugins that can take advantage of message ownership should overwrite this method
112+
* along with supportsUniquePtrPub().
113+
*/
114+
virtual void publishUniquePtr(sensor_msgs::msg::Image::UniquePtr /*message*/) const
115+
{
116+
throw std::logic_error("publishUniquePtr() is not implemented.");
117+
}
118+
98119
/**
99120
* \brief Publish an image using the transport associated with this PublisherPlugin.
100121
* This version of the function can be used to optimize cases where you don't want to

image_transport/include/image_transport/raw_publisher.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define IMAGE_TRANSPORT__RAW_PUBLISHER_HPP_
3131

3232
#include <string>
33+
#include <utility>
3334

3435
#include "sensor_msgs/msg/image.hpp"
3536

@@ -56,12 +57,30 @@ class RawPublisher : public SimplePublisherPlugin<sensor_msgs::msg::Image>
5657
return "raw";
5758
}
5859

60+
virtual bool supportsUniquePtrPub() const
61+
{
62+
return true;
63+
}
64+
5965
protected:
66+
[[deprecated("Use publish(const sensor_msgs::msg::Image&, const PublisherT&) instead.")]]
6067
virtual void publish(const sensor_msgs::msg::Image & message, const PublishFn & publish_fn) const
6168
{
6269
publish_fn(message);
6370
}
6471

72+
virtual void publish(const sensor_msgs::msg::Image & message, const PublisherT & publisher) const
73+
{
74+
publisher->publish(message);
75+
}
76+
77+
virtual void publish(
78+
sensor_msgs::msg::Image::UniquePtr message,
79+
const PublisherT & publisher) const
80+
{
81+
publisher->publish(std::move(message));
82+
}
83+
6584
virtual std::string getTopicToAdvertise(const std::string & base_topic) const
6685
{
6786
return base_topic;

image_transport/include/image_transport/simple_publisher_plugin.hpp

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
#define IMAGE_TRANSPORT__SIMPLE_PUBLISHER_PLUGIN_HPP_
3131

3232
#include <memory>
33+
#include <stdexcept>
3334
#include <string>
35+
#include <utility>
3436

3537
#include "rclcpp/node.hpp"
3638
#include "rclcpp/logger.hpp"
@@ -89,7 +91,20 @@ class SimplePublisherPlugin : public PublisherPlugin
8991
return;
9092
}
9193

92-
publish(message, bindInternalPublisher(simple_impl_->pub_.get()));
94+
publish(message, simple_impl_->pub_);
95+
}
96+
97+
void publishUniquePtr(sensor_msgs::msg::Image::UniquePtr message) const override
98+
{
99+
if (!simple_impl_ || !simple_impl_->pub_) {
100+
auto logger = simple_impl_ ? simple_impl_->logger_ : rclcpp::get_logger("image_transport");
101+
RCLCPP_ERROR(
102+
logger,
103+
"Call to publish() on an invalid image_transport::SimplePublisherPlugin");
104+
return;
105+
}
106+
107+
publish(std::move(message), simple_impl_->pub_);
93108
}
94109

95110
void shutdown() override
@@ -112,20 +127,54 @@ class SimplePublisherPlugin : public PublisherPlugin
112127
simple_impl_->pub_ = node->create_publisher<M>(transport_topic, qos, options);
113128
}
114129

130+
typedef typename rclcpp::Publisher<M>::SharedPtr PublisherT;
131+
115132
//! Generic function for publishing the internal message type.
116133
typedef std::function<void (const M &)> PublishFn;
117134

118135
/**
119-
* \brief Publish an image using the specified publish function. Must be implemented by
120-
* the subclass.
136+
* \brief Publish an image using the specified publish function.
137+
*
138+
* \deprecated Use publish(const sensor_msgs::msg::Image&, const PublisherT&) instead.
121139
*
122140
* The PublishFn publishes the transport-specific message type. This indirection allows
123141
* SimpleSubscriberPlugin to use this function for both normal broadcast publishing and
124142
* single subscriber publishing (in subscription callbacks).
125143
*/
144+
virtual void publish(
145+
const sensor_msgs::msg::Image & /*message*/,
146+
const PublishFn & /*publish_fn*/) const
147+
{
148+
throw std::logic_error(
149+
"publish(const sensor_msgs::msg::Image&, const PublishFn&) is not implemented.");
150+
}
151+
152+
/**
153+
* \brief Publish an image using the specified publisher.
154+
*/
126155
virtual void publish(
127156
const sensor_msgs::msg::Image & message,
128-
const PublishFn & publish_fn) const = 0;
157+
const PublisherT & publisher) const
158+
{
159+
// Fallback to old, deprecated method
160+
publish(message, bindInternalPublisher(publisher.get()));
161+
}
162+
163+
/**
164+
* \brief Publish an image using the specified publisher.
165+
*
166+
* This version of the function can be used to optimize cases where the Plugin can
167+
* avoid doing copies of the data when having the ownership to the image message.
168+
* Plugins that can take advantage of message ownership should overwrite this method
169+
* along with supportsUniquePtrPub().
170+
*/
171+
virtual void publish(
172+
sensor_msgs::msg::Image::UniquePtr /*message*/,
173+
const PublisherT & /*publisher*/) const
174+
{
175+
throw std::logic_error(
176+
"publish(sensor_msgs::msg::Image::UniquePtr, const PublisherT&) is not implemented.");
177+
}
129178

130179
/**
131180
* \brief Return the communication topic name for a given base topic.
@@ -148,7 +197,7 @@ class SimplePublisherPlugin : public PublisherPlugin
148197

149198
rclcpp::Node * node_;
150199
rclcpp::Logger logger_;
151-
typename rclcpp::Publisher<M>::SharedPtr pub_;
200+
PublisherT pub_;
152201
};
153202

154203
std::unique_ptr<SimplePublisherPluginImpl> simple_impl_;

image_transport/src/camera_publisher.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include <memory>
3232
#include <string>
33+
#include <utility>
3334

3435
#include "rclcpp/expand_topic_or_service_name.hpp"
3536
#include "rclcpp/logging.hpp"
@@ -124,7 +125,6 @@ void CameraPublisher::publish(
124125
const sensor_msgs::msg::CameraInfo & info) const
125126
{
126127
if (!impl_ || !impl_->isValid()) {
127-
// TODO(ros2) Switch to RCUTILS_ASSERT when ros2/rcutils#112 is merged
128128
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
129129
RCLCPP_FATAL(
130130
logger,
@@ -141,7 +141,6 @@ void CameraPublisher::publish(
141141
const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info) const
142142
{
143143
if (!impl_ || !impl_->isValid()) {
144-
// TODO(ros2) Switch to RCUTILS_ASSERT when ros2/rcutils#112 is merged
145144
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
146145
RCLCPP_FATAL(
147146
logger,
@@ -153,12 +152,27 @@ void CameraPublisher::publish(
153152
impl_->info_pub_->publish(*info);
154153
}
155154

155+
void CameraPublisher::publish(
156+
sensor_msgs::msg::Image::UniquePtr image,
157+
sensor_msgs::msg::CameraInfo::UniquePtr info) const
158+
{
159+
if (!impl_ || !impl_->isValid()) {
160+
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
161+
RCLCPP_FATAL(
162+
logger,
163+
"Call to publish() on an invalid image_transport::CameraPublisher");
164+
return;
165+
}
166+
167+
impl_->image_pub_.publish(std::move(image));
168+
impl_->info_pub_->publish(std::move(info));
169+
}
170+
156171
void CameraPublisher::publish(
157172
sensor_msgs::msg::Image & image, sensor_msgs::msg::CameraInfo & info,
158173
rclcpp::Time stamp) const
159174
{
160175
if (!impl_ || !impl_->isValid()) {
161-
// TODO(ros2) Switch to RCUTILS_ASSERT when ros2/rcutils#112 is merged
162176
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
163177
RCLCPP_FATAL(
164178
logger,
@@ -172,6 +186,25 @@ void CameraPublisher::publish(
172186
impl_->info_pub_->publish(info);
173187
}
174188

189+
void CameraPublisher::publish(
190+
sensor_msgs::msg::Image::UniquePtr image,
191+
sensor_msgs::msg::CameraInfo::UniquePtr info,
192+
rclcpp::Time stamp) const
193+
{
194+
if (!impl_ || !impl_->isValid()) {
195+
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
196+
RCLCPP_FATAL(
197+
logger,
198+
"Call to publish() on an invalid image_transport::CameraPublisher");
199+
return;
200+
}
201+
202+
image->header.stamp = stamp;
203+
info->header.stamp = stamp;
204+
impl_->image_pub_.publish(std::move(image));
205+
impl_->info_pub_->publish(std::move(info));
206+
}
207+
175208
void CameraPublisher::shutdown()
176209
{
177210
if (impl_) {

image_transport/src/publisher.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "image_transport/publisher.hpp"
3030

3131
#include <memory>
32+
#include <optional>
3233
#include <set>
3334
#include <string>
3435
#include <utility>
@@ -202,6 +203,36 @@ void Publisher::publish(const sensor_msgs::msg::Image::ConstSharedPtr & message)
202203
}
203204
}
204205

206+
void Publisher::publish(sensor_msgs::msg::Image::UniquePtr message) const
207+
{
208+
if (!impl_ || !impl_->isValid()) {
209+
auto logger = impl_ ? impl_->logger_ : rclcpp::get_logger("image_transport");
210+
RCLCPP_FATAL(logger, "Call to publish() on an invalid image_transport::Publisher");
211+
return;
212+
}
213+
214+
std::vector<std::shared_ptr<PublisherPlugin>> pubs_take_reference;
215+
std::optional<std::shared_ptr<PublisherPlugin>> pub_takes_ownership = std::nullopt;
216+
217+
for (const auto & pub : impl_->publishers_) {
218+
if (pub->getNumSubscribers() > 0) {
219+
if (pub->supportsUniquePtrPub() && !pub_takes_ownership.has_value()) {
220+
pub_takes_ownership = pub;
221+
} else {
222+
pubs_take_reference.push_back(pub);
223+
}
224+
}
225+
}
226+
227+
for (const auto & pub : pubs_take_reference) {
228+
pub->publish(*message);
229+
}
230+
231+
if (pub_takes_ownership.has_value()) {
232+
pub_takes_ownership.value()->publishUniquePtr(std::move(message));
233+
}
234+
}
235+
205236
void Publisher::shutdown()
206237
{
207238
if (impl_) {

0 commit comments

Comments
 (0)