22 #include "webview-ptzcam-processor.h" 24 #include <core/exception.h> 25 #include <core/threading/mutex_locker.h> 26 #include <logging/logger.h> 27 #include <webview/page_reply.h> 28 #include <webview/error_reply.h> 29 #include <webview/redirect_reply.h> 30 #include <blackboard/blackboard.h> 31 #include <interfaces/PanTiltInterface.h> 32 #include <interfaces/CameraControlInterface.h> 33 #include <interfaces/SwitchInterface.h> 64 std::string base_url, std::string image_id,
65 std::string pantilt_id, std::string camctrl_id,
66 std::string power_id, std::string camera_id,
67 float pan_increment,
float tilt_increment,
68 unsigned int zoom_increment,
float post_powerup_time,
69 std::map<std::string, std::tuple<std::string, float, float, unsigned int>> presets,
73 blackboard_ = blackboard;
76 pan_increment_ = pan_increment;
77 tilt_increment_ = tilt_increment;
78 zoom_increment_ = zoom_increment;
79 post_powerup_time_ = (
long int)roundf(fabs(post_powerup_time) * 1000000);
92 blackboard_->close(ptu_if_);
93 blackboard_->close(camctrl_if_);
94 blackboard_->close(power_if_);
95 blackboard_->close(camen_if_);
102 if ( request->
url().find(baseurl_) == 0 ) {
103 std::string subpath = request->
url().substr(baseurl_.length());
106 if (power_if_->has_writer() && ! camen_if_->is_enabled()) {
110 logger_->log_warn(
"WebviewPtzCamReqProc",
"Failed to power up camera, exception follows");
111 logger_->log_warn(
"WebviewPtzCamReqProc", e);
116 if (power_if_->has_writer() && ! power_if_->is_enabled()) {
119 usleep(post_powerup_time_);
121 logger_->log_warn(
"WebviewPtzCamReqProc",
"Failed to power up PTU, exception follows");
122 logger_->log_warn(
"WebviewPtzCamReqProc", e);
126 if (subpath ==
"/ping") {
131 }
else if (subpath ==
"/move" || subpath ==
"/move/") {
137 float pan_val = ptu_if_->pan(), tilt_val = ptu_if_->tilt();
138 unsigned int zoom_val = camctrl_if_->zoom();
139 float zoom = std::max(1u, camctrl_if_->zoom());
140 std::string pan_str = request->
get_value(
"pan");
141 std::string tilt_str = request->
get_value(
"tilt");
142 std::string zoom_str = request->
get_value(
"zoom");
145 if (pan_str ==
"right") {
146 pan_val = std::max(ptu_if_->min_pan(), ptu_if_->pan() - pan_increment_ / zoom);
147 }
else if (pan_str ==
"left") {
148 pan_val = std::min(ptu_if_->max_pan(), ptu_if_->pan() + pan_increment_ / zoom);
151 pan_val = std::stof(request->
get_value(
"pan").c_str());
152 }
catch (std::exception &e) {}
155 if (tilt_str !=
"") {
156 if (tilt_str ==
"up") {
157 tilt_val = std::max(ptu_if_->min_tilt(), ptu_if_->tilt() - tilt_increment_ / zoom);
158 }
else if (tilt_str ==
"down") {
159 tilt_val = std::min(ptu_if_->max_tilt(), ptu_if_->tilt() + tilt_increment_ / zoom);
162 tilt_val = std::stof(request->
get_value(
"tilt").c_str());
163 }
catch (std::exception &e) {}
167 if (tilt_str !=
"" || pan_str !=
"") {
170 ptu_if_->msgq_enqueue(gotomsg);
173 if (zoom_str !=
"") {
174 if (zoom_str ==
"out") {
175 zoom_val = std::max((
long int)camctrl_if_->zoom_min(), (
long int)camctrl_if_->zoom() - zoom_increment_);
176 }
else if (zoom_str ==
"in") {
177 zoom_val = std::min((
long int)camctrl_if_->zoom_max(), (
long int)camctrl_if_->zoom() + zoom_increment_);
180 zoom_val = std::stol(request->
get_value(
"zoom").c_str());
181 }
catch (std::exception &e) {}
186 camctrl_if_->msgq_enqueue(setmsg);
191 r->
append_body(
"OK PAN %f TILT %f ZOOM %u\n", pan_val, tilt_val, zoom_val);
195 }
else if (subpath ==
"/effect" || subpath ==
"/effect/") {
201 std::string effect_str = request->
get_value(
"set");
202 if (effect_str ==
"none") {
204 }
else if (effect_str ==
"negative") {
206 }
else if (effect_str ==
"pastel") {
208 }
else if (effect_str ==
"bw") {
210 }
else if (effect_str ==
"solarize") {
215 r->
append_body(
"FAIL UNKNOWN EFFECT %s\n", effect_str.c_str());
219 camctrl_if_->msgq_enqueue(setmsg);
223 r->
append_body(
"OK EFFECT %s\n", effect_str.c_str());
226 }
else if (subpath ==
"" || subpath ==
"/") {
229 " <link type=\"text/css\" href=\"/static/css/jqtheme/jquery-ui.custom.css\" rel=\"stylesheet\" />\n" 230 " <link type=\"text/css\" href=\"/static/css/webview-ptzcam.css\" rel=\"stylesheet\" />\n" 231 " <script type=\"text/javascript\" src=\"/static/js/jquery.min.js\"></script>\n" 232 " <script type=\"text/javascript\" src=\"/static/js/jquery-ui.custom.min.js\"></script>\n");
234 *r +=
"<h2>SkyCam</h2>\n";
236 r->
append_body(
"<p><img id=\"image\" src=\"/images/view/%s.jpg\" /></p>\n", image_id_.c_str());
241 "var frame_number = 0;\n" 242 "var move_jqxhr = null;\n" 244 " $( \"#toggle-stream\" ).button({\n" 246 " primary: \"ui-icon-play\"\n" 250 " .click(function() {\n" 253 " var src = $('#image').attr('src');\n" 254 " var pos = src.indexOf('?');\n" 255 " if(pos != -1) src = src.substring(0, pos);\n" 256 " var srcstem = src.substring(0, src.lastIndexOf('.'));\n" 257 " if ( $( this ).text() === \"play\" ) {\n" 259 " label: \"pause\",\n" 261 " primary: \"ui-icon-pause\"\n" 264 " $('#image').attr('src', srcstem + '.mjpeg');\n" 265 " $.ajax(\"/ptzcam/ping\");\n" 268 " label: \"play\",\n" 270 " primary: \"ui-icon-play\"\n" 273 " frame_number += 1;\n" 274 " $('#image').attr('src', srcstem + '.jpg?' + frame_number);\n" 276 " $( this ).button( \"option\", options );\n" 278 " $( \"#refresh\" ).button({\n" 280 " primary: \"ui-icon-refresh\"\n" 284 " .click(function() {\n" 286 " var src = $('#image').attr('src');\n" 287 " // check for existing ? and remove if found\n" 288 " var pos = src.indexOf('?');\n" 289 " if(pos != -1) src = src.substring(0, pos);\n" 290 " frame_number += 1;\n" 291 " $('#image').attr('src', src + '?' + frame_number);\n" 292 " $.ajax(\"/ptzcam/ping\");\n" 295 " $( \"#left\" ).button({\n" 297 " primary: \"ui-icon-arrowthick-1-w\"\n" 301 " .click(function() {\n" 303 " if (move_jqxhr != null) move_jqxhr.abort();\n" 304 " move_jqxhr = $.ajax(\"/ptzcam/move?pan=left\");\n" 306 " $( \"#right\" ).button({\n" 308 " primary: \"ui-icon-arrowthick-1-e\"\n" 312 " .click(function() {\n" 314 " if (move_jqxhr != null) move_jqxhr.abort();\n" 315 " move_jqxhr = $.ajax(\"/ptzcam/move?pan=right\");\n" 317 " $( \"#up\" ).button({\n" 319 " primary: \"ui-icon-arrowthick-1-n\"\n" 323 " .click(function() {\n" 325 " if (move_jqxhr != null) move_jqxhr.abort();\n" 326 " move_jqxhr = $.ajax(\"/ptzcam/move?tilt=up\");\n" 328 " $( \"#down\" ).button({\n" 330 " primary: \"ui-icon-arrowthick-1-s\"\n" 334 " .click(function() {\n" 336 " if (move_jqxhr != null) move_jqxhr.abort();\n" 337 " move_jqxhr = $.ajax(\"/ptzcam/move?tilt=down\");\n" 339 " $( \"#center\" ).button({\n" 341 " primary: \"ui-icon-bullet\"\n" 345 " .click(function() {\n" 347 " if (move_jqxhr != null) move_jqxhr.abort();\n" 348 " move_jqxhr = $.ajax(\"/ptzcam/move?pan=0&tilt=0\");\n" 350 " $( \"#zoom-in\" ).button({\n" 352 " primary: \"ui-icon-zoomin\"\n" 356 " .click(function() {\n" 358 " if (move_jqxhr != null) move_jqxhr.abort();\n" 359 " move_jqxhr = $.ajax(\"/ptzcam/move?zoom=in\");\n" 361 " $( \"#zoom-out\" ).button({\n" 363 " primary: \"ui-icon-zoomout\"\n" 367 " .click(function() {\n" 369 " if (move_jqxhr != null) move_jqxhr.abort();\n" 370 " move_jqxhr = $.ajax(\"/ptzcam/move?zoom=out\");\n" 372 " $( \"#zoom-reset\" ).button({\n" 374 " primary: \"ui-icon-search\"\n" 378 " .click(function() {\n" 380 " if (move_jqxhr != null) move_jqxhr.abort();\n" 381 " move_jqxhr = $.ajax(\"/ptzcam/move?zoom=0\");\n" 386 "<button id=\"refresh\" title=\"Refresh\">Refresh</button>\n" 387 "<button id=\"toggle-stream\" title=\"Toggle Stream\">play</button>\n" 388 "<button id=\"left\" title=\"Pan left\">left</button>\n" 389 "<button id=\"right\" title=\"Pan right\">right</button>\n" 390 "<button id=\"up\" title=\"Tilt up\">up</button>\n" 391 "<button id=\"down\" title=\"Tilt down\">down</button>\n" 392 "<button id=\"center\" title=\"Re-center camera\">center</button>\n" 393 "<button id=\"zoom-in\" title=\"Zoom in\">zoom-out</button>\n" 394 "<button id=\"zoom-out\" title=\"Zoom out\">zoom-in</button>\n" 395 "<button id=\"zoom-reset\" title=\"Reset zoom\">zoom-reset</button>\n" 397 "<form style=\"margin-top: 1em;\">\n" 398 " <div id=\"filter\">\n" 399 " <input type=\"radio\" id=\"filter-title\" name=\"radio\" />" 400 "<label for=\"filter-title\">Filter</label>\n" 401 " <input type=\"radio\" id=\"filter-none\" name=\"radio\" checked=\"checked\"/>" 402 "<label for=\"filter-none\">None</label>\n" 403 " <input type=\"radio\" id=\"filter-negative\" name=\"radio\" />" 404 "<label for=\"filter-negative\">Negative</label>\n" 405 " <input type=\"radio\" id=\"filter-bw\" name=\"radio\" />" 406 "<label for=\"filter-bw\">Black/White</label>\n" 407 " <input type=\"radio\" id=\"filter-solarize\" name=\"radio\" />" 408 "<label for=\"filter-solarize\">Solarize</label>\n" 409 " <input type=\"radio\" id=\"filter-pastel\" name=\"radio\" />" 410 "<label for=\"filter-pastel\">Pastel</label>\n" 414 "var effect_jqxhr = null;\n" 416 " $('#filter').buttonset();\n" 417 " $('#filter-title').button('option', 'disabled', true );\n" 418 " $('#filter-none').click(function() {\n" 419 " if (effect_jqxhr != null) effect_jqxhr.abort();\n" 420 " effect_jqxhr = $.ajax(\"/ptzcam/effect?set=none\");\n" 422 " $('#filter-negative').click(function() {\n" 423 " if (effect_jqxhr != null) effect_jqxhr.abort();\n" 424 " effect_jqxhr = $.ajax(\"/ptzcam/effect?set=negative\");\n" 426 " $('#filter-bw').click(function() {\n" 427 " if (effect_jqxhr != null) effect_jqxhr.abort();\n" 428 " effect_jqxhr = $.ajax(\"/ptzcam/effect?set=bw\");\n" 430 " $('#filter-solarize').click(function() {\n" 431 " if (effect_jqxhr != null) effect_jqxhr.abort();\n" 432 " effect_jqxhr = $.ajax(\"/ptzcam/effect?set=solarize\");\n" 434 " $('#filter-pastel').click(function() {\n" 435 " if (effect_jqxhr != null) effect_jqxhr.abort();\n" 436 " effect_jqxhr = $.ajax(\"/ptzcam/effect?set=pastel\");\n" 441 if (! presets_.empty()) {
443 for (
auto p : presets_) {
445 "<button id=\"preset-%s\" title=\"Look at %s\">%s</button>\n" 448 " $( \"#preset-%s\" ).button()\n" 449 " .click(function() {\n" 451 " if (move_jqxhr != null) move_jqxhr.abort();\n" 452 " move_jqxhr = $.ajax(\"/ptzcam/move?pan=%f&tilt=%f&zoom=%u\");\n" 456 p.first.c_str(), std::get<0>(p.second).c_str(),
457 std::get<0>(p.second).c_str(), p.first.c_str(),
458 std::get<1>(p.second), std::get<2>(p.second), std::get<3>(p.second));
virtual fawkes::WebReply * process_request(const fawkes::WebRequest *request)
Process a request.
virtual ~WebviewPtzCamRequestProcessor()
Destructor.
Fawkes library namespace.
void add_header(std::string header, std::string content)
Add a HTTP header.
WebviewPtzCamRequestProcessor(std::string base_url, std::string image_id, std::string pantilt_id, std::string camctrl_id, std::string power_id, std::string camera_id, float pan_increment, float tilt_increment, unsigned int zoom_increment, float post_powerup_time, std::map< std::string, std::tuple< std::string, float, float, unsigned int >> presets, fawkes::BlackBoard *blackboard, fawkes::Logger *logger)
Constructor.
CameraControlInterface Fawkes BlackBoard Interface.
void set_effect(const Effect new_effect)
Set effect value.
SwitchInterface Fawkes BlackBoard Interface.
SetEffectMessage Fawkes BlackBoard Interface Message.
Base class for exceptions in Fawkes.
std::string get_value(std::string &key) const
Get specific GET value.
SetZoomMessage Fawkes BlackBoard Interface Message.
Web request meta data carrier.
GotoMessage Fawkes BlackBoard Interface Message.
EnableSwitchMessage Fawkes BlackBoard Interface Message.
void append_body(const char *format,...)
Append to body.
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
PanTiltInterface Fawkes BlackBoard Interface.
const std::string & url() const
Get URL.
The BlackBoard abstract class.
Negative/Positive Reversal.