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