diff --git a/src/Makefile.am b/src/Makefile.am index 172087a7..20233073 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,10 +46,13 @@ motionplus_SOURCES = \ video_common.hpp video_common.cpp \ video_loopback.hpp video_loopback.cpp \ webu.hpp webu.cpp \ + webu_ans.hpp webu_ans.cpp \ webu_file.hpp webu_file.cpp \ webu_html.hpp webu_html.cpp \ webu_json.hpp webu_json.cpp \ webu_post.hpp webu_post.cpp \ + webu_common.hpp webu_common.cpp \ webu_stream.hpp webu_stream.cpp \ + webu_getimg.hpp webu_getimg.cpp \ webu_mpegts.hpp webu_mpegts.cpp diff --git a/src/event.cpp b/src/event.cpp index a2e4e9b3..230e4a2e 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -27,7 +27,7 @@ #include "dbse.hpp" #include "video_loopback.hpp" #include "video_common.hpp" -#include "webu_stream.hpp" +#include "webu_getimg.hpp" #include "alg_sec.hpp" const char *eventList[] = { @@ -106,7 +106,7 @@ static void on_event_end_command(ctx_dev *cam) static void event_stream_put(ctx_dev *cam) { - webu_stream_getimg(cam); + webu_getimg_main(cam); } static void event_vlp_putpipe(ctx_dev *cam) diff --git a/src/motion_loop.cpp b/src/motion_loop.cpp index b68e5e97..518b81fd 100644 --- a/src/motion_loop.cpp +++ b/src/motion_loop.cpp @@ -37,7 +37,7 @@ #include "webu.hpp" #include "dbse.hpp" #include "draw.hpp" -#include "webu_stream.hpp" +#include "webu_getimg.hpp" /* Resize the image ring */ static void mlp_ring_resize(ctx_dev *cam) @@ -615,7 +615,7 @@ void mlp_cleanup(ctx_dev *cam) dbse_exec(cam, NULL, "event_end"); } - webu_stream_deinit(cam); + webu_getimg_deinit(cam); algsec_deinit(cam); @@ -685,7 +685,7 @@ static void mlp_init(ctx_dev *cam) mlp_init_buffers(cam); - webu_stream_init(cam); + webu_getimg_init(cam); algsec_init(cam); diff --git a/src/motionplus.cpp b/src/motionplus.cpp index becf10f7..69698e10 100644 --- a/src/motionplus.cpp +++ b/src/motionplus.cpp @@ -56,7 +56,7 @@ static void motpls_signal_process(ctx_motapp *motapp) break; case MOTPLS_SIGNAL_SIGHUP: /* Reload the parameters and restart*/ motapp->reload_all = true; - motapp->webcontrol_finish = true; + motapp->webu->wb_finish = true; for (indx=0; indxcam_cnt; indx++) { motapp->cam_list[indx]->event_stop = true; motapp->cam_list[indx]->finish_dev = true; @@ -70,7 +70,7 @@ static void motpls_signal_process(ctx_motapp *motapp) break; case MOTPLS_SIGNAL_SIGTERM: /* Quit application */ - motapp->webcontrol_finish = true; + motapp->webu->wb_finish = true; for (indx=0; indxcam_cnt; indx++) { motapp->cam_list[indx]->event_stop = true; motapp->cam_list[indx]->finish_dev = true; @@ -501,13 +501,17 @@ static void motpls_shutdown(ctx_motapp *motapp) log_deinit(motapp); - webu_deinit(motapp); + delete motapp->webu; dbse_deinit(motapp); conf_deinit(motapp); + delete motapp->conf; + motapp->conf = nullptr;; + motpls_allcams_deinit(motapp); + } static void motpls_device_ids(ctx_motapp *motapp) @@ -635,9 +639,10 @@ static void motpls_ntc(void) /** Initialize upon start up or restart */ static void motpls_startup(ctx_motapp *motapp, int daemonize) { - log_init_app(motapp); /* This is needed prior to any function possibly calling motion_log*/ + motapp->conf = new ctx_config; + conf_init(motapp); log_init(motapp); @@ -669,7 +674,7 @@ static void motpls_startup(ctx_motapp *motapp, int daemonize) draw_init_chars(); - webu_init(motapp); + motapp->webu = new cls_webu(motapp); motpls_allcams_init(motapp); @@ -810,7 +815,7 @@ static void motpls_watchdog(ctx_motapp *motapp, int camindx) } motapp->restart_all = true; motapp->finish_all = true; - motapp->webcontrol_finish = true; + motapp->webu->wb_finish = true; motapp->threads_running = 0; } @@ -832,8 +837,8 @@ static int motpls_check_threadcount(ctx_motapp *motapp) } } - if ((motapp->webcontrol_finish == false) && - (motapp->webcontrol_daemon != NULL)) { + if ((motapp->webu->wb_finish == false) && + (motapp->webu->wb_daemon != NULL)) { thrdcnt++; } @@ -868,17 +873,9 @@ static void motpls_init(ctx_motapp *motapp, int argc, char *argv[]) motapp->cam_cnt = 0; motapp->snd_cnt = 0; - motapp->conf = new ctx_config; - - motapp->dbse = NULL; - - motapp->webcontrol_running = false; - motapp->webcontrol_finish = false; - motapp->webcontrol_daemon = NULL; - motapp->webcontrol_headers = NULL; - motapp->webcontrol_actions = NULL; - motapp->webcontrol_clients.clear(); - memset(motapp->webcontrol_digest_rand, 0, sizeof(motapp->webcontrol_digest_rand)); + motapp->conf = nullptr; + motapp->dbse = nullptr; + motapp->webu = nullptr; pthread_key_create(&tls_key_threadnr, NULL); pthread_setspecific(tls_key_threadnr, (void *)(0)); diff --git a/src/motionplus.hpp b/src/motionplus.hpp index fa187e85..c11c9564 100644 --- a/src/motionplus.hpp +++ b/src/motionplus.hpp @@ -53,6 +53,10 @@ #include #include #include +#include +#include +#include + #if defined(HAVE_PTHREAD_NP_H) #include @@ -121,6 +125,15 @@ struct ctx_webui; struct ctx_netcam; class cls_libcam; +class cls_webu; +class cls_webu_ans; +class cls_webu_file; +class cls_webu_html; +class cls_webu_json; +class cls_webu_mpegts; +class cls_webu_post; +class cls_webu_common; +class cls_webu_stream; #define MYFFVER (LIBAVFORMAT_VERSION_MAJOR * 1000)+LIBAVFORMAT_VERSION_MINOR @@ -553,16 +566,8 @@ struct ctx_motapp { int cam_cnt; int snd_cnt; ctx_all_sizes *all_sizes; - - volatile int webcontrol_running; - volatile int webcontrol_finish; - struct MHD_Daemon *webcontrol_daemon; - struct MHD_Daemon *webcontrol_daemon2; - char webcontrol_digest_rand[12]; - std::list webcontrol_clients; /* C++ list of client ips */ - ctx_params *webcontrol_headers; /* parameters for header */ - ctx_params *webcontrol_actions; /* parameters for actions */ - ctx_dbse *dbse; /* user specified database */ + cls_webu *webu; + ctx_dbse *dbse; /* user specified database */ bool parms_changed; /*bool indicating if the parms have changed */ pthread_mutex_t mutex_parms; /* mutex used to lock when changing parms */ diff --git a/src/util.hpp b/src/util.hpp index d9c90094..bc9cb54f 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -92,11 +92,17 @@ while (nanosleep(&ts1, &ts1) == -1); \ } - #if MHD_VERSION >= 0x00097002 - typedef enum MHD_Result mhdrslt; /* Version independent return result from MHD */ - #else - typedef int mhdrslt; /* Version independent return result from MHD */ - #endif +#if MHD_VERSION >= 0x00097002 + typedef enum MHD_Result mhdrslt; /* Version independent return result from MHD */ +#else + typedef int mhdrslt; /* Version independent return result from MHD */ +#endif +/* Version independent uint */ +#if (MYFFVER <= 60016) + typedef uint8_t myuint; +#else + typedef const uint8_t myuint; +#endif void myfree(void *ptr_addr); diff --git a/src/webu.cpp b/src/webu.cpp index aae5657a..1fa7dc1b 100644 --- a/src/webu.cpp +++ b/src/webu.cpp @@ -16,1058 +16,68 @@ * */ -#include -#include -#include - #include "motionplus.hpp" #include "conf.hpp" #include "logger.hpp" #include "util.hpp" #include "webu.hpp" +#include "webu_ans.hpp" #include "webu_html.hpp" -#include "webu_stream.hpp" -#include "webu_mpegts.hpp" #include "webu_json.hpp" #include "webu_post.hpp" #include "webu_file.hpp" +#include "webu_common.hpp" +#include "webu_stream.hpp" +#include "webu_mpegts.hpp" #include "video_v4l2.hpp" -/* Context to pass the parms to functions to start mhd */ -struct ctx_mhdstart { - ctx_motapp *motapp; - std::string tls_cert; - std::string tls_key; - bool tls_use; - struct MHD_OptionItem *mhd_ops; - int mhd_opt_nbr; - unsigned int mhd_flags; - int ipv6; - struct sockaddr_in lpbk_ipv4; - struct sockaddr_in6 lpbk_ipv6; -}; - -/* Set defaults for the webui context */ -static void webu_context_init(ctx_motapp *motapp, ctx_webui *webui) -{ - char *tmplang; - - webui->url = ""; - webui->uri_camid = ""; - webui->uri_cmd1 = ""; - webui->uri_cmd2 = ""; - webui->uri_cmd3 = ""; - webui->clientip = ""; - webui->lang = ""; /* Two digit lang code */ - - webui->auth_opaque = (char*)mymalloc(WEBUI_LEN_PARM); - webui->auth_realm = (char*)mymalloc(WEBUI_LEN_PARM); - webui->auth_user = NULL; /* Buffer to hold the user name*/ - webui->auth_pass = NULL; /* Buffer to hold the password */ - webui->authenticated = false; /* boolean for whether we are authenticated*/ - webui->resp_size = 0; /* The size of the resp_page buffer. May get adjusted */ - webui->resp_used = 0; /* How many bytes used so far in resp_page*/ - webui->resp_image = NULL; /* Buffer for sending the images */ - webui->stream_pos = 0; /* Stream position of image being sent */ - webui->stream_fps = 1; /* Stream rate */ - webui->resp_page = ""; /* The response being constructed */ - webui->post_info = NULL; - webui->req_file = NULL; - webui->post_sz = 0; - webui->motapp = motapp; /* The motion application context */ - webui->cam = NULL; /* The context pointer for a single camera */ - webui->cnct_type = WEBUI_CNCT_UNKNOWN; - webui->resp_type = WEBUI_RESP_HTML; /* Default to html response */ - webui->cnct_method = WEBUI_METHOD_GET; - webui->camindx = -1; - webui->device_id = -1; - webui->all_img_data = NULL; - - tmplang = setlocale(LC_ALL, NULL); - if (tmplang == NULL) { - webui->lang = "en"; - } else { - webui->lang.assign(tmplang, 2); - } - - return; -} - -/* Free the variables in the webui context */ -static void webu_context_free(ctx_webui *webui) -{ - int indx; - - myfree(&webui->auth_user); - myfree(&webui->auth_pass); - myfree(&webui->auth_opaque); - myfree(&webui->auth_realm); - myfree(&webui->resp_image); - myfree(&webui->all_img_data); - - for (indx = 0; indxpost_sz; indx++) { - myfree(&webui->post_info[indx].key_nm); - myfree(&webui->post_info[indx].key_val); - } - myfree(&webui->post_info); - - delete webui; - - return; -} - -/* Edit the parameters specified in the url sent */ -static void webu_parms_edit(ctx_webui *webui) -{ - int indx, is_nbr; - - if (webui->uri_camid.length() > 0) { - is_nbr = true; - for (indx=0; indx < (int)webui->uri_camid.length(); indx++) { - if ((webui->uri_camid[indx] > '9') || (webui->uri_camid[indx] < '0')) { - is_nbr = false; - } - } - if (is_nbr) { - webui->device_id = atoi(webui->uri_camid.c_str()); - } - } - - for (indx=0; indxmotapp->cam_cnt; indx++) { - if (webui->motapp->cam_list[indx]->device_id == webui->device_id) { - webui->camindx = indx; - webui->cam = webui->motapp->cam_list[indx]; - } - } - - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "camid: >%s< camindx: >%d< cmd1: >%s< cmd2: >%s< cmd3: >%s<" - , webui->uri_camid.c_str(), webui->camindx - , webui->uri_cmd1.c_str(), webui->uri_cmd2.c_str() - , webui->uri_cmd3.c_str()); - -} - -/* Extract the camid and cmds from the url */ -static int webu_parseurl(ctx_webui *webui) -{ - char *tmpurl; - size_t pos_slash1, pos_slash2, baselen; - - /* Example: /camid/cmd1/cmd2/cmd3 */ - webui->uri_camid = ""; - webui->uri_cmd1 = ""; - webui->uri_cmd2 = ""; - webui->uri_cmd3 = ""; - - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO, _("Sent url: %s"),webui->url.c_str()); - - tmpurl = (char*)mymalloc(webui->url.length()+1); - memcpy(tmpurl, webui->url.c_str(), webui->url.length()); - - MHD_http_unescape(tmpurl); - - webui->url.assign(tmpurl); - free(tmpurl); - - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO, _("Decoded url: %s"),webui->url.c_str()); - - baselen = webui->motapp->conf->webcontrol_base_path.length(); - - if (webui->url.length() < baselen) { - return -1; - } - - if (webui->url.substr(baselen) == "/favicon.ico") { - return -1; - } - - if (webui->url.substr(0, baselen) != - webui->motapp->conf->webcontrol_base_path) { - return -1; - } - - if (webui->url == "/") { - return 0; - } - - /* Remove any trailing slash to keep parms clean */ - if (webui->url.substr(webui->url.length()-1,1) == "/") { - webui->url = webui->url.substr(0, webui->url.length()-1); - } - - if (webui->url.length() == baselen) { - return 0; - } - - pos_slash1 = webui->url.find("/", baselen+1); - if (pos_slash1 != std::string::npos) { - webui->uri_camid = webui->url.substr(baselen+1, pos_slash1-baselen- 1); - } else { - webui->uri_camid = webui->url.substr(baselen+1); - return 0; - } - - pos_slash1++; - if (pos_slash1 >= webui->url.length()) { - return 0; - } - - pos_slash2 = webui->url.find("/", pos_slash1); - if (pos_slash2 != std::string::npos) { - webui->uri_cmd1 = webui->url.substr(pos_slash1, pos_slash2 - pos_slash1); - } else { - webui->uri_cmd1 = webui->url.substr(pos_slash1); - return 0; - } - - pos_slash1 = ++pos_slash2; - if (pos_slash1 >= webui->url.length()) { - return 0; - } - - if (webui->uri_cmd1 == "movies") { - /* Whole remaining url is the movie name and possibly subdir */ - webui->uri_cmd2 = webui->url.substr(pos_slash1); - return 0; - } else { - pos_slash2 = webui->url.find("/", pos_slash1); - if (pos_slash2 != std::string::npos) { - webui->uri_cmd2 = webui->url.substr(pos_slash1, pos_slash2 - pos_slash1); - } else { - webui->uri_cmd2 = webui->url.substr(pos_slash1); - return 0; - } - - pos_slash1 = ++pos_slash2; - if (pos_slash1 >= webui->url.length()) { - return 0; - } - webui->uri_cmd3 = webui->url.substr(pos_slash1); - } - return 0; - -} - -/* Log the ip of the client connecting*/ -static void webu_clientip(ctx_webui *webui) -{ - const union MHD_ConnectionInfo *con_info; - char client[WEBUI_LEN_URLI]; - const char *ip_dst; - struct sockaddr_in6 *con_socket6; - struct sockaddr_in *con_socket4; - int is_ipv6; - - is_ipv6 = false; - if (webui->motapp->conf->webcontrol_ipv6) { - is_ipv6 = true; - } - - con_info = MHD_get_connection_info(webui->connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); - if (is_ipv6) { - con_socket6 = (struct sockaddr_in6 *)con_info->client_addr; - ip_dst = inet_ntop(AF_INET6, &con_socket6->sin6_addr, client, WEBUI_LEN_URLI); - if (ip_dst == NULL) { - webui->clientip = "Unknown"; - } else { - webui->clientip.assign(client); - if (webui->clientip.substr(0, 7) == "::ffff:") { - webui->clientip = webui->clientip.substr(7); - } - } - } else { - con_socket4 = (struct sockaddr_in *)con_info->client_addr; - ip_dst = inet_ntop(AF_INET, &con_socket4->sin_addr, client, WEBUI_LEN_URLI); - if (ip_dst == NULL) { - webui->clientip = "Unknown"; - } else { - webui->clientip.assign(client); - } - } - -} - -/* Get the hostname */ -static void webu_hostname(ctx_webui *webui) -{ - const char *hdr; - - hdr = MHD_lookup_connection_value(webui->connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST); - if (hdr == NULL) { - webui->hostfull = "//localhost:" + - std::to_string(webui->motapp->conf->webcontrol_port) + - webui->motapp->conf->webcontrol_base_path; - } else { - webui->hostfull = "//" + std::string(hdr) + - webui->motapp->conf->webcontrol_base_path; - } - - MOTPLS_LOG(DBG,TYPE_ALL, NO_ERRNO, _("Full Host: %s"), webui->hostfull.c_str()); - - return; -} - -/* Log the failed authentication check */ -static void webu_failauth_log(ctx_webui *webui, bool userid_fail) -{ - timespec tm_cnct; - ctx_webu_clients clients; - std::list::iterator it; - - MOTPLS_LOG(ALR, TYPE_STREAM, NO_ERRNO - ,_("Failed authentication from %s"), webui->clientip.c_str()); - - clock_gettime(CLOCK_MONOTONIC, &tm_cnct); - - it = webui->motapp->webcontrol_clients.begin(); - while (it != webui->motapp->webcontrol_clients.end()) { - if (it->clientip == webui->clientip) { - it->conn_nbr++; - it->conn_time.tv_sec =tm_cnct.tv_sec; - it->authenticated = false; - if (userid_fail) { - it->userid_fail_nbr++; - } - return; - } - it++; - } - - clients.clientip = webui->clientip; - clients.conn_nbr = 1; - clients.conn_time = tm_cnct; - clients.authenticated = false; - if (userid_fail) { - clients.userid_fail_nbr = 1; - } else { - clients.userid_fail_nbr = 0; - } - - webui->motapp->webcontrol_clients.push_back(clients); - - return; - -} - -static void webu_client_connect(ctx_webui *webui) -{ - timespec tm_cnct; - ctx_webu_clients clients; - std::list::iterator it; - - clock_gettime(CLOCK_MONOTONIC, &tm_cnct); - - /* First we need to clean out any old IPs from the list*/ - it = webui->motapp->webcontrol_clients.begin(); - while (it != webui->motapp->webcontrol_clients.end()) { - if ((tm_cnct.tv_sec - it->conn_time.tv_sec) >= - (webui->motapp->conf->webcontrol_lock_minutes*60)) { - it = webui->motapp->webcontrol_clients.erase(it); - } - it++; - } - - /* When this function is called, we know that we are authenticated - * so we reset the info and as needed print a message that the - * ip is connected. - */ - it = webui->motapp->webcontrol_clients.begin(); - while (it != webui->motapp->webcontrol_clients.end()) { - if (it->clientip == webui->clientip) { - if (it->authenticated == false) { - MOTPLS_LOG(INF,TYPE_ALL, NO_ERRNO, _("Connection from: %s"),webui->clientip.c_str()); - } - it->authenticated = true; - it->conn_nbr = 1; - it->userid_fail_nbr = 0; - it->conn_time.tv_sec = tm_cnct.tv_sec; - return; - } - it++; - } - - /* The ip was not already in our list. */ - clients.clientip = webui->clientip; - clients.conn_nbr = 1; - clients.userid_fail_nbr = 0; - clients.conn_time = tm_cnct; - clients.authenticated = true; - webui->motapp->webcontrol_clients.push_back(clients); - - MOTPLS_LOG(INF,TYPE_ALL, NO_ERRNO, _("Connection from: %s"),webui->clientip.c_str()); - - return; - -} - -/* Check for ips with excessive failed authentication attempts */ -static mhdrslt webu_failauth_check(ctx_webui *webui) -{ - timespec tm_cnct; - std::list::iterator it; - std::string tmp; - - if (webui->motapp->webcontrol_clients.size() == 0) { - return MHD_YES; - } - - clock_gettime(CLOCK_MONOTONIC, &tm_cnct); - it = webui->motapp->webcontrol_clients.begin(); - while (it != webui->motapp->webcontrol_clients.end()) { - if ((it->clientip == webui->clientip) && - ((tm_cnct.tv_sec - it->conn_time.tv_sec) < - (webui->motapp->conf->webcontrol_lock_minutes*60)) && - (it->authenticated == false) && - (it->conn_nbr > webui->motapp->conf->webcontrol_lock_attempts)) { - MOTPLS_LOG(EMG, TYPE_STREAM, NO_ERRNO - , "Ignoring connection from: %s" - , webui->clientip.c_str()); - it->conn_time = tm_cnct; - if (webui->motapp->conf->webcontrol_lock_script != "") { - tmp = webui->motapp->conf->webcontrol_lock_script + " " + - std::to_string(it->userid_fail_nbr) + " " + webui->clientip; - util_exec_command(webui->cam, tmp.c_str(), NULL); - } - return MHD_NO; - } else if ((tm_cnct.tv_sec - it->conn_time.tv_sec) >= - (webui->motapp->conf->webcontrol_lock_minutes*60)) { - it = webui->motapp->webcontrol_clients.erase(it); - } else { - it++; - } - } - - return MHD_YES; - -} - -/* Create a authorization denied response to user*/ -static mhdrslt webu_mhd_digest_fail(ctx_webui *webui,int signal_stale) -{ - struct MHD_Response *response; - mhdrslt retcd; - - webui->authenticated = false; - - webui->resp_page = "Access denied" - "Access denied"; - - response = MHD_create_response_from_buffer(webui->resp_page.length() - ,(void *)webui->resp_page.c_str(), MHD_RESPMEM_PERSISTENT); - - if (response == NULL) { - return MHD_NO; - } - - retcd = MHD_queue_auth_fail_response(webui->connection, webui->auth_realm - ,webui->auth_opaque, response - ,(signal_stale == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO); - - MHD_destroy_response(response); - - return retcd; -} - -/* Perform digest authentication */ -static mhdrslt webu_mhd_digest(ctx_webui *webui) -{ - /* This function gets called a couple of - * times by MHD during the authentication process. - */ - int retcd; - char *user; - - /*Get username or prompt for a user/pass */ - user = MHD_digest_auth_get_username(webui->connection); - if (user == NULL) { - return webu_mhd_digest_fail(webui, MHD_NO); - } - - /* Check for valid user name */ - if (mystrne(user, webui->auth_user)) { - webu_failauth_log(webui, true); - myfree(&user); - return webu_mhd_digest_fail(webui, MHD_NO); - } - myfree(&user); - - /* Check the password as well*/ - retcd = MHD_digest_auth_check(webui->connection, webui->auth_realm - , webui->auth_user, webui->auth_pass, 300); - - if (retcd == MHD_NO) { - webu_failauth_log(webui, false); - } - - if ( (retcd == MHD_INVALID_NONCE) || (retcd == MHD_NO) ) { - return webu_mhd_digest_fail(webui, retcd); - } - - webui->authenticated = true; - return MHD_YES; - -} - -/* Create a authorization denied response to user*/ -static mhdrslt webu_mhd_basic_fail(ctx_webui *webui) -{ - struct MHD_Response *response; - int retcd; - - webui->authenticated = false; - - webui->resp_page = "Access denied" - "Access denied"; - - response = MHD_create_response_from_buffer(webui->resp_page.length() - ,(void *)webui->resp_page.c_str(), MHD_RESPMEM_PERSISTENT); - - if (response == NULL) { - return MHD_NO; - } - - retcd = MHD_queue_basic_auth_fail_response (webui->connection, webui->auth_realm, response); - - MHD_destroy_response(response); - - if (retcd == MHD_YES) { - return MHD_YES; - } else { - return MHD_NO; - } - -} - -/* Perform Basic Authentication. */ -static mhdrslt webu_mhd_basic(ctx_webui *webui) -{ - char *user, *pass; - - pass = NULL; - user = NULL; - - user = MHD_basic_auth_get_username_password (webui->connection, &pass); - if ((user == NULL) || (pass == NULL)) { - myfree(&user); - myfree(&pass); - return webu_mhd_basic_fail(webui); - } - - if ((mystrne(user, webui->auth_user)) || (mystrne(pass, webui->auth_pass))) { - webu_failauth_log(webui, mystrne(user, webui->auth_user)); - myfree(&user); - myfree(&pass); - return webu_mhd_basic_fail(webui); - } - - myfree(&user); - myfree(&pass); - - webui->authenticated = true; - - return MHD_YES; - -} - -/* Parse apart the user:pass provided*/ -static void webu_mhd_auth_parse(ctx_webui *webui) -{ - int auth_len; - char *col_pos; - - myfree(&webui->auth_user); - myfree(&webui->auth_pass); - - auth_len = (int)webui->motapp->conf->webcontrol_authentication.length(); - col_pos =(char*) strstr(webui->motapp->conf->webcontrol_authentication.c_str() ,":"); - if (col_pos == NULL) { - webui->auth_user = (char*)mymalloc(auth_len+1); - webui->auth_pass = (char*)mymalloc(2); - snprintf(webui->auth_user, auth_len + 1, "%s" - ,webui->motapp->conf->webcontrol_authentication.c_str()); - snprintf(webui->auth_pass, 2, "%s",""); - } else { - webui->auth_user = (char*)mymalloc(auth_len - strlen(col_pos) + 1); - webui->auth_pass =(char*)mymalloc(strlen(col_pos)); - snprintf(webui->auth_user, auth_len - strlen(col_pos) + 1, "%s" - ,webui->motapp->conf->webcontrol_authentication.c_str()); - snprintf(webui->auth_pass, strlen(col_pos), "%s", col_pos + 1); - } - -} - -/* Initialize for authorization */ -static mhdrslt webu_mhd_auth(ctx_webui *webui) -{ - unsigned int rand1,rand2; - - srand((unsigned int)time(NULL)); - rand1 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); - rand2 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); - snprintf(webui->auth_opaque, WEBUI_LEN_PARM, "%08x%08x", rand1, rand2); - - snprintf(webui->auth_realm, WEBUI_LEN_PARM, "%s","Motion"); - - if (webui->motapp->conf->webcontrol_authentication == "") { - webui->authenticated = true; - if (webui->motapp->conf->webcontrol_auth_method != "none") { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("No webcontrol user:pass provided")); - } - return MHD_YES; - } - - if (webui->auth_user == NULL) { - webu_mhd_auth_parse(webui); - } - - if (webui->motapp->conf->webcontrol_auth_method == "basic") { - return webu_mhd_basic(webui); - } else if (webui->motapp->conf->webcontrol_auth_method == "digest") { - return webu_mhd_digest(webui); - } - - - webui->authenticated = true; - return MHD_YES; - -} - -/* Send the response that we created back to the user. */ -static mhdrslt webu_mhd_send(ctx_webui *webui) -{ - mhdrslt retcd; - struct MHD_Response *response; - p_lst *lst = &webui->motapp->webcontrol_headers->params_array; - p_it it; - - response = MHD_create_response_from_buffer(webui->resp_page.length() - ,(void *)webui->resp_page.c_str(), MHD_RESPMEM_PERSISTENT); - if (!response) { - MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response")); - return MHD_NO; - } - - if (webui->motapp->webcontrol_headers->params_count > 0) { - for (it = lst->begin(); it != lst->end(); it++) { - MHD_add_response_header (response - , it->param_name.c_str(),it->param_value.c_str()); - } - } - - if (webui->resp_type == WEBUI_RESP_TEXT) { - MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain;"); - } else if (webui->resp_type == WEBUI_RESP_JSON) { - MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json;"); - } else { - MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html"); - } - - retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response); - MHD_destroy_response (response); - - return retcd; -} - - -/* Process the post data command */ -static mhdrslt webu_answer_post(ctx_webui *webui) -{ - mhdrslt retcd; - - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,"processing post"); - - pthread_mutex_lock(&webui->motapp->mutex_post); - webu_post_main(webui); - pthread_mutex_unlock(&webui->motapp->mutex_post); - - if (webui->motapp->conf->webcontrol_interface == "user") { - webu_html_user(webui); - } else { - webu_html_page(webui); - } - - retcd = webu_mhd_send(webui); - if (retcd == MHD_NO) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,"send post page failed"); - } - - return retcd; - -} - -/*Append more data on to an existing entry in the post info structure */ -static void webu_iterate_post_append(ctx_webui *webui, int indx - , const char *data, size_t datasz) -{ - - webui->post_info[indx].key_val = (char*)realloc( - webui->post_info[indx].key_val - , webui->post_info[indx].key_sz + datasz + 1); - - memset(webui->post_info[indx].key_val + - webui->post_info[indx].key_sz, 0, datasz + 1); - - if (datasz > 0) { - memcpy(webui->post_info[indx].key_val + - webui->post_info[indx].key_sz, data, datasz); - } - - webui->post_info[indx].key_sz += datasz; - -} - -/*Create new entry in the post info structure */ -static void webu_iterate_post_new(ctx_webui *webui, const char *key - , const char *data, size_t datasz) -{ - int retcd; - - webui->post_sz++; - if (webui->post_sz == 1) { - webui->post_info = (ctx_key *)malloc(sizeof(ctx_key)); - } else { - webui->post_info = (ctx_key *)realloc(webui->post_info - , webui->post_sz * sizeof(ctx_key)); - } - - webui->post_info[webui->post_sz-1].key_nm = (char*)malloc(strlen(key)+1); - retcd = snprintf(webui->post_info[webui->post_sz-1].key_nm, strlen(key)+1, "%s", key); - - webui->post_info[webui->post_sz-1].key_val = (char*)malloc(datasz+1); - memset(webui->post_info[webui->post_sz-1].key_val,0,datasz+1); - if (datasz > 0) { - memcpy(webui->post_info[webui->post_sz-1].key_val, data, datasz); - } - - webui->post_info[webui->post_sz-1].key_sz = datasz; - - if (retcd < 0) { - printf("Error processing post data\n"); - } - -} - -static mhdrslt webu_iterate_post (void *ptr, enum MHD_ValueKind kind - , const char *key, const char *filename, const char *content_type - , const char *transfer_encoding, const char *data, uint64_t off, size_t datasz) -{ - (void) kind; - (void) filename; - (void) content_type; - (void) transfer_encoding; - (void) off; - - ctx_webui *webui = (ctx_webui *)ptr; - int indx; - - for (indx=0; indx < webui->post_sz; indx++) { - if (mystreq(webui->post_info[indx].key_nm, key)) { - break; - } - } - if (indx < webui->post_sz) { - webu_iterate_post_append(webui, indx, data, datasz); - } else { - webu_iterate_post_new(webui, key, data, datasz); - } - - return MHD_YES; -} - -/* Answer the get request from the user */ -static mhdrslt webu_answer_get(ctx_webui *webui) -{ - mhdrslt retcd; - - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,"processing get"); - - retcd = MHD_NO; - if ((webui->uri_cmd1 == "mjpg") || - (webui->uri_cmd1 == "mpegts") || - (webui->uri_cmd1 == "static")) { - - retcd = webu_stream_main(webui); - if (retcd == MHD_NO) { - webu_html_badreq(webui); - retcd = webu_mhd_send(webui); - } - - } else if (webui->uri_cmd1 == "movies") { - - retcd = webu_file_main(webui); - if (retcd == MHD_NO) { - webu_html_badreq(webui); - retcd = webu_mhd_send(webui); - } - - } else if (webui->uri_cmd1 == "config.json") { - - pthread_mutex_lock(&webui->motapp->mutex_post); - webu_json_config(webui); - pthread_mutex_unlock(&webui->motapp->mutex_post); - - retcd = webu_mhd_send(webui); - if (retcd == MHD_NO) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("send page failed.")); - } - - } else if (webui->uri_cmd1 == "movies.json") { - - pthread_mutex_lock(&webui->motapp->mutex_post); - webu_json_movies(webui); - pthread_mutex_unlock(&webui->motapp->mutex_post); - - retcd = webu_mhd_send(webui); - if (retcd == MHD_NO) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("send page failed.")); - } - - } else if (webui->uri_cmd1 == "status.json") { - - pthread_mutex_lock(&webui->motapp->mutex_post); - webu_json_status(webui); - pthread_mutex_unlock(&webui->motapp->mutex_post); - - retcd = webu_mhd_send(webui); - if (retcd == MHD_NO) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("send page failed.")); - } - - } else { - pthread_mutex_lock(&webui->motapp->mutex_post); - if (webui->motapp->conf->webcontrol_interface == "user") { - webu_html_user(webui); - } else { - webu_html_page(webui); - } - pthread_mutex_unlock(&webui->motapp->mutex_post); - - retcd = webu_mhd_send(webui); - if (retcd == MHD_NO) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("send page failed.")); - } - } - - return retcd; - -} - - -/* Answer the connection request for the webcontrol*/ -static mhdrslt webu_answer(void *cls, struct MHD_Connection *connection, const char *url - , const char *method, const char *version, const char *upload_data, size_t *upload_data_size - , void **ptr) -{ - (void)cls; - (void)url; - (void)version; - (void)upload_data; - (void)upload_data_size; - - mhdrslt retcd; - ctx_webui *webui =(ctx_webui *) *ptr; - - webui->cnct_type = WEBUI_CNCT_CONTROL; - webui->connection = connection; - - /* Throw bad URLS back to user*/ - if (webui->url.length() == 0) { - webu_html_badreq(webui); - retcd = webu_mhd_send(webui); - return retcd; - } - - if (webui->motapp->finish_all) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Shutting down camera")); - return MHD_NO; - } - - if (webui->cam != NULL) { - if (webui->cam->finish_dev) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Shutting down camera")); - return MHD_NO; - } - } - - if (webui->clientip.length() == 0) { - webu_clientip(webui); - } - - if (webu_failauth_check(webui) == MHD_NO) { - return MHD_NO; - } - - webu_hostname(webui); - - if (!webui->authenticated) { - retcd = webu_mhd_auth(webui); - if (!webui->authenticated) { - return retcd; - } - } - - webu_client_connect(webui); - - if (webui->mhd_first) { - webui->mhd_first = false; - if (mystreq(method,"POST")) { - webui->post_processor = MHD_create_post_processor (webui->connection - , WEBUI_POST_BFRSZ, webu_iterate_post, (void *)webui); - if (webui->post_processor == NULL) { - return MHD_NO; - } - webui->cnct_method = WEBUI_METHOD_POST; - } else { - webui->cnct_method = WEBUI_METHOD_GET; - } - - return MHD_YES; - } - - if (mystreq(method,"POST")) { - if (*upload_data_size != 0) { - retcd = MHD_post_process (webui->post_processor, upload_data, *upload_data_size); - *upload_data_size = 0; - } else { - retcd = webu_answer_post(webui); - } - } else { - retcd = webu_answer_get(webui); - } - - return retcd; - -} - /* Initialize the MHD answer */ static void *webu_mhd_init(void *cls, const char *uri, struct MHD_Connection *connection) { - ctx_motapp *motapp = (ctx_motapp *)cls; - ctx_webui *webui; - int retcd; - (void)connection; + ctx_motapp *p_motapp =(ctx_motapp *)cls; + cls_webu_ans *webua; mythreadname_set("wc", 0, NULL); - webui = new ctx_webui; + webua = new cls_webu_ans(p_motapp, uri); - webu_context_init(motapp, webui); - - webui->mhd_first = true; - - webui->url.assign(uri); - - retcd = webu_parseurl(webui); - if (retcd != 0) { - webui->uri_camid = ""; - webui->uri_cmd1 = ""; - webui->uri_cmd2 = ""; - webui->uri_cmd3 = ""; - webui->url = ""; - } - - webu_parms_edit(webui); - - return webui; + return webua; } -static void webu_mhd_deinit_counter(ctx_webui *webui) -{ - ctx_stream_data *strm; - ctx_dev *cam; - int indx, cam_max, cam_min; - - if (webui->cnct_type < WEBUI_CNCT_JPG_MIN) { - return; - } - - if (webui->device_id == 0) { - cam_min = 0; - cam_max = webui->motapp->cam_cnt; - } else if ((webui->device_id > 0) && (webui->camindx >= 0)) { - cam_min = webui->camindx; - cam_max = cam_min +1; - } else { - cam_min = 1; - cam_max = 0; - } - - for (indx=cam_min; indxmotapp->cam_list[indx]; - pthread_mutex_lock(&cam->stream.mutex); - if ((webui->cnct_type == WEBUI_CNCT_JPG_FULL) || - (webui->cnct_type == WEBUI_CNCT_TS_FULL)) { - strm = &cam->stream.norm; - } else if ( (webui->cnct_type == WEBUI_CNCT_JPG_SUB) || - (webui->cnct_type == WEBUI_CNCT_TS_SUB)) { - strm = &cam->stream.sub; - } else if ( (webui->cnct_type == WEBUI_CNCT_JPG_MOTION) || - (webui->cnct_type == WEBUI_CNCT_TS_MOTION )) { - strm = &cam->stream.motion; - } else if ( (webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) || - (webui->cnct_type == WEBUI_CNCT_TS_SOURCE)) { - strm = &cam->stream.source; - } else if ( (webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) || - (webui->cnct_type == WEBUI_CNCT_TS_SECONDARY)) { - strm = &cam->stream.secondary; - } else { - strm = &cam->stream.norm; - } - if ((webui->cnct_type > WEBUI_CNCT_JPG_MIN) && - (webui->cnct_type < WEBUI_CNCT_JPG_MAX)) { - if ((webui->device_id == 0) && (strm->all_cnct > 0)) { - strm->all_cnct--; - } else if ((webui->device_id > 0) && (strm->jpg_cnct > 0)) { - strm->jpg_cnct--; - } - } else if ((webui->cnct_type > WEBUI_CNCT_TS_MIN) && - (webui->cnct_type < WEBUI_CNCT_TS_MAX)) { - if ((webui->device_id == 0) && (strm->all_cnct > 0)) { - strm->all_cnct--; - } else if ((webui->device_id > 0) && (strm->ts_cnct > 0)) { - strm->ts_cnct--; - } - } - if ((strm->all_cnct == 0) && - (strm->jpg_cnct == 0) && - (strm->ts_cnct == 0) && - (cam->passflag)) { - myfree(&strm->img_data); - myfree(&strm->jpg_data); - } - pthread_mutex_unlock(&cam->stream.mutex); - } -} - -/* Clean up when the MHD connection closes */ +/* Clean up our variables when the MHD connection closes */ static void webu_mhd_deinit(void *cls, struct MHD_Connection *connection , void **con_cls, enum MHD_RequestTerminationCode toe) { (void)connection; (void)cls; (void)toe; - ctx_webui *webui =(ctx_webui *) *con_cls; + cls_webu_ans *webua =(cls_webu_ans *) *con_cls; - webu_mhd_deinit_counter(webui); - - if ((webui->cnct_type > WEBUI_CNCT_TS_MIN) && - (webui->cnct_type < WEBUI_CNCT_TS_MAX)) { - webu_mpegts_free_context(webui); + if (webua != nullptr) { + delete webua; + webua = nullptr; } +} - if (webui->cnct_method == WEBUI_METHOD_POST) { - MHD_destroy_post_processor (webui->post_processor); - } +/* Answer the connection request for the webcontrol*/ +static mhdrslt mhd_answer(void *cls + , struct MHD_Connection *connection + , const char *url, const char *method, const char *version + , const char *upload_data, size_t *upload_data_size + , void **ptr) +{ + (void)cls; + (void)url; + (void)version; - webu_context_free(webui); + cls_webu_ans *webua =(cls_webu_ans *) *ptr; - return; + return webua->answer_main(connection, method, upload_data, upload_data_size); } /* Validate that the MHD version installed can process basic authentication */ -static void webu_mhd_features_basic(ctx_mhdstart *mhdst) +void cls_webu::mhd_features_basic() { #if MHD_VERSION < 0x00094400 (void)mhdst; @@ -1077,9 +87,9 @@ static void webu_mhd_features_basic(ctx_mhdstart *mhdst) if (retcd == MHD_YES) { MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: available")); } else { - if (mhdst->motapp->conf->webcontrol_auth_method == "basic") { + if (c_motapp->conf->webcontrol_auth_method == "basic") { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: disabled")); - mhdst->motapp->conf->webcontrol_auth_method = "none"; + c_motapp->conf->webcontrol_auth_method = "none"; } else { MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("Basic authentication: disabled")); } @@ -1088,7 +98,7 @@ static void webu_mhd_features_basic(ctx_mhdstart *mhdst) } /* Validate that the MHD version installed can process digest authentication */ -static void webu_mhd_features_digest(ctx_mhdstart *mhdst) +void cls_webu::mhd_features_digest() { #if MHD_VERSION < 0x00094400 (void)mhdst; @@ -1098,9 +108,9 @@ static void webu_mhd_features_digest(ctx_mhdstart *mhdst) if (retcd == MHD_YES) { MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: available")); } else { - if (mhdst->motapp->conf->webcontrol_auth_method == "digest") { + if (c_motapp->conf->webcontrol_auth_method == "digest") { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: disabled")); - mhdst->motapp->conf->webcontrol_auth_method = "none"; + c_motapp->conf->webcontrol_auth_method = "none"; } else { MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO ,_("Digest authentication: disabled")); } @@ -1109,7 +119,7 @@ static void webu_mhd_features_digest(ctx_mhdstart *mhdst) } /* Validate that the MHD version installed can process IPV6 */ -static void webu_mhd_features_ipv6(ctx_mhdstart *mhdst) +void cls_webu::mhd_features_ipv6() { #if MHD_VERSION < 0x00094400 if (mhdst->ipv6) { @@ -1133,7 +143,7 @@ static void webu_mhd_features_ipv6(ctx_mhdstart *mhdst) } /* Validate that the MHD version installed can process tls */ -static void webu_mhd_features_tls(ctx_mhdstart *mhdst) +void cls_webu::mhd_features_tls() { #if MHD_VERSION < 0x00094400 if (mhdst->tls_use) { @@ -1157,26 +167,21 @@ static void webu_mhd_features_tls(ctx_mhdstart *mhdst) } /* Validate the features that MHD can support */ -static void webu_mhd_features(ctx_mhdstart *mhdst) +void cls_webu::mhd_features() { - webu_mhd_features_basic(mhdst); - - webu_mhd_features_digest(mhdst); - - webu_mhd_features_ipv6(mhdst); - - webu_mhd_features_tls(mhdst); - + mhd_features_basic(); + mhd_features_digest(); + mhd_features_ipv6(); + mhd_features_tls(); } /* Load a either the key or cert file for MHD*/ -static std::string webu_mhd_loadfile(std::string fname) +void cls_webu::mhd_loadfile(std::string fname,std::string &filestr) { /* This needs conversion to c++ stream */ FILE *infile; size_t file_size, read_size; char *file_char; - std::string filestr; filestr = ""; if (fname != "") { @@ -1200,21 +205,18 @@ static std::string webu_mhd_loadfile(std::string fname) myfclose(infile); } } - return filestr; - } /* Validate that we have the files needed for tls*/ -static void webu_mhd_checktls(ctx_mhdstart *mhdst) +void cls_webu::mhd_checktls() { - if (mhdst->tls_use) { - if ((mhdst->motapp->conf->webcontrol_cert == "") || (mhdst->tls_cert == "")) { + if ((c_motapp->conf->webcontrol_cert == "") || (mhdst->tls_cert == "")) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("SSL/TLS requested but no cert file provided. SSL/TLS disabled")); mhdst->tls_use = false; } - if ((mhdst->motapp->conf->webcontrol_key == "") || (mhdst->tls_key == "")) { + if ((c_motapp->conf->webcontrol_key == "") || (mhdst->tls_key == "")) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("SSL/TLS requested but no key file provided. SSL/TLS disabled")); mhdst->tls_use = false; @@ -1224,16 +226,16 @@ static void webu_mhd_checktls(ctx_mhdstart *mhdst) } /* Set the initialization function for MHD to call upon getting a connection */ -static void webu_mhd_opts_init(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts_init() { mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_URI_LOG_CALLBACK; mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = (intptr_t)webu_mhd_init; - mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = mhdst->motapp; + mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = c_motapp; mhdst->mhd_opt_nbr++; } /* Set the MHD option on the function to call when the connection closes */ -static void webu_mhd_opts_deinit(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts_deinit() { mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_NOTIFY_COMPLETED; mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = (intptr_t)webu_mhd_deinit; @@ -1243,13 +245,13 @@ static void webu_mhd_opts_deinit(ctx_mhdstart *mhdst) } /* Set the MHD option on acceptable connections */ -static void webu_mhd_opts_localhost(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts_localhost() { - if (mhdst->motapp->conf->webcontrol_localhost) { + if (c_motapp->conf->webcontrol_localhost) { if (mhdst->ipv6) { memset(&mhdst->lpbk_ipv6, 0, sizeof(struct sockaddr_in6)); mhdst->lpbk_ipv6.sin6_family = AF_INET6; - mhdst->lpbk_ipv6.sin6_port = htons((uint16_t)mhdst->motapp->conf->webcontrol_port); + mhdst->lpbk_ipv6.sin6_port = htons((uint16_t)c_motapp->conf->webcontrol_port); mhdst->lpbk_ipv6.sin6_addr = in6addr_loopback; mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_SOCK_ADDR; @@ -1260,7 +262,7 @@ static void webu_mhd_opts_localhost(ctx_mhdstart *mhdst) } else { memset(&mhdst->lpbk_ipv4, 0, sizeof(struct sockaddr_in)); mhdst->lpbk_ipv4.sin_family = AF_INET; - mhdst->lpbk_ipv4.sin_port = htons((uint16_t)mhdst->motapp->conf->webcontrol_port); + mhdst->lpbk_ipv4.sin_port = htons((uint16_t)c_motapp->conf->webcontrol_port); mhdst->lpbk_ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_SOCK_ADDR; @@ -1273,14 +275,13 @@ static void webu_mhd_opts_localhost(ctx_mhdstart *mhdst) } /* Set the mhd digest options */ -static void webu_mhd_opts_digest(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts_digest() { - - if (mhdst->motapp->conf->webcontrol_auth_method == "digest") { + if (c_motapp->conf->webcontrol_auth_method == "digest") { mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_DIGEST_AUTH_RANDOM; - mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = sizeof(mhdst->motapp->webcontrol_digest_rand); - mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = mhdst->motapp->webcontrol_digest_rand; + mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = sizeof(wb_digest_rand); + mhdst->mhd_ops[mhdst->mhd_opt_nbr].ptr_value = wb_digest_rand; mhdst->mhd_opt_nbr++; mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_NONCE_NC_SIZE; @@ -1297,7 +298,7 @@ static void webu_mhd_opts_digest(ctx_mhdstart *mhdst) } /* Set the MHD options needed when we want TLS connections */ -static void webu_mhd_opts_tls(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts_tls() { if (mhdst->tls_use) { @@ -1315,21 +316,16 @@ static void webu_mhd_opts_tls(ctx_mhdstart *mhdst) } /* Set all the MHD options based upon the configuration parameters*/ -static void webu_mhd_opts(ctx_mhdstart *mhdst) +void cls_webu::mhd_opts() { mhdst->mhd_opt_nbr = 0; - webu_mhd_checktls(mhdst); - - webu_mhd_opts_deinit(mhdst); - - webu_mhd_opts_init(mhdst); - - webu_mhd_opts_localhost(mhdst); - - webu_mhd_opts_digest(mhdst); - - webu_mhd_opts_tls(mhdst); + mhd_checktls(); + mhd_opts_deinit(); + mhd_opts_init(); + mhd_opts_localhost(); + mhd_opts_digest(); + mhd_opts_tls(); mhdst->mhd_ops[mhdst->mhd_opt_nbr].option = MHD_OPTION_END; mhdst->mhd_ops[mhdst->mhd_opt_nbr].value = 0; @@ -1339,7 +335,7 @@ static void webu_mhd_opts(ctx_mhdstart *mhdst) } /* Set the mhd start up flags */ -static void webu_mhd_flags(ctx_mhdstart *mhdst) +void cls_webu::mhd_flags() { mhdst->mhd_flags = MHD_USE_THREAD_PER_CONNECTION; @@ -1354,151 +350,185 @@ static void webu_mhd_flags(ctx_mhdstart *mhdst) } /* Set the values for the action commands */ -static void webu_init_actions(ctx_motapp *motapp) +void cls_webu::init_actions() { std::string parm_vl; - motapp->webcontrol_actions = new ctx_params; - motapp->webcontrol_actions->update_params = true; - util_parms_parse(motapp->webcontrol_actions - ,"webcontrol_actions", motapp->conf->webcontrol_actions); + wb_actions = new ctx_params; + wb_actions->update_params = true; + util_parms_parse(wb_actions + ,"webcontrol_actions", c_motapp->conf->webcontrol_actions); - if (motapp->conf->webcontrol_parms == 0) { + if (c_motapp->conf->webcontrol_parms == 0) { parm_vl = "off"; } else { parm_vl = "on"; } - util_parms_add_default(motapp->webcontrol_actions,"event",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"snapshot",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"pause",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"restart",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"stop",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"config_write",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"camera_add",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"camera_delete",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"config",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"ptz",parm_vl); - util_parms_add_default(motapp->webcontrol_actions,"movies","on"); - util_parms_add_default(motapp->webcontrol_actions,"action_user",parm_vl); + util_parms_add_default(wb_actions,"event",parm_vl); + util_parms_add_default(wb_actions,"snapshot",parm_vl); + util_parms_add_default(wb_actions,"pause",parm_vl); + util_parms_add_default(wb_actions,"restart",parm_vl); + util_parms_add_default(wb_actions,"stop",parm_vl); + util_parms_add_default(wb_actions,"config_write",parm_vl); + util_parms_add_default(wb_actions,"camera_add",parm_vl); + util_parms_add_default(wb_actions,"camera_delete",parm_vl); + util_parms_add_default(wb_actions,"config",parm_vl); + util_parms_add_default(wb_actions,"ptz",parm_vl); + util_parms_add_default(wb_actions,"movies","on"); + util_parms_add_default(wb_actions,"action_user",parm_vl); } -/* Start the webcontrol */ -static void webu_init_webcontrol(ctx_motapp *motapp) +void cls_webu::start_daemon_port1() { - ctx_mhdstart mhdst; - unsigned int randnbr; + mhdst = new ctx_mhdstart; - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO - , _("Starting webcontrol on port %d") - , motapp->conf->webcontrol_port); + mhd_loadfile(c_motapp->conf->webcontrol_cert, mhdst->tls_cert); + mhd_loadfile(c_motapp->conf->webcontrol_key, mhdst->tls_key); + mhdst->ipv6 = c_motapp->conf->webcontrol_ipv6; + mhdst->tls_use = c_motapp->conf->webcontrol_tls; - motapp->webcontrol_headers = new ctx_params; - motapp->webcontrol_headers->update_params = true; - util_parms_parse(motapp->webcontrol_headers - , "webcontrol_headers", motapp->conf->webcontrol_headers); + mhdst->mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem)*WEBUI_MHD_OPTS); + mhd_features(); + mhd_opts(); + mhd_flags(); - webu_init_actions(motapp); - - mhdst.tls_cert = webu_mhd_loadfile(motapp->conf->webcontrol_cert); - mhdst.tls_key = webu_mhd_loadfile(motapp->conf->webcontrol_key); - mhdst.motapp = motapp; - mhdst.ipv6 = motapp->conf->webcontrol_ipv6; - mhdst.tls_use = motapp->conf->webcontrol_tls; - - /* Set the rand number for webcontrol digest if needed */ - srand((unsigned int)time(NULL)); - randnbr = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); - snprintf(motapp->webcontrol_digest_rand - ,sizeof(motapp->webcontrol_digest_rand),"%d",randnbr); - - mhdst.mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem)*WEBUI_MHD_OPTS); - webu_mhd_features(&mhdst); - webu_mhd_opts(&mhdst); - webu_mhd_flags(&mhdst); - - motapp->webcontrol_daemon = MHD_start_daemon ( - mhdst.mhd_flags - , (uint16_t)motapp->conf->webcontrol_port + wb_daemon = MHD_start_daemon ( + mhdst->mhd_flags + , (uint16_t)c_motapp->conf->webcontrol_port , NULL, NULL - , &webu_answer, motapp->cam_list - , MHD_OPTION_ARRAY, mhdst.mhd_ops + , &mhd_answer, c_motapp + , MHD_OPTION_ARRAY, mhdst->mhd_ops , MHD_OPTION_END); - free(mhdst.mhd_ops); - if (motapp->webcontrol_daemon == NULL) { + free(mhdst->mhd_ops); + if (wb_daemon == nullptr) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Unable to start MHD")); } else { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Started webcontrol on port %d") - ,motapp->conf->webcontrol_port); + ,c_motapp->conf->webcontrol_port); + } + delete mhdst; + mhdst = nullptr; +} + +void cls_webu::start_daemon_port2() +{ + if ((c_motapp->conf->webcontrol_port2 == 0 ) || + (c_motapp->conf->webcontrol_port2 == c_motapp->conf->webcontrol_port)) { + return; } - if ((motapp->conf->webcontrol_port2 != 0 ) && - (motapp->conf->webcontrol_port2 != motapp->conf->webcontrol_port)) { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO + , _("Starting secondary webcontrol on port %d") + , c_motapp->conf->webcontrol_port2); + + mhdst = new ctx_mhdstart; + + mhd_loadfile(c_motapp->conf->webcontrol_cert, mhdst->tls_cert); + mhd_loadfile(c_motapp->conf->webcontrol_key, mhdst->tls_key); + mhdst->ipv6 = c_motapp->conf->webcontrol_ipv6; + mhdst->tls_use = false; + + if (c_motapp->conf->webcontrol_tls) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO - , _("Starting secondary webcontrol on port %d") - , motapp->conf->webcontrol_port2); - - if (motapp->conf->webcontrol_tls) { - mhdst.tls_use = false; - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO - , _("TLS will be disabled on webcontrol port %d") - , motapp->conf->webcontrol_port2); - } - - mhdst.mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem)*WEBUI_MHD_OPTS); - webu_mhd_opts(&mhdst); - webu_mhd_flags(&mhdst); - - motapp->webcontrol_daemon2 = MHD_start_daemon ( - mhdst.mhd_flags - , (uint16_t)motapp->conf->webcontrol_port2 - , NULL, NULL - , &webu_answer, motapp->cam_list - , MHD_OPTION_ARRAY, mhdst.mhd_ops - , MHD_OPTION_END); - - free(mhdst.mhd_ops); - if (motapp->webcontrol_daemon2 == NULL) { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Unable to start port2 MHD")); - } else { - MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO - ,_("Started webcontrol on port %d") - ,motapp->conf->webcontrol_port2); - } + , _("TLS will be disabled on webcontrol port %d") + , c_motapp->conf->webcontrol_port2); } - return; + mhdst->mhd_ops =(struct MHD_OptionItem*)mymalloc(sizeof(struct MHD_OptionItem)*WEBUI_MHD_OPTS); + mhd_opts(); + mhd_flags(); + + wb_daemon2 = MHD_start_daemon ( + mhdst->mhd_flags + , (uint16_t)c_motapp->conf->webcontrol_port2 + , NULL, NULL + //, &webu_answer, motapp->cam_list + , &mhd_answer, c_motapp + , MHD_OPTION_ARRAY, mhdst->mhd_ops + , MHD_OPTION_END); + + free(mhdst->mhd_ops); + if (wb_daemon2 == nullptr) { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Unable to start port2 MHD")); + } else { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO + ,_("Started webcontrol on port %d") + ,c_motapp->conf->webcontrol_port2); + } + + delete mhdst; + mhdst = nullptr; + } -/* Shut down the webcontrol */ -void webu_deinit(ctx_motapp *motapp) +cls_webu::cls_webu(ctx_motapp *motapp) { - if (motapp->webcontrol_daemon != NULL) { - motapp->webcontrol_finish = true; - MHD_stop_daemon (motapp->webcontrol_daemon); + unsigned int randnbr; + + c_motapp = motapp; + wb_daemon = nullptr; + wb_daemon2 = nullptr; + wb_finish = false; + wb_clients.clear(); + + memset(wb_digest_rand, 0, sizeof(wb_digest_rand)); + + if (c_motapp->conf->webcontrol_port == 0 ) { + return; } - if (motapp->webcontrol_daemon2 != NULL) { - motapp->webcontrol_finish = true; - MHD_stop_daemon (motapp->webcontrol_daemon2); - } + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO + , _("Starting webcontrol on port %d") + , c_motapp->conf->webcontrol_port); - delete motapp->webcontrol_actions; - delete motapp->webcontrol_headers; + wb_headers = new ctx_params; + wb_headers->update_params = true; + util_parms_parse(wb_headers + , "webcontrol_headers", c_motapp->conf->webcontrol_headers); + + init_actions(); + + srand((unsigned int)time(NULL)); + randnbr = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); + snprintf(wb_digest_rand, sizeof(wb_digest_rand),"%d",randnbr); + + start_daemon_port1(); + + start_daemon_port2(); + cnct_cnt = 0; } -/* Start the webcontrol and streams */ -void webu_init(ctx_motapp *motapp) +cls_webu::~cls_webu() { - motapp->webcontrol_daemon = NULL; - motapp->webcontrol_daemon2 = NULL; - motapp->webcontrol_finish = false; + int chkcnt; - if (motapp->conf->webcontrol_port != 0 ) { - webu_init_webcontrol(motapp); + wb_finish = true; + + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Closing webcontrol")); + + chkcnt = 0; + while ((chkcnt < 1000) && (cnct_cnt >0)) { + SLEEP(0, 5000000); + chkcnt++; } - return; + if (chkcnt>=1000){ + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Excessive wait closing webcontrol")); + } + + if (wb_daemon != nullptr) { + MHD_stop_daemon (wb_daemon); + wb_daemon = nullptr; + } + + if (wb_daemon2 != nullptr) { + MHD_stop_daemon (wb_daemon2); + wb_daemon2 = nullptr; + } + + delete wb_actions; + delete wb_headers; } diff --git a/src/webu.hpp b/src/webu.hpp index 5b81045b..93739e72 100644 --- a/src/webu.hpp +++ b/src/webu.hpp @@ -64,61 +64,52 @@ size_t key_sz; /* The size of the value */ }; - struct ctx_webui { - std::string url; /* The URL sent from the client */ - std::string uri_camid; /* Parsed camera number from the url eg /camid/cmd1/cmd2/cmd3 */ - std::string uri_cmd1; /* Parsed command1 from the url eg /camid/cmd1/cmd2/cmd3 */ - std::string uri_cmd2; /* Parsed command2 from the url eg /camid/cmd1/cmd2/cmd3 */ - std::string uri_cmd3; /* Parsed command3 from the url eg /camid/cmd1/cmd2/cmd3 */ - - std::string clientip; /* IP of the connecting client */ - std::string hostfull; /* Full http name for host with port number */ - - char *auth_opaque; /* Opaque string for digest authentication*/ - char *auth_realm; /* Realm string for digest authentication*/ - char *auth_user; /* Parsed user from config authentication string*/ - char *auth_pass; /* Parsed password from config authentication string*/ - int authenticated; /* Boolean for whether authentication has been passed */ - - std::string resp_page; /* The response that will be sent */ - unsigned char *resp_image; /* Response image to provide to user */ - int resp_type; /* indicator for the type of response to provide. */ - size_t resp_size; /* The allocated size of the response */ - size_t resp_used; /* The amount of the response page used */ - size_t aviobuf_sz; /* The size of the mpegts avio buffer */ - struct timespec start_time; /* Start time of the mpegts stream*/ - - AVFormatContext *fmtctx; - AVCodecContext *ctx_codec; - AVFrame *picture; /* contains default image pointers */ - - std::string lang; /* Two character abbreviation for locale language*/ - int camindx; /* Index number of the cam */ - int device_id; /* Device id number requested */ - enum WEBUI_CNCT cnct_type; /* Type of connection we are processing */ - - int post_sz; /* The number of entries in the post info */ - std::string post_cmd; /* The command sent with the post */ - ctx_key *post_info; /* Structure of the entries provided from the post data */ - struct MHD_PostProcessor *post_processor; /* Processor for handling Post method connections */ - - FILE *req_file; /* requested file*/ - - unsigned char *all_img_data; /* Image for all cameras */ - - enum WEBUI_METHOD cnct_method; /* Connection method. Get or Post */ - - size_t stream_pos; /* Stream position of sent image */ - int stream_fps; /* Stream rate per second */ - struct timespec time_last; /* Keep track of processing time for stream thread*/ - int mhd_first; /* Boolean for whether it is the first connection*/ - struct MHD_Connection *connection; /* The MHD connection value from the client */ - ctx_motapp *motapp; /* The motionplus context pointer */ - ctx_dev *cam; /* The ctx_dev information for the camera requested */ - + /* Context to pass the parms to functions to start mhd */ + struct ctx_mhdstart { + std::string tls_cert; + std::string tls_key; + bool tls_use; + struct MHD_OptionItem *mhd_ops; + int mhd_opt_nbr; + unsigned int mhd_flags; + int ipv6; + struct sockaddr_in lpbk_ipv4; + struct sockaddr_in6 lpbk_ipv6; }; - void webu_init(ctx_motapp *motapp); - void webu_deinit(ctx_motapp *motapp); + class cls_webu { + public: + cls_webu(ctx_motapp *p_motapp); + ~cls_webu(); + bool wb_finish; + ctx_params *wb_headers; + ctx_params *wb_actions; + char wb_digest_rand[12]; + struct MHD_Daemon *wb_daemon; + struct MHD_Daemon *wb_daemon2; + std::list wb_clients; + int cnct_cnt; -#endif /* _INCLUDE_WEBU_HPP_ */ + private: + ctx_mhdstart *mhdst; + ctx_motapp *c_motapp; + void init_actions(); + void start_daemon_port1(); + void start_daemon_port2(); + void mhd_features_basic(); + void mhd_features_digest(); + void mhd_features_ipv6(); + void mhd_features_tls(); + void mhd_features(); + void mhd_loadfile(std::string fname, std::string &filestr); + void mhd_checktls(); + void mhd_opts_init(); + void mhd_opts_deinit(); + void mhd_opts_localhost(); + void mhd_opts_digest(); + void mhd_opts_tls(); + void mhd_opts(); + void mhd_flags(); + }; + +#endif diff --git a/src/webu_ans.cpp b/src/webu_ans.cpp new file mode 100644 index 00000000..912057b6 --- /dev/null +++ b/src/webu_ans.cpp @@ -0,0 +1,856 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#include "motionplus.hpp" +#include "conf.hpp" +#include "logger.hpp" +#include "util.hpp" +#include "webu.hpp" +#include "webu_ans.hpp" +#include "webu_html.hpp" +#include "webu_common.hpp" +#include "webu_stream.hpp" +#include "webu_mpegts.hpp" +#include "webu_json.hpp" +#include "webu_post.hpp" +#include "webu_file.hpp" +#include "video_v4l2.hpp" + + +/* Extract the camid and cmds from the url */ +int cls_webu_ans::parseurl() +{ + char *tmpurl; + size_t pos_slash1, pos_slash2, baselen; + + /* Example: /camid/cmd1/cmd2/cmd3 */ + uri_camid = ""; + uri_cmd1 = ""; + uri_cmd2 = ""; + uri_cmd3 = ""; + + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO, _("Sent url: %s"),url.c_str()); + + tmpurl = (char*)mymalloc(url.length()+1); + memcpy(tmpurl, url.c_str(), url.length()); + + MHD_http_unescape(tmpurl); + + url.assign(tmpurl); + free(tmpurl); + + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO, _("Decoded url: %s"),url.c_str()); + + baselen = app->conf->webcontrol_base_path.length(); + + if (url.length() < baselen) { + return -1; + } + + if (url.substr(baselen) == "/favicon.ico") { + return -1; + } + + if (url.substr(0, baselen) != + app->conf->webcontrol_base_path) { + return -1; + } + + if (url == "/") { + return 0; + } + + /* Remove any trailing slash to keep parms clean */ + if (url.substr(url.length()-1,1) == "/") { + url = url.substr(0, url.length()-1); + } + + if (url.length() == baselen) { + return 0; + } + + pos_slash1 = url.find("/", baselen+1); + if (pos_slash1 != std::string::npos) { + uri_camid = url.substr(baselen+1, pos_slash1-baselen- 1); + } else { + uri_camid = url.substr(baselen+1); + return 0; + } + + pos_slash1++; + if (pos_slash1 >= url.length()) { + return 0; + } + + pos_slash2 = url.find("/", pos_slash1); + if (pos_slash2 != std::string::npos) { + uri_cmd1 = url.substr(pos_slash1, pos_slash2 - pos_slash1); + } else { + uri_cmd1 = url.substr(pos_slash1); + return 0; + } + + pos_slash1 = ++pos_slash2; + if (pos_slash1 >= url.length()) { + return 0; + } + + if (uri_cmd1 == "movies") { + /* Whole remaining url is the movie name and possibly subdir */ + uri_cmd2 = url.substr(pos_slash1); + return 0; + } else { + pos_slash2 = url.find("/", pos_slash1); + if (pos_slash2 != std::string::npos) { + uri_cmd2 = url.substr(pos_slash1, pos_slash2 - pos_slash1); + } else { + uri_cmd2 = url.substr(pos_slash1); + return 0; + } + + pos_slash1 = ++pos_slash2; + if (pos_slash1 >= url.length()) { + return 0; + } + uri_cmd3 = url.substr(pos_slash1); + } + return 0; + +} +/* Edit the parameters specified in the url sent */ +void cls_webu_ans::parms_edit() +{ + int indx, is_nbr; + + if (parseurl() != 0) { + uri_camid = ""; + uri_cmd1 = ""; + uri_cmd2 = ""; + uri_cmd3 = ""; + url = ""; + } + + if (uri_camid.length() > 0) { + is_nbr = true; + for (indx=0; indx < (int)uri_camid.length(); indx++) { + if ((uri_camid[indx] > '9') || (uri_camid[indx] < '0')) { + is_nbr = false; + } + } + if (is_nbr) { + device_id = atoi(uri_camid.c_str()); + } + } + + for (indx=0; indxcam_cnt; indx++) { + if (app->cam_list[indx]->device_id == device_id) { + camindx = indx; + cam = app->cam_list[indx]; + } + } + + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "camid: >%s< camindx: >%d< cmd1: >%s< cmd2: >%s< cmd3: >%s<" + , uri_camid.c_str(), camindx + , uri_cmd1.c_str(), uri_cmd2.c_str() + , uri_cmd3.c_str()); + +} + +/* Log the ip of the client connecting*/ +void cls_webu_ans::clientip_get() +{ + const union MHD_ConnectionInfo *con_info; + char client[WEBUI_LEN_URLI]; + const char *ip_dst; + struct sockaddr_in6 *con_socket6; + struct sockaddr_in *con_socket4; + int is_ipv6; + + is_ipv6 = false; + if (app->conf->webcontrol_ipv6) { + is_ipv6 = true; + } + + con_info = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); + if (is_ipv6) { + con_socket6 = (struct sockaddr_in6 *)con_info->client_addr; + ip_dst = inet_ntop(AF_INET6, &con_socket6->sin6_addr, client, WEBUI_LEN_URLI); + if (ip_dst == NULL) { + clientip = "Unknown"; + } else { + clientip.assign(client); + if (clientip.substr(0, 7) == "::ffff:") { + clientip = clientip.substr(7); + } + } + } else { + con_socket4 = (struct sockaddr_in *)con_info->client_addr; + ip_dst = inet_ntop(AF_INET, &con_socket4->sin_addr, client, WEBUI_LEN_URLI); + if (ip_dst == NULL) { + clientip = "Unknown"; + } else { + clientip.assign(client); + } + } + +} + +/* Get the hostname */ +void cls_webu_ans::hostname_get() +{ + const char *hdr; + + hdr = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST); + if (hdr == NULL) { + hostfull = "//localhost:" + + std::to_string(app->conf->webcontrol_port) + + app->conf->webcontrol_base_path; + } else { + hostfull = "//" + std::string(hdr) + + app->conf->webcontrol_base_path; + } + + MOTPLS_LOG(DBG,TYPE_ALL, NO_ERRNO, _("Full Host: %s"), hostfull.c_str()); + + return; +} + +/* Log the failed authentication check */ +void cls_webu_ans::failauth_log(bool userid_fail) +{ + timespec tm_cnct; + ctx_webu_clients clients; + std::list::iterator it; + + MOTPLS_LOG(ALR, TYPE_STREAM, NO_ERRNO + ,_("Failed authentication from %s"), clientip.c_str()); + + clock_gettime(CLOCK_MONOTONIC, &tm_cnct); + + it = webu->wb_clients.begin(); + while (it != webu->wb_clients.end()) { + if (it->clientip == clientip) { + it->conn_nbr++; + it->conn_time.tv_sec =tm_cnct.tv_sec; + it->authenticated = false; + if (userid_fail) { + it->userid_fail_nbr++; + } + return; + } + it++; + } + + clients.clientip = clientip; + clients.conn_nbr = 1; + clients.conn_time = tm_cnct; + clients.authenticated = false; + if (userid_fail) { + clients.userid_fail_nbr = 1; + } else { + clients.userid_fail_nbr = 0; + } + + webu->wb_clients.push_back(clients); + + return; + +} + +void cls_webu_ans::client_connect() +{ + timespec tm_cnct; + ctx_webu_clients clients; + std::list::iterator it; + + clock_gettime(CLOCK_MONOTONIC, &tm_cnct); + + /* First we need to clean out any old IPs from the list*/ + it = webu->wb_clients.begin(); + while (it != webu->wb_clients.end()) { + if ((tm_cnct.tv_sec - it->conn_time.tv_sec) >= + (app->conf->webcontrol_lock_minutes*60)) { + it = webu->wb_clients.erase(it); + } + it++; + } + + /* When this function is called, we know that we are authenticated + * so we reset the info and as needed print a message that the + * ip is connected. + */ + it = webu->wb_clients.begin(); + while (it != webu->wb_clients.end()) { + if (it->clientip == clientip) { + if (it->authenticated == false) { + MOTPLS_LOG(INF,TYPE_ALL, NO_ERRNO, _("Connection from: %s"),clientip.c_str()); + } + it->authenticated = true; + it->conn_nbr = 1; + it->userid_fail_nbr = 0; + it->conn_time.tv_sec = tm_cnct.tv_sec; + return; + } + it++; + } + + /* The ip was not already in our list. */ + clients.clientip = clientip; + clients.conn_nbr = 1; + clients.userid_fail_nbr = 0; + clients.conn_time = tm_cnct; + clients.authenticated = true; + webu->wb_clients.push_back(clients); + + MOTPLS_LOG(INF,TYPE_ALL, NO_ERRNO, _("Connection from: %s"),clientip.c_str()); + + return; + +} + +/* Check for ips with excessive failed authentication attempts */ +mhdrslt cls_webu_ans::failauth_check() +{ + timespec tm_cnct; + std::list::iterator it; + std::string tmp; + + if (webu->wb_clients.size() == 0) { + return MHD_YES; + } + + clock_gettime(CLOCK_MONOTONIC, &tm_cnct); + it = webu->wb_clients.begin(); + while (it != webu->wb_clients.end()) { + if ((it->clientip == clientip) && + ((tm_cnct.tv_sec - it->conn_time.tv_sec) < + (app->conf->webcontrol_lock_minutes*60)) && + (it->authenticated == false) && + (it->conn_nbr > app->conf->webcontrol_lock_attempts)) { + MOTPLS_LOG(EMG, TYPE_STREAM, NO_ERRNO + , "Ignoring connection from: %s" + , clientip.c_str()); + it->conn_time = tm_cnct; + if (app->conf->webcontrol_lock_script != "") { + tmp = app->conf->webcontrol_lock_script + " " + + std::to_string(it->userid_fail_nbr) + " " + clientip; + util_exec_command(cam, tmp.c_str(), NULL); + } + return MHD_NO; + } else if ((tm_cnct.tv_sec - it->conn_time.tv_sec) >= + (app->conf->webcontrol_lock_minutes*60)) { + it = webu->wb_clients.erase(it); + } else { + it++; + } + } + + return MHD_YES; + +} + +/* Create a authorization denied response to user*/ +mhdrslt cls_webu_ans::mhd_digest_fail(int signal_stale) +{ + struct MHD_Response *response; + mhdrslt retcd; + + authenticated = false; + + resp_page = "Access denied" + "Access denied"; + + response = MHD_create_response_from_buffer(resp_page.length() + ,(void *)resp_page.c_str(), MHD_RESPMEM_PERSISTENT); + + if (response == NULL) { + return MHD_NO; + } + + retcd = MHD_queue_auth_fail_response(connection, auth_realm + ,auth_opaque, response + ,(signal_stale == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO); + + MHD_destroy_response(response); + + return retcd; +} + +/* Perform digest authentication */ +mhdrslt cls_webu_ans::mhd_digest() +{ + /* This function gets called a couple of + * times by MHD during the authentication process. + */ + int retcd; + char *user; + + /*Get username or prompt for a user/pass */ + user = MHD_digest_auth_get_username(connection); + if (user == NULL) { + return mhd_digest_fail(MHD_NO); + } + + /* Check for valid user name */ + if (mystrne(user, auth_user)) { + failauth_log(true); + myfree(&user); + return mhd_digest_fail(MHD_NO); + } + myfree(&user); + + /* Check the password as well*/ + retcd = MHD_digest_auth_check(connection, auth_realm + , auth_user, auth_pass, 300); + + if (retcd == MHD_NO) { + failauth_log(false); + } + + if ( (retcd == MHD_INVALID_NONCE) || (retcd == MHD_NO) ) { + return mhd_digest_fail(retcd); + } + + authenticated = true; + return MHD_YES; +} + +/* Create a authorization denied response to user*/ +mhdrslt cls_webu_ans::mhd_basic_fail() +{ + struct MHD_Response *response; + int retcd; + + authenticated = false; + + resp_page = "Access denied" + "Access denied"; + + response = MHD_create_response_from_buffer(resp_page.length() + ,(void *)resp_page.c_str(), MHD_RESPMEM_PERSISTENT); + + if (response == NULL) { + return MHD_NO; + } + + retcd = MHD_queue_basic_auth_fail_response (connection, auth_realm, response); + + MHD_destroy_response(response); + + if (retcd == MHD_YES) { + return MHD_YES; + } else { + return MHD_NO; + } +} + +/* Perform Basic Authentication. */ +mhdrslt cls_webu_ans::mhd_basic() +{ + char *user, *pass; + + pass = NULL; + user = NULL; + + user = MHD_basic_auth_get_username_password (connection, &pass); + if ((user == NULL) || (pass == NULL)) { + myfree(&user); + myfree(&pass); + return mhd_basic_fail(); + } + + if ((mystrne(user, auth_user)) || (mystrne(pass, auth_pass))) { + failauth_log(mystrne(user, auth_user)); + myfree(&user); + myfree(&pass); + return mhd_basic_fail(); + } + + myfree(&user); + myfree(&pass); + + authenticated = true; + + return MHD_YES; + +} + +/* Parse apart the user:pass provided*/ +void cls_webu_ans::mhd_auth_parse() +{ + int auth_len; + char *col_pos; + + myfree(&auth_user); + myfree(&auth_pass); + + auth_len = (int)app->conf->webcontrol_authentication.length(); + col_pos =(char*) strstr(app->conf->webcontrol_authentication.c_str() ,":"); + if (col_pos == NULL) { + auth_user = (char*)mymalloc(auth_len+1); + auth_pass = (char*)mymalloc(2); + snprintf(auth_user, auth_len + 1, "%s" + ,app->conf->webcontrol_authentication.c_str()); + snprintf(auth_pass, 2, "%s",""); + } else { + auth_user = (char*)mymalloc(auth_len - strlen(col_pos) + 1); + auth_pass =(char*)mymalloc(strlen(col_pos)); + snprintf(auth_user, auth_len - strlen(col_pos) + 1, "%s" + ,app->conf->webcontrol_authentication.c_str()); + snprintf(auth_pass, strlen(col_pos), "%s", col_pos + 1); + } +} + +/* Initialize for authorization */ +mhdrslt cls_webu_ans::mhd_auth() +{ + unsigned int rand1,rand2; + + srand((unsigned int)time(NULL)); + rand1 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); + rand2 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0)); + snprintf(auth_opaque, WEBUI_LEN_PARM, "%08x%08x", rand1, rand2); + + snprintf(auth_realm, WEBUI_LEN_PARM, "%s","Motion"); + + if (app->conf->webcontrol_authentication == "") { + authenticated = true; + if (app->conf->webcontrol_auth_method != "none") { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("No webcontrol user:pass provided")); + } + return MHD_YES; + } + + if (auth_user == NULL) { + mhd_auth_parse(); + } + + if (app->conf->webcontrol_auth_method == "basic") { + return mhd_basic(); + } else if (app->conf->webcontrol_auth_method == "digest") { + return mhd_digest(); + } + + + authenticated = true; + return MHD_YES; + +} + +/* Send the response that we created back to the user. */ +void cls_webu_ans::mhd_send() +{ + mhdrslt retcd; + struct MHD_Response *response; + p_lst *lst = &webu->wb_headers->params_array; + p_it it; + + response = MHD_create_response_from_buffer(resp_page.length() + ,(void *)resp_page.c_str(), MHD_RESPMEM_PERSISTENT); + if (!response) { + MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response")); + return; + } + + if (webu->wb_headers->params_count > 0) { + for (it = lst->begin(); it != lst->end(); it++) { + MHD_add_response_header (response + , it->param_name.c_str(),it->param_value.c_str()); + } + } + + if (resp_type == WEBUI_RESP_TEXT) { + MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain;"); + } else if (resp_type == WEBUI_RESP_JSON) { + MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json;"); + } else { + MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html"); + } + + retcd = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + + if (retcd == MHD_NO) { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("send page failed.")); + } +} + +void cls_webu_ans::bad_request() +{ + resp_page = + "\n" + "\n" + "\n" + "

Bad Request

\n" + "

The server did not understand your request.

\n" + "\n" + "\n"; + mhd_send(); +} + +/* Answer the get request from the user */ +void cls_webu_ans::answer_get() +{ + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,"processing get"); + + if ((uri_cmd1 == "mjpg") || (uri_cmd1 == "mpegts") || + (uri_cmd1 == "static")) { + if (webu_stream == nullptr) { + webu_stream = new cls_webu_stream(this); + } + webu_stream->main(); + + } else if (uri_cmd1 == "movies") { + if (webu_file == nullptr) { + webu_file = new cls_webu_file(this); + } + webu_file->main(); + + } else if ((uri_cmd1 == "config.json") || + (uri_cmd1 == "movies.json") || (uri_cmd1 == "status.json")) { + if (webu_json == nullptr) { + webu_json = new cls_webu_json(this); + } + webu_json->main(); + + } else { + if (webu_html == nullptr) { + webu_html = new cls_webu_html(this); + } + webu_html->main(); + } +} + +/* Answer the connection request for the webcontrol*/ +mhdrslt cls_webu_ans::answer_main(struct MHD_Connection *p_connection + , const char *method, const char *upload_data, size_t *upload_data_size) +{ + mhdrslt retcd; + + cnct_type = WEBUI_CNCT_CONTROL; + connection = p_connection; + + if (url.length() == 0) { + bad_request(); + return MHD_YES; + } + + if (app->finish_all) { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Shutting down camera")); + return MHD_NO; + } + + if (cam != NULL) { + if (cam->finish_dev) { + MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Shutting down camera")); + return MHD_NO; + } + } + + if (clientip.length() == 0) { + clientip_get(); + } + + if (failauth_check() == MHD_NO) { + return MHD_NO; + } + + if (authenticated == false) { + retcd = mhd_auth(); + if (authenticated == false) { + return retcd; + } + } + + client_connect(); + + if (mhd_first) { + mhd_first = false; + if (mystreq(method,"POST")) { + if (webu_post == nullptr) { + webu_post = new cls_webu_post(this); + } + cnct_method = WEBUI_METHOD_POST; + retcd = webu_post->processor_init(); + } else { + cnct_method = WEBUI_METHOD_GET; + retcd = MHD_YES; + } + + return retcd; + } + + hostname_get(); + + if (mystreq(method,"POST")) { + retcd = webu_post->processor_start(upload_data, upload_data_size); + } else { + answer_get(); + retcd = MHD_YES; + } + return retcd; + +} + +cls_webu_ans::cls_webu_ans(ctx_motapp *p_motapp, const char *uri) +{ + app = p_motapp; + webu = p_motapp->webu; + + char *tmplang; + + url = ""; + uri_camid = ""; + uri_cmd1 = ""; + uri_cmd2 = ""; + uri_cmd3 = ""; + clientip = ""; + lang = ""; /* Two digit lang code */ + + auth_opaque = (char*)mymalloc(WEBUI_LEN_PARM); + auth_realm = (char*)mymalloc(WEBUI_LEN_PARM); + auth_user = nullptr; /* Buffer to hold the user name*/ + auth_pass = nullptr; /* Buffer to hold the password */ + authenticated = false; /* boolean for whether we are authenticated*/ + + resp_page = ""; /* The response being constructed */ + req_file = nullptr; + + cnct_type = WEBUI_CNCT_UNKNOWN; + resp_type = WEBUI_RESP_HTML; /* Default to html response */ + cnct_method = WEBUI_METHOD_GET; + camindx = -1; + device_id = -1; + + tmplang = setlocale(LC_ALL, NULL); + if (tmplang == nullptr) { + lang = "en"; + } else { + lang.assign(tmplang, 2); + } + mhd_first = true; + + cam = nullptr; + webu_file = nullptr; + webu_html = nullptr; + webu_json = nullptr; + webu_post = nullptr; + webu_stream = nullptr; + + url.assign(uri); + + parms_edit(); + webu->cnct_cnt++; +} + +void cls_webu_ans::deinit_counter() +{ + ctx_stream_data *strm; + ctx_dev *p_cam; + int indx, cam_max, cam_min; + + if (cnct_type < WEBUI_CNCT_JPG_MIN) { + return; + } + + if (device_id == 0) { + cam_min = 0; + cam_max = app->cam_cnt; + } else if ((device_id > 0) && (camindx >= 0)) { + cam_min = camindx; + cam_max = cam_min +1; + } else { + cam_min = 1; + cam_max = 0; + } + + for (indx=cam_min; indxcam_list[indx]; + pthread_mutex_lock(&p_cam->stream.mutex); + if ((cnct_type == WEBUI_CNCT_JPG_FULL) || + (cnct_type == WEBUI_CNCT_TS_FULL)) { + strm = &p_cam->stream.norm; + } else if ( (cnct_type == WEBUI_CNCT_JPG_SUB) || + (cnct_type == WEBUI_CNCT_TS_SUB)) { + strm = &p_cam->stream.sub; + } else if ( (cnct_type == WEBUI_CNCT_JPG_MOTION) || + (cnct_type == WEBUI_CNCT_TS_MOTION )) { + strm = &p_cam->stream.motion; + } else if ( (cnct_type == WEBUI_CNCT_JPG_SOURCE) || + (cnct_type == WEBUI_CNCT_TS_SOURCE)) { + strm = &p_cam->stream.source; + } else if ( (cnct_type == WEBUI_CNCT_JPG_SECONDARY) || + (cnct_type == WEBUI_CNCT_TS_SECONDARY)) { + strm = &p_cam->stream.secondary; + } else { + strm = &p_cam->stream.norm; + } + + if ((cnct_type > WEBUI_CNCT_JPG_MIN) && + (cnct_type < WEBUI_CNCT_JPG_MAX)) { + if ((device_id == 0) && (strm->all_cnct > 0)) { + strm->all_cnct--; + } else if ((device_id > 0) && (strm->jpg_cnct > 0)) { + strm->jpg_cnct--; + } + } else if ((cnct_type > WEBUI_CNCT_TS_MIN) && + (cnct_type < WEBUI_CNCT_TS_MAX)) { + if ((device_id == 0) && (strm->all_cnct > 0)) { + strm->all_cnct--; + } else if ((device_id > 0) && (strm->ts_cnct > 0)) { + strm->ts_cnct--; + } + } + if ((strm->all_cnct == 0) && + (strm->jpg_cnct == 0) && + (strm->ts_cnct == 0) && + (p_cam->passflag)) { + myfree(&strm->img_data); + myfree(&strm->jpg_data); + } + pthread_mutex_unlock(&p_cam->stream.mutex); + } +} + +cls_webu_ans::~cls_webu_ans() +{ + deinit_counter(); + + if (webu_file != nullptr) { + delete webu_file; + } + if (webu_html != nullptr) { + delete webu_html; + } + if (webu_json != nullptr) { + delete webu_json; + } + if (webu_post != nullptr) { + delete webu_post; + } + if (webu_stream != nullptr) { + delete webu_stream; + } + + myfree(&auth_user); + myfree(&auth_pass); + myfree(&auth_opaque); + myfree(&auth_realm); + webu->cnct_cnt--; +} \ No newline at end of file diff --git a/src/webu_ans.hpp b/src/webu_ans.hpp new file mode 100644 index 00000000..fb4f8260 --- /dev/null +++ b/src/webu_ans.hpp @@ -0,0 +1,87 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#ifndef _INCLUDE_WEBU_ANS_HPP_ +#define _INCLUDE_WEBU_ANS_HPP_ + class cls_webu_ans { + public: + cls_webu_ans(ctx_motapp *p_motapp, const char *uri); + ~cls_webu_ans(); + + mhdrslt answer_main(struct MHD_Connection *connection, const char *method + , const char *upload_data, size_t *upload_data_size); + + void mhd_send(); + void bad_request(); + + ctx_motapp *app; + cls_webu *webu; + ctx_dev *cam; + + struct MHD_Connection *connection; + + FILE *req_file; /* requested file*/ + std::string lang; /* Two character abbreviation for locale language*/ + + std::string url; /* The URL sent from the client */ + std::string uri_camid; /* Parsed camera number from the url eg /camid/cmd1/cmd2/cmd3 */ + std::string uri_cmd1; /* Parsed command1 from the url eg /camid/cmd1/cmd2/cmd3 */ + std::string uri_cmd2; /* Parsed command2 from the url eg /camid/cmd1/cmd2/cmd3 */ + std::string uri_cmd3; /* Parsed command3 from the url eg /camid/cmd1/cmd2/cmd3 */ + + enum WEBUI_RESP resp_type; /* indicator for the type of response to provide. */ + std::string resp_page; /* The response that will be sent */ + int camindx; /* Index number of the cam */ + int device_id; /* Device id number requested */ + enum WEBUI_CNCT cnct_type; /* Type of connection we are processing */ + std::string clientip; /* IP of the connecting client */ + std::string hostfull; /* Full http name for host with port number */ + + private: + cls_webu_file *webu_file; + cls_webu_html *webu_html; + cls_webu_json *webu_json; + cls_webu_post *webu_post; + cls_webu_stream *webu_stream; + + int mhd_first; /* Boolean for whether it is the first connection*/ + char *auth_opaque; /* Opaque string for digest authentication*/ + char *auth_realm; /* Realm string for digest authentication*/ + char *auth_user; /* Parsed user from config authentication string*/ + char *auth_pass; /* Parsed password from config authentication string*/ + bool authenticated; /* Boolean for whether authentication has been passed */ + enum WEBUI_METHOD cnct_method; /* Connection method. Get or Post */ + + void parms_edit(); + int parseurl(); + void clientip_get(); + void hostname_get(); + void failauth_log(bool userid_fail); + void client_connect(); + mhdrslt failauth_check(); + mhdrslt mhd_digest_fail(int signal_stale); + mhdrslt mhd_digest(); + mhdrslt mhd_basic_fail(); + mhdrslt mhd_basic(); + void mhd_auth_parse(); + mhdrslt mhd_auth(); + void deinit_counter(); + void answer_get(); + }; + +#endif \ No newline at end of file diff --git a/src/webu_common.cpp b/src/webu_common.cpp new file mode 100644 index 00000000..9e17cccb --- /dev/null +++ b/src/webu_common.cpp @@ -0,0 +1,599 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#include "motionplus.hpp" +#include "conf.hpp" +#include "logger.hpp" +#include "util.hpp" +#include "webu.hpp" +#include "webu_common.hpp" +#include "webu_ans.hpp" +#include "webu_html.hpp" +#include "webu_stream.hpp" +#include "webu_mpegts.hpp" +#include "webu_json.hpp" +#include "webu_post.hpp" +#include "webu_file.hpp" +#include "video_v4l2.hpp" + + +bool cls_webu_common::check_finish() +{ + if (webu->wb_finish){ + resp_used = 0; + return true; + } + if (webua->cam != NULL) { + if ((webua->cam->finish_dev == true) || + (webua->cam->passflag == false)) { + resp_used = 0; + return true; + } + } + return false; +} + +void cls_webu_common::set_fps() +{ + if ((webua->cam->detecting_motion == false) && + (app->cam_list[webua->camindx]->conf->stream_motion)) { + stream_fps = 1; + } else { + stream_fps = app->cam_list[webua->camindx]->conf->stream_maxrate; + } +} + +/* Sleep required time to get to the user requested framerate for the stream */ +void cls_webu_common::delay() +{ + long stream_rate; + struct timespec time_curr; + long stream_delay; + + if (check_finish()) { + return; + } + + clock_gettime(CLOCK_MONOTONIC, &time_curr); + + /* The stream rate MUST be less than 1000000000 otherwise undefined behaviour + * will occur with the SLEEP function. + */ + stream_delay = ((time_curr.tv_nsec - time_last.tv_nsec)) + + ((time_curr.tv_sec - time_last.tv_sec)*1000000000); + if (stream_delay < 0) { + stream_delay = 0; + } + if (stream_delay > 1000000000 ) { + stream_delay = 1000000000; + } + + if (stream_fps >= 1) { + stream_rate = ( (1000000000 / stream_fps) - stream_delay); + if ((stream_rate > 0) && (stream_rate < 1000000000)) { + SLEEP(0,stream_rate); + } else if (stream_rate == 1000000000) { + SLEEP(1,0); + } + } + clock_gettime(CLOCK_MONOTONIC, &time_last); +} + +void cls_webu_common::img_sizes(ctx_dev *p_cam, int &img_w, int &img_h) +{ + if (((webua->cnct_type == WEBUI_CNCT_JPG_SUB) || + (webua->cnct_type == WEBUI_CNCT_TS_SUB)) && + (((p_cam->imgs.width % 16) == 0) && + ((p_cam->imgs.height % 16) == 0))) { + img_w = (p_cam->imgs.width/2); + img_h = (p_cam->imgs.height/2); + } else { + img_w = p_cam->imgs.width; + img_h = p_cam->imgs.height; + } + img_w = ((p_cam->all_loc.scale * img_w) / 100); + if ((img_w % 16) != 0) { + img_w = img_w - (img_w % 16) + 16; + } + + img_h = ((p_cam->all_loc.scale * img_h) / 100); + if ((img_h % 16) != 0) { + img_h = img_h - (img_h % 16) + 16; + } + + if (img_w < 64){ + img_w = 64; + } + if (img_h < 64){ + img_h = 64; + } +} + +void cls_webu_common::img_resize(ctx_dev *p_cam + , uint8_t *src, uint8_t *dst, int dst_w, int dst_h) +{ + int retcd, img_sz, src_h, src_w; + char errstr[128]; + uint8_t *buf; + AVFrame *frm_in, *frm_out; + struct SwsContext *swsctx; + + src_h = p_cam->imgs.height; + src_w = p_cam->imgs.width; + + img_sz = (dst_h * dst_w * 3)/2; + memset(dst, 0x00, (size_t)img_sz); + + frm_in = myframe_alloc(); + if (frm_in == NULL) { + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + , _("Unable to allocate frm_in.")); + return; + } + + frm_out = myframe_alloc(); + if (frm_out == NULL) { + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + , _("Unable to allocate frm_out.")); + myframe_free(frm_in); + return; + } + + retcd = myimage_fill_arrays(frm_in, src, MY_PIX_FMT_YUV420P, src_w, src_h); + if (retcd < 0) { + av_strerror(retcd, errstr, sizeof(errstr)); + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + , "Error filling arrays: %s", errstr); + myframe_free(frm_in); + myframe_free(frm_out); + return; + } + + buf = (uint8_t *)mymalloc((size_t)img_sz); + + retcd = myimage_fill_arrays(frm_out, buf, MY_PIX_FMT_YUV420P, dst_w, dst_h); + if (retcd < 0) { + av_strerror(retcd, errstr, sizeof(errstr)); + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + , "Error Filling array 2: %s", errstr); + free(buf); + myframe_free(frm_in); + myframe_free(frm_out); + return; + } + + swsctx = sws_getContext( + src_w, src_h, MY_PIX_FMT_YUV420P + ,dst_w, dst_h, MY_PIX_FMT_YUV420P + ,SWS_BICUBIC, NULL, NULL, NULL); + if (swsctx == NULL) { + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + , _("Unable to allocate scaling context.")); + free(buf); + myframe_free(frm_in); + myframe_free(frm_out); + return; + } + + retcd = sws_scale(swsctx + , (const uint8_t* const *)frm_in->data, frm_in->linesize + , 0, src_h, frm_out->data, frm_out->linesize); + if (retcd < 0) { + av_strerror(retcd, errstr, sizeof(errstr)); + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + ,_("Error resizing/reformatting: %s"), errstr); + free(buf); + myframe_free(frm_in); + myframe_free(frm_out); + sws_freeContext(swsctx); + return; + } + + retcd = myimage_copy_to_buffer( + frm_out, (uint8_t *)dst + ,MY_PIX_FMT_YUV420P, dst_w, dst_h, img_sz); + if (retcd < 0) { + av_strerror(retcd, errstr, sizeof(errstr)); + MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO + ,_("Error putting frame into output buffer: %s"), errstr); + free(buf); + myframe_free(frm_in); + myframe_free(frm_out); + sws_freeContext(swsctx); + return; + } + + free(buf); + myframe_free(frm_in); + myframe_free(frm_out); + sws_freeContext(swsctx); +} + +void cls_webu_common::all_getimg() +{ + int a_y, a_u, a_v; /* all img y,u,v */ + int c_y, c_u, c_v; /* camera img y,u,v */ + int dst_h, dst_w, dst_sz, src_sz, img_orow, img_ocol; + int indx, row, indx1; + unsigned char *dst_img, *src_img; + ctx_stream_data *strm; + ctx_all_sizes *all_sz; + ctx_dev *p_cam; + + memset(resp_image, '\0', resp_size); + + all_sz = app->all_sizes; + + a_y = 0; + a_u = (all_sz->width * all_sz->height); + a_v = a_u + (a_u / 4); + + memset(all_img_data , 0x80, (size_t)a_u); + memset(all_img_data + a_u, 0x80, (size_t)(a_u/2)); + + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, dst_w, dst_h); + + dst_sz = (dst_h * dst_w * 3)/2; + src_sz = (p_cam->imgs.width * p_cam->imgs.height * 3)/2; + img_orow = p_cam->all_loc.offset_row; + img_ocol = p_cam->all_loc.offset_col; + + if ((webua->cnct_type == WEBUI_CNCT_JPG_FULL) || + (webua->cnct_type == WEBUI_CNCT_TS_FULL)) { + strm = &p_cam->stream.norm; + } else if ((webua->cnct_type == WEBUI_CNCT_JPG_SUB) || + (webua->cnct_type == WEBUI_CNCT_TS_SUB)) { + /* The use of the full size image is is is not an error here. + For the all_img, we are using a different scaling/resizing method + and as a result, we need to start with the full size image then + resize to substream and stream_preview_scale*/ + strm = &p_cam->stream.norm; /* <<==Normal size is correct here*/ + } else if ((webua->cnct_type == WEBUI_CNCT_JPG_MOTION) || + (webua->cnct_type == WEBUI_CNCT_TS_MOTION)) { + strm = &p_cam->stream.motion; + } else if ((webua->cnct_type == WEBUI_CNCT_JPG_SOURCE) || + (webua->cnct_type == WEBUI_CNCT_TS_SOURCE )) { + strm = &p_cam->stream.source; + } else if ((webua->cnct_type == WEBUI_CNCT_JPG_SECONDARY) || + (webua->cnct_type == WEBUI_CNCT_TS_SECONDARY)) { + strm = &p_cam->stream.secondary; + } else { /* Should not be possible*/ + return; + } + + dst_img = (unsigned char*) mymalloc(dst_sz); + src_img = (unsigned char*) mymalloc(src_sz); + + pthread_mutex_lock(&p_cam->stream.mutex); + indx1=0; + while (indx1 < 1000) { + if (strm->img_data == NULL) { + if (strm->all_cnct == 0){ + strm->all_cnct++; + } + pthread_mutex_unlock(&p_cam->stream.mutex); + SLEEP(0, 1000); + pthread_mutex_lock(&p_cam->stream.mutex); + } else { + break; + } + indx1++; + } + if (strm->img_data == NULL) { + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Could not get image for device %d", p_cam->device_id); + memset(src_img, 0x00, src_sz); + } else { + memcpy(src_img, strm->img_data, src_sz); + } + pthread_mutex_unlock(&p_cam->stream.mutex); + + img_resize(p_cam, src_img, dst_img, dst_w, dst_h); + + /* + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "src w %d h %d dst w %d h %d all w %d h %d " + , p_cam->imgs.width, p_cam->imgs.height + , dst_w, dst_h + , all_sz->width,all_sz->height); + */ + a_y = (img_orow * all_sz->width) + img_ocol; + a_u =(all_sz->height * all_sz->width) + + ((img_orow / 4) * all_sz->width) + (img_ocol / 2) ; + a_v = a_u + ((all_sz->height * all_sz->width) / 4); + + c_y = 0; + c_u = (dst_w * dst_h); + c_v = c_u + (c_u / 4); + + /* + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "r %d c %d a %d %d %d h %d w %d" + , img_orow, img_ocol + , a_y, a_u, a_v + , all_sz->height, all_sz->width); + */ + + for (row=0; rowwidth; + c_y += dst_w; + if (row % 2) { + memcpy(all_img_data + a_u, dst_img + c_u, dst_w / 2); + //memset(webui->all_img_data + a_u, 0xFA, dst_w/2); + a_u += (all_sz->width / 2); + c_u += (dst_w / 2); + memcpy(all_img_data + a_v, dst_img + c_v, dst_w / 2); + a_v += (all_sz->width / 2); + c_v += (dst_w / 2); + } + } + + myfree(&dst_img); + myfree(&src_img); + } + +} + +void cls_webu_common::all_sizes() +{ + int indx, row, col; + int chk_sz, chk_w, mx_col, mx_row; + int mx_h, mx_w, img_h, img_w; + bool dflt_scale; + ctx_dev *p_cam; + + if (app->all_sizes->reset == false) { + return; + } + + mx_row = 0; + mx_col = 0; + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + if (mx_row < p_cam->all_loc.row) { + mx_row = p_cam->all_loc.row; + } + if (mx_col < p_cam->all_loc.col) { + mx_col = p_cam->all_loc.col; + } + } + + dflt_scale = false; + for (indx=0; indxcam_cnt; indx++) { + if (app->cam_list[indx]->all_loc.scale == -1) { + dflt_scale = true; + } + } + if (dflt_scale) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->all_loc.scale = 100; + } + for (row=1; row<=mx_row; row++) { + mx_h = 0; + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + if (row == p_cam->all_loc.row) { + img_sizes(p_cam, img_w, img_h); + if (mx_h < img_h) { + mx_h = img_h; + } + } + } + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + if (row == p_cam->all_loc.row) { + img_sizes(p_cam, img_w, img_h); + p_cam->all_loc.scale = (int)((float)(mx_h*100 / img_h )); + } + } + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Device %d Original Size %dx%d Scale %d New Size %dx%d" + , p_cam->device_id + , p_cam->imgs.width, p_cam->imgs.height + , p_cam->all_loc.scale, img_w, img_h); + } + } + } + + app->all_sizes->width = 0; + app->all_sizes->height = 0; + for (row=1; row<=mx_row; row++) { + chk_sz = 0; + mx_h = 0; + for (col=1; col<=mx_col; col++) { + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + if ((row == p_cam->all_loc.row) && + (col == p_cam->all_loc.col)) { + p_cam->all_loc.offset_col = chk_sz; + chk_sz += img_w; + if (mx_h < img_h) { + mx_h = img_h; + } + } + } + } + /* Align/center vert. the images in each row*/ + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + if (p_cam->all_loc.row == row) { + p_cam->all_loc.offset_row = + app->all_sizes->height + + ((mx_h - img_h)/2) ; + } + } + app->all_sizes->height += mx_h; + if (app->all_sizes->width < chk_sz) { + app->all_sizes->width = chk_sz; + } + } + + /* Align/center horiz. the images within each column area */ + chk_w = 0; + for (col=1; col<=mx_col; col++) { + chk_sz = 0; + mx_w = 0; + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + if (p_cam->all_loc.col == col) { + if (p_cam->all_loc.offset_col < chk_w) { + p_cam->all_loc.offset_col = chk_w; + } + if (chk_sz < p_cam->all_loc.offset_col) { + chk_sz = p_cam->all_loc.offset_col; + } + if (mx_w < img_w) { + mx_w = img_w; + } + } + } + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + if (p_cam->all_loc.col == col) { + p_cam->all_loc.offset_col = + chk_sz + ((mx_w - img_w) /2) ; + } + } + chk_w = mx_w + chk_sz; + if (app->all_sizes->width < chk_w) { + app->all_sizes->width = chk_w; + } + } + + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + img_sizes(p_cam, img_w, img_h); + + chk_sz = p_cam->all_loc.offset_col + p_cam->all_loc.offset_user_col; + if (chk_sz < 0) { + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Device %d invalid image column offset. (%d + %d) less than zero " + , p_cam->device_id + , p_cam->all_loc.offset_col + , p_cam->all_loc.offset_user_col); + } else if ((chk_sz + img_w) > app->all_sizes->width) { + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Device %d invalid image column offset. (%d + %d) over image size" + , p_cam->device_id + , p_cam->all_loc.offset_col + , p_cam->all_loc.offset_user_col); + } else { + p_cam->all_loc.offset_col = chk_sz; + } + + chk_sz = p_cam->all_loc.offset_row + p_cam->all_loc.offset_user_row; + if (chk_sz < 0 ) { + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Device %d invalid image row offset. (%d + %d) less than zero " + , p_cam->device_id + , p_cam->all_loc.offset_row + , p_cam->all_loc.offset_user_row); + } else if ((chk_sz + img_h) > app->all_sizes->height) { + MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO + , "Device %d invalid image row offset. (%d + %d) over image size" + , p_cam->device_id + , p_cam->all_loc.offset_row + , p_cam->all_loc.offset_user_row); + } else { + p_cam->all_loc.offset_row = chk_sz; + } + } + + app->all_sizes->img_sz =(( + app->all_sizes->height * + app->all_sizes->width * 3)/2); + + /* + for (indx=0; indxcam_cnt; indx++) { + MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO + , "row %d col %d offset row %d offset col %d" + , app->cam_list[indx]->all_loc.row + , app->cam_list[indx]->all_loc.col + , app->cam_list[indx]->all_loc.offset_row + , app->cam_list[indx]->all_loc.offset_col); + } + */ + +} + +/* Allocate buffers if needed. */ +void cls_webu_common::one_buffer() +{ + if (webua->cam == NULL) { + return; + } + if (resp_size < (size_t)webua->cam->imgs.size_norm) { + if (resp_image != NULL) { + myfree(&resp_image); + } + resp_image = (unsigned char*) mymalloc(webua->cam->imgs.size_norm); + memset(resp_image,'\0',webua->cam->imgs.size_norm); + resp_size = webua->cam->imgs.size_norm; + resp_used = 0; + } +} + +void cls_webu_common::all_buffer() +{ + if (resp_size < (size_t)app->all_sizes->img_sz) { + if (resp_image != nullptr) { + myfree(&resp_image); + } + resp_size = app->all_sizes->img_sz; + resp_image = (unsigned char*) mymalloc(resp_size); + memset(resp_image, '\0', resp_size); + resp_used = 0; + } + if ((all_img_data == nullptr) && + (app->all_sizes->img_sz >0)) { + all_img_data = (unsigned char*) + mymalloc((size_t)app->all_sizes->img_sz); + } +} + +cls_webu_common::cls_webu_common(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; + + all_img_data = nullptr; + resp_image = nullptr; + resp_size = 0; /* The size of the resp_page buffer. May get adjusted */ + resp_used = 0; /* How many bytes used so far in resp_page*/ + stream_fps = 1; /* Stream rate */ +} + +cls_webu_common::~cls_webu_common() +{ + app = nullptr; + webu = nullptr; + webua = nullptr; + myfree(&resp_image); + myfree(&all_img_data); +} diff --git a/src/webu_common.hpp b/src/webu_common.hpp new file mode 100644 index 00000000..b46db21a --- /dev/null +++ b/src/webu_common.hpp @@ -0,0 +1,52 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#ifndef _INCLUDE_WEBU_COMMON_HPP_ +#define _INCLUDE_WEBU_COMMON_HPP_ + class cls_webu_common { + public: + cls_webu_common(cls_webu_ans *p_webua); + ~cls_webu_common(); + bool check_finish(); + void delay(); + void set_fps(); + void all_getimg(); + void all_sizes(); + void all_buffer(); + void one_buffer(); + + struct timespec time_last; /* Keep track of processing time for stream thread*/ + + size_t resp_size; /* The allocated size of the response */ + size_t resp_used; /* The amount of the response page used */ + unsigned char *resp_image; /* Response image to provide to user */ + unsigned char *all_img_data; /* Image for all cameras */ + int stream_fps; /* Stream rate per second */ + + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; + + void img_sizes(ctx_dev *cam, int &img_w, int &img_h); + void img_resize(ctx_dev *cam + , uint8_t *src, uint8_t *dst, int dst_w, int dst_h); + + }; + +#endif \ No newline at end of file diff --git a/src/webu_file.cpp b/src/webu_file.cpp index c23267ba..56d2e916 100644 --- a/src/webu_file.cpp +++ b/src/webu_file.cpp @@ -22,51 +22,54 @@ #include "util.hpp" #include "picture.hpp" #include "webu.hpp" +#include "webu_ans.hpp" +#include "webu_common.hpp" #include "webu_file.hpp" #include "dbse.hpp" - /* Callback for the file reader response*/ static ssize_t webu_file_reader (void *cls, uint64_t pos, char *buf, size_t max) { - ctx_webui *webui =(ctx_webui *)cls; + cls_webu_ans *webu_ans =(cls_webu_ans *)cls; - (void)fseek (webui->req_file, (long)pos, SEEK_SET); - return fread (buf, 1, max, webui->req_file); + (void)fseek (webu_ans->req_file, (long)pos, SEEK_SET); + return fread (buf, 1, max, webu_ans->req_file); } /* Close the requested file */ static void webu_file_free (void *cls) { - ctx_webui *webui =(ctx_webui *)cls; - myfclose(webui->req_file); + cls_webu_ans *webu_ans =(cls_webu_ans *)cls; + myfclose(webu_ans->req_file); } -/* Entry point for answering file request*/ -mhdrslt webu_file_main(ctx_webui *webui) -{ +/****************************************************/ + +void cls_webu_file::main() { mhdrslt retcd; struct stat statbuf; struct MHD_Response *response; std::string full_nm; int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; /*If we have not fully started yet, simply return*/ - if (webui->cam->motapp->dbse == NULL) { - return MHD_NO; + if (app->dbse == NULL) { + webua->bad_request(); + return; } - if (webui->cam->motapp->dbse->movie_cnt == 0) { - dbse_movies_getlist(webui->cam->motapp, webui->cam->device_id); + if (app->dbse->movie_cnt == 0) { + dbse_movies_getlist(app, webua->cam->device_id); } for (it = lst->begin(); it != lst->end(); it++) { if (it->param_name == "movies") { if (it->param_value == "off") { MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "Movies via webcontrol disabled"); - return MHD_NO; + webua->bad_request(); + return; } else { break; } @@ -74,45 +77,58 @@ mhdrslt webu_file_main(ctx_webui *webui) } full_nm = ""; - for (indx=0; indx < webui->cam->motapp->dbse->movie_cnt; indx++) { - if (mystreq(webui->cam->motapp->dbse->movie_list[indx].movie_nm - , webui->uri_cmd2.c_str())) { - full_nm = webui->cam->motapp->dbse->movie_list[indx].full_nm; + for (indx=0; indx < app->dbse->movie_cnt; indx++) { + if (mystreq(app->dbse->movie_list[indx].movie_nm + ,webua->uri_cmd2.c_str())) { + full_nm = app->dbse->movie_list[indx].full_nm; } } if (stat(full_nm.c_str(), &statbuf) == 0) { - webui->req_file = myfopen(full_nm.c_str(), "rbe"); + webua->req_file = myfopen(full_nm.c_str(), "rbe"); } else { - webui->req_file = NULL; + webua->req_file = NULL; MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO ,"Security warning: Client IP %s requested file: %s" - ,webui->clientip.c_str(), webui->uri_cmd2.c_str()); + ,webua->clientip.c_str(), webua->uri_cmd2.c_str()); } - if (webui->req_file == NULL) { - webui->resp_page = "Bad File" + if (webua->req_file == NULL) { + webua->resp_page = "Bad File" "Bad File"; - - response = MHD_create_response_from_buffer(webui->resp_page.length() - ,(void *)webui->resp_page.c_str(), MHD_RESPMEM_PERSISTENT); - retcd = MHD_queue_response (webui->connection, MHD_HTTP_NOT_FOUND, response); - MHD_destroy_response (response); + webua->resp_type = WEBUI_RESP_HTML; + webua->mhd_send(); } else { response = MHD_create_response_from_callback ( statbuf.st_size, 32 * 1024 , &webu_file_reader - , webui + , this , &webu_file_free); if (response == NULL) { - myfclose(webui->req_file); - return MHD_NO; + myfclose(webua->req_file); + webua->bad_request(); + return; } - retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response); + retcd = MHD_queue_response (webua->connection, MHD_HTTP_OK, response); MHD_destroy_response (response); } + if (retcd == MHD_NO) { + MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "Error processing file request"); + } - return retcd; } +cls_webu_file::cls_webu_file(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; +} + +cls_webu_file::~cls_webu_file() +{ + app = nullptr; + webu = nullptr; + webua = nullptr; +} \ No newline at end of file diff --git a/src/webu_file.hpp b/src/webu_file.hpp index e8ca3347..1568084e 100644 --- a/src/webu_file.hpp +++ b/src/webu_file.hpp @@ -18,7 +18,15 @@ #ifndef _INCLUDE_WEBU_FILE_HPP_ #define _INCLUDE_WEBU_FILE_HPP_ - - mhdrslt webu_file_main(ctx_webui *webui); + class cls_webu_file { + public: + cls_webu_file(cls_webu_ans *p_webua); + ~cls_webu_file(); + void main(); + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; + }; #endif /* _INCLUDE_WEBU_FILE_HPP_ */ diff --git a/src/webu_getimg.cpp b/src/webu_getimg.cpp new file mode 100644 index 00000000..e08ce726 --- /dev/null +++ b/src/webu_getimg.cpp @@ -0,0 +1,317 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#include "motionplus.hpp" +#include "conf.hpp" +#include "logger.hpp" +#include "util.hpp" +#include "picture.hpp" +#include "webu_getimg.hpp" +#include "alg_sec.hpp" + +/* NOTE: These run on the motion_loop thread. */ + +/* Initial the stream context items for the camera */ +void webu_getimg_init(ctx_dev *cam) +{ + pthread_mutex_init(&cam->stream.mutex, NULL); + + cam->imgs.image_substream = NULL; + + cam->stream.norm.jpg_sz = 0; + cam->stream.norm.jpg_data = NULL; + cam->stream.norm.jpg_cnct = 0; + cam->stream.norm.ts_cnct = 0; + cam->stream.norm.all_cnct = 0; + cam->stream.norm.consumed = true; + cam->stream.norm.img_data = NULL; + + cam->stream.sub.jpg_sz = 0; + cam->stream.sub.jpg_data = NULL; + cam->stream.sub.jpg_cnct = 0; + cam->stream.sub.ts_cnct = 0; + cam->stream.sub.all_cnct = 0; + cam->stream.sub.consumed = true; + cam->stream.sub.img_data = NULL; + + cam->stream.motion.jpg_sz = 0; + cam->stream.motion.jpg_data = NULL; + cam->stream.motion.jpg_cnct = 0; + cam->stream.motion.ts_cnct = 0; + cam->stream.motion.all_cnct = 0; + cam->stream.motion.consumed = true; + cam->stream.motion.img_data = NULL; + + cam->stream.source.jpg_sz = 0; + cam->stream.source.jpg_data = NULL; + cam->stream.source.jpg_cnct = 0; + cam->stream.source.ts_cnct = 0; + cam->stream.source.all_cnct = 0; + cam->stream.source.consumed = true; + cam->stream.source.img_data = NULL; + + cam->stream.secondary.jpg_sz = 0; + cam->stream.secondary.jpg_data = NULL; + cam->stream.secondary.jpg_cnct = 0; + cam->stream.secondary.ts_cnct = 0; + cam->stream.secondary.all_cnct = 0; + cam->stream.secondary.consumed = true; + cam->stream.secondary.img_data = NULL; + +} + +/* Free the stream buffers and mutex for shutdown */ +void webu_getimg_deinit(ctx_dev *cam) +{ + /* NOTE: This runs on the motion_loop thread. */ + myfree(&cam->imgs.image_substream); + + pthread_mutex_lock(&cam->stream.mutex); + myfree(&cam->stream.norm.jpg_data); + myfree(&cam->stream.sub.jpg_data); + myfree(&cam->stream.motion.jpg_data); + myfree(&cam->stream.source.jpg_data); + myfree(&cam->stream.secondary.jpg_data); + + myfree(&cam->stream.norm.img_data) ; + myfree(&cam->stream.sub.img_data) ; + myfree(&cam->stream.motion.img_data) ; + myfree(&cam->stream.source.img_data) ; + myfree(&cam->stream.secondary.img_data) ; + pthread_mutex_unlock(&cam->stream.mutex); + + pthread_mutex_destroy(&cam->stream.mutex); + +} + +/* Get a normal image from the motion loop and compress it*/ +static void webu_getimg_norm(ctx_dev *cam) +{ + if ((cam->stream.norm.jpg_cnct == 0) && + (cam->stream.norm.ts_cnct == 0) && + (cam->stream.norm.all_cnct == 0)) { + return; + } + + if (cam->stream.norm.jpg_cnct > 0) { + if (cam->stream.norm.jpg_data == NULL) { + cam->stream.norm.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + if (cam->current_image->image_norm != NULL && cam->stream.norm.consumed) { + cam->stream.norm.jpg_sz = pic_put_memory(cam + ,cam->stream.norm.jpg_data + ,cam->imgs.size_norm + ,cam->current_image->image_norm + ,cam->conf->stream_quality + ,cam->imgs.width + ,cam->imgs.height); + cam->stream.norm.consumed = false; + } + } + if ((cam->stream.norm.ts_cnct > 0) || (cam->stream.norm.all_cnct > 0)) { + if (cam->stream.norm.img_data == NULL) { + cam->stream.norm.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + memcpy(cam->stream.norm.img_data, cam->current_image->image_norm, cam->imgs.size_norm); + } +} + +/* Get a substream image from the motion loop and compress it*/ +static void webu_getimg_sub(ctx_dev *cam) +{ + int subsize; + + if ((cam->stream.sub.jpg_cnct == 0) && + (cam->stream.sub.ts_cnct == 0) && + (cam->stream.sub.all_cnct == 0)) { + return; + } + + if (cam->stream.sub.jpg_cnct > 0) { + if (cam->stream.sub.jpg_data == NULL) { + cam->stream.sub.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + if (cam->current_image->image_norm != NULL && cam->stream.sub.consumed) { + /* Resulting substream image must be multiple of 8 */ + if (((cam->imgs.width % 16) == 0) && + ((cam->imgs.height % 16) == 0)) { + + subsize = ((cam->imgs.width / 2) * (cam->imgs.height / 2) * 3 / 2); + if (cam->imgs.image_substream == NULL) { + cam->imgs.image_substream =(unsigned char*)mymalloc(subsize); + } + pic_scale_img(cam->imgs.width + ,cam->imgs.height + ,cam->current_image->image_norm + ,cam->imgs.image_substream); + cam->stream.sub.jpg_sz = pic_put_memory(cam + ,cam->stream.sub.jpg_data + ,subsize + ,cam->imgs.image_substream + ,cam->conf->stream_quality + ,(cam->imgs.width / 2) + ,(cam->imgs.height / 2)); + } else { + /* Substream was not multiple of 8 so send full image*/ + cam->stream.sub.jpg_sz = pic_put_memory(cam + ,cam->stream.sub.jpg_data + ,cam->imgs.size_norm + ,cam->current_image->image_norm + ,cam->conf->stream_quality + ,cam->imgs.width + ,cam->imgs.height); + } + cam->stream.sub.consumed = false; + } + } + + if ((cam->stream.sub.ts_cnct > 0) || (cam->stream.sub.all_cnct > 0)) { + if (cam->stream.sub.img_data == NULL) { + cam->stream.sub.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + if (((cam->imgs.width % 16) == 0) && + ((cam->imgs.height % 16) == 0)) { + subsize = ((cam->imgs.width / 2) * (cam->imgs.height / 2) * 3 / 2); + if (cam->imgs.image_substream == NULL) { + cam->imgs.image_substream =(unsigned char*)mymalloc(subsize); + } + pic_scale_img(cam->imgs.width + ,cam->imgs.height + ,cam->current_image->image_norm + ,cam->imgs.image_substream); + memcpy(cam->stream.sub.img_data, cam->imgs.image_substream, subsize); + } else { + memcpy(cam->stream.sub.img_data, cam->current_image->image_norm, cam->imgs.size_norm); + } + } + +} + +/* Get a motion image from the motion loop and compress it*/ +static void webu_getimg_motion(ctx_dev *cam) +{ + if ((cam->stream.motion.jpg_cnct == 0) && + (cam->stream.motion.ts_cnct == 0) && + (cam->stream.motion.all_cnct == 0)) { + return; + } + + if (cam->stream.motion.jpg_cnct > 0) { + if (cam->stream.motion.jpg_data == NULL) { + cam->stream.motion.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + if (cam->imgs.image_motion.image_norm != NULL && cam->stream.motion.consumed) { + cam->stream.motion.jpg_sz = pic_put_memory(cam + ,cam->stream.motion.jpg_data + ,cam->imgs.size_norm + ,cam->imgs.image_motion.image_norm + ,cam->conf->stream_quality + ,cam->imgs.width + ,cam->imgs.height); + cam->stream.motion.consumed = false; + } + } + if ((cam->stream.motion.ts_cnct > 0) || (cam->stream.motion.all_cnct > 0)) { + if (cam->stream.motion.img_data == NULL) { + cam->stream.motion.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + memcpy(cam->stream.motion.img_data + , cam->imgs.image_motion.image_norm + , cam->imgs.size_norm); + } +} + +/* Get a source image from the motion loop and compress it*/ +static void webu_getimg_source(ctx_dev *cam) +{ + if ((cam->stream.source.jpg_cnct == 0) && + (cam->stream.source.ts_cnct == 0) && + (cam->stream.source.all_cnct == 0)) { + return; + } + + if (cam->stream.source.jpg_cnct > 0) { + if (cam->stream.source.jpg_data == NULL) { + cam->stream.source.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + if (cam->imgs.image_virgin != NULL && cam->stream.source.consumed) { + cam->stream.source.jpg_sz = pic_put_memory(cam + ,cam->stream.source.jpg_data + ,cam->imgs.size_norm + ,cam->imgs.image_virgin + ,cam->conf->stream_quality + ,cam->imgs.width + ,cam->imgs.height); + cam->stream.source.consumed = false; + } + } + if ((cam->stream.source.ts_cnct > 0) || (cam->stream.source.all_cnct > 0)) { + if (cam->stream.source.img_data == NULL) { + cam->stream.source.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + memcpy(cam->stream.source.img_data + , cam->imgs.image_virgin + , cam->imgs.size_norm); + } +} + +/* Get a secondary image from the motion loop and compress it*/ +static void webu_getimg_secondary(ctx_dev *cam) +{ + if ((cam->stream.secondary.jpg_cnct == 0) && + (cam->stream.secondary.ts_cnct == 0) && + (cam->stream.secondary.all_cnct == 0)) { + return; + } + + if (cam->stream.secondary.jpg_cnct > 0) { + if (cam->imgs.size_secondary>0) { + pthread_mutex_lock(&cam->algsec->mutex); + if (cam->stream.secondary.jpg_data == NULL) { + cam->stream.secondary.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + + memcpy(cam->stream.secondary.jpg_data,cam->imgs.image_secondary,cam->imgs.size_secondary); + cam->stream.secondary.jpg_sz = cam->imgs.size_secondary; + pthread_mutex_unlock(&cam->algsec->mutex); + } else { + myfree(&cam->stream.secondary.jpg_data); + } + } + if ((cam->stream.secondary.ts_cnct > 0) || (cam->stream.secondary.all_cnct > 0)) { + if (cam->stream.secondary.img_data == NULL) { + cam->stream.secondary.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); + } + memcpy(cam->stream.secondary.img_data + , cam->current_image->image_norm, cam->imgs.size_norm); + } + +} + +/* Get image from the motion loop and compress it*/ +void webu_getimg_main(ctx_dev *cam) +{ + /*This is on the motion_loop thread */ + pthread_mutex_lock(&cam->stream.mutex); + webu_getimg_norm(cam); + webu_getimg_sub(cam); + webu_getimg_motion(cam); + webu_getimg_source(cam); + webu_getimg_secondary(cam); + pthread_mutex_unlock(&cam->stream.mutex); +} diff --git a/src/webu_getimg.hpp b/src/webu_getimg.hpp new file mode 100644 index 00000000..b1777c5a --- /dev/null +++ b/src/webu_getimg.hpp @@ -0,0 +1,26 @@ +/* + * This file is part of MotionPlus. + * + * MotionPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MotionPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MotionPlus. If not, see . + * +*/ + +#ifndef _INCLUDE_WEBU_GETIMG_HPP_ +#define _INCLUDE_WEBU_GETIMG_HPP_ + + void webu_getimg_init(ctx_dev *cam); + void webu_getimg_deinit(ctx_dev *cam); + void webu_getimg_main(ctx_dev *cam); + +#endif diff --git a/src/webu_html.cpp b/src/webu_html.cpp index 14165b4a..0a65047d 100644 --- a/src/webu_html.cpp +++ b/src/webu_html.cpp @@ -21,13 +21,14 @@ #include "logger.hpp" #include "util.hpp" #include "webu.hpp" +#include "webu_common.hpp" +#include "webu_ans.hpp" #include "webu_html.hpp" - /* Create the CSS styles used in the navigation bar/side of the page */ -static void webu_html_style_navbar(ctx_webui *webui) +void cls_webu_html::style_navbar() { - webui->resp_page += + webua->resp_page += " .sidenav {\n" " height: 100%;\n" " width: 10rem;\n" @@ -108,9 +109,9 @@ static void webu_html_style_navbar(ctx_webui *webui) } /* Create the css styles used in the config sections */ -static void webu_html_style_config(ctx_webui *webui) +void cls_webu_html::style_config() { - webui->resp_page += + webua->resp_page += " .cls_config {\n" " background-color: #000000;\n" " color: #fff;\n" @@ -221,10 +222,9 @@ static void webu_html_style_config(ctx_webui *webui) } /* Write out the starting style section of the web page */ -static void webu_html_style_base(ctx_webui *webui) +void cls_webu_html::style_base() { - - webui->resp_page += + webua->resp_page += " * {\n" " margin: 0;\n" " padding: 0;\n" @@ -277,39 +277,36 @@ static void webu_html_style_base(ctx_webui *webui) } /* Write out the style section of the web page */ -static void webu_html_style(ctx_webui *webui) +void cls_webu_html::style() { - webui->resp_page += " \n"; + style_config(); + webua->resp_page += " \n"; } /* Create the header section of the page */ -static void webu_html_head(ctx_webui *webui) +void cls_webu_html::head() { - - webui->resp_page += " \n" + webua->resp_page += " \n" " \n" "MotionPlus \n" " \n"; - webu_html_style(webui); - - webui->resp_page += "\n\n"; + style(); + webua->resp_page += "\n\n"; } /* Create the navigation bar section of the page */ -static void webu_html_navbar(ctx_webui *webui) +void cls_webu_html::navbar() { - webui->resp_page += + webua->resp_page += "
\n" " X\n" "
\n" @@ -340,13 +337,12 @@ static void webu_html_navbar(ctx_webui *webui) " \n" "
\n" "
\n\n"; - } /* Create the body main section of the page */ -static void webu_html_divmain(ctx_webui *webui) +void cls_webu_html::divmain() { - webui->resp_page += + webua->resp_page += "
\n" "
\n\n" " \n\n"; - } /* Create the javascript function send_config */ -static void webu_html_script_nav(ctx_webui *webui) +void cls_webu_html::script_nav() { - webui->resp_page += + webua->resp_page += " function nav_open() {\n" " document.getElementById('divnav_main').style.width = '10rem';\n" " document.getElementById('divmain').style.marginLeft = '10rem';\n" @@ -384,9 +379,9 @@ static void webu_html_script_nav(ctx_webui *webui) } /* Create the javascript function send_config */ -static void webu_html_script_send_config(ctx_webui *webui) +void cls_webu_html::script_send_config() { - webui->resp_page += + webua->resp_page += " function send_config(category) {\n" " var formData = new FormData();\n" " var request = new XMLHttpRequest();\n" @@ -426,9 +421,9 @@ static void webu_html_script_send_config(ctx_webui *webui) } /* Create the send_action javascript function */ -static void webu_html_script_send_action(ctx_webui *webui) +void cls_webu_html::script_send_action() { - webui->resp_page += + webua->resp_page += " function send_action(actval) {\n\n" " var dsp_cam = document.getElementById('div_cam').style.display;\n" @@ -459,9 +454,9 @@ static void webu_html_script_send_action(ctx_webui *webui) } /* Create the send_reload javascript function */ -static void webu_html_script_send_reload(ctx_webui *webui) +void cls_webu_html::script_send_reload() { - webui->resp_page += + webua->resp_page += " function send_reload(actval) {\n\n" " var formData = new FormData();\n" " var request = new XMLHttpRequest();\n" @@ -505,9 +500,9 @@ static void webu_html_script_send_reload(ctx_webui *webui) } /* Create the javascript function dropchange_cam */ -static void webu_html_script_dropchange_cam(ctx_webui *webui) +void cls_webu_html::script_dropchange_cam() { - webui->resp_page += + webua->resp_page += " function dropchange_cam(camobj) {\n" " var indx;\n\n" @@ -529,9 +524,9 @@ static void webu_html_script_dropchange_cam(ctx_webui *webui) } /* Create the javascript function config_hideall */ -static void webu_html_script_config_hideall(ctx_webui *webui) +void cls_webu_html::script_config_hideall() { - webui->resp_page += + webua->resp_page += " function config_hideall() {\n" " var sect = document.getElementsByClassName('cls_config');\n" " for (var i = 0; i < sect.length; i++) {\n" @@ -542,9 +537,9 @@ static void webu_html_script_config_hideall(ctx_webui *webui) } /* Create the javascript function config_click */ -static void webu_html_script_config_click(ctx_webui *webui) +void cls_webu_html::script_config_click() { - webui->resp_page += + webua->resp_page += " function config_click(actval) {\n" " config_hideall();\n" " document.getElementById('div_cam').style.display='none';\n" @@ -556,9 +551,9 @@ static void webu_html_script_config_click(ctx_webui *webui) } /* Create the javascript function assign_camid */ -static void webu_html_script_assign_camid(ctx_webui *webui) +void cls_webu_html::script_assign_camid() { - webui->resp_page += + webua->resp_page += " function assign_camid() {\n" " if (gIndxCam == -1 ) {\n" " camid = 0;\n" @@ -567,25 +562,22 @@ static void webu_html_script_assign_camid(ctx_webui *webui) " }\n\n" " return camid; \n" " }\n\n"; - } - /* Create the javascript function assign_version */ -static void webu_html_script_assign_version(ctx_webui *webui) +void cls_webu_html::script_assign_version() { - webui->resp_page += + webua->resp_page += " function assign_version() {\n" " var verstr ='MotionPlus \\n'+pData['version'] +'';\n" " document.getElementById('divnav_version').innerHTML = verstr;\n" " }\n\n"; - } /* Create the javascript function assign_cams */ -static void webu_html_script_assign_cams(ctx_webui *webui) +void cls_webu_html::script_assign_cams() { - webui->resp_page += + webua->resp_page += " function assign_cams() {\n" " var camcnt = pData['cameras']['count'];\n" " var indx = 0;\n" @@ -626,12 +618,12 @@ static void webu_html_script_assign_cams(ctx_webui *webui) } /* Create the javascript function assign_actions */ -static void webu_html_script_assign_actions(ctx_webui *webui) +void cls_webu_html::script_assign_actions() { - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; - webui->resp_page += + webua->resp_page += " function assign_actions() {\n" " var html_actions = \"\\n\";\n" " html_actions += \" \";\n"; @@ -639,14 +631,14 @@ static void webu_html_script_assign_actions(ctx_webui *webui) for (it = lst->begin(); it != lst->end(); it++) { if ((it->param_name == "snapshot") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Snapshot\\n\";\n\n" ; } else if ((it->param_name == "event") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Start Event\\n\";\n\n" @@ -657,7 +649,7 @@ static void webu_html_script_assign_actions(ctx_webui *webui) ; } else if ((it->param_name == "pause") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Pause\\n\";\n\n" @@ -668,42 +660,42 @@ static void webu_html_script_assign_actions(ctx_webui *webui) ; } else if ((it->param_name == "camera_add") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Add Camera\\n\";\n\n" ; } else if ((it->param_name == "camera_delete") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Delete Camera\\n\";\n\n" ; } else if ((it->param_name == "config_write") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Save Config\\n\";\n\n" ; } else if ((it->param_name == "stop") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Stop\\n\";\n\n" ; } else if ((it->param_name == "restart") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"Start/Restart\\n\";\n\n" ; } else if ((it->param_name == "action_user") && (it->param_value == "on")) { - webui->resp_page += + webua->resp_page += " html_actions += \"\";\n" " html_actions += \"User Action\\n\";\n\n" @@ -711,20 +703,17 @@ static void webu_html_script_assign_actions(ctx_webui *webui) } } - webui->resp_page += + webua->resp_page += " document.getElementById(\"divnav_actions\").innerHTML = html_actions;\n\n" " return;\n" " }\n\n"; - - } - /* Create the javascript function assign_vals */ -static void webu_html_script_assign_vals(ctx_webui *webui) +void cls_webu_html::script_assign_vals() { - webui->resp_page += + webua->resp_page += " function assign_vals(camid) {\n" " var pCfg;\n\n" @@ -755,9 +744,9 @@ static void webu_html_script_assign_vals(ctx_webui *webui) } /* Create the javascript function assign_config_nav */ -static void webu_html_script_assign_config_nav(ctx_webui *webui) +void cls_webu_html::script_assign_config_nav() { - webui->resp_page += + webua->resp_page += " function assign_config_nav() {\n" " var pCfg = pData['configuration']['default'];\n" " var pCat = pData['categories'];\n" @@ -775,9 +764,9 @@ static void webu_html_script_assign_config_nav(ctx_webui *webui) } /* Create the javascript function assign_config_item */ -static void webu_html_script_assign_config_item(ctx_webui *webui) +void cls_webu_html::script_assign_config_item() { - webui->resp_page += + webua->resp_page += " function assign_config_item(jkey) {\n" " var pCfg = pData['configuration']['default'];\n" " var html_cfg = \"\";\n" @@ -814,9 +803,9 @@ static void webu_html_script_assign_config_item(ctx_webui *webui) } /* Create the javascript function assign_config_cat */ -static void webu_html_script_assign_config_cat(ctx_webui *webui) +void cls_webu_html::script_assign_config_cat() { - webui->resp_page += + webua->resp_page += " function assign_config_cat(jcat) {\n" " var pCfg = pData['configuration']['default'];\n" " var pCat = pData['categories'];\n" @@ -851,10 +840,9 @@ static void webu_html_script_assign_config_cat(ctx_webui *webui) } /* Create the javascript function assign_config */ -static void webu_html_script_assign_config(ctx_webui *webui) +void cls_webu_html::script_assign_config() { - - webui->resp_page += + webua->resp_page += " function assign_config() {\n" " var pCat = pData['categories'];\n" " var html_cfg = \"\";\n\n" @@ -871,9 +859,9 @@ static void webu_html_script_assign_config(ctx_webui *webui) } /* Create the javascript function init_form */ -static void webu_html_script_initform(ctx_webui *webui) +void cls_webu_html::script_initform() { - webui->resp_page += + webua->resp_page += " function initform() {\n" " var xmlhttp = new XMLHttpRequest();\n\n" @@ -903,9 +891,9 @@ static void webu_html_script_initform(ctx_webui *webui) } /* Create the javascript function display_cameras */ -static void webu_html_script_display_cameras(ctx_webui *webui) +void cls_webu_html::script_display_cameras() { - webui->resp_page += + webua->resp_page += " function display_cameras() {\n" " document.getElementById('divnav_config').style.display = 'none';\n" " document.getElementById('divnav_actions').style.display = 'none';\n" @@ -919,9 +907,9 @@ static void webu_html_script_display_cameras(ctx_webui *webui) } /* Create the javascript function display_config */ -static void webu_html_script_display_config(ctx_webui *webui) +void cls_webu_html::script_display_config() { - webui->resp_page += + webua->resp_page += " function display_config() {\n" " document.getElementById('divnav_cam').style.display = 'none';\n" " document.getElementById('divnav_actions').style.display = 'none';\n" @@ -937,9 +925,9 @@ static void webu_html_script_display_config(ctx_webui *webui) } /* Create the javascript function display_movies */ -static void webu_html_script_display_movies(ctx_webui *webui) +void cls_webu_html::script_display_movies() { - webui->resp_page += + webua->resp_page += " function display_movies() {\n" " document.getElementById('divnav_cam').style.display = 'none';\n" " document.getElementById('divnav_actions').style.display = 'none';\n" @@ -955,13 +943,13 @@ static void webu_html_script_display_movies(ctx_webui *webui) } /* Create the javascript function display_actions */ -static void webu_html_script_display_actions(ctx_webui *webui) +void cls_webu_html::script_display_actions() { - webui->resp_page += + webua->resp_page += " function display_actions() {\n" " document.getElementById('divnav_cam').style.display = 'none';\n" " document.getElementById('divnav_config').style.display = 'none';\n" - " if (document.getElementById('divnav_actions').style.display == 'block') {\n" + " if (document.getElementById('divnav_actions').style.display == 'block') {\n" " document.getElementById('divnav_actions').style.display = 'none';\n" " } else {\n" " document.getElementById('divnav_actions').style.display = 'block';\n" @@ -971,10 +959,9 @@ static void webu_html_script_display_actions(ctx_webui *webui) } /* Create the camera_buttons_ptz javascript function */ -static void webu_html_script_camera_buttons_ptz(ctx_webui *webui) +void cls_webu_html::script_camera_buttons_ptz() { - - webui->resp_page += + webua->resp_page += " function camera_buttons_ptz() {\n\n" " var html_preview = \"\";\n" @@ -1016,13 +1003,12 @@ static void webu_html_script_camera_buttons_ptz(ctx_webui *webui) " return html_preview;\n\n" " }\n\n"; - } /* Create the image_pantilt javascript function */ -static void webu_html_script_image_pantilt(ctx_webui *webui) +void cls_webu_html::script_image_pantilt() { - webui->resp_page += + webua->resp_page += " function image_pantilt() {\n\n" " if (gIndxCam == -1 ) {\n" " return;\n" @@ -1046,21 +1032,19 @@ static void webu_html_script_image_pantilt(ctx_webui *webui) " }\n" " });\n" " }\n\n"; - } /* Create the cams_reset javascript function */ -static void webu_html_script_cams_reset(ctx_webui *webui) +void cls_webu_html::script_cams_reset() { - - webui->resp_page += + webua->resp_page += " function cams_timer_stop() {\n" " clearInterval(cams_one_timer);\n" " clearInterval(cams_all_timer);\n" " clearInterval(cams_scan_timer);\n" " }\n\n"; - webui->resp_page += + webua->resp_page += " function cams_reset() {\n" " var indx, camcnt;\n" " camcnt = pData['cameras']['count'];\n" @@ -1070,14 +1054,12 @@ static void webu_html_script_cams_reset(ctx_webui *webui) " }\n" " }\n" " } \n\n"; - } /* Create the cams_one_click javascript function */ -static void webu_html_script_cams_one_click(ctx_webui *webui) +void cls_webu_html::script_cams_one_click() { - - webui->resp_page += + webua->resp_page += " function cams_one_click(index_cam) {\n\n" " var html_preview = \"\";\n" " var camid;\n\n" @@ -1114,14 +1096,12 @@ static void webu_html_script_cams_one_click(ctx_webui *webui) " image_pantilt();\n\n" " cams_one_timer = setInterval(cams_one_fnc, 1000);\n\n" " }\n\n"; - } /* Create the cams_all_click javascript function */ -static void webu_html_script_cams_all_click(ctx_webui *webui) +void cls_webu_html::script_cams_all_click() { - - webui->resp_page += + webua->resp_page += " function cams_all_click() {\n\n" " var html_preview = \"\";\n" " var indx, chk;\n" @@ -1182,10 +1162,11 @@ static void webu_html_script_cams_all_click(ctx_webui *webui) " cams_all_timer = setInterval(cams_all_fnc, 1000);\n\n" " }\n\n"; } + /* Create the movies_page javascript function */ -static void webu_html_script_movies_page(ctx_webui *webui) +void cls_webu_html::script_movies_page() { - webui->resp_page += + webua->resp_page += " function movies_page() {\n\n" " var html_tab = \"
\";\n" " var indx, movcnt, camid, uri;\n" @@ -1256,14 +1237,12 @@ static void webu_html_script_movies_page(ctx_webui *webui) " document.getElementById('div_movies').style.display='block';\n" " document.getElementById('div_movies').innerHTML = html_tab;\n\n" " }\n\n"; - } /* Create the movies_page javascript function */ -static void webu_html_script_movies_click(ctx_webui *webui) +void cls_webu_html::script_movies_click() { - - webui->resp_page += + webua->resp_page += " function movies_click(index_cam) {\n" " var camid, indx, camcnt, uri;\n\n" @@ -1283,12 +1262,12 @@ static void webu_html_script_movies_click(ctx_webui *webui) " xmlhttp.open('GET', uri);\n" " xmlhttp.send();\n" " }\n\n"; - } + /* Create the cams_scan_click javascript function */ -static void webu_html_script_cams_scan_click(ctx_webui *webui) +void cls_webu_html::script_cams_scan_click() { - webui->resp_page += + webua->resp_page += " function cams_scan_click() {\n\n" " cams_timer_stop();\n\n" " gIndxCam = -1; \n" @@ -1298,9 +1277,9 @@ static void webu_html_script_cams_scan_click(ctx_webui *webui) } /* Create the cams_one_fnc javascript function */ -static void webu_html_script_cams_one_fnc(ctx_webui *webui) +void cls_webu_html::script_cams_one_fnc() { - webui->resp_page += + webua->resp_page += " function cams_one_fnc () {\n" " var img = new Image();\n" " var camid;\n\n" @@ -1314,13 +1293,12 @@ static void webu_html_script_cams_one_fnc(ctx_webui *webui) " document.getElementById('pic'+gIndxCam).src = pic_url[0];\n" " }\n" " }\n\n "; - } /* Create the cams_all_fnc javascript function */ -static void webu_html_script_cams_all_fnc(ctx_webui *webui) +void cls_webu_html::script_cams_all_fnc() { - webui->resp_page += + webua->resp_page += " function cams_all_fnc () {\n" " var previndx = gGetImgs;\n" " gGetImgs++;\n" @@ -1335,13 +1313,12 @@ static void webu_html_script_cams_all_fnc(ctx_webui *webui) " pData['cameras'][gGetImgs]['url'] + \"mjpg/stream\";\n" " }\n" " }\n\n"; - } /* Create the scancam_function javascript function */ -static void webu_html_script_cams_scan_fnc(ctx_webui *webui) +void cls_webu_html::script_cams_scan_fnc() { - webui->resp_page += + webua->resp_page += " function cams_scan_fnc() {\n" " var html_preview = \"\";\n" " var camid;\n" @@ -1379,131 +1356,131 @@ static void webu_html_script_cams_scan_fnc(ctx_webui *webui) " document.getElementById('div_cam').style.display='block';\n" " document.getElementById('div_cam').innerHTML = html_preview;\n" " };\n\n"; - } /* Call all the functions to create the java scripts of page*/ -static void webu_html_script(ctx_webui *webui) +void cls_webu_html::script() { - webui->resp_page += " \n\n"; + script_movies_page(); + script_movies_click(); + webua->resp_page += " \n\n"; } /* Create the body section of the web page */ -static void webu_html_body(ctx_webui *webui) +void cls_webu_html::body() { - webui->resp_page += "\n"; + webua->resp_page += "\n"; - webu_html_navbar(webui); + navbar(); - webu_html_divmain(webui); + divmain(); - webu_html_script(webui); - - webui->resp_page += "\n"; + script(); + webua->resp_page += "\n"; } -/* Create the default motionplus page */ -void webu_html_page(ctx_webui *webui) +void cls_webu_html::default_page() { - webui->resp_page += "\n" - "\n"; - - webu_html_head(webui); - - webu_html_body(webui); - - webui->resp_page += "\n"; + webua->resp_page += "\n" + "\n"; + head(); + body(); + webua->resp_page += "\n"; } -/*Create the bad request page*/ -void webu_html_badreq(ctx_webui *webui) -{ - webui->resp_page = - "\n" - "\n" - "\n" - "

Bad Request

\n" - "

The server did not understand your request.

\n" - "\n" - "\n"; - -} - -/* Load a user provided html page */ -void webu_html_user(ctx_webui *webui) +void cls_webu_html::user_page() { char response[PATH_MAX]; FILE *fp = NULL; - fp = myfopen(webui->motapp->conf->webcontrol_html.c_str(), "re"); - + webua->resp_page = ""; + fp = myfopen(app->conf->webcontrol_html.c_str(), "re"); if (fp == NULL) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO , _("Invalid user html file: %s") - , webui->motapp->conf->webcontrol_html.c_str()); - - webu_html_badreq(webui); - - return; + , app->conf->webcontrol_html.c_str()); + } else { + while (fgets(response, PATH_MAX-1, fp)) { + webua->resp_page += response; + } + myfclose(fp); } - - webui->resp_page = ""; - while (fgets(response, PATH_MAX-1, fp)) { - webui->resp_page += response; - } - - myfclose(fp); - } +void cls_webu_html::main() +{ + pthread_mutex_lock(&app->mutex_post); + if (app->conf->webcontrol_interface == "user") { + user_page(); + } else { + default_page(); + } + pthread_mutex_unlock(&app->mutex_post); + if (webua->resp_page == "") { + webua->bad_request(); + } else { + webua->mhd_send(); + } +} + +cls_webu_html::cls_webu_html(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; +} + +cls_webu_html::~cls_webu_html() +{ + app = nullptr; + webu = nullptr; + webua = nullptr; +} diff --git a/src/webu_html.hpp b/src/webu_html.hpp index 1662906b..94ca65e5 100644 --- a/src/webu_html.hpp +++ b/src/webu_html.hpp @@ -18,9 +18,59 @@ #ifndef _INCLUDE_WEBU_HTML_HPP_ #define _INCLUDE_WEBU_HTML_HPP_ + class cls_webu_html { + public: + cls_webu_html(cls_webu_ans *p_webua); + ~cls_webu_html(); + void main(); + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; - void webu_html_badreq(ctx_webui *webui); - void webu_html_user(ctx_webui *webui); - void webu_html_page(ctx_webui *webui); + void style_navbar(); + void style_config(); + void style_base(); + void style(); + void head(); + void navbar(); + void divmain(); + void script_nav(); + void script_send_config(); + void script_send_action(); + void script_send_reload(); + void script_dropchange_cam(); + void script_config_hideall(); + void script_config_click(); + void script_assign_camid(); + void script_assign_version(); + void script_assign_cams(); + void script_assign_actions(); + void script_assign_vals(); + void script_assign_config_nav(); + void script_assign_config_item(); + void script_assign_config_cat(); + void script_assign_config(); + void script_initform(); + void script_display_cameras(); + void script_display_config(); + void script_display_movies(); + void script_display_actions(); + void script_camera_buttons_ptz(); + void script_image_pantilt(); + void script_cams_reset(); + void script_cams_one_click(); + void script_cams_all_click(); + void script_movies_page(); + void script_movies_click(); + void script_cams_scan_click(); + void script_cams_one_fnc(); + void script_cams_all_fnc(); + void script_cams_scan_fnc(); + void script(); + void body(); + void default_page(); + void user_page(); + }; #endif /* _INCLUDE_WEBU_HTML_HPP_ */ diff --git a/src/webu_json.cpp b/src/webu_json.cpp index f5ff94c5..c92dd756 100644 --- a/src/webu_json.cpp +++ b/src/webu_json.cpp @@ -21,10 +21,12 @@ #include "logger.hpp" #include "util.hpp" #include "webu.hpp" +#include "webu_ans.hpp" +#include "webu_common.hpp" #include "webu_json.hpp" #include "dbse.hpp" -static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_parm) +void cls_webu_json::parms_item(ctx_config *conf, int indx_parm) { size_t indx; std::string parm_orig, parm_val, parm_list, parm_enable; @@ -33,7 +35,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p parm_val = ""; parm_list = ""; - if (webui->motapp->conf->webcontrol_parms < WEBUI_LEVEL_LIMITED) { + if (app->conf->webcontrol_parms < WEBUI_LEVEL_LIMITED) { parm_enable = "false"; } else { parm_enable = "true"; @@ -51,7 +53,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p } if (config_parms[indx_parm].parm_type == PARM_TYP_INT) { - webui->resp_page += + webua->resp_page += "\"" + config_parms[indx_parm].parm_name + "\"" + ":{" + " \"value\":" + parm_val + @@ -62,7 +64,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p } else if (config_parms[indx_parm].parm_type == PARM_TYP_BOOL) { if (parm_val == "on") { - webui->resp_page += + webua->resp_page += "\"" + config_parms[indx_parm].parm_name + "\"" + ":{" + " \"value\":true" + @@ -71,7 +73,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p ",\"type\":\"" + conf_type_desc(config_parms[indx_parm].parm_type) + "\""+ "}"; } else { - webui->resp_page += + webua->resp_page += "\"" + config_parms[indx_parm].parm_name + "\"" + ":{" + " \"value\":false" + @@ -84,7 +86,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p conf_edit_list(conf, config_parms[indx_parm].parm_name , parm_list, config_parms[indx_parm].parm_cat); - webui->resp_page += + webua->resp_page += "\"" + config_parms[indx_parm].parm_name + "\"" + ":{" + " \"value\": \"" + parm_val + "\"" + @@ -95,7 +97,7 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p "}"; } else { - webui->resp_page += + webua->resp_page += "\"" + config_parms[indx_parm].parm_name + "\"" + ":{" + " \"value\":\"" + parm_val + "\"" + @@ -104,10 +106,9 @@ static void webu_json_config_item(ctx_webui *webui, ctx_config *conf, int indx_p ",\"type\":\""+ conf_type_desc(config_parms[indx_parm].parm_type) + "\"" + "}"; } - } -static void webu_json_config_parms(ctx_webui *webui, ctx_config *conf) +void cls_webu_json::parms_one(ctx_config *conf) { int indx_parm; bool first; @@ -122,16 +123,16 @@ static void webu_json_config_parms(ctx_webui *webui, ctx_config *conf) } if (first) { first = false; - webui->resp_page += "{"; + webua->resp_page += "{"; } else { - webui->resp_page += ","; + webua->resp_page += ","; } /* Allow limited parameters to be read only to the web page */ if ((config_parms[indx_parm].webui_level > - webui->motapp->conf->webcontrol_parms) && + app->conf->webcontrol_parms) && (config_parms[indx_parm].webui_level > WEBUI_LEVEL_LIMITED)) { - webui->resp_page += + webua->resp_page += "\""+config_parms[indx_parm].parm_name+"\"" + ":{" + " \"value\":\"\"" + @@ -140,128 +141,118 @@ static void webu_json_config_parms(ctx_webui *webui, ctx_config *conf) ",\"type\":\""+ conf_type_desc(config_parms[indx_parm].parm_type) + "\""; if (config_parms[indx_parm].parm_type == PARM_TYP_LIST) { - webui->resp_page += ",\"list\":[\"na\"]"; + webua->resp_page += ",\"list\":[\"na\"]"; } - webui->resp_page +="}"; + webua->resp_page +="}"; } else { - webu_json_config_item(webui, conf, indx_parm); + parms_item(conf, indx_parm); } indx_parm++; } - webui->resp_page += "}"; - + webua->resp_page += "}"; } -static void webu_json_config_cam_parms(ctx_webui *webui) +void cls_webu_json::parms_all() { int indx_cam; - webui->resp_page += "{"; - webui->resp_page += "\"default\": "; - webu_json_config_parms(webui, webui->motapp->conf); + webua->resp_page += "{"; + webua->resp_page += "\"default\": "; + parms_one(app->conf); - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - webui->resp_page += ",\"cam" + - std::to_string(webui->motapp->cam_list[indx_cam]->device_id) + "\": "; - webu_json_config_parms(webui, webui->motapp->cam_list[indx_cam]->conf); + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + webua->resp_page += ",\"cam" + + std::to_string(app->cam_list[indx_cam]->device_id) + "\": "; + parms_one(app->cam_list[indx_cam]->conf); } - webui->resp_page += "}"; - - return; - + webua->resp_page += "}"; } -static void webu_json_config_cam_list(ctx_webui *webui) +void cls_webu_json::cameras_list() { int indx_cam; std::string response; std::string strid; ctx_dev *cam; - webui->resp_page += "{\"count\" : " + std::to_string(webui->motapp->cam_cnt); + webua->resp_page += "{\"count\" : " + std::to_string(app->cam_cnt); - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - cam = webui->motapp->cam_list[indx_cam]; + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + cam = app->cam_list[indx_cam]; strid =std::to_string(cam->device_id); - webui->resp_page += ",\"" + std::to_string(indx_cam) + "\":"; + webua->resp_page += ",\"" + std::to_string(indx_cam) + "\":"; if (cam->conf->device_name == "") { - webui->resp_page += "{\"name\": \"camera " + strid + "\""; + webua->resp_page += "{\"name\": \"camera " + strid + "\""; } else { - webui->resp_page += "{\"name\": \"" + cam->conf->device_name + "\""; + webua->resp_page += "{\"name\": \"" + cam->conf->device_name + "\""; } - webui->resp_page += ",\"id\": " + strid; - webui->resp_page += ",\"url\": \"" + webui->hostfull + "/" + strid + "/\"} "; + webua->resp_page += ",\"id\": " + strid; + webua->resp_page += ",\"url\": \"" + webua->hostfull + "/" + strid + "/\"} "; } - webui->resp_page += "}"; - - return; + webua->resp_page += "}"; } -static void webu_json_config_categories(ctx_webui *webui) +void cls_webu_json::categories_list() { int indx_cat; std::string catnm_short, catnm_long; - webui->resp_page += "{"; + webua->resp_page += "{"; indx_cat = 0; while (indx_cat != PARM_CAT_MAX) { if (indx_cat != 0) { - webui->resp_page += ","; + webua->resp_page += ","; } - webui->resp_page += "\"" + std::to_string(indx_cat) + "\": "; + webua->resp_page += "\"" + std::to_string(indx_cat) + "\": "; catnm_long = conf_cat_desc((enum PARM_CAT)indx_cat, false); catnm_short = conf_cat_desc((enum PARM_CAT)indx_cat, true); - webui->resp_page += "{\"name\":\"" + catnm_short + "\",\"display\":\"" + catnm_long + "\"}"; + webua->resp_page += "{\"name\":\"" + catnm_short + "\",\"display\":\"" + catnm_long + "\"}"; indx_cat++; } - webui->resp_page += "}"; - - return; - + webua->resp_page += "}"; } -void webu_json_config(ctx_webui *webui) +void cls_webu_json::config() { - webui->resp_type = WEBUI_RESP_JSON; + webua->resp_type = WEBUI_RESP_JSON; - webui->resp_page += "{\"version\" : \"" VERSION "\""; + webua->resp_page += "{\"version\" : \"" VERSION "\""; - webui->resp_page += ",\"cameras\" : "; - webu_json_config_cam_list(webui); + webua->resp_page += ",\"cameras\" : "; + cameras_list(); - webui->resp_page += ",\"configuration\" : "; - webu_json_config_cam_parms(webui); + webua->resp_page += ",\"configuration\" : "; + parms_all(); - webui->resp_page += ",\"categories\" : "; - webu_json_config_categories(webui); - - webui->resp_page += "}"; + webua->resp_page += ",\"categories\" : "; + categories_list(); + webua->resp_page += "}"; } -static void webu_json_movies_list(ctx_webui *webui) +void cls_webu_json::movies_list() { int indx_mov, indx, movie_cnt; std::string response; char fmt[PATH_MAX]; ctx_dbse_rec db; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { if (it->param_name == "movies") { if (it->param_value == "off") { MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "Movies via webcontrol disabled"); - webui->resp_page += "{\"count\" : 0} "; - webui->resp_page += ",\"device_id\" : "; - webui->resp_page += std::to_string(webui->cam->device_id); - webui->resp_page += "}"; + webua->resp_page += "{\"count\" : 0} "; + webua->resp_page += ",\"device_id\" : "; + webua->resp_page += std::to_string(webua->cam->device_id); + webua->resp_page += "}"; return; } else { break; @@ -269,13 +260,13 @@ static void webu_json_movies_list(ctx_webui *webui) } } - dbse_movies_getlist(webui->motapp, webui->cam->device_id); + dbse_movies_getlist(app, webua->cam->device_id); - movie_cnt = webui->motapp->dbse->movie_cnt; - webui->resp_page += "{"; + movie_cnt = app->dbse->movie_cnt; + webua->resp_page += "{"; indx = 0; for (indx_mov=0; indx_mov < movie_cnt; indx_mov++) { - db = webui->motapp->dbse->movie_list[indx_mov]; + db = app->dbse->movie_list[indx_mov]; if (db.found == true) { if ((db.movie_sz/1000) < 1000) { snprintf(fmt,PATH_MAX,"%.1fKB" @@ -287,152 +278,178 @@ static void webu_json_movies_list(ctx_webui *webui) snprintf(fmt,PATH_MAX,"%.1fGB" ,((double)db.movie_sz/1000000000)); } - webui->resp_page += "\""+ std::to_string(indx) + "\":"; + webua->resp_page += "\""+ std::to_string(indx) + "\":"; - webui->resp_page += "{\"name\": \""; - webui->resp_page += std::string(db.movie_nm) + "\""; + webua->resp_page += "{\"name\": \""; + webua->resp_page += std::string(db.movie_nm) + "\""; - webui->resp_page += ",\"size\": \""; - webui->resp_page += std::string(fmt) + "\""; + webua->resp_page += ",\"size\": \""; + webua->resp_page += std::string(fmt) + "\""; - webui->resp_page += ",\"date\": \""; - webui->resp_page += std::to_string(db.movie_dtl) + "\""; + webua->resp_page += ",\"date\": \""; + webua->resp_page += std::to_string(db.movie_dtl) + "\""; if (db.movie_tmc != NULL) { - webui->resp_page += ",\"time\": \""; - webui->resp_page += std::string(db.movie_tmc) + "\""; + webua->resp_page += ",\"time\": \""; + webua->resp_page += std::string(db.movie_tmc) + "\""; } - webui->resp_page += ",\"diff_avg\": \""; - webui->resp_page += std::to_string(db.diff_avg) + "\""; + webua->resp_page += ",\"diff_avg\": \""; + webua->resp_page += std::to_string(db.diff_avg) + "\""; - webui->resp_page += ",\"sdev_min\": \""; - webui->resp_page += std::to_string(db.sdev_min) + "\""; + webua->resp_page += ",\"sdev_min\": \""; + webua->resp_page += std::to_string(db.sdev_min) + "\""; - webui->resp_page += ",\"sdev_max\": \""; - webui->resp_page += std::to_string(db.sdev_max) + "\""; + webua->resp_page += ",\"sdev_max\": \""; + webua->resp_page += std::to_string(db.sdev_max) + "\""; - webui->resp_page += ",\"sdev_avg\": \""; - webui->resp_page += std::to_string(db.sdev_avg) + "\""; + webua->resp_page += ",\"sdev_avg\": \""; + webua->resp_page += std::to_string(db.sdev_avg) + "\""; - webui->resp_page += "}"; - webui->resp_page += ","; + webua->resp_page += "}"; + webua->resp_page += ","; indx++; } } - webui->resp_page += "\"count\" : " + std::to_string(indx); - webui->resp_page += ",\"device_id\" : "; - webui->resp_page += std::to_string(webui->cam->device_id); - webui->resp_page += "}"; - - return; - + webua->resp_page += "\"count\" : " + std::to_string(indx); + webua->resp_page += ",\"device_id\" : "; + webua->resp_page += std::to_string(webua->cam->device_id); + webua->resp_page += "}"; } -void webu_json_movies(ctx_webui *webui) +void cls_webu_json::movies() { int indx_cam, indx_req; - webui->resp_type = WEBUI_RESP_JSON; + webua->resp_type = WEBUI_RESP_JSON; - webui->resp_page += "{\"movies\" : "; - if (webui->cam == NULL) { - webui->resp_page += "{\"count\" :" + std::to_string(webui->motapp->cam_cnt); + webua->resp_page += "{\"movies\" : "; + if (webua->cam == NULL) { + webua->resp_page += "{\"count\" :" + std::to_string(app->cam_cnt); - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - webui->cam = webui->motapp->cam_list[indx_cam]; - webui->resp_page += ",\""+ std::to_string(indx_cam) + "\":"; - webu_json_movies_list(webui); + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + webua->cam = app->cam_list[indx_cam]; + webua->resp_page += ",\""+ std::to_string(indx_cam) + "\":"; + movies_list(); } - webui->resp_page += "}"; - webui->cam = NULL; + webua->resp_page += "}"; + webua->cam = NULL; } else { indx_req = -1; - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - if (webui->cam->device_id == webui->motapp->cam_list[indx_cam]->device_id){ + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + if (webua->cam->device_id == app->cam_list[indx_cam]->device_id){ indx_req = indx_cam; } } - webui->resp_page += "{\"count\" : 1"; - webui->resp_page += ",\""+ std::to_string(indx_req) + "\":"; - webu_json_movies_list(webui); - webui->resp_page += "}"; + webua->resp_page += "{\"count\" : 1"; + webua->resp_page += ",\""+ std::to_string(indx_req) + "\":"; + movies_list(); + webua->resp_page += "}"; } - webui->resp_page += "}"; - + webua->resp_page += "}"; } -static void webu_json_status_vars(ctx_webui *webui, int indx_cam) +void cls_webu_json::status_vars(int indx_cam) { char buf[32]; struct tm timestamp_tm; struct timespec curr_ts; ctx_dev *cam; - cam = webui->motapp->cam_list[indx_cam]; + cam = app->cam_list[indx_cam]; - webui->resp_page += "{"; + webua->resp_page += "{"; - webui->resp_page += "\"name\":\"" + cam->conf->device_name+"\""; - webui->resp_page += ",\"id\":" + std::to_string(cam->device_id); - webui->resp_page += ",\"width\":" + std::to_string(cam->imgs.width); - webui->resp_page += ",\"height\":" + std::to_string(cam->imgs.height); - webui->resp_page += ",\"fps\":" + std::to_string(cam->lastrate); + webua->resp_page += "\"name\":\"" + cam->conf->device_name+"\""; + webua->resp_page += ",\"id\":" + std::to_string(cam->device_id); + webua->resp_page += ",\"width\":" + std::to_string(cam->imgs.width); + webua->resp_page += ",\"height\":" + std::to_string(cam->imgs.height); + webua->resp_page += ",\"fps\":" + std::to_string(cam->lastrate); clock_gettime(CLOCK_REALTIME, &curr_ts); localtime_r(&curr_ts.tv_sec, ×tamp_tm); strftime(buf, sizeof(buf), "%FT%T", ×tamp_tm); - webui->resp_page += ",\"current_time\":\"" + std::string(buf)+"\""; + webua->resp_page += ",\"current_time\":\"" + std::string(buf)+"\""; - webui->resp_page += ",\"missing_frame_counter\":" + + webua->resp_page += ",\"missing_frame_counter\":" + std::to_string(cam->missing_frame_counter); if (cam->lost_connection) { - webui->resp_page += ",\"lost_connection\":true"; + webua->resp_page += ",\"lost_connection\":true"; } else { - webui->resp_page += ",\"lost_connection\":false"; + webua->resp_page += ",\"lost_connection\":false"; } if (cam->connectionlosttime.tv_sec != 0) { localtime_r(&cam->connectionlosttime.tv_sec, ×tamp_tm); strftime(buf, sizeof(buf), "%FT%T", ×tamp_tm); - webui->resp_page += ",\"connection_lost_time\":\"" + std::string(buf)+"\""; + webua->resp_page += ",\"connection_lost_time\":\"" + std::string(buf)+"\""; } else { - webui->resp_page += ",\"connection_lost_time\":\"\"" ; + webua->resp_page += ",\"connection_lost_time\":\"\"" ; } if (cam->detecting_motion) { - webui->resp_page += ",\"detecting\":true"; + webua->resp_page += ",\"detecting\":true"; } else { - webui->resp_page += ",\"detecting\":false"; + webua->resp_page += ",\"detecting\":false"; } if (cam->pause) { - webui->resp_page += ",\"pause\":true"; + webua->resp_page += ",\"pause\":true"; } else { - webui->resp_page += ",\"pause\":false"; + webua->resp_page += ",\"pause\":false"; } - webui->resp_page += "}"; - + webua->resp_page += "}"; } -void webu_json_status(ctx_webui *webui) +void cls_webu_json::status() { int indx_cam; - webui->resp_type = WEBUI_RESP_JSON; + webua->resp_type = WEBUI_RESP_JSON; - webui->resp_page += "{\"version\" : \"" VERSION "\""; - webui->resp_page += ",\"status\" : "; + webua->resp_page += "{\"version\" : \"" VERSION "\""; + webua->resp_page += ",\"status\" : "; - webui->resp_page += "{\"count\" : " + std::to_string(webui->motapp->cam_cnt); - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - webui->resp_page += ",\"cam" + - std::to_string(webui->motapp->cam_list[indx_cam]->device_id) + "\": "; - webu_json_status_vars(webui, indx_cam); + webua->resp_page += "{\"count\" : " + std::to_string(app->cam_cnt); + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + webua->resp_page += ",\"cam" + + std::to_string(app->cam_list[indx_cam]->device_id) + "\": "; + status_vars(indx_cam); } - webui->resp_page += "}"; - - webui->resp_page += "}"; + webua->resp_page += "}"; + webua->resp_page += "}"; } + +void cls_webu_json::main() +{ + pthread_mutex_lock(&app->mutex_post); + if (webua->uri_cmd1 == "config.json") { + config(); + } else if (webua->uri_cmd1 == "movies.json") { + movies(); + } else if (webua->uri_cmd1 == "status.json") { + status(); + } else { + webua->bad_request(); + pthread_mutex_unlock(&app->mutex_post); + return; + } + pthread_mutex_unlock(&app->mutex_post); + webua->mhd_send(); +} + +cls_webu_json::cls_webu_json(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; +} + +cls_webu_json::~cls_webu_json() +{ + app = nullptr; + webu = nullptr; + webua = nullptr; +} \ No newline at end of file diff --git a/src/webu_json.hpp b/src/webu_json.hpp index 0d1891d7..1bd990ca 100644 --- a/src/webu_json.hpp +++ b/src/webu_json.hpp @@ -18,9 +18,25 @@ #ifndef _INCLUDE_WEBU_JSON_HPP_ #define _INCLUDE_WEBU_JSON_HPP_ - - void webu_json_config(ctx_webui *webui); - void webu_json_movies(ctx_webui *webui); - void webu_json_status(ctx_webui *webui); + class cls_webu_json { + public: + cls_webu_json(cls_webu_ans *p_webua); + ~cls_webu_json(); + void main(); + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; + void parms_item(ctx_config *conf, int indx_parm); + void parms_one(ctx_config *conf); + void parms_all(); + void cameras_list(); + void categories_list(); + void config(); + void movies_list(); + void movies(); + void status_vars(int indx_cam); + void status(); + }; #endif /* _INCLUDE_WEBU_JSON_HPP_ */ diff --git a/src/webu_mpegts.cpp b/src/webu_mpegts.cpp index 1c5ab1e3..de633e85 100644 --- a/src/webu_mpegts.cpp +++ b/src/webu_mpegts.cpp @@ -22,91 +22,78 @@ #include "util.hpp" #include "picture.hpp" #include "webu.hpp" +#include "webu_common.hpp" +#include "webu_ans.hpp" #include "webu_stream.hpp" #include "webu_mpegts.hpp" -#include "alg_sec.hpp" -/* Version independent uint */ -#if (MYFFVER <= 60016) - typedef uint8_t myuint; -#else - typedef const uint8_t myuint; -#endif +/****** Callback functions for MHD ****************************************/ -void webu_mpegts_free_context(ctx_webui *webui) +static int webu_mpegts_avio_buf(void *opaque, myuint *buf, int buf_size) { - if (webui->picture != NULL) { - myframe_free(webui->picture); - webui->picture = NULL; - } - if (webui->ctx_codec != NULL) { - myavcodec_close(webui->ctx_codec); - webui->ctx_codec = NULL; - } - if (webui->fmtctx != NULL) { - if (webui->fmtctx->pb != NULL) { - if (webui->fmtctx->pb->buffer != NULL) { - av_free(webui->fmtctx->pb->buffer); - webui->fmtctx->pb->buffer = NULL; - } - avio_context_free(&webui->fmtctx->pb); - webui->fmtctx->pb = NULL; - } - avformat_free_context(webui->fmtctx); - webui->fmtctx = NULL; - } - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO, _("closed")); - + cls_webu_mpegts *webu_mpegts; + webu_mpegts =(cls_webu_mpegts *)opaque; + return webu_mpegts->avio_buf(buf, buf_size); } -static int webu_mpegts_pic_send(ctx_webui *webui, unsigned char *img) +static ssize_t webu_mpegts_response(void *cls, uint64_t pos, char *buf, size_t max) +{ + cls_webu_mpegts *webu_mpegts; + (void)pos; + webu_mpegts =(cls_webu_mpegts *)cls; + return webu_mpegts->response(buf, max); +} + +/********Class Functions ****************************************************/ + +int cls_webu_mpegts::pic_send(unsigned char *img) { int retcd; char errstr[128]; struct timespec curr_ts; int64_t pts_interval; - if (webui->picture == NULL) { - webui->picture = myframe_alloc(); - webui->picture->linesize[0] = webui->ctx_codec->width; - webui->picture->linesize[1] = webui->ctx_codec->width / 2; - webui->picture->linesize[2] = webui->ctx_codec->width / 2; + if (picture == NULL) { + picture = myframe_alloc(); + picture->linesize[0] = ctx_codec->width; + picture->linesize[1] = ctx_codec->width / 2; + picture->linesize[2] = ctx_codec->width / 2; - webui->picture->format = webui->ctx_codec->pix_fmt; - webui->picture->width = webui->ctx_codec->width; - webui->picture->height = webui->ctx_codec->height; + picture->format = ctx_codec->pix_fmt; + picture->width = ctx_codec->width; + picture->height = ctx_codec->height; - webui->picture->pict_type = AV_PICTURE_TYPE_I; - myframe_key(webui->picture); - webui->picture->pts = 1; + picture->pict_type = AV_PICTURE_TYPE_I; + myframe_key(picture); + picture->pts = 1; } - webui->picture->data[0] = img; - webui->picture->data[1] = webui->picture->data[0] + - (webui->ctx_codec->width * webui->ctx_codec->height); - webui->picture->data[2] = webui->picture->data[1] + - ((webui->ctx_codec->width * webui->ctx_codec->height) / 4); + picture->data[0] = img; + picture->data[1] = picture->data[0] + + (ctx_codec->width * ctx_codec->height); + picture->data[2] = picture->data[1] + + ((ctx_codec->width * ctx_codec->height) / 4); clock_gettime(CLOCK_REALTIME, &curr_ts); - pts_interval = ((1000000L * (curr_ts.tv_sec - webui->start_time.tv_sec)) + - (curr_ts.tv_nsec/1000) - (webui->start_time.tv_nsec/1000)); - webui->picture->pts = av_rescale_q(pts_interval - ,av_make_q(1,1000000L), webui->ctx_codec->time_base); + pts_interval = ((1000000L * (curr_ts.tv_sec - start_time.tv_sec)) + + (curr_ts.tv_nsec/1000) - (start_time.tv_nsec/1000)); + picture->pts = av_rescale_q(pts_interval + ,av_make_q(1,1000000L), ctx_codec->time_base); - retcd = avcodec_send_frame(webui->ctx_codec, webui->picture); + retcd = avcodec_send_frame(ctx_codec, picture); if (retcd < 0 ) { av_strerror(retcd, errstr, sizeof(errstr)); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO , _("Error sending frame for encoding:%s"), errstr); - myframe_free(webui->picture); - webui->picture = NULL; + myframe_free(picture); + picture = NULL; return -1; } return 0; } -static int webu_mpegts_pic_get(ctx_webui *webui) +int cls_webu_mpegts::pic_get() { int retcd; char errstr[128]; @@ -115,7 +102,7 @@ static int webu_mpegts_pic_get(ctx_webui *webui) pkt = NULL; pkt = mypacket_alloc(pkt); - retcd = avcodec_receive_packet(webui->ctx_codec, pkt); + retcd = avcodec_receive_packet(ctx_codec, pkt); if (retcd == AVERROR(EAGAIN)) { mypacket_free(pkt); pkt = NULL; @@ -129,9 +116,9 @@ static int webu_mpegts_pic_get(ctx_webui *webui) return -1; } - pkt->pts = webui->picture->pts; + pkt->pts = picture->pts; - retcd = av_interleaved_write_frame(webui->fmtctx, pkt); + retcd = av_interleaved_write_frame(fmtctx, pkt); if (retcd < 0 ) { av_strerror(retcd, errstr, sizeof(errstr)); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO @@ -145,144 +132,134 @@ static int webu_mpegts_pic_get(ctx_webui *webui) return 0; } -static void webu_mpegts_resetpos(ctx_webui *webui) +void cls_webu_mpegts::resetpos() { - webui->stream_pos = 0; - webui->resp_used = 0; + stream_pos = 0; + webuc->resp_used = 0; } -static int webu_mpegts_getimg(ctx_webui *webui) +int cls_webu_mpegts::getimg() { ctx_stream_data *strm; struct timespec curr_ts; unsigned char *img_data; int img_sz; - if (webu_stream_check_finish(webui)) { - webu_mpegts_resetpos(webui); + if (webuc->check_finish()) { + resetpos(); return 0; } clock_gettime(CLOCK_REALTIME, &curr_ts); - memset(webui->resp_image, '\0', webui->resp_size); - webui->resp_used = 0; + memset(webuc->resp_image, '\0', webuc->resp_size); + webuc->resp_used = 0; - if (webui->device_id > 0) { - if ((webui->cam->detecting_motion == false) && - (webui->motapp->cam_list[webui->camindx]->conf->stream_motion)) { - webui->stream_fps = 1; - } else { - webui->stream_fps = webui->motapp->cam_list[webui->camindx]->conf->stream_maxrate; - } + if (webua->device_id > 0) { + webuc->set_fps(); /* Assign to a local pointer the stream we want */ - if (webui->cnct_type == WEBUI_CNCT_TS_FULL) { - strm = &webui->cam->stream.norm; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SUB) { - strm = &webui->cam->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_TS_MOTION) { - strm = &webui->cam->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SOURCE) { - strm = &webui->cam->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SECONDARY) { - strm = &webui->cam->stream.secondary; + if (webua->cnct_type == WEBUI_CNCT_TS_FULL) { + strm = &webua->cam->stream.norm; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SUB) { + strm = &webua->cam->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_TS_MOTION) { + strm = &webua->cam->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SOURCE) { + strm = &webua->cam->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SECONDARY) { + strm = &webua->cam->stream.secondary; } else { return 0; } - img_sz = (webui->ctx_codec->width * webui->ctx_codec->height * 3)/2; + img_sz = (ctx_codec->width * ctx_codec->height * 3)/2; img_data = (unsigned char*) mymalloc(img_sz); - pthread_mutex_lock(&webui->cam->stream.mutex); + pthread_mutex_lock(&webua->cam->stream.mutex); if (strm->img_data == NULL) { memset(img_data, 0x00, img_sz); } else { memcpy(img_data, strm->img_data, img_sz); strm->consumed = true; } - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); } else { - webu_stream_all_getimg(webui); + webuc->all_getimg(); - img_data = (unsigned char*) mymalloc(webui->motapp->all_sizes->img_sz); + img_data = (unsigned char*) mymalloc(app->all_sizes->img_sz); - memcpy(img_data, webui->all_img_data, webui->motapp->all_sizes->img_sz); + memcpy(img_data, webuc->all_img_data, app->all_sizes->img_sz); } - if (webu_mpegts_pic_send(webui, img_data) < 0) { + if (pic_send(img_data) < 0) { myfree(&img_data); return -1; } myfree(&img_data); - if (webu_mpegts_pic_get(webui) < 0) { + if (pic_get() < 0) { return -1; } return 0; } -static int webu_mpegts_avio_buf(void *opaque, myuint *buf, int buf_size) +int cls_webu_mpegts::avio_buf(myuint *buf, int buf_size) { - ctx_webui *webui =(ctx_webui *)opaque; - - if (webui->resp_size < (size_t)(buf_size + webui->resp_used)) { - webui->resp_size = (size_t)(buf_size + webui->resp_used); - webui->resp_image = (unsigned char*)realloc( - webui->resp_image, webui->resp_size); + if (webuc->resp_size < (size_t)(buf_size + webuc->resp_used)) { + webuc->resp_size = (size_t)(buf_size + webuc->resp_used); + webuc->resp_image = (unsigned char*)realloc( + webuc->resp_image, webuc->resp_size); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("resp_image reallocated %d %d %d") - ,webui->resp_size - ,webui->resp_used + ,webuc->resp_size + ,webuc->resp_used ,buf_size); } - memcpy(webui->resp_image + webui->resp_used, buf, buf_size); - webui->resp_used += buf_size; + memcpy(webuc->resp_image + webuc->resp_used, buf, buf_size); + webuc->resp_used += buf_size; return buf_size; } -static ssize_t webu_mpegts_response(void *cls, uint64_t pos, char *buf, size_t max) +ssize_t cls_webu_mpegts::response(char *buf, size_t max) { - ctx_webui *webui =(ctx_webui *)cls; size_t sent_bytes; - (void)pos; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return -1; } - if (webui->stream_pos == 0) { - webu_stream_delay(webui); - webu_mpegts_resetpos(webui); - if (webu_mpegts_getimg(webui) < 0) { + if (stream_pos == 0) { + webuc->delay(); + resetpos(); + if (getimg() < 0) { return 0; } } /* If we don't have anything in the avio buffer at this point bail out */ - if (webui->resp_used == 0) { - webu_mpegts_resetpos(webui); + if (webuc->resp_used == 0) { + resetpos(); return 0; } - if ((webui->resp_used - webui->stream_pos) > max) { + if ((webuc->resp_used - stream_pos) > max) { sent_bytes = max; } else { - sent_bytes = webui->resp_used - webui->stream_pos; + sent_bytes = webuc->resp_used - stream_pos; } - memcpy(buf, webui->resp_image + webui->stream_pos, sent_bytes); + memcpy(buf, webuc->resp_image + stream_pos, sent_bytes); - webui->stream_pos = webui->stream_pos + sent_bytes; - if (webui->stream_pos >= webui->resp_used) { - webui->stream_pos = 0; + stream_pos = stream_pos + sent_bytes; + if (stream_pos >= webuc->resp_used) { + stream_pos = 0; } return sent_bytes; - } -int webu_mpegts_open(ctx_webui *webui) +int cls_webu_mpegts::open_mpegts() { int retcd, img_w, img_h; char errstr[128]; @@ -290,131 +267,126 @@ int webu_mpegts_open(ctx_webui *webui) AVStream *strm; const AVCodec *codec; AVDictionary *opts; + size_t aviobuf_sz; opts = NULL; - webui->picture = NULL; - webui->ctx_codec = NULL; - webui->fmtctx = NULL; - webui->stream_fps = 10000; /* For quick start up*/ - clock_gettime(CLOCK_REALTIME, &webui->start_time); + webuc->stream_fps = 10000; /* For quick start up*/ + aviobuf_sz = 4096; + clock_gettime(CLOCK_REALTIME, &start_time); - webui->fmtctx = avformat_alloc_context(); - webui->fmtctx->oformat = av_guess_format("mpegts", NULL, NULL); - webui->fmtctx->video_codec_id = MY_CODEC_ID_H264; + fmtctx = avformat_alloc_context(); + fmtctx->oformat = av_guess_format("mpegts", NULL, NULL); + fmtctx->video_codec_id = MY_CODEC_ID_H264; codec = avcodec_find_encoder(MY_CODEC_ID_H264); - strm = avformat_new_stream(webui->fmtctx, codec); + strm = avformat_new_stream(fmtctx, codec); - if (webui->device_id > 0) { - if ((webui->cnct_type == WEBUI_CNCT_TS_SUB) && - ((webui->cam->imgs.width % 16) == 0) && - ((webui->cam->imgs.height % 16) == 0)) { - img_w = (webui->cam->imgs.width/2); - img_h = (webui->cam->imgs.height/2); + if (webua->device_id > 0) { + if ((webua->cnct_type == WEBUI_CNCT_TS_SUB) && + ((webua->cam->imgs.width % 16) == 0) && + ((webua->cam->imgs.height % 16) == 0)) { + img_w = (webua->cam->imgs.width/2); + img_h = (webua->cam->imgs.height/2); } else { - img_w = webui->cam->imgs.width; - img_h = webui->cam->imgs.height; + img_w = webua->cam->imgs.width; + img_h = webua->cam->imgs.height; } } else { - webu_stream_all_sizes(webui); - img_w = webui->motapp->all_sizes->width; - img_h = webui->motapp->all_sizes->height; + webuc->all_sizes(); + img_w = app->all_sizes->width; + img_h = app->all_sizes->height; } - webui->ctx_codec = avcodec_alloc_context3(codec); - webui->ctx_codec->gop_size = 15; - webui->ctx_codec->codec_id = MY_CODEC_ID_H264; - webui->ctx_codec->codec_type = AVMEDIA_TYPE_VIDEO; - webui->ctx_codec->bit_rate = 400000; - webui->ctx_codec->width = img_w; - webui->ctx_codec->height = img_h; - webui->ctx_codec->time_base.num = 1; - webui->ctx_codec->time_base.den = 90000; - webui->ctx_codec->pix_fmt = MY_PIX_FMT_YUV420P; - webui->ctx_codec->max_b_frames = 1; - webui->ctx_codec->flags |= MY_CODEC_FLAG_GLOBAL_HEADER; - webui->ctx_codec->framerate.num = 1; - webui->ctx_codec->framerate.den = 1; - av_opt_set(webui->ctx_codec->priv_data, "profile", "main", 0); - av_opt_set(webui->ctx_codec->priv_data, "crf", "22", 0); - av_opt_set(webui->ctx_codec->priv_data, "tune", "zerolatency", 0); - av_opt_set(webui->ctx_codec->priv_data, "preset", "superfast",0); + ctx_codec = avcodec_alloc_context3(codec); + ctx_codec->gop_size = 15; + ctx_codec->codec_id = MY_CODEC_ID_H264; + ctx_codec->codec_type = AVMEDIA_TYPE_VIDEO; + ctx_codec->bit_rate = 400000; + ctx_codec->width = img_w; + ctx_codec->height = img_h; + ctx_codec->time_base.num = 1; + ctx_codec->time_base.den = 90000; + ctx_codec->pix_fmt = MY_PIX_FMT_YUV420P; + ctx_codec->max_b_frames = 1; + ctx_codec->flags |= MY_CODEC_FLAG_GLOBAL_HEADER; + ctx_codec->framerate.num = 1; + ctx_codec->framerate.den = 1; + av_opt_set(ctx_codec->priv_data, "profile", "main", 0); + av_opt_set(ctx_codec->priv_data, "crf", "22", 0); + av_opt_set(ctx_codec->priv_data, "tune", "zerolatency", 0); + av_opt_set(ctx_codec->priv_data, "preset", "superfast",0); av_dict_set(&opts, "movflags", "empty_moov", 0); - retcd = avcodec_open2(webui->ctx_codec, codec, &opts); + retcd = avcodec_open2(ctx_codec, codec, &opts); if (retcd < 0) { av_strerror(retcd, errstr, sizeof(errstr)); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("Failed to copy decoder parameters!: %s"), errstr); - webu_mpegts_free_context(webui); av_dict_free(&opts); return -1; } - retcd = avcodec_parameters_from_context(strm->codecpar, webui->ctx_codec); + retcd = avcodec_parameters_from_context(strm->codecpar, ctx_codec); if (retcd < 0) { av_strerror(retcd, errstr, sizeof(errstr)); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("Failed to copy decoder parameters!: %s"), errstr); - webu_mpegts_free_context(webui); av_dict_free(&opts); return -1; } - if (webui->device_id > 0) { - webu_stream_checkbuffers(webui); + if (webua->device_id > 0) { + webuc->one_buffer(); } else { - webu_stream_all_buffers(webui); + webuc->all_buffer(); } - webui->aviobuf_sz = 4096; - buf_image = (unsigned char*)av_malloc(webui->aviobuf_sz); - webui->fmtctx->pb = avio_alloc_context( - buf_image, (int)webui->aviobuf_sz, 1, webui - , NULL, &webu_mpegts_avio_buf, NULL); - webui->fmtctx->flags = AVFMT_FLAG_CUSTOM_IO; - retcd = avformat_write_header(webui->fmtctx, &opts); + buf_image = (unsigned char*)av_malloc(aviobuf_sz); + fmtctx->pb = avio_alloc_context( + buf_image, (int)aviobuf_sz, 1, this + , NULL, &webu_mpegts_avio_buf, NULL); + fmtctx->flags = AVFMT_FLAG_CUSTOM_IO; + + retcd = avformat_write_header(fmtctx, &opts); if (retcd < 0) { av_strerror(retcd, errstr, sizeof(errstr)); MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("Failed to write header!: %s"), errstr); - webu_mpegts_free_context(webui); av_dict_free(&opts); return -1; } - webui->stream_pos = 0; - webui->resp_used = 0; + stream_pos = 0; + webuc->resp_used = 0; av_dict_free(&opts); return 0; - } -mhdrslt webu_mpegts_main(ctx_webui *webui) +mhdrslt cls_webu_mpegts::main() { mhdrslt retcd; struct MHD_Response *response; - p_lst *lst = &webui->motapp->webcontrol_headers->params_array; + p_lst *lst = &webu->wb_headers->params_array; p_it it; - if (webu_mpegts_open(webui) < 0 ) { - MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Unable top open mpegts")); + if (open_mpegts() < 0 ) { + MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Unable to open mpegts")); return MHD_NO; } - clock_gettime(CLOCK_MONOTONIC, &webui->time_last); + clock_gettime(CLOCK_MONOTONIC, &webuc->time_last); response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 4096 - ,&webu_mpegts_response, webui, NULL); + ,&webu_mpegts_response, this, NULL); if (!response) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response")); return MHD_NO; } - if (webui->motapp->webcontrol_headers->params_count > 0) { + if (webu->wb_headers->params_count > 0) { for (it = lst->begin(); it != lst->end(); it++) { MHD_add_response_header (response , it->param_name.c_str(), it->param_value.c_str()); @@ -424,10 +396,48 @@ mhdrslt webu_mpegts_main(ctx_webui *webui) MHD_add_response_header(response, "Content-Transfer-Encoding", "BINARY"); MHD_add_response_header(response, "Content-Type", "application/octet-stream"); - retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response); + retcd = MHD_queue_response (webua->connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return retcd; - } +cls_webu_mpegts::cls_webu_mpegts(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; + webuc = new cls_webu_common(p_webua); + stream_pos = 0; + picture = nullptr;; + ctx_codec = nullptr; + fmtctx = nullptr; +} + +cls_webu_mpegts::~cls_webu_mpegts() +{ + app = nullptr; + webu = nullptr; + webua = nullptr; + delete webuc; + if (picture != nullptr) { + myframe_free(picture); + picture = nullptr; + } + if (ctx_codec != nullptr) { + myavcodec_close(ctx_codec); + ctx_codec = nullptr; + } + if (fmtctx != nullptr) { + if (fmtctx->pb != nullptr) { + if (fmtctx->pb->buffer != nullptr) { + av_free(fmtctx->pb->buffer); + fmtctx->pb->buffer = nullptr; + } + avio_context_free(&fmtctx->pb); + fmtctx->pb = nullptr; + } + avformat_free_context(fmtctx); + fmtctx = nullptr; + } +} diff --git a/src/webu_mpegts.hpp b/src/webu_mpegts.hpp index 75486770..83e47197 100644 --- a/src/webu_mpegts.hpp +++ b/src/webu_mpegts.hpp @@ -19,7 +19,31 @@ #ifndef _INCLUDE_WEBU_MPEGTS_HPP_ #define _INCLUDE_WEBU_MPEGTS_HPP_ - mhdrslt webu_mpegts_main(ctx_webui *webui); - void webu_mpegts_free_context(ctx_webui *webui); + class cls_webu_mpegts { + public: + cls_webu_mpegts(cls_webu_ans *p_webua); + ~cls_webu_mpegts(); + int avio_buf(myuint *buf, int buf_size); + ssize_t response(char *buf, size_t max); + mhdrslt main(); + + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; + cls_webu_common *webuc; + + AVFrame *picture; + AVFormatContext *fmtctx; + AVCodecContext *ctx_codec; + size_t stream_pos; /* Stream position of sent image */ + struct timespec start_time; /* Start time of the stream*/ + + int pic_send(unsigned char *img); + int pic_get(); + void resetpos(); + int getimg(); + int open_mpegts(); + }; #endif /* _INCLUDE_WEBU_MPEGTS_HPP_ */ diff --git a/src/webu_post.cpp b/src/webu_post.cpp index c3a4ae8d..a89ebe1a 100644 --- a/src/webu_post.cpp +++ b/src/webu_post.cpp @@ -21,13 +21,35 @@ #include "logger.hpp" #include "util.hpp" #include "webu.hpp" +#include "webu_ans.hpp" +#include "webu_html.hpp" +#include "webu_common.hpp" #include "webu_post.hpp" +/**************Callback functions for MHD **********************/ + +mhdrslt webup_iterate_post (void *ptr, enum MHD_ValueKind kind + , const char *key, const char *filename, const char *content_type + , const char *transfer_encoding, const char *data, uint64_t off, size_t datasz) +{ + (void) kind; + (void) filename; + (void) content_type; + (void) transfer_encoding; + (void) off; + cls_webu_post *webu_post; + + webu_post = (cls_webu_post *)ptr; + return webu_post->iterate_post(key, data, datasz); +} + +/**************Class methods**********************/ + /* Process the add camera action */ -static void webu_post_cam_add(ctx_webui *webui) +void cls_webu_post::cam_add() { int indx, maxcnt; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -45,15 +67,15 @@ static void webu_post_cam_add(ctx_webui *webui) maxcnt = 100; - webui->motapp->cam_add = true; + app->cam_add = true; indx = 0; - while ((webui->motapp->cam_add == true) && (indx < maxcnt)) { + while ((app->cam_add == true) && (indx < maxcnt)) { SLEEP(0, 50000000) indx++; } if (indx == maxcnt) { - webui->motapp->cam_add = false; + app->cam_add = false; MOTPLS_LOG(ERR, TYPE_ALL, NO_ERRNO, "Error adding camera. Timed out"); return; } @@ -61,11 +83,12 @@ static void webu_post_cam_add(ctx_webui *webui) MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "New camera added."); } + /* Process the delete camera action */ -static void webu_post_cam_delete(ctx_webui *webui) +void cls_webu_post::cam_delete() { int indx, maxcnt; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -79,66 +102,65 @@ static void webu_post_cam_delete(ctx_webui *webui) } } - if (webui->camindx == -1) { + if (webua->camindx == -1) { MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "No camera specified for deletion." ); return; } else { MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO, "Deleting camera."); } - webui->motapp->cam_delete = webui->camindx; + app->cam_delete = webua->camindx; maxcnt = 100; indx = 0; - while ((webui->motapp->cam_delete != -1) && (indx < maxcnt)) { + while ((app->cam_delete != -1) && (indx < maxcnt)) { SLEEP(0, 50000000) indx++; } if (indx == maxcnt) { MOTPLS_LOG(ERR, TYPE_ALL, NO_ERRNO, "Error stopping camera. Timed out shutting down"); - webui->motapp->cam_delete = -1; + app->cam_delete = -1; return; } - } /* Get the command, device_id and camera index from the post data */ -void webu_post_cmdindx(ctx_webui *webui) +void cls_webu_post::parse_cmd() { int indx; - webui->post_cmd = ""; - webui->camindx = -1; - webui->device_id = -1; + post_cmd = ""; + webua->camindx = -1; + webua->device_id = -1; - for (indx = 0; indx < webui->post_sz; indx++) { - if (mystreq(webui->post_info[indx].key_nm, "command")) { - webui->post_cmd = webui->post_info[indx].key_val; + for (indx = 0; indx < post_sz; indx++) { + if (mystreq(post_info[indx].key_nm, "command")) { + post_cmd = post_info[indx].key_val; } - if (mystreq(webui->post_info[indx].key_nm, "camid")) { - webui->device_id = atoi(webui->post_info[indx].key_val); + if (mystreq(post_info[indx].key_nm, "camid")) { + webua->device_id = atoi(post_info[indx].key_val); } MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO ,"key: %s value: %s " - , webui->post_info[indx].key_nm - , webui->post_info[indx].key_val + , post_info[indx].key_nm + , post_info[indx].key_val ); } - if (webui->post_cmd == "") { + if (post_cmd == "") { MOTPLS_LOG(ERR, TYPE_ALL, NO_ERRNO , "Invalid post request. No command"); return; } - if (webui->device_id == -1) { + if (webua->device_id == -1) { MOTPLS_LOG(ERR, TYPE_ALL, NO_ERRNO , "Invalid post request. No camera id provided"); return; } - for (indx=0; indxmotapp->cam_cnt; indx++) { - if (webui->motapp->cam_list[indx]->device_id == webui->device_id) { - webui->camindx = indx; + for (indx=0; indxcam_cnt; indx++) { + if (app->cam_list[indx]->device_id == webua->device_id) { + webua->camindx = indx; break; } } @@ -146,10 +168,10 @@ void webu_post_cmdindx(ctx_webui *webui) } /* Process the event end action */ -void webu_post_action_eventend(ctx_webui *webui) +void cls_webu_post::action_eventend() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -163,21 +185,21 @@ void webu_post_action_eventend(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->event_stop = true; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->event_stop = true; } } else { - webui->motapp->cam_list[webui->camindx]->event_stop = true; + app->cam_list[webua->camindx]->event_stop = true; } } /* Process the event start action */ -void webu_post_action_eventstart(ctx_webui *webui) +void cls_webu_post::action_eventstart() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -191,21 +213,21 @@ void webu_post_action_eventstart(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->event_user = true; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->event_user = true; } } else { - webui->motapp->cam_list[webui->camindx]->event_user = true; + app->cam_list[webua->camindx]->event_user = true; } } /* Process the snapshot action */ -void webu_post_action_snapshot(ctx_webui *webui) +void cls_webu_post::action_snapshot() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -219,21 +241,21 @@ void webu_post_action_snapshot(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->snapshot = true; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->snapshot = true; } } else { - webui->motapp->cam_list[webui->camindx]->snapshot = true; + app->cam_list[webua->camindx]->snapshot = true; } } /* Process the pause action */ -void webu_post_action_pause(ctx_webui *webui) +void cls_webu_post::action_pause() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -247,21 +269,21 @@ void webu_post_action_pause(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->pause = true; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->pause = true; } } else { - webui->motapp->cam_list[webui->camindx]->pause = true; + app->cam_list[webua->camindx]->pause = true; } } /* Process the unpause action */ -void webu_post_action_unpause(ctx_webui *webui) +void cls_webu_post::action_unpause() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -275,21 +297,21 @@ void webu_post_action_unpause(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->pause = false; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->pause = false; } } else { - webui->motapp->cam_list[webui->camindx]->pause = false; + app->cam_list[webua->camindx]->pause = false; } } /* Process the restart action */ -void webu_post_action_restart(ctx_webui *webui) +void cls_webu_post::action_restart() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -302,26 +324,26 @@ void webu_post_action_restart(ctx_webui *webui) } } } - if (webui->device_id == 0) { + if (webua->device_id == 0) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Restarting all cameras")); - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->restart_dev = true; - webui->motapp->cam_list[indx]->finish_dev = true; + for (indx=0; indxcam_cnt; indx++) { + app->cam_list[indx]->restart_dev = true; + app->cam_list[indx]->finish_dev = true; } } else { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO , _("Restarting camera %d") - , webui->motapp->cam_list[webui->camindx]->device_id); - webui->motapp->cam_list[webui->camindx]->restart_dev = true; - webui->motapp->cam_list[webui->camindx]->finish_dev = true; + , app->cam_list[webua->camindx]->device_id); + app->cam_list[webua->camindx]->restart_dev = true; + app->cam_list[webua->camindx]->finish_dev = true; } } /* Process the stop action */ -void webu_post_action_stop(ctx_webui *webui) +void cls_webu_post::action_stop() { int indx; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -334,35 +356,35 @@ void webu_post_action_stop(ctx_webui *webui) } } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO , _("Stopping cam %d") - , webui->motapp->cam_list[indx]->device_id); - webui->motapp->cam_list[indx]->restart_dev = false; - webui->motapp->cam_list[indx]->event_stop = true; - webui->motapp->cam_list[indx]->event_user = false; - webui->motapp->cam_list[indx]->finish_dev = true; + , app->cam_list[indx]->device_id); + app->cam_list[indx]->restart_dev = false; + app->cam_list[indx]->event_stop = true; + app->cam_list[indx]->event_user = false; + app->cam_list[indx]->finish_dev = true; } } else { MOTPLS_LOG(NTC, TYPE_STREAM, NO_ERRNO , _("Stopping cam %d") - , webui->motapp->cam_list[webui->camindx]->device_id); - webui->motapp->cam_list[webui->camindx]->restart_dev = false; - webui->motapp->cam_list[webui->camindx]->event_stop = true; - webui->motapp->cam_list[webui->camindx]->event_user = false; - webui->motapp->cam_list[webui->camindx]->finish_dev = true; + , app->cam_list[webua->camindx]->device_id); + app->cam_list[webua->camindx]->restart_dev = false; + app->cam_list[webua->camindx]->event_stop = true; + app->cam_list[webua->camindx]->event_user = false; + app->cam_list[webua->camindx]->finish_dev = true; } } /* Process the action_user */ -void webu_post_action_user(ctx_webui *webui) +void cls_webu_post::action_user() { int indx, indx2; ctx_dev *cam; std::string tmp; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -376,13 +398,13 @@ void webu_post_action_user(ctx_webui *webui) } } - if (webui->device_id == 0) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; + if (webua->device_id == 0) { + for (indx=0; indxcam_cnt; indx++) { + cam = app->cam_list[indx]; cam->action_user[0] = '\0'; - for (indx2 = 0; indx2 < webui->post_sz; indx2++) { - if (mystreq(webui->post_info[indx2].key_nm, "user")) { - tmp = std::string(webui->post_info[indx2].key_val); + for (indx2 = 0; indx2 < post_sz; indx2++) { + if (mystreq(post_info[indx2].key_nm, "user")) { + tmp = std::string(post_info[indx2].key_val); } } for (indx2 = 0; indx2<(int)tmp.length(); indx2++) { @@ -400,11 +422,11 @@ void webu_post_action_user(ctx_webui *webui) util_exec_command(cam, cam->conf->on_action_user.c_str(), NULL); } } else { - cam = webui->motapp->cam_list[webui->camindx]; + cam = app->cam_list[webua->camindx]; cam->action_user[0] = '\0'; - for (indx2 = 0; indx2 < webui->post_sz; indx2++) { - if (mystreq(webui->post_info[indx2].key_nm, "user")) { - tmp = std::string(webui->post_info[indx2].key_val); + for (indx2 = 0; indx2 < post_sz; indx2++) { + if (mystreq(post_info[indx2].key_nm, "user")) { + tmp = std::string(post_info[indx2].key_val); } } for (indx2 = 0; indx2<(int)tmp.length(); indx2++) { @@ -426,9 +448,9 @@ void webu_post_action_user(ctx_webui *webui) } /* Process the write config action */ -void webu_post_write_config(ctx_webui *webui) +void cls_webu_post::write_config() { - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; for (it = lst->begin(); it != lst->end(); it++) { @@ -442,19 +464,19 @@ void webu_post_write_config(ctx_webui *webui) } } - conf_parms_write(webui->motapp); + conf_parms_write(app); } /* Process the configuration parameters */ -static void webu_post_config(ctx_webui *webui) +void cls_webu_post::config() { int indx, indx2; std::string tmpname; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; - if (webui->camindx == -1) { + if (webua->camindx == -1) { return; } @@ -469,11 +491,11 @@ static void webu_post_config(ctx_webui *webui) } } - for (indx = 0; indx < webui->post_sz; indx++) { - if (mystrne(webui->post_info[indx].key_nm, "command") && - mystrne(webui->post_info[indx].key_nm, "camid")) { + for (indx = 0; indx < post_sz; indx++) { + if (mystrne(post_info[indx].key_nm, "command") && + mystrne(post_info[indx].key_nm, "camid")) { - tmpname = webui->post_info[indx].key_nm; + tmpname = post_info[indx].key_nm; indx2=0; while (config_parms_depr[indx2].parm_name != "") { if (config_parms_depr[indx2].parm_name == tmpname) { @@ -486,7 +508,7 @@ static void webu_post_config(ctx_webui *webui) /* Ignore any requests for parms above webcontrol_parms level. */ indx2=0; while (config_parms[indx2].parm_name != "") { - if ((config_parms[indx2].webui_level > webui->motapp->conf->webcontrol_parms) || + if ((config_parms[indx2].webui_level > app->conf->webcontrol_parms) || (config_parms[indx2].webui_level == WEBUI_LEVEL_NEVER) ) { indx2++; continue; @@ -499,13 +521,13 @@ static void webu_post_config(ctx_webui *webui) if (config_parms[indx2].parm_name != "") { if (config_parms[indx2].parm_cat == PARM_CAT_00) { - conf_edit_set(webui->motapp->conf + conf_edit_set(app->conf , config_parms[indx2].parm_name - , webui->post_info[indx].key_val); + , post_info[indx].key_val); } else { - conf_edit_set(webui->motapp->cam_list[webui->camindx]->conf + conf_edit_set(app->cam_list[webua->camindx]->conf , config_parms[indx2].parm_name - , webui->post_info[indx].key_val); + , post_info[indx].key_val); } } } @@ -514,13 +536,13 @@ static void webu_post_config(ctx_webui *webui) } /* Process the ptz action */ -void webu_post_ptz(ctx_webui *webui) +void cls_webu_post::ptz() { ctx_dev *cam; - p_lst *lst = &webui->motapp->webcontrol_actions->params_array; + p_lst *lst = &webu->wb_actions->params_array; p_it it; - if (webui->camindx == -1) { + if (webua->camindx == -1) { return; } @@ -534,34 +556,34 @@ void webu_post_ptz(ctx_webui *webui) } } } - cam = webui->motapp->cam_list[webui->camindx]; + cam = app->cam_list[webua->camindx]; - if ((webui->post_cmd == "pan_left") && + if ((post_cmd == "pan_left") && (cam->conf->ptz_pan_left != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_pan_left.c_str(), NULL); - } else if ((webui->post_cmd == "pan_right") && + } else if ((post_cmd == "pan_right") && (cam->conf->ptz_pan_right != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_pan_right.c_str(), NULL); - } else if ((webui->post_cmd == "tilt_up") && + } else if ((post_cmd == "tilt_up") && (cam->conf->ptz_tilt_up != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_tilt_up.c_str(), NULL); - } else if ((webui->post_cmd == "tilt_down") && + } else if ((post_cmd == "tilt_down") && (cam->conf->ptz_tilt_down != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_tilt_down.c_str(), NULL); - } else if ((webui->post_cmd == "zoom_in") && + } else if ((post_cmd == "zoom_in") && (cam->conf->ptz_zoom_in != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_zoom_in.c_str(), NULL); - } else if ((webui->post_cmd == "zoom_out") && + } else if ((post_cmd == "zoom_out") && (cam->conf->ptz_zoom_out != "")) { cam->frame_skip = cam->conf->ptz_wait; util_exec_command(cam, cam->conf->ptz_zoom_out.c_str(), NULL); @@ -573,65 +595,189 @@ void webu_post_ptz(ctx_webui *webui) } /* Process the actions from the webcontrol that the user requested */ -void webu_post_main(ctx_webui *webui) +void cls_webu_post::process_actions() { + parse_cmd(); - webu_post_cmdindx(webui); - - if (webui->post_cmd == "") { + if (post_cmd == "") { return; } - if (webui->post_cmd == "eventend") { - webu_post_action_eventend(webui); + if (post_cmd == "eventend") { + action_eventend(); - } else if (webui->post_cmd == "eventstart") { - webu_post_action_eventstart(webui); + } else if (post_cmd == "eventstart") { + action_eventstart(); - } else if (webui->post_cmd == "snapshot") { - webu_post_action_snapshot(webui); + } else if (post_cmd == "snapshot") { + action_snapshot(); - } else if (webui->post_cmd == "pause") { - webu_post_action_pause(webui); + } else if (post_cmd == "pause") { + action_pause(); - } else if (webui->post_cmd == "unpause") { - webu_post_action_unpause(webui); + } else if (post_cmd == "unpause") { + action_unpause(); - } else if (webui->post_cmd == "restart") { - webu_post_action_restart(webui); + } else if (post_cmd == "restart") { + action_restart(); - } else if (webui->post_cmd == "stop") { - webu_post_action_stop(webui); + } else if (post_cmd == "stop") { + action_stop(); - } else if (webui->post_cmd == "config_write") { - webu_post_write_config(webui); + } else if (post_cmd == "config_write") { + write_config(); - } else if (webui->post_cmd == "camera_add") { - webu_post_cam_add(webui); + } else if (post_cmd == "camera_add") { + cam_add(); - } else if (webui->post_cmd == "camera_delete") { - webu_post_cam_delete(webui); + } else if (post_cmd == "camera_delete") { + cam_delete(); - } else if (webui->post_cmd == "config") { - webu_post_config(webui); + } else if (post_cmd == "config") { + config(); - } else if (webui->post_cmd == "action_user") { - webu_post_action_user(webui); + } else if (post_cmd == "action_user") { + action_user(); } else if ( - (webui->post_cmd == "pan_left") || - (webui->post_cmd == "pan_right") || - (webui->post_cmd == "tilt_up") || - (webui->post_cmd == "tilt_down") || - (webui->post_cmd == "zoom_in") || - (webui->post_cmd == "zoom_out")) { - webu_post_ptz(webui); + (post_cmd == "pan_left") || + (post_cmd == "pan_right") || + (post_cmd == "tilt_up") || + (post_cmd == "tilt_down") || + (post_cmd == "zoom_in") || + (post_cmd == "zoom_out")) { + ptz(); } else { MOTPLS_LOG(INF, TYPE_STREAM, NO_ERRNO , _("Invalid action requested: command: >%s< camindx : >%d< ") - , webui->post_cmd.c_str(), webui->camindx); + , post_cmd.c_str(), webua->camindx); } } +/*Append more data on to an existing entry in the post info structure */ +void cls_webu_post::iterate_post_append(int indx + , const char *data, size_t datasz) +{ + post_info[indx].key_val = (char*)realloc( + post_info[indx].key_val + , post_info[indx].key_sz + datasz + 1); + + memset(post_info[indx].key_val + + post_info[indx].key_sz, 0, datasz + 1); + + if (datasz > 0) { + memcpy(post_info[indx].key_val + + post_info[indx].key_sz, data, datasz); + } + + post_info[indx].key_sz += datasz; +} + +/*Create new entry in the post info structure */ +void cls_webu_post::iterate_post_new(const char *key + , const char *data, size_t datasz) +{ + int retcd; + + post_sz++; + if (post_sz == 1) { + post_info = (ctx_key *)malloc(sizeof(ctx_key)); + } else { + post_info = (ctx_key *)realloc(post_info + , post_sz * sizeof(ctx_key)); + } + + post_info[post_sz-1].key_nm = (char*)malloc(strlen(key)+1); + retcd = snprintf(post_info[post_sz-1].key_nm, strlen(key)+1, "%s", key); + + post_info[post_sz-1].key_val = (char*)malloc(datasz+1); + memset(post_info[post_sz-1].key_val,0,datasz+1); + if (datasz > 0) { + memcpy(post_info[post_sz-1].key_val, data, datasz); + } + + post_info[post_sz-1].key_sz = datasz; + + if (retcd < 0) { + printf("Error processing post data\n"); + } +} + +mhdrslt cls_webu_post::iterate_post (const char *key, const char *data, size_t datasz) +{ + int indx; + + for (indx=0; indx < post_sz; indx++) { + if (mystreq(post_info[indx].key_nm, key)) { + break; + } + } + if (indx < post_sz) { + iterate_post_append(indx, data, datasz); + } else { + iterate_post_new(key, data, datasz); + } + + return MHD_YES; +} + +mhdrslt cls_webu_post::processor_init() +{ + post_processor = MHD_create_post_processor (webua->connection + , WEBUI_POST_BFRSZ, webup_iterate_post, (void *)this); + if (post_processor == NULL) { + return MHD_NO; + } + return MHD_YES; +} + +mhdrslt cls_webu_post::processor_start(const char *upload_data, size_t *upload_data_size) +{ + mhdrslt retcd; + + if (*upload_data_size != 0) { + retcd = MHD_post_process (post_processor, upload_data, *upload_data_size); + *upload_data_size = 0; + } else { + pthread_mutex_lock(&app->mutex_post); + process_actions(); + pthread_mutex_unlock(&app->mutex_post); + /* Send updated page back to user */ + webu_html = new cls_webu_html(webua); + webu_html->main(); + delete webu_html; + webu_html = nullptr; + webua->mhd_send(); + retcd = MHD_YES; + } + return retcd; +} + +cls_webu_post::cls_webu_post(cls_webu_ans *p_webua) +{ + app = p_webua->app; + webu = p_webua->webu; + webua = p_webua; + + post_processor = nullptr; + post_info = nullptr; + post_sz = 0; + +} + +cls_webu_post::~cls_webu_post() +{ + int indx; + + if (post_processor != nullptr) { + MHD_destroy_post_processor (post_processor); + } + + for (indx = 0; indxcam == NULL) { - return; - } - if (webui->resp_size < (size_t)webui->cam->imgs.size_norm) { - if (webui->resp_image != NULL) { - myfree(&webui->resp_image); - } - webui->resp_image = (unsigned char*) mymalloc(webui->cam->imgs.size_norm); - memset(webui->resp_image,'\0',webui->cam->imgs.size_norm); - webui->resp_size = webui->cam->imgs.size_norm; - webui->resp_used = 0; - } + cls_webu_stream *webu_stream = (cls_webu_stream *)cls; + (void)pos; + return webu_stream->mjpeg_response(buf, max); } -void webu_stream_img_resize(ctx_dev *cam, uint8_t *src, uint8_t *dst, int dst_w, int dst_h) -{ - int retcd, img_sz, src_h, src_w; - char errstr[128]; - uint8_t *buf; - AVFrame *frm_in, *frm_out; - struct SwsContext *swsctx; - - src_h = cam->imgs.height; - src_w = cam->imgs.width; - - img_sz = (dst_h * dst_w * 3)/2; - memset(dst, 0x00, (size_t)img_sz); - - frm_in = myframe_alloc(); - if (frm_in == NULL) { - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - , _("Unable to allocate frm_in.")); - return; - } - - frm_out = myframe_alloc(); - if (frm_out == NULL) { - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - , _("Unable to allocate frm_out.")); - myframe_free(frm_in); - return; - } - - retcd = myimage_fill_arrays(frm_in, src, MY_PIX_FMT_YUV420P, src_w, src_h); - if (retcd < 0) { - av_strerror(retcd, errstr, sizeof(errstr)); - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - , "Error filling arrays: %s", errstr); - myframe_free(frm_in); - myframe_free(frm_out); - return; - } - - buf = (uint8_t *)mymalloc((size_t)img_sz); - - retcd = myimage_fill_arrays(frm_out, buf, MY_PIX_FMT_YUV420P, dst_w, dst_h); - if (retcd < 0) { - av_strerror(retcd, errstr, sizeof(errstr)); - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - , "Error Filling array 2: %s", errstr); - free(buf); - myframe_free(frm_in); - myframe_free(frm_out); - return; - } - - swsctx = sws_getContext( - src_w, src_h, MY_PIX_FMT_YUV420P - ,dst_w, dst_h, MY_PIX_FMT_YUV420P - ,SWS_BICUBIC, NULL, NULL, NULL); - if (swsctx == NULL) { - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - , _("Unable to allocate scaling context.")); - free(buf); - myframe_free(frm_in); - myframe_free(frm_out); - return; - } - - retcd = sws_scale(swsctx - , (const uint8_t* const *)frm_in->data, frm_in->linesize - , 0, src_h, frm_out->data, frm_out->linesize); - if (retcd < 0) { - av_strerror(retcd, errstr, sizeof(errstr)); - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - ,_("Error resizing/reformatting: %s"), errstr); - free(buf); - myframe_free(frm_in); - myframe_free(frm_out); - sws_freeContext(swsctx); - return; - } - - retcd = myimage_copy_to_buffer( - frm_out, (uint8_t *)dst - ,MY_PIX_FMT_YUV420P, dst_w, dst_h, img_sz); - if (retcd < 0) { - av_strerror(retcd, errstr, sizeof(errstr)); - MOTPLS_LOG(ERR, TYPE_NETCAM, NO_ERRNO - ,_("Error putting frame into output buffer: %s"), errstr); - free(buf); - myframe_free(frm_in); - myframe_free(frm_out); - sws_freeContext(swsctx); - return; - } - - free(buf); - myframe_free(frm_in); - myframe_free(frm_out); - sws_freeContext(swsctx); - -} - -void webu_stream_img_sizes(ctx_webui *webui, ctx_dev *cam, int &img_w, int &img_h) -{ - if (((webui->cnct_type == WEBUI_CNCT_JPG_SUB) || - (webui->cnct_type == WEBUI_CNCT_TS_SUB)) && - (((cam->imgs.width % 16) == 0) && - ((cam->imgs.height % 16) == 0))) { - img_w = (cam->imgs.width/2); - img_h = (cam->imgs.height/2); - } else { - img_w = cam->imgs.width; - img_h = cam->imgs.height; - } - img_w = ((cam->all_loc.scale * img_w) / 100); - if ((img_w % 16) != 0) { - img_w = img_w - (img_w % 16) + 16; - } - - img_h = ((cam->all_loc.scale * img_h) / 100); - if ((img_h % 16) != 0) { - img_h = img_h - (img_h % 16) + 16; - } - - if (img_w < 64){ - img_w = 64; - } - if (img_h < 64){ - img_h = 64; - } -} - -void webu_stream_all_sizes(ctx_webui *webui) -{ - int indx, row, col; - int chk_sz, chk_w, mx_col, mx_row; - int mx_h, mx_w, img_h, img_w; - bool dflt_scale; - ctx_dev *cam; - - if (webui->motapp->all_sizes->reset == false) { - return; - } - - mx_row = 0; - mx_col = 0; - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - if (mx_row < cam->all_loc.row) { - mx_row = cam->all_loc.row; - } - if (mx_col < cam->all_loc.col) { - mx_col = cam->all_loc.col; - } - } - - dflt_scale = false; - for (indx=0; indxmotapp->cam_cnt; indx++) { - if (webui->motapp->cam_list[indx]->all_loc.scale == -1) { - dflt_scale = true; - } - } - if (dflt_scale) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - webui->motapp->cam_list[indx]->all_loc.scale = 100; - } - for (row=1; row<=mx_row; row++) { - mx_h = 0; - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - if (row == cam->all_loc.row) { - webu_stream_img_sizes(webui, cam, img_w, img_h); - if (mx_h < img_h) { - mx_h = img_h; - } - } - } - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - if (row == cam->all_loc.row) { - webu_stream_img_sizes(webui, cam, img_w, img_h); - cam->all_loc.scale = (int)((float)(mx_h*100 / img_h )); - } - } - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Device %d Original Size %dx%d Scale %d New Size %dx%d" - , cam->device_id - , cam->imgs.width, cam->imgs.height - , cam->all_loc.scale, img_w, img_h); - } - } - } - - webui->motapp->all_sizes->width = 0; - webui->motapp->all_sizes->height = 0; - for (row=1; row<=mx_row; row++) { - chk_sz = 0; - mx_h = 0; - for (col=1; col<=mx_col; col++) { - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - if ((row == cam->all_loc.row) && - (col == cam->all_loc.col)) { - cam->all_loc.offset_col = chk_sz; - chk_sz += img_w; - if (mx_h < img_h) { - mx_h = img_h; - } - } - } - } - /* Align/center vert. the images in each row*/ - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - if (cam->all_loc.row == row) { - cam->all_loc.offset_row = - webui->motapp->all_sizes->height + - ((mx_h - img_h)/2) ; - } - } - webui->motapp->all_sizes->height += mx_h; - if (webui->motapp->all_sizes->width < chk_sz) { - webui->motapp->all_sizes->width = chk_sz; - } - } - - /* Align/center horiz. the images within each column area */ - chk_w = 0; - for (col=1; col<=mx_col; col++) { - chk_sz = 0; - mx_w = 0; - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - if (cam->all_loc.col == col) { - if (cam->all_loc.offset_col < chk_w) { - cam->all_loc.offset_col = chk_w; - } - if (chk_sz < cam->all_loc.offset_col) { - chk_sz = cam->all_loc.offset_col; - } - if (mx_w < img_w) { - mx_w = img_w; - } - } - } - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - if (cam->all_loc.col == col) { - cam->all_loc.offset_col = - chk_sz + ((mx_w - img_w) /2) ; - } - } - chk_w = mx_w + chk_sz; - if (webui->motapp->all_sizes->width < chk_w) { - webui->motapp->all_sizes->width = chk_w; - } - } - - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, img_w, img_h); - - chk_sz = cam->all_loc.offset_col + cam->all_loc.offset_user_col; - if (chk_sz < 0) { - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Device %d invalid image column offset. (%d + %d) less than zero " - , cam->device_id - , cam->all_loc.offset_col - , cam->all_loc.offset_user_col); - } else if ((chk_sz + img_w) > webui->motapp->all_sizes->width) { - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Device %d invalid image column offset. (%d + %d) over image size" - , cam->device_id - , cam->all_loc.offset_col - , cam->all_loc.offset_user_col); - } else { - cam->all_loc.offset_col = chk_sz; - } - - chk_sz = cam->all_loc.offset_row + cam->all_loc.offset_user_row; - if (chk_sz < 0 ) { - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Device %d invalid image row offset. (%d + %d) less than zero " - , cam->device_id - , cam->all_loc.offset_row - , cam->all_loc.offset_user_row); - } else if ((chk_sz + img_h) > webui->motapp->all_sizes->height) { - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Device %d invalid image row offset. (%d + %d) over image size" - , cam->device_id - , cam->all_loc.offset_row - , cam->all_loc.offset_user_row); - } else { - cam->all_loc.offset_row = chk_sz; - } - - } - - webui->motapp->all_sizes->img_sz =(( - webui->motapp->all_sizes->height * - webui->motapp->all_sizes->width * 3)/2); - - /* - for (indx=0; indxmotapp->cam_cnt; indx++) { - MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO - , "row %d col %d offset row %d offset col %d" - , webui->motapp->cam_list[indx]->all_loc.row - , webui->motapp->cam_list[indx]->all_loc.col - , webui->motapp->cam_list[indx]->all_loc.offset_row - , webui->motapp->cam_list[indx]->all_loc.offset_col); - } - */ - -} - -void webu_stream_all_buffers(ctx_webui *webui) -{ - if (webui->resp_size < (size_t)webui->motapp->all_sizes->img_sz) { - if (webui->resp_image != NULL) { - myfree(&webui->resp_image); - } - webui->resp_size = webui->motapp->all_sizes->img_sz; - webui->resp_image = (unsigned char*) mymalloc(webui->resp_size); - memset(webui->resp_image, '\0', webui->resp_size); - webui->resp_used = 0; - } - if (webui->all_img_data == NULL) { - webui->all_img_data = (unsigned char*) - mymalloc((size_t)webui->motapp->all_sizes->img_sz); - } -} - -bool webu_stream_all_ready(ctx_webui *webui) +bool cls_webu_stream::all_ready() { int indx, indx1; - ctx_dev *cam; + ctx_dev *p_cam; - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - if (cam->passflag == false) { - webui->motapp->all_sizes->reset = true; + for (indx=0; indxcam_cnt; indx++) { + p_cam = app->cam_list[indx]; + if (p_cam->passflag == false) { + app->all_sizes->reset = true; indx1 = 0; while (indx1 < 1000) { SLEEP(0, 1000); - if (cam->passflag) { + if (p_cam->passflag) { break; } indx1++; } - if (cam->passflag == false) { + if (p_cam->passflag == false) { return false; } } @@ -406,263 +61,81 @@ bool webu_stream_all_ready(ctx_webui *webui) return true; } -bool webu_stream_check_finish(ctx_webui *webui) -{ - if (webui->motapp->webcontrol_finish){ - webui->resp_used = 0; - return true; - } - if (webui->cam != NULL) { - if ((webui->cam->finish_dev == true) || - (webui->cam->passflag == false)) { - webui->resp_used = 0; - return true; - } - } - return false; -} - -/* Sleep required time to get to the user requested framerate for the stream */ -void webu_stream_delay(ctx_webui *webui) -{ - long stream_rate; - struct timespec time_curr; - long stream_delay; - - if (webu_stream_check_finish(webui)) { - return; - } - - clock_gettime(CLOCK_MONOTONIC, &time_curr); - - /* The stream rate MUST be less than 1000000000 otherwise undefined behaviour - * will occur with the SLEEP function. - */ - stream_delay = ((time_curr.tv_nsec - webui->time_last.tv_nsec)) + - ((time_curr.tv_sec - webui->time_last.tv_sec)*1000000000); - if (stream_delay < 0) { - stream_delay = 0; - } - if (stream_delay > 1000000000 ) { - stream_delay = 1000000000; - } - - if (webui->stream_fps >= 1) { - stream_rate = ( (1000000000 / webui->stream_fps) - stream_delay); - if ((stream_rate > 0) && (stream_rate < 1000000000)) { - SLEEP(0,stream_rate); - } else if (stream_rate == 1000000000) { - SLEEP(1,0); - } - } - clock_gettime(CLOCK_MONOTONIC, &webui->time_last); - -} - -void webu_stream_all_getimg(ctx_webui *webui) -{ - int a_y, a_u, a_v; /* all img y,u,v */ - int c_y, c_u, c_v; /* camera img y,u,v */ - int dst_h, dst_w, dst_sz, src_sz, img_orow, img_ocol; - int indx, row, indx1; - unsigned char *dst_img, *src_img; - ctx_stream_data *strm; - ctx_all_sizes *all_sz; - ctx_dev *cam; - - memset(webui->resp_image, '\0', webui->resp_size); - - all_sz = webui->motapp->all_sizes; - - a_y = 0; - a_u = (all_sz->width * all_sz->height); - a_v = a_u + (a_u / 4); - - memset(webui->all_img_data , 0x80, (size_t)a_u); - memset(webui->all_img_data + a_u, 0x80, (size_t)(a_u/2)); - - for (indx=0; indxmotapp->cam_cnt; indx++) { - cam = webui->motapp->cam_list[indx]; - webu_stream_img_sizes(webui, cam, dst_w, dst_h); - - dst_sz = (dst_h * dst_w * 3)/2; - src_sz = (cam->imgs.width * cam->imgs.height * 3)/2; - img_orow = cam->all_loc.offset_row; - img_ocol = cam->all_loc.offset_col; - - if ((webui->cnct_type == WEBUI_CNCT_JPG_FULL) || - (webui->cnct_type == WEBUI_CNCT_TS_FULL)) { - strm = &cam->stream.norm; - } else if ((webui->cnct_type == WEBUI_CNCT_JPG_SUB) || - (webui->cnct_type == WEBUI_CNCT_TS_SUB)) { - /* The use of the full size image is is is not an error here. - For the all_img, we are using a different scaling/resizing method - and as a result, we need to start with the full size image then - resize to substream and stream_preview_scale*/ - strm = &cam->stream.norm; /* <<==Normal size is correct here*/ - } else if ((webui->cnct_type == WEBUI_CNCT_JPG_MOTION) || - (webui->cnct_type == WEBUI_CNCT_TS_MOTION)) { - strm = &cam->stream.motion; - } else if ((webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) || - (webui->cnct_type == WEBUI_CNCT_TS_SOURCE )) { - strm = &cam->stream.source; - } else if ((webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) || - (webui->cnct_type == WEBUI_CNCT_TS_SECONDARY)) { - strm = &cam->stream.secondary; - } else { /* Should not be possible*/ - return; - } - - dst_img = (unsigned char*) mymalloc(dst_sz); - src_img = (unsigned char*) mymalloc(src_sz); - - pthread_mutex_lock(&cam->stream.mutex); - indx1=0; - while (indx1 < 1000) { - if (strm->img_data == NULL) { - if (strm->all_cnct == 0){ - strm->all_cnct++; - } - pthread_mutex_unlock(&cam->stream.mutex); - SLEEP(0, 1000); - pthread_mutex_lock(&cam->stream.mutex); - } else { - break; - } - indx1++; - } - if (strm->img_data == NULL) { - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "Could not get image for device %d", cam->device_id); - memset(src_img, 0x00, src_sz); - } else { - memcpy(src_img, strm->img_data, src_sz); - } - pthread_mutex_unlock(&cam->stream.mutex); - - webu_stream_img_resize(cam, src_img, dst_img, dst_w, dst_h); - - /* - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "src w %d h %d dst w %d h %d all w %d h %d " - , cam->imgs.width, cam->imgs.height - , dst_w, dst_h - , all_sz->width,all_sz->height); - */ - a_y = (img_orow * all_sz->width) + img_ocol; - a_u =(all_sz->height * all_sz->width) + - ((img_orow / 4) * all_sz->width) + (img_ocol / 2) ; - a_v = a_u + ((all_sz->height * all_sz->width) / 4); - - c_y = 0; - c_u = (dst_w * dst_h); - c_v = c_u + (c_u / 4); - - /* - MOTPLS_LOG(DBG, TYPE_STREAM, NO_ERRNO - , "r %d c %d a %d %d %d h %d w %d" - , img_orow, img_ocol - , a_y, a_u, a_v - , all_sz->height, all_sz->width); - */ - - for (row=0; rowall_img_data + a_y, dst_img + c_y, dst_w); - a_y += all_sz->width; - c_y += dst_w; - if (row % 2) { - memcpy(webui->all_img_data + a_u, dst_img + c_u, dst_w / 2); - //memset(webui->all_img_data + a_u, 0xFA, dst_w/2); - a_u += (all_sz->width / 2); - c_u += (dst_w / 2); - memcpy(webui->all_img_data + a_v, dst_img + c_v, dst_w / 2); - a_v += (all_sz->width / 2); - c_v += (dst_w / 2); - } - } - myfree(&dst_img); - myfree(&src_img); - } -} - -static void webu_stream_mjpeg_all_img(ctx_webui *webui) +void cls_webu_stream::mjpeg_all_img() { int header_len, jpg_sz; char resp_head[80]; ctx_all_sizes *all_sz; unsigned char *jpg_data; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return; } - if (webu_stream_all_ready(webui) == false) { + if (all_ready() == false) { return; } - webu_stream_all_sizes(webui); - webu_stream_all_buffers(webui); - webu_stream_all_getimg(webui); - all_sz = webui->motapp->all_sizes; + webuc->all_sizes(); + webuc->all_buffer(); + webuc->all_getimg(); + + all_sz = app->all_sizes; jpg_data = (unsigned char*) mymalloc(all_sz->img_sz); jpg_sz = jpgutl_put_yuv420p(jpg_data, all_sz->img_sz - , webui->all_img_data, all_sz->width, all_sz->height + , webuc->all_img_data, all_sz->width, all_sz->height , 70, NULL,NULL,NULL); - webui->stream_fps = 1; + webuc->stream_fps = 1; header_len = snprintf(resp_head, 80 ,"--BoundaryString\r\n" "Content-type: image/jpeg\r\n" "Content-Length: %9d\r\n\r\n" ,jpg_sz); - memcpy(webui->resp_image, resp_head, header_len); - memcpy(webui->resp_image + header_len, jpg_data, jpg_sz); - memcpy(webui->resp_image + header_len + jpg_sz,"\r\n",2); - webui->resp_used = header_len + jpg_sz + 2; + memcpy(webuc->resp_image, resp_head, header_len); + memcpy(webuc->resp_image + header_len, jpg_data, jpg_sz); + memcpy(webuc->resp_image + header_len + jpg_sz,"\r\n",2); + webuc->resp_used = header_len + jpg_sz + 2; myfree(&jpg_data); + } -static void webu_stream_mjpeg_getimg(ctx_webui *webui) +void cls_webu_stream::mjpeg_one_img() { char resp_head[80]; int header_len; ctx_stream_data *strm; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return; } - memset(webui->resp_image, '\0', webui->resp_size); + memset(webuc->resp_image, '\0', webuc->resp_size); /* Assign to a local pointer the stream we want */ - if (webui->cam == NULL) { + if (webua->cam == NULL) { return; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_FULL) { - strm = &webui->cam->stream.norm; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SUB) { - strm = &webui->cam->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_MOTION) { - strm = &webui->cam->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) { - strm = &webui->cam->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { - strm = &webui->cam->stream.secondary; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_FULL) { + strm = &webua->cam->stream.norm; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SUB) { + strm = &webua->cam->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_MOTION) { + strm = &webua->cam->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SOURCE) { + strm = &webua->cam->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { + strm = &webua->cam->stream.secondary; } else { return; } /* Copy jpg from the motion loop thread */ - pthread_mutex_lock(&webui->cam->stream.mutex); - if ((webui->cam->detecting_motion == false) && - (webui->motapp->cam_list[webui->camindx]->conf->stream_motion)) { - webui->stream_fps = 1; - } else { - webui->stream_fps = webui->motapp->cam_list[webui->camindx]->conf->stream_maxrate; - } + pthread_mutex_lock(&webua->cam->stream.mutex); + webuc->set_fps(); if (strm->jpg_data == NULL) { - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); return; } header_len = snprintf(resp_head, 80 @@ -670,137 +143,133 @@ static void webu_stream_mjpeg_getimg(ctx_webui *webui) "Content-type: image/jpeg\r\n" "Content-Length: %9d\r\n\r\n" ,strm->jpg_sz); - memcpy(webui->resp_image, resp_head, header_len); - memcpy(webui->resp_image + header_len + memcpy(webuc->resp_image, resp_head, header_len); + memcpy(webuc->resp_image + header_len ,strm->jpg_data ,strm->jpg_sz); /* Copy in the terminator after the jpg data at the end*/ - memcpy(webui->resp_image + header_len + strm->jpg_sz,"\r\n",2); - webui->resp_used = header_len + strm->jpg_sz + 2; + memcpy(webuc->resp_image + header_len + strm->jpg_sz,"\r\n",2); + webuc->resp_used = header_len + strm->jpg_sz + 2; strm->consumed = true; - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); } -/* Callback function for mhd to get stream */ -static ssize_t webu_stream_mjpeg_response (void *cls, uint64_t pos, char *buf, size_t max) +ssize_t cls_webu_stream::mjpeg_response (char *buf, size_t max) { - ctx_webui *webui =(ctx_webui *)cls; size_t sent_bytes; - (void)pos; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return -1; } - if ((webui->stream_pos == 0) || (webui->resp_used == 0)) { + if ((stream_pos == 0) || (webuc->resp_used == 0)) { - webu_stream_delay(webui); + webuc->delay(); - webui->stream_pos = 0; - webui->resp_used = 0; + stream_pos = 0; + webuc->resp_used = 0; - if (webui->device_id == 0) { - webu_stream_mjpeg_all_img(webui); + if (webua->device_id == 0) { + mjpeg_all_img(); } else { - webu_stream_mjpeg_getimg(webui); + mjpeg_one_img(); } - if (webui->resp_used == 0) { + if (webuc->resp_used == 0) { return 0; } } - if ((webui->resp_used - webui->stream_pos) > max) { + if ((webuc->resp_used - stream_pos) > max) { sent_bytes = max; } else { - sent_bytes = webui->resp_used - webui->stream_pos; + sent_bytes = webuc->resp_used - stream_pos; } - memcpy(buf, webui->resp_image + webui->stream_pos, sent_bytes); + memcpy(buf, webuc->resp_image + stream_pos, sent_bytes); - webui->stream_pos = webui->stream_pos + sent_bytes; - if (webui->stream_pos >= webui->resp_used) { - webui->stream_pos = 0; + stream_pos = stream_pos + sent_bytes; + if (stream_pos >= webuc->resp_used) { + stream_pos = 0; } return sent_bytes; - } /* Increment the all camera stream counters */ -static void webu_stream_all_cnct(ctx_webui *webui) +void cls_webu_stream::all_cnct() { ctx_stream_data *strm; int indx_cam; - for (indx_cam=0; indx_cammotapp->cam_cnt; indx_cam++) { - if (webui->cnct_type == WEBUI_CNCT_JPG_SUB) { - strm = &webui->motapp->cam_list[indx_cam]->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_MOTION) { - strm = &webui->motapp->cam_list[indx_cam]->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) { - strm = &webui->motapp->cam_list[indx_cam]->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { - strm = &webui->motapp->cam_list[indx_cam]->stream.secondary; + for (indx_cam=0; indx_camcam_cnt; indx_cam++) { + if (webua->cnct_type == WEBUI_CNCT_JPG_SUB) { + strm = &app->cam_list[indx_cam]->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_MOTION) { + strm = &app->cam_list[indx_cam]->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SOURCE) { + strm = &app->cam_list[indx_cam]->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { + strm = &app->cam_list[indx_cam]->stream.secondary; } else { - strm = &webui->motapp->cam_list[indx_cam]->stream.norm; + strm = &app->cam_list[indx_cam]->stream.norm; } - pthread_mutex_lock(&webui->motapp->cam_list[indx_cam]->stream.mutex); + pthread_mutex_lock(&app->cam_list[indx_cam]->stream.mutex); strm->all_cnct++; - pthread_mutex_unlock(&webui->motapp->cam_list[indx_cam]->stream.mutex); + pthread_mutex_unlock(&app->cam_list[indx_cam]->stream.mutex); } } /* Obtain the current image for the camera.*/ -static void webu_stream_static_all_img(ctx_webui *webui) +void cls_webu_stream::static_all_img() { ctx_all_sizes *all_sz; unsigned char *jpg_data; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return; } - if (webu_stream_all_ready(webui) == false) { + if (all_ready() == false) { return; } - webu_stream_all_sizes(webui); - webu_stream_all_buffers(webui); - webu_stream_all_getimg(webui); + webuc->all_sizes(); + webuc->all_buffer(); + webuc->all_getimg(); - all_sz = webui->motapp->all_sizes; + all_sz = app->all_sizes; jpg_data = (unsigned char*)mymalloc((size_t)all_sz->img_sz); - webui->resp_used = jpgutl_put_yuv420p(jpg_data - , all_sz->img_sz, webui->all_img_data, all_sz->width + webuc->resp_used = jpgutl_put_yuv420p(jpg_data + , all_sz->img_sz, webuc->all_img_data, all_sz->width , all_sz->height, 70, NULL,NULL,NULL); - memcpy(webui->resp_image, jpg_data, webui->resp_used); + memcpy(webuc->resp_image, jpg_data, webuc->resp_used); myfree(&jpg_data); } /* Increment the jpg stream counters */ -static void webu_stream_jpg_cnct(ctx_webui *webui) +void cls_webu_stream::jpg_cnct() { ctx_stream_data *strm; - if (webui->cam == NULL) { + if (webua->cam == NULL) { return; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SUB) { - strm = &webui->cam->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_MOTION) { - strm = &webui->cam->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) { - strm = &webui->cam->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { - strm = &webui->cam->stream.secondary; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SUB) { + strm = &webua->cam->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_MOTION) { + strm = &webua->cam->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SOURCE) { + strm = &webua->cam->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { + strm = &webua->cam->stream.secondary; } else { - strm = &webui->cam->stream.norm; + strm = &webua->cam->stream.norm; } - pthread_mutex_lock(&webui->cam->stream.mutex); + pthread_mutex_lock(&webua->cam->stream.mutex); strm->jpg_cnct++; - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); if (strm->jpg_cnct == 1) { @@ -813,91 +282,91 @@ static void webu_stream_jpg_cnct(ctx_webui *webui) } /* Obtain the current image for the camera.*/ -static void webu_stream_static_getimg(ctx_webui *webui) +void cls_webu_stream::static_one_img() { ctx_stream_data *strm; - webu_stream_checkbuffers(webui); + webuc->one_buffer(); - webui->resp_used = 0; - memset(webui->resp_image, '\0', webui->resp_size); + webuc->resp_used = 0; + memset(webuc->resp_image, '\0', webuc->resp_size); /* Assign to a local pointer the stream we want */ - if (webui->cam == NULL) { + if (webua->cam == NULL) { return; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_FULL) { - strm = &webui->cam->stream.norm; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SUB) { - strm = &webui->cam->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_MOTION) { - strm = &webui->cam->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SOURCE) { - strm = &webui->cam->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { - strm = &webui->cam->stream.secondary; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_FULL) { + strm = &webua->cam->stream.norm; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SUB) { + strm = &webua->cam->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_MOTION) { + strm = &webua->cam->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SOURCE) { + strm = &webua->cam->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_JPG_SECONDARY) { + strm = &webua->cam->stream.secondary; } else { return; } - pthread_mutex_lock(&webui->cam->stream.mutex); + pthread_mutex_lock(&webua->cam->stream.mutex); if (strm->jpg_data == NULL) { - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); return; } - memcpy(webui->resp_image + memcpy(webuc->resp_image ,strm->jpg_data ,strm->jpg_sz); - webui->resp_used =strm->jpg_sz; + webuc->resp_used =strm->jpg_sz; strm->consumed = true; - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); } /* Determine whether the user specified a valid URL for the particular port */ -static int webu_stream_checks(ctx_webui *webui) +int cls_webu_stream::checks() { - pthread_mutex_lock(&webui->motapp->mutex_camlst); - if (webui->device_id < 0) { + pthread_mutex_lock(&app->mutex_camlst); + if (webua->device_id < 0) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO - , _("Invalid camera specified: %s"), webui->url.c_str()); - pthread_mutex_unlock(&webui->motapp->mutex_camlst); + , _("Invalid camera specified: %s"), webua->url.c_str()); + pthread_mutex_unlock(&app->mutex_camlst); return -1; } - if ((webui->device_id > 0) && (webui->cam == NULL)) { + if ((webua->device_id > 0) && (webua->cam == NULL)) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO - , _("Invalid camera specified: %s"), webui->url.c_str()); - pthread_mutex_unlock(&webui->motapp->mutex_camlst); + , _("Invalid camera specified: %s"), webua->url.c_str()); + pthread_mutex_unlock(&app->mutex_camlst); return -1; } - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return -1; } - pthread_mutex_unlock(&webui->motapp->mutex_camlst); + pthread_mutex_unlock(&app->mutex_camlst); return 0; } /* Increment the transport stream counters */ -static void webu_stream_ts_cnct(ctx_webui *webui) +void cls_webu_stream::ts_cnct() { ctx_stream_data *strm; - if (webui->cam == NULL) { + if (webua->cam == NULL) { return; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SUB) { - strm = &webui->cam->stream.sub; - } else if (webui->cnct_type == WEBUI_CNCT_TS_MOTION) { - strm = &webui->cam->stream.motion; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SOURCE) { - strm = &webui->cam->stream.source; - } else if (webui->cnct_type == WEBUI_CNCT_TS_SECONDARY) { - strm = &webui->cam->stream.secondary; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SUB) { + strm = &webua->cam->stream.sub; + } else if (webua->cnct_type == WEBUI_CNCT_TS_MOTION) { + strm = &webua->cam->stream.motion; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SOURCE) { + strm = &webua->cam->stream.source; + } else if (webua->cnct_type == WEBUI_CNCT_TS_SECONDARY) { + strm = &webua->cam->stream.secondary; } else { - strm = &webui->cam->stream.norm; + strm = &webua->cam->stream.norm; } - pthread_mutex_lock(&webui->cam->stream.mutex); + pthread_mutex_lock(&webua->cam->stream.mutex); strm->ts_cnct++; - pthread_mutex_unlock(&webui->cam->stream.mutex); + pthread_mutex_unlock(&webua->cam->stream.mutex); if (strm->ts_cnct == 1) { /* This is the first connection so we need to wait half a sec @@ -908,76 +377,76 @@ static void webu_stream_ts_cnct(ctx_webui *webui) } /* Assign the type of stream that is being answered*/ -static void webu_stream_type(ctx_webui *webui) +void cls_webu_stream::set_cnct_type() { - if (webui->uri_cmd1 == "mpegts") { - if (webui->uri_cmd2 == "stream") { - webui->cnct_type = WEBUI_CNCT_TS_FULL; - } else if (webui->uri_cmd2 == "substream") { - webui->cnct_type = WEBUI_CNCT_TS_SUB; - } else if (webui->uri_cmd2 == "motion") { - webui->cnct_type = WEBUI_CNCT_TS_MOTION; - } else if (webui->uri_cmd2 == "source") { - webui->cnct_type = WEBUI_CNCT_TS_SOURCE; - } else if (webui->uri_cmd2 == "secondary") { - if (webui->cam == NULL) { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + if (webua->uri_cmd1 == "mpegts") { + if (webua->uri_cmd2 == "stream") { + webua->cnct_type = WEBUI_CNCT_TS_FULL; + } else if (webua->uri_cmd2 == "substream") { + webua->cnct_type = WEBUI_CNCT_TS_SUB; + } else if (webua->uri_cmd2 == "motion") { + webua->cnct_type = WEBUI_CNCT_TS_MOTION; + } else if (webua->uri_cmd2 == "source") { + webua->cnct_type = WEBUI_CNCT_TS_SOURCE; + } else if (webua->uri_cmd2 == "secondary") { + if (webua->cam == NULL) { + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } else { - if (webui->cam->algsec_inuse) { - webui->cnct_type = WEBUI_CNCT_TS_SECONDARY; + if (webua->cam->algsec_inuse) { + webua->cnct_type = WEBUI_CNCT_TS_SECONDARY; } else { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } } - } else if (webui->uri_cmd2 == "") { - webui->cnct_type = WEBUI_CNCT_TS_FULL; + } else if (webua->uri_cmd2 == "") { + webua->cnct_type = WEBUI_CNCT_TS_FULL; } else { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } } else { - if (webui->uri_cmd2 == "stream") { - webui->cnct_type = WEBUI_CNCT_JPG_FULL; - } else if (webui->uri_cmd2 == "substream") { - webui->cnct_type = WEBUI_CNCT_JPG_SUB; - } else if (webui->uri_cmd2 == "motion") { - webui->cnct_type = WEBUI_CNCT_JPG_MOTION; - } else if (webui->uri_cmd2 == "source") { - webui->cnct_type = WEBUI_CNCT_JPG_SOURCE; - } else if (webui->uri_cmd2 == "secondary") { - if (webui->cam == NULL) { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + if (webua->uri_cmd2 == "stream") { + webua->cnct_type = WEBUI_CNCT_JPG_FULL; + } else if (webua->uri_cmd2 == "substream") { + webua->cnct_type = WEBUI_CNCT_JPG_SUB; + } else if (webua->uri_cmd2 == "motion") { + webua->cnct_type = WEBUI_CNCT_JPG_MOTION; + } else if (webua->uri_cmd2 == "source") { + webua->cnct_type = WEBUI_CNCT_JPG_SOURCE; + } else if (webua->uri_cmd2 == "secondary") { + if (webua->cam == NULL) { + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } else { - if (webui->cam->algsec_inuse) { - webui->cnct_type = WEBUI_CNCT_JPG_SECONDARY; + if (webua->cam->algsec_inuse) { + webua->cnct_type = WEBUI_CNCT_JPG_SECONDARY; } else { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } } - } else if (webui->uri_cmd2 == "") { - webui->cnct_type = WEBUI_CNCT_JPG_FULL; + } else if (webua->uri_cmd2 == "") { + webua->cnct_type = WEBUI_CNCT_JPG_FULL; } else { - webui->cnct_type = WEBUI_CNCT_UNKNOWN; + webua->cnct_type = WEBUI_CNCT_UNKNOWN; } } } -static mhdrslt webu_stream_mjpeg(ctx_webui *webui) +mhdrslt cls_webu_stream::stream_mjpeg() { mhdrslt retcd; struct MHD_Response *response; - p_lst *lst = &webui->motapp->webcontrol_headers->params_array; + p_lst *lst = &webu->wb_headers->params_array; p_it it; - clock_gettime(CLOCK_MONOTONIC, &webui->time_last); + clock_gettime(CLOCK_MONOTONIC, &webuc->time_last); response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024 - ,&webu_stream_mjpeg_response, webui, NULL); + , &webu_mjpeg_response, (void *)this, NULL); if (response == NULL) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response")); return MHD_NO; } - if (webui->motapp->webcontrol_headers->params_count > 0) { + if (webu->wb_headers->params_count > 0) { for (it = lst->begin(); it != lst->end(); it++) { MHD_add_response_header (response , it->param_name.c_str(), it->param_value.c_str()); @@ -987,34 +456,35 @@ static mhdrslt webu_stream_mjpeg(ctx_webui *webui) MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE , "multipart/x-mixed-replace; boundary=BoundaryString"); - retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response); + retcd = MHD_queue_response(webua->connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return retcd; } /* Create the response for the static image request*/ -static mhdrslt webu_stream_static(ctx_webui *webui) +mhdrslt cls_webu_stream::stream_static() { mhdrslt retcd; struct MHD_Response *response; char resp_used[20]; - p_lst *lst = &webui->motapp->webcontrol_headers->params_array; + p_lst *lst = &webu->wb_headers->params_array; p_it it; - if (webui->resp_used == 0) { + if (webuc->resp_used == 0) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Could not get image to stream.")); return MHD_NO; } - response = MHD_create_response_from_buffer (webui->resp_size - ,(void *)webui->resp_image, MHD_RESPMEM_MUST_COPY); + response = MHD_create_response_from_buffer ( + webuc->resp_size,(void *)webuc->resp_image + , MHD_RESPMEM_MUST_COPY); if (response == NULL) { MOTPLS_LOG(ERR, TYPE_STREAM, NO_ERRNO, _("Invalid response")); return MHD_NO; } - if (webui->motapp->webcontrol_headers->params_count > 0) { + if (webu->wb_headers->params_count > 0) { for (it = lst->begin(); it != lst->end(); it++) { MHD_add_response_header (response , it->param_name.c_str(), it->param_value.c_str()); @@ -1022,61 +492,70 @@ static mhdrslt webu_stream_static(ctx_webui *webui) } MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "image/jpeg"); - snprintf(resp_used, 20, "%9ld\r\n\r\n",(long)webui->resp_used); + snprintf(resp_used, 20, "%9ld\r\n\r\n",(long)webuc->resp_used); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_LENGTH, resp_used); - retcd = MHD_queue_response (webui->connection, MHD_HTTP_OK, response); + retcd = MHD_queue_response (webua->connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return retcd; } /* Entry point for answering stream*/ -mhdrslt webu_stream_main(ctx_webui *webui) +mhdrslt cls_webu_stream::main() { mhdrslt retcd; - if (webu_stream_check_finish(webui)) { + if (webuc->check_finish()) { return MHD_NO; } - if (webui->cam != NULL) { - if ((webui->cam->passflag == false) || (webui->cam->finish_dev)) { + if (webua->cam != NULL) { + if ((webua->cam->passflag == false) || (webua->cam->finish_dev)) { return MHD_NO; } } - webu_stream_type(webui); + set_cnct_type(); - if (webu_stream_checks(webui) == -1) { + if (checks() == -1) { + webua->bad_request(); return MHD_NO; } - if (webui->uri_cmd1 == "static") { - if (webui->device_id > 0) { - webu_stream_jpg_cnct(webui); - webu_stream_static_getimg(webui); + if (webua->uri_cmd1 == "static") { + if (webua->device_id > 0) { + jpg_cnct(); + static_one_img(); } else { - webu_stream_all_cnct(webui); - webu_stream_static_all_img(webui); + all_cnct(); + static_all_img(); } - retcd = webu_stream_static(webui); - } else if (webui->uri_cmd1 == "mjpg") { - if (webui->device_id > 0) { - webu_stream_jpg_cnct(webui); - webu_stream_checkbuffers(webui); + retcd = stream_static(); + } else if (webua->uri_cmd1 == "mjpg") { + if (webua->device_id > 0) { + jpg_cnct(); + webuc->one_buffer(); } else { - webu_stream_all_cnct(webui); + all_cnct(); + webuc->all_buffer(); } - retcd = webu_stream_mjpeg(webui); - } else if (webui->uri_cmd1 == "mpegts") { - if (webui->device_id > 0) { - webu_stream_ts_cnct(webui); - retcd = webu_mpegts_main(webui); + retcd = stream_mjpeg(); + } else if (webua->uri_cmd1 == "mpegts") { + if (webua->device_id > 0) { + ts_cnct(); } else { - webu_stream_all_cnct(webui); - retcd = webu_mpegts_main(webui); + all_cnct(); } + if (webu_mpegts == nullptr){ + webu_mpegts = new cls_webu_mpegts(webua); + } + retcd = webu_mpegts->main(); + if (retcd == MHD_NO) { + delete webu_mpegts; + webu_mpegts = nullptr; + } + } else { retcd = MHD_NO; } @@ -1084,294 +563,22 @@ mhdrslt webu_stream_main(ctx_webui *webui) return retcd; } -/* Initial the stream context items for the camera */ -void webu_stream_init(ctx_dev *cam) +cls_webu_stream::cls_webu_stream(cls_webu_ans *p_webua) { - /* NOTE: This runs on the motion_loop thread. */ - - pthread_mutex_init(&cam->stream.mutex, NULL); - - cam->imgs.image_substream = NULL; - - cam->stream.norm.jpg_sz = 0; - cam->stream.norm.jpg_data = NULL; - cam->stream.norm.jpg_cnct = 0; - cam->stream.norm.ts_cnct = 0; - cam->stream.norm.all_cnct = 0; - cam->stream.norm.consumed = true; - cam->stream.norm.img_data = NULL; - - cam->stream.sub.jpg_sz = 0; - cam->stream.sub.jpg_data = NULL; - cam->stream.sub.jpg_cnct = 0; - cam->stream.sub.ts_cnct = 0; - cam->stream.sub.all_cnct = 0; - cam->stream.sub.consumed = true; - cam->stream.sub.img_data = NULL; - - cam->stream.motion.jpg_sz = 0; - cam->stream.motion.jpg_data = NULL; - cam->stream.motion.jpg_cnct = 0; - cam->stream.motion.ts_cnct = 0; - cam->stream.motion.all_cnct = 0; - cam->stream.motion.consumed = true; - cam->stream.motion.img_data = NULL; - - cam->stream.source.jpg_sz = 0; - cam->stream.source.jpg_data = NULL; - cam->stream.source.jpg_cnct = 0; - cam->stream.source.ts_cnct = 0; - cam->stream.source.all_cnct = 0; - cam->stream.source.consumed = true; - cam->stream.source.img_data = NULL; - - cam->stream.secondary.jpg_sz = 0; - cam->stream.secondary.jpg_data = NULL; - cam->stream.secondary.jpg_cnct = 0; - cam->stream.secondary.ts_cnct = 0; - cam->stream.secondary.all_cnct = 0; - cam->stream.secondary.consumed = true; - cam->stream.secondary.img_data = NULL; - + app = p_webua->app; + webu = p_webua->webu; + webuc = new cls_webu_common(p_webua); + webua = p_webua; + webu_mpegts = nullptr; + stream_pos = 0; } -/* Free the stream buffers and mutex for shutdown */ -void webu_stream_deinit(ctx_dev *cam) +cls_webu_stream::~cls_webu_stream() { - /* NOTE: This runs on the motion_loop thread. */ - myfree(&cam->imgs.image_substream); - - pthread_mutex_lock(&cam->stream.mutex); - myfree(&cam->stream.norm.jpg_data); - myfree(&cam->stream.sub.jpg_data); - myfree(&cam->stream.motion.jpg_data); - myfree(&cam->stream.source.jpg_data); - myfree(&cam->stream.secondary.jpg_data); - - myfree(&cam->stream.norm.img_data) ; - myfree(&cam->stream.sub.img_data) ; - myfree(&cam->stream.motion.img_data) ; - myfree(&cam->stream.source.img_data) ; - myfree(&cam->stream.secondary.img_data) ; - pthread_mutex_unlock(&cam->stream.mutex); - - pthread_mutex_destroy(&cam->stream.mutex); - -} - -/* Get a normal image from the motion loop and compress it*/ -static void webu_stream_getimg_norm(ctx_dev *cam) -{ - if ((cam->stream.norm.jpg_cnct == 0) && - (cam->stream.norm.ts_cnct == 0) && - (cam->stream.norm.all_cnct == 0)) { - return; + if (webu_mpegts != nullptr){ + delete webu_mpegts; } - - if (cam->stream.norm.jpg_cnct > 0) { - if (cam->stream.norm.jpg_data == NULL) { - cam->stream.norm.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - if (cam->current_image->image_norm != NULL && cam->stream.norm.consumed) { - cam->stream.norm.jpg_sz = pic_put_memory(cam - ,cam->stream.norm.jpg_data - ,cam->imgs.size_norm - ,cam->current_image->image_norm - ,cam->conf->stream_quality - ,cam->imgs.width - ,cam->imgs.height); - cam->stream.norm.consumed = false; - } - } - if ((cam->stream.norm.ts_cnct > 0) || (cam->stream.norm.all_cnct > 0)) { - if (cam->stream.norm.img_data == NULL) { - cam->stream.norm.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - memcpy(cam->stream.norm.img_data, cam->current_image->image_norm, cam->imgs.size_norm); + if (webuc != nullptr){ + delete webuc; } } - -/* Get a substream image from the motion loop and compress it*/ -static void webu_stream_getimg_sub(ctx_dev *cam) -{ - int subsize; - - if ((cam->stream.sub.jpg_cnct == 0) && - (cam->stream.sub.ts_cnct == 0) && - (cam->stream.sub.all_cnct == 0)) { - return; - } - - if (cam->stream.sub.jpg_cnct > 0) { - if (cam->stream.sub.jpg_data == NULL) { - cam->stream.sub.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - if (cam->current_image->image_norm != NULL && cam->stream.sub.consumed) { - /* Resulting substream image must be multiple of 8 */ - if (((cam->imgs.width % 16) == 0) && - ((cam->imgs.height % 16) == 0)) { - - subsize = ((cam->imgs.width / 2) * (cam->imgs.height / 2) * 3 / 2); - if (cam->imgs.image_substream == NULL) { - cam->imgs.image_substream =(unsigned char*)mymalloc(subsize); - } - pic_scale_img(cam->imgs.width - ,cam->imgs.height - ,cam->current_image->image_norm - ,cam->imgs.image_substream); - cam->stream.sub.jpg_sz = pic_put_memory(cam - ,cam->stream.sub.jpg_data - ,subsize - ,cam->imgs.image_substream - ,cam->conf->stream_quality - ,(cam->imgs.width / 2) - ,(cam->imgs.height / 2)); - } else { - /* Substream was not multiple of 8 so send full image*/ - cam->stream.sub.jpg_sz = pic_put_memory(cam - ,cam->stream.sub.jpg_data - ,cam->imgs.size_norm - ,cam->current_image->image_norm - ,cam->conf->stream_quality - ,cam->imgs.width - ,cam->imgs.height); - } - cam->stream.sub.consumed = false; - } - } - - if ((cam->stream.sub.ts_cnct > 0) || (cam->stream.sub.all_cnct > 0)) { - if (cam->stream.sub.img_data == NULL) { - cam->stream.sub.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - if (((cam->imgs.width % 16) == 0) && - ((cam->imgs.height % 16) == 0)) { - subsize = ((cam->imgs.width / 2) * (cam->imgs.height / 2) * 3 / 2); - if (cam->imgs.image_substream == NULL) { - cam->imgs.image_substream =(unsigned char*)mymalloc(subsize); - } - pic_scale_img(cam->imgs.width - ,cam->imgs.height - ,cam->current_image->image_norm - ,cam->imgs.image_substream); - memcpy(cam->stream.sub.img_data, cam->imgs.image_substream, subsize); - } else { - memcpy(cam->stream.sub.img_data, cam->current_image->image_norm, cam->imgs.size_norm); - } - } - -} - -/* Get a motion image from the motion loop and compress it*/ -static void webu_stream_getimg_motion(ctx_dev *cam) -{ - if ((cam->stream.motion.jpg_cnct == 0) && - (cam->stream.motion.ts_cnct == 0) && - (cam->stream.motion.all_cnct == 0)) { - return; - } - - if (cam->stream.motion.jpg_cnct > 0) { - if (cam->stream.motion.jpg_data == NULL) { - cam->stream.motion.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - if (cam->imgs.image_motion.image_norm != NULL && cam->stream.motion.consumed) { - cam->stream.motion.jpg_sz = pic_put_memory(cam - ,cam->stream.motion.jpg_data - ,cam->imgs.size_norm - ,cam->imgs.image_motion.image_norm - ,cam->conf->stream_quality - ,cam->imgs.width - ,cam->imgs.height); - cam->stream.motion.consumed = false; - } - } - if ((cam->stream.motion.ts_cnct > 0) || (cam->stream.motion.all_cnct > 0)) { - if (cam->stream.motion.img_data == NULL) { - cam->stream.motion.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - memcpy(cam->stream.motion.img_data - , cam->imgs.image_motion.image_norm - , cam->imgs.size_norm); - } -} - -/* Get a source image from the motion loop and compress it*/ -static void webu_stream_getimg_source(ctx_dev *cam) -{ - if ((cam->stream.source.jpg_cnct == 0) && - (cam->stream.source.ts_cnct == 0) && - (cam->stream.source.all_cnct == 0)) { - return; - } - - if (cam->stream.source.jpg_cnct > 0) { - if (cam->stream.source.jpg_data == NULL) { - cam->stream.source.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - if (cam->imgs.image_virgin != NULL && cam->stream.source.consumed) { - cam->stream.source.jpg_sz = pic_put_memory(cam - ,cam->stream.source.jpg_data - ,cam->imgs.size_norm - ,cam->imgs.image_virgin - ,cam->conf->stream_quality - ,cam->imgs.width - ,cam->imgs.height); - cam->stream.source.consumed = false; - } - } - if ((cam->stream.source.ts_cnct > 0) || (cam->stream.source.all_cnct > 0)) { - if (cam->stream.source.img_data == NULL) { - cam->stream.source.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - memcpy(cam->stream.source.img_data - , cam->imgs.image_virgin - , cam->imgs.size_norm); - } -} - -/* Get a secondary image from the motion loop and compress it*/ -static void webu_stream_getimg_secondary(ctx_dev *cam) -{ - if ((cam->stream.secondary.jpg_cnct == 0) && - (cam->stream.secondary.ts_cnct == 0) && - (cam->stream.secondary.all_cnct == 0)) { - return; - } - - if (cam->stream.secondary.jpg_cnct > 0) { - if (cam->imgs.size_secondary>0) { - pthread_mutex_lock(&cam->algsec->mutex); - if (cam->stream.secondary.jpg_data == NULL) { - cam->stream.secondary.jpg_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - - memcpy(cam->stream.secondary.jpg_data,cam->imgs.image_secondary,cam->imgs.size_secondary); - cam->stream.secondary.jpg_sz = cam->imgs.size_secondary; - pthread_mutex_unlock(&cam->algsec->mutex); - } else { - myfree(&cam->stream.secondary.jpg_data); - } - } - if ((cam->stream.secondary.ts_cnct > 0) || (cam->stream.secondary.all_cnct > 0)) { - if (cam->stream.secondary.img_data == NULL) { - cam->stream.secondary.img_data =(unsigned char*)mymalloc(cam->imgs.size_norm); - } - memcpy(cam->stream.secondary.img_data - , cam->current_image->image_norm, cam->imgs.size_norm); - } - -} - -/* Get image from the motion loop and compress it*/ -void webu_stream_getimg(ctx_dev *cam) -{ - /*This is on the motion_loop thread */ - pthread_mutex_lock(&cam->stream.mutex); - webu_stream_getimg_norm(cam); - webu_stream_getimg_sub(cam); - webu_stream_getimg_motion(cam); - webu_stream_getimg_source(cam); - webu_stream_getimg_secondary(cam); - pthread_mutex_unlock(&cam->stream.mutex); -} diff --git a/src/webu_stream.hpp b/src/webu_stream.hpp index be593e61..7f0bd2c0 100644 --- a/src/webu_stream.hpp +++ b/src/webu_stream.hpp @@ -18,18 +18,36 @@ #ifndef _INCLUDE_WEBU_STREAM_HPP_ #define _INCLUDE_WEBU_STREAM_HPP_ + class cls_webu_stream { + public: + cls_webu_stream(cls_webu_ans *webua); + ~cls_webu_stream(); - void webu_stream_init(ctx_dev *cam); - void webu_stream_deinit(ctx_dev *cam); - void webu_stream_getimg(ctx_dev *cam); + mhdrslt main(); + ssize_t mjpeg_response (char *buf, size_t max); - mhdrslt webu_stream_main(ctx_webui *webui); - void webu_stream_delay(ctx_webui *webui); - void webu_stream_checkbuffers(ctx_webui *webui); - void webu_stream_img_sizes(ctx_webui *webui, ctx_dev *cam, int &img_w, int &img_h); - void webu_stream_all_sizes(ctx_webui *webui); - void webu_stream_all_buffers(ctx_webui *webui); - void webu_stream_all_getimg(ctx_webui *webui); - bool webu_stream_check_finish(ctx_webui *webui); + private: + ctx_motapp *app; + cls_webu *webu; + cls_webu_ans *webua; + cls_webu_common *webuc; + cls_webu_mpegts *webu_mpegts; + + size_t stream_pos; + + void mjpeg_all_img(); + void mjpeg_one_img(); + void static_all_img(); + void static_one_img(); + mhdrslt stream_static(); + mhdrslt stream_mjpeg(); + + int checks(); + bool all_ready(); + void all_cnct(); + void jpg_cnct(); + void ts_cnct(); + void set_cnct_type(); + }; #endif /* _INCLUDE_WEBU_STREAM_HPP_ */