00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <dynamic_reconfigure/server.h>
00032 #include <nodelet/nodelet.h>
00033 #include <ros/ros.h>
00034 #include <screen_grab/ScreenGrabConfig.h>
00035 #include <sensor_msgs/Image.h>
00036 #include <sensor_msgs/image_encodings.h>
00037 #include <sensor_msgs/RegionOfInterest.h>
00038
00039
00040 #include <X11/Xlib.h>
00041 #include <X11/Xutil.h>
00042
00043 void XImage2RosImage(XImage& ximage, Display& _xDisplay, Screen& _xScreen,
00044 sensor_msgs::ImagePtr& im)
00045 {
00046 XColor color;
00047
00048 im->header.stamp = ros::Time::now();
00049
00050 if (_xScreen.depths->depth == 24)
00051 {
00052
00053
00054 const int wd = ximage.width;
00055 const int ht = ximage.height;
00056 const int frame_size = wd * ht * 4;
00057 im->width = wd;
00058 im->height = ht;
00059 im->step = im->width * 4;
00060
00061 im->encoding = sensor_msgs::image_encodings::BGRA8;
00062 im->data.resize(frame_size);
00063 memcpy(&im->data[0], ximage.data, frame_size);
00064 }
00065 else
00066 {
00067 Colormap colmap = DefaultColormap(&_xDisplay, DefaultScreen(&_xDisplay));
00068 for (unsigned int x = 0; x < ximage.width; x++)
00069 {
00070 for (unsigned int y = 0; y < ximage.height; y++)
00071 {
00072 color.pixel = XGetPixel(&ximage, x, y);
00073 XQueryColor(&_xDisplay, colmap, &color);
00074
00075
00076 }
00077 }
00078 }
00079 return;
00080 }
00081
00082 namespace screen_grab
00083 {
00084
00085 class ScreenGrab : public nodelet::Nodelet
00086 {
00087
00088
00089 ros::Publisher screen_pub_;
00090
00091 ros::Subscriber roi_sub_;
00092 void roiCallback(const sensor_msgs::RegionOfInterest::ConstPtr& msg);
00093
00094 double update_rate_;
00095
00096 typedef dynamic_reconfigure::Server<screen_grab::ScreenGrabConfig> ReconfigureServer;
00097 boost::shared_ptr< ReconfigureServer > server_;
00098 void callback(screen_grab::ScreenGrabConfig &config,
00099 uint32_t level);
00100
00101 void checkRoi(int& x_offset, int& y_offset, int& width, int& height);
00102 void updateConfig();
00103
00104 int x_offset_;
00105 int y_offset_;
00106 int width_;
00107 int height_;
00108
00109 int screen_w_;
00110 int screen_h_;
00111
00112 boost::recursive_mutex dr_mutex_;
00113
00114 void spinOnce(const ros::TimerEvent& e);
00115 bool first_error_;
00116
00117 ros::Timer timer_;
00118
00119
00120 Display* display;
00121 Screen* screen;
00122 XImage* xImageSample;
00123 XColor col;
00124
00125 public:
00126 virtual void onInit();
00127
00128 ScreenGrab();
00129
00130 bool spin();
00131 };
00132 }
00133
00134 #include <pluginlib/class_list_macros.h>
00135
00136 PLUGINLIB_EXPORT_CLASS(screen_grab::ScreenGrab, nodelet::Nodelet)
00137
00138 namespace screen_grab
00139 {
00140
00141 ScreenGrab::ScreenGrab() :
00142 x_offset_(0),
00143 y_offset_(0),
00144 width_(640),
00145 height_(480),
00146 first_error_(false)
00147
00148 {
00149 }
00150
00151 void ScreenGrab::roiCallback(const sensor_msgs::RegionOfInterest::ConstPtr& msg)
00152 {
00153 x_offset_ = msg->x_offset;
00154 y_offset_ = msg->y_offset;
00155 width_ = msg->width;
00156 height_ = msg->height;
00157
00158 updateConfig();
00159 }
00160
00161 void ScreenGrab::checkRoi(int& x_offset, int& y_offset, int& width, int& height)
00162 {
00163
00164
00165
00166 if ((x_offset + width) > screen_w_)
00167 {
00168
00169 if (screen_w_ > width)
00170 {
00171 x_offset = screen_w_ - width;
00172 }
00173 else
00174 {
00175 x_offset = 0;
00176 width = screen_w_;
00177 }
00178 }
00179
00180 if ((y_offset + height) > screen_h_)
00181 {
00182
00183 if (screen_h_ > height)
00184 {
00185 y_offset = screen_h_ - height;
00186 }
00187 else
00188 {
00189 y_offset = 0;
00190 height = screen_h_;
00191 }
00192 }
00193
00194
00195 }
00196
00197 void ScreenGrab::callback(
00198 screen_grab::ScreenGrabConfig &config,
00199 uint32_t level)
00200 {
00201 if (level & 1)
00202 {
00203 checkRoi(config.x_offset, config.y_offset, config.width, config.height);
00204 x_offset_ = config.x_offset;
00205 y_offset_ = config.y_offset;
00206 width_ = config.width;
00207 height_ = config.height;
00208 }
00209
00210 if (level & 2)
00211 {
00212 if (config.update_rate != update_rate_)
00213 {
00214 update_rate_ = config.update_rate;
00215
00216 }
00217 }
00218 }
00219
00220 void ScreenGrab::updateConfig()
00221 {
00222 checkRoi(x_offset_, y_offset_, width_, height_);
00223
00224
00225 screen_grab::ScreenGrabConfig config;
00226 config.update_rate = update_rate_;
00227 config.x_offset = x_offset_;
00228 config.y_offset = y_offset_;
00229 config.width = width_;
00230 config.height = height_;
00231
00232 server_->updateConfig(config);
00233 }
00234
00235 void ScreenGrab::onInit()
00236 {
00237 screen_pub_ = getNodeHandle().advertise<sensor_msgs::Image>(
00238 "image", 5);
00239
00240
00241
00242 {
00243 display = XOpenDisplay(NULL);
00244 if (display == NULL)
00245 {
00246 ROS_ERROR_STREAM("bad display");
00247 return;
00248 }
00249
00250 screen = DefaultScreenOfDisplay(display);
00251 if (screen == NULL)
00252 {
00253 ROS_ERROR_STREAM("bad screen");
00254 return;
00255 }
00256
00257 Window wid = DefaultRootWindow(display);
00258 if (0 > wid)
00259 {
00260 ROS_ERROR_STREAM("Failed to obtain the root windows Id "
00261 "of the default screen of given display.\n");
00262 return;
00263 }
00264
00265 XWindowAttributes xwAttr;
00266 Status ret = XGetWindowAttributes(display, wid, &xwAttr);
00267 screen_w_ = xwAttr.width;
00268 screen_h_ = xwAttr.height;
00269 }
00270
00271 double update_rate = 15;
00272 int x_offset = 0;
00273 int y_offset = 0;
00274 int width = 0;
00275 int height = 0;
00276
00277 bool rv0 = getPrivateNodeHandle().getParam("update_rate", update_rate);
00278 bool rv1 = getPrivateNodeHandle().getParam("x_offset", x_offset);
00279 bool rv2 = getPrivateNodeHandle().getParam("y_offset", y_offset);
00280 bool rv3 = getPrivateNodeHandle().getParam("width", width);
00281 bool rv4 = getPrivateNodeHandle().getParam("height", height);
00282
00283 ROS_INFO_STREAM(static_cast<int>(rv0) << static_cast<int>(rv1)
00284 << static_cast<int>(rv2) << static_cast<int>(rv3) << static_cast<int>(rv4));
00285 ROS_INFO_STREAM(update_rate << " " << width << " " << height);
00286 server_.reset(new ReconfigureServer(dr_mutex_, getPrivateNodeHandle()));
00287
00288 dynamic_reconfigure::Server<screen_grab::ScreenGrabConfig>::CallbackType cbt =
00289 boost::bind(&ScreenGrab::callback, this, _1, _2);
00290 server_->setCallback(cbt);
00291
00292
00293 update_rate_ = update_rate;
00294 x_offset_ = x_offset;
00295 y_offset_ = y_offset;
00296 width_ = width;
00297 height_ = height;
00298 checkRoi(x_offset_, y_offset_, width_, height_);
00299 updateConfig();
00300
00301 roi_sub_ = getPrivateNodeHandle().subscribe("roi", 0, &ScreenGrab::roiCallback, this);
00302
00303 const float period = 1.0 / update_rate_;
00304 ROS_INFO_STREAM("period " << period);
00305 timer_ = getPrivateNodeHandle().createTimer(ros::Duration(period),
00306 &ScreenGrab::spinOnce, this);
00307 }
00308
00309 void ScreenGrab::spinOnce(const ros::TimerEvent& e)
00310 {
00311 sensor_msgs::ImagePtr im(new sensor_msgs::Image);
00312
00313
00314 xImageSample = XGetImage(display, DefaultRootWindow(display),
00315 x_offset_, y_offset_, width_, height_, AllPlanes, ZPixmap);
00316
00317
00318 if (xImageSample == NULL)
00319 {
00320 if (first_error_)
00321 ROS_ERROR_STREAM("Error taking screenshot! "
00322 << ", " << x_offset_ << " " << y_offset_
00323 << ", " << width_ << " " << height_
00324 << ", " << screen_w_ << " " << screen_h_);
00325 first_error_ = false;
00326 return;
00327 }
00328
00329 if (!first_error_)
00330 ROS_INFO_STREAM(width_ << " " << height_);
00331 first_error_ = true;
00332
00333 XImage2RosImage(*xImageSample, *display, *screen, im);
00334
00335 XDestroyImage(xImageSample);
00336
00337
00338
00339 screen_pub_.publish(im);
00340 }
00341 }
00342
00343 #if 0
00344 int main(int argc, char **argv)
00345 {
00346 ros::init(argc, argv, "screen_grab");
00347
00348 ScreenGrab screen_grab;
00349 screen_grab.spin();
00350 }
00351 #endif
00352