1 #include <boost/foreach.hpp> 2 #include <boost/lexical_cast.hpp> 3 #include <boost/algorithm/string/predicate.hpp> 6 #include <opencv2/opencv.hpp> 15 #include "async_web_server_cpp/http_reply.hpp" 25 const async_web_server_cpp::HttpRequest &request,
26 async_web_server_cpp::HttpConnectionPtr connection,
const char* begin,
35 forward(request, connection, begin, end);
38 catch (std::exception &e)
47 nh_(nh), handler_group_(
48 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::not_found))
50 #if ROS_HAS_STEADYTIMER || defined USE_STEADY_TIMER 57 private_nh.
param(
"verbose", __verbose,
true);
59 private_nh.
param<std::string>(
"address",
address_,
"0.0.0.0");
62 private_nh.
param(
"server_threads", server_threads, 1);
85 new async_web_server_cpp::HttpServer(address_, boost::lexical_cast<std::string>(
port_),
89 catch(boost::exception& e)
91 ROS_ERROR(
"Exception when creating the web server! %s:%d", address_.c_str(),
port_);
126 typedef std::vector<boost::shared_ptr<ImageStreamer> >::iterator itr_type;
130 (*itr)->restreamFrame( max_age );
139 typedef std::vector<boost::shared_ptr<ImageStreamer> >::iterator itr_type;
154 async_web_server_cpp::HttpConnectionPtr connection,
const char* begin,
157 std::string type = request.get_query_param_value_or_default(
"type", __default_stream_type);
160 std::string topic = request.get_query_param_value_or_default(
"topic",
"");
162 if (type == std::string(
"ros_compressed"))
164 std::string compressed_topic_name = topic +
"/compressed";
167 bool did_find_compressed_topic =
false;
168 for(ros::master::V_TopicInfo::iterator it = topics.begin(); it != topics.end(); ++it)
170 if (it->name == compressed_topic_name)
172 did_find_compressed_topic =
true;
176 if (!did_find_compressed_topic)
178 ROS_WARN_STREAM(
"Could not find compressed image topic for " << topic <<
", falling back to mjpeg");
189 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::not_found)(request, connection, begin,
196 async_web_server_cpp::HttpConnectionPtr connection,
const char* begin,
208 async_web_server_cpp::HttpConnectionPtr connection,
const char* begin,
211 std::string type = request.get_query_param_value_or_default(
"type", __default_stream_type);
214 std::string topic = request.get_query_param_value_or_default(
"topic",
"");
216 if (type == std::string(
"ros_compressed"))
219 std::string compressed_topic_name = topic +
"/compressed";
222 bool did_find_compressed_topic =
false;
223 for(ros::master::V_TopicInfo::iterator it = topics.begin(); it != topics.end(); ++it)
225 if (it->name == compressed_topic_name)
227 did_find_compressed_topic =
true;
231 if (!did_find_compressed_topic)
233 ROS_WARN_STREAM(
"Could not find compressed image topic for " << topic <<
", falling back to mjpeg");
238 async_web_server_cpp::HttpReply::builder(async_web_server_cpp::HttpReply::ok).header(
"Connection",
"close").header(
239 "Server",
"web_video_server").header(
"Content-type",
"text/html;").write(connection);
241 std::stringstream ss;
242 ss <<
"<html><head><title>" << topic <<
"</title></head><body>";
243 ss <<
"<h1>" << topic <<
"</h1>";
245 ss <<
"</body></html>";
246 connection->write(ss.str());
250 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::not_found)(request, connection, begin,
257 async_web_server_cpp::HttpConnectionPtr connection,
const char* begin,
260 std::string image_message_type = ros::message_traits::datatype<sensor_msgs::Image>();
261 std::string camera_info_message_type = ros::message_traits::datatype<sensor_msgs::CameraInfo>();
265 ros::master::V_TopicInfo::iterator it;
266 std::vector<std::string> image_topics;
267 std::vector<std::string> camera_info_topics;
268 for (it = topics.begin(); it != topics.end(); ++it)
271 if (topic.
datatype == image_message_type)
273 image_topics.push_back(topic.
name);
275 else if (topic.
datatype == camera_info_message_type)
277 camera_info_topics.push_back(topic.
name);
281 async_web_server_cpp::HttpReply::builder(async_web_server_cpp::HttpReply::ok).header(
"Connection",
"close").header(
282 "Server",
"web_video_server").header(
"Cache-Control",
283 "no-cache, no-store, must-revalidate, pre-check=0, post-check=0, max-age=0").header(
284 "Pragma",
"no-cache").header(
"Content-type",
"text/html;").write(connection);
286 connection->write(
"<html>" 287 "<head><title>ROS Image Topic List</title></head>" 288 "<body><h1>Available ROS Image Topics:</h1>");
289 connection->write(
"<ul>");
290 BOOST_FOREACH(std::string & camera_info_topic, camera_info_topics)
292 if (boost::algorithm::ends_with(camera_info_topic,
"/camera_info"))
294 std::string base_topic = camera_info_topic.substr(0, camera_info_topic.size() - strlen(
"camera_info"));
295 connection->write(
"<li>");
296 connection->write(base_topic);
297 connection->write(
"<ul>");
298 std::vector<std::string>::iterator image_topic_itr = image_topics.begin();
299 for (; image_topic_itr != image_topics.end();)
301 if (boost::starts_with(*image_topic_itr, base_topic))
303 connection->write(
"<li><a href=\"/stream_viewer?topic=");
304 connection->write(*image_topic_itr);
305 connection->write(
"\">");
306 connection->write(image_topic_itr->substr(base_topic.size()));
307 connection->write(
"</a> (");
308 connection->write(
"<a href=\"/snapshot?topic=");
309 connection->write(*image_topic_itr);
310 connection->write(
"\">Snapshot</a>)");
311 connection->write(
"</li>");
313 image_topic_itr = image_topics.erase(image_topic_itr);
320 connection->write(
"</ul>");
322 connection->write(
"</li>");
324 connection->write(
"</ul>");
326 connection->write(
"<ul>");
327 std::vector<std::string>::iterator image_topic_itr = image_topics.begin();
328 for (; image_topic_itr != image_topics.end();) {
329 connection->write(
"<li><a href=\"/stream_viewer?topic=");
330 connection->write(*image_topic_itr);
331 connection->write(
"\">");
332 connection->write(*image_topic_itr);
333 connection->write(
"</a> (");
334 connection->write(
"<a href=\"/snapshot?topic=");
335 connection->write(*image_topic_itr);
336 connection->write(
"\">Snapshot</a>)");
337 connection->write(
"</li>");
339 image_topic_itr = image_topics.erase(image_topic_itr);
341 connection->write(
"</ul></body></html>");
347 int main(
int argc,
char **argv)
349 ros::init(argc, argv,
"web_video_server");
bool handle_stream_viewer(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, const char *begin, const char *end)
ros::Timer cleanup_timer_
static bool ros_connection_logger(async_web_server_cpp::HttpServerRequestHandler forward, const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, const char *begin, const char *end)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::map< std::string, boost::shared_ptr< ImageStreamerType > > stream_types_
ROSCPP_DECL bool getTopics(V_TopicInfo &topics)
bool handle_list_streams(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, const char *begin, const char *end)
boost::mutex subscriber_mutex_
virtual ~WebVideoServer()
Destructor - Cleans up.
std::vector< TopicInfo > V_TopicInfo
std::vector< boost::shared_ptr< ImageStreamer > > image_subscribers_
async_web_server_cpp::HttpRequestHandlerGroup handler_group_
bool handle_snapshot(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, const char *begin, const char *end)
SteadyTimer createSteadyTimer(WallDuration period, void(T::*callback)(const SteadyTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
static std::string __default_stream_type
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
bool handle_stream(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, const char *begin, const char *end)
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
int main(int argc, char **argv)
#define ROS_WARN_STREAM(args)
boost::shared_ptr< async_web_server_cpp::HttpServer > server_
void spin()
Starts the server and spins.
#define ROS_INFO_STREAM(args)
void restreamFrames(double max_age)
void cleanup_inactive_streams()
ROSCPP_DECL void waitForShutdown()
WebVideoServer(ros::NodeHandle &nh, ros::NodeHandle &private_nh)
Constructor.