@@ -85,6 +85,12 @@ ImageDisplay::ImageDisplay(std::unique_ptr<ROSImageTextureIface> texture)
85
85
this ->qos_profile_property_ =
86
86
new rviz_common::properties::QosProfileProperty (this ->topic_property_ , rclcpp::QoS (5 ));
87
87
88
+ transport_override_property_ = new rviz_common::properties::EnumProperty (
89
+ " Transport Override" , " " , " By default this display uses the topic name to determine the" +
90
+ " image_transport type. If this is not possible, use this field to manually set the transport." ,
91
+ this ->topic_property_ , SLOT (subscribe ()), this
92
+ );
93
+
88
94
normalize_property_ = new rviz_common::properties::BoolProperty (
89
95
" Normalize Range" , true ,
90
96
" If set to true, will try to estimate the range of possible values from the received images." ,
@@ -134,16 +140,16 @@ void ImageDisplay::incomingMessage(const sensor_msgs::msg::Image::ConstSharedPtr
134
140
ImageTransportDisplay<sensor_msgs::msg::Image>::incomingMessage (img_msg);
135
141
}
136
142
137
- void ImageDisplay::subscribe ()
143
+ void ImageDisplay::updateTopic ()
138
144
{
139
145
if (!isEnabled ()) {
140
146
return ;
141
147
}
148
+ transport_override_property_->setStdString (" " );
142
149
143
- // TODO(mjforan) this should really be in onInitialize but setStatus does not work there
144
150
// Populate topic message types based on installed image_transport plugins
145
151
image_transport::ImageTransport image_transport_ (rviz_ros_node_.lock ()->get_raw_node ());
146
- std::vector<std::string> transports = image_transport_.getLoadableTransports ();
152
+ std::vector<std::string> loadable_transports = image_transport_.getLoadableTransports ();
147
153
std::vector<QString> message_types;
148
154
// Map to message types
149
155
const std::unordered_map<std::string, std::string> transport_message_types_ = {
@@ -156,10 +162,13 @@ void ImageDisplay::subscribe()
156
162
std::string transports_str = " " ;
157
163
rviz_common::properties::StatusProperty::Level transports_status_level =
158
164
rviz_common::properties::StatusProperty::Ok;
159
- for (std::string & transport : transports) {
165
+ // Populate topic message types and transport override options
166
+ transport_override_property_->addOptionStd (" " );
167
+ for (std::string & transport : loadable_transports) {
160
168
transport = transport.substr (transport.find_last_of (' /' ) + 1 );
161
169
try {
162
170
message_types.push_back (QString::fromStdString (transport_message_types_.at (transport)));
171
+ transport_override_property_->addOptionStd (transport);
163
172
transports_str += transport + " , " ;
164
173
} catch (const std::out_of_range & e) {
165
174
transports_status_level = rviz_common::properties::StatusProperty::Warn;
@@ -173,26 +182,51 @@ void ImageDisplay::subscribe()
173
182
((rviz_common::properties::RosTopicMultiProperty *)topic_property_)
174
183
->setMessageTypes (message_types);
175
184
185
+ rviz_default_plugins::displays::ImageTransportDisplay<sensor_msgs::msg::Image>::updateTopic ();
186
+ }
187
+
188
+ void ImageDisplay::subscribe ()
189
+ {
190
+ if (!isEnabled ()) {
191
+ return ;
192
+ }
193
+
176
194
if (topic_property_->isEmpty ()) {
177
195
setStatus (
178
196
rviz_common::properties::StatusProperty::Error, " Topic" ,
179
197
QString (" Error subscribing: Empty topic name" ));
180
198
return ;
181
199
}
182
-
183
200
try {
184
201
rclcpp::Node::SharedPtr node = rviz_ros_node_.lock ()->get_raw_node ();
185
202
image_transport::ImageTransport image_transport_ (node);
186
203
// This part differs from the parent class. ImageTransportDisplay uses an
187
204
// image_transport::SubscriberFilter, which requires a different callback for each transport
188
205
// type. image_transport::Subscriber only requires one callback for "raw" and the other types
189
206
// are automatically converted.
207
+ std::vector<std::string> transports = image_transport_.getLoadableTransports ();
208
+ // Strip down to basic transport names
209
+ for (std::string & transport : transports) {
210
+ transport = transport.substr (transport.find_last_of (' /' ) + 1 );
211
+ }
212
+ // Use override property for transport hint if set, otherwise deduce from topic name
213
+ std::string transport_hint = transport_override_property_->getStdString ();
214
+ if (transport_hint.empty ()) {
215
+ transport_hint = getTransportFromTopic (topic_property_->getStdString ());
216
+ }
217
+ // Check if the specified transport is in the list of loadable transports
218
+ if (std::find (transports.begin (), transports.end (), transport_hint) == transports.end ()) {
219
+ setStatus (
220
+ rviz_common::properties::StatusProperty::Error, " Topic" ,
221
+ QString (" Error subscribing: Specified image transport is not installed" ));
222
+ return ;
223
+ }
190
224
subscription_ = image_transport_.subscribe (
191
225
rviz_default_plugins::displays::getBaseTopicFromTopic (topic_property_->getTopicStd ()),
192
226
qos_profile.get_rmw_qos_profile ().depth ,
193
227
&ImageDisplay::incomingMessage, this ,
194
228
new image_transport::TransportHints (
195
- node.get (), getTransportFromTopic (topic_property_-> getStdString ()) , " image_transport" ));
229
+ node.get (), transport_hint , " image_transport" ));
196
230
197
231
setStatus (rviz_common::properties::StatusProperty::Ok, " Topic" , " OK" );
198
232
} catch (rclcpp::exceptions::InvalidTopicNameError & e) {
0 commit comments