Revise to use webu classes

This commit is contained in:
Mr-Dave
2024-06-17 21:20:55 -06:00
parent 4ae0161e33
commit 2e36b99e95
26 changed files with 3554 additions and 3059 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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; indx<motapp->cam_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; indx<motapp->cam_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));

View File

@@ -53,6 +53,10 @@
#include <regex.h>
#include <dirent.h>
#include <algorithm>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#if defined(HAVE_PTHREAD_NP_H)
#include <pthread_np.h>
@@ -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<ctx_webu_clients> 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 */

View File

@@ -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);

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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<ctx_webu_clients> 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

856
src/webu_ans.cpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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; indx<app->cam_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<ctx_webu_clients>::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<ctx_webu_clients>::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<ctx_webu_clients>::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 = "<html><head><title>Access denied</title>"
"</head><body>Access denied</body></html>";
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 = "<html><head><title>Access denied</title>"
"</head><body>Access denied</body></html>";
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 =
"<!DOCTYPE html>\n"
"<html>\n"
"<body>\n"
"<p>Bad Request</p>\n"
"<p>The server did not understand your request.</p>\n"
"</body>\n"
"</html>\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; indx<cam_max; indx++) {
p_cam = app->cam_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--;
}

87
src/webu_ans.hpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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

599
src/webu_common.cpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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; indx<app->cam_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; row<dst_h; row++) {
memcpy(all_img_data + a_y, dst_img + c_y, dst_w);
a_y += all_sz->width;
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; indx<app->cam_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; indx<app->cam_cnt; indx++) {
if (app->cam_list[indx]->all_loc.scale == -1) {
dflt_scale = true;
}
}
if (dflt_scale) {
for (indx=0; indx<app->cam_cnt; indx++) {
app->cam_list[indx]->all_loc.scale = 100;
}
for (row=1; row<=mx_row; row++) {
mx_h = 0;
for (indx=0; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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; indx<app->cam_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);
}

52
src/webu_common.hpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -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 = "<html><head><title>Bad File</title>"
if (webua->req_file == NULL) {
webua->resp_page = "<html><head><title>Bad File</title>"
"</head><body>Bad File</body></html>";
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;
}

View File

@@ -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_ */

317
src/webu_getimg.cpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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);
}

26
src/webu_getimg.hpp Normal file
View File

@@ -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 <https://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -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 += " <style>\n";
webua->resp_page += " <style>\n";
webu_html_style_base(webui);
style_base();
webu_html_style_navbar(webui);
style_navbar();
webu_html_style_config(webui);
webui->resp_page += " </style>\n";
style_config();
webua->resp_page += " </style>\n";
}
/* Create the header section of the page */
static void webu_html_head(ctx_webui *webui)
void cls_webu_html::head()
{
webui->resp_page += "<head> \n"
webua->resp_page += "<head> \n"
"<meta charset='UTF-8'> \n"
"<title>MotionPlus</title> \n"
"<meta name='viewport' content='width=device-width, initial-scale=1'> \n";
webu_html_style(webui);
webui->resp_page += "</head>\n\n";
style();
webua->resp_page += "</head>\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 +=
" <div id=\"divnav_main\" class=\"sidenav\">\n"
" <a class='closebtn' onclick='nav_close()'>X</a>\n"
" <div id=\"divnav_version\">\n"
@@ -340,13 +337,12 @@ static void webu_html_navbar(ctx_webui *webui)
" <!-- Filled in by script -->\n"
" </div>\n"
" </div>\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 +=
" <div id='divmain' style='margin-left:10rem' >\n"
" <button id='menu_btn' \n"
" onclick='nav_open();' \n"
@@ -363,13 +359,12 @@ static void webu_html_divmain(ctx_webui *webui)
" <!-- Filled in by script -->\n"
" </div>\n\n"
" </div>\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 ='<a>MotionPlus \\n'+pData['version'] +'</a>';\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 += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'snapshot');\\\">\";\n"
" html_actions += \"Snapshot</a>\\n\";\n\n"
;
} else if ((it->param_name == "event") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'eventstart');\\\">\";\n"
" html_actions += \"Start Event</a>\\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 += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'pause');\\\">\";\n"
" html_actions += \"Pause</a>\\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 += \"<a onclick=\\\"send_reload(\";\n"
" html_actions += \"'camera_add');\\\">\";\n"
" html_actions += \"Add Camera</a>\\n\";\n\n"
;
} else if ((it->param_name == "camera_delete") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_reload(\";\n"
" html_actions += \"'camera_delete');\\\">\";\n"
" html_actions += \"Delete Camera</a>\\n\";\n\n"
;
} else if ((it->param_name == "config_write") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'config_write');\\\">\";\n"
" html_actions += \"Save Config</a>\\n\";\n\n"
;
} else if ((it->param_name == "stop") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'stop');\\\">\";\n"
" html_actions += \"Stop</a>\\n\";\n\n"
;
} else if ((it->param_name == "restart") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'restart');\\\">\";\n"
" html_actions += \"Start/Restart</a>\\n\";\n\n"
;
} else if ((it->param_name == "action_user") &&
(it->param_value == "on")) {
webui->resp_page +=
webua->resp_page +=
" html_actions += \"<a onclick=\\\"send_action(\";\n"
" html_actions += \"'action_user');\\\">\";\n"
" html_actions += \"User Action</a>\\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 = \"<div>\";\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 += " <script>\n"
webua->resp_page += " <script>\n"
" var pData, pMovies, pHostFull;\n"
" var gIndxScan, gIndxCam, gGetImgs;\n"
" var pic_url = Array(4);\n"
" var cams_scan_timer, cams_all_timer, cams_one_timer;\n\n";
webu_html_script_nav(webui);
script_nav();
webu_html_script_send_config(webui);
webu_html_script_send_action(webui);
webu_html_script_send_reload(webui);
script_send_config();
script_send_action();
script_send_reload();
webu_html_script_dropchange_cam(webui);
webu_html_script_config_hideall(webui);
webu_html_script_config_click(webui);
script_dropchange_cam();
script_config_hideall();
script_config_click();
webu_html_script_assign_camid(webui);
webu_html_script_assign_version(webui);
webu_html_script_assign_cams(webui);
webu_html_script_assign_actions(webui);
webu_html_script_assign_vals(webui);
webu_html_script_assign_config_nav(webui);
webu_html_script_assign_config_item(webui);
webu_html_script_assign_config_cat(webui);
webu_html_script_assign_config(webui);
script_assign_camid();
script_assign_version();
script_assign_cams();
script_assign_actions();
script_assign_vals();
script_assign_config_nav();
script_assign_config_item();
script_assign_config_cat();
script_assign_config();
webu_html_script_initform(webui);
webu_html_script_display_cameras(webui);
webu_html_script_display_config(webui);
webu_html_script_display_movies(webui);
webu_html_script_display_actions(webui);
script_initform();
script_display_cameras();
script_display_config();
script_display_movies();
script_display_actions();
webu_html_script_camera_buttons_ptz(webui);
webu_html_script_image_pantilt(webui);
script_camera_buttons_ptz();
script_image_pantilt();
webu_html_script_cams_reset(webui);
script_cams_reset();
webu_html_script_cams_all_click(webui);
webu_html_script_cams_one_click(webui);
webu_html_script_cams_scan_click(webui);
script_cams_all_click();
script_cams_one_click();
script_cams_scan_click();
webu_html_script_cams_one_fnc(webui);
webu_html_script_cams_all_fnc(webui);
webu_html_script_cams_scan_fnc(webui);
script_cams_one_fnc();
script_cams_all_fnc();
script_cams_scan_fnc();
webu_html_script_movies_page(webui);
webu_html_script_movies_click(webui);
webui->resp_page += " </script>\n\n";
script_movies_page();
script_movies_click();
webua->resp_page += " </script>\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 += "<body class='body' onload='initform()'>\n";
webua->resp_page += "<body class='body' onload='initform()'>\n";
webu_html_navbar(webui);
navbar();
webu_html_divmain(webui);
divmain();
webu_html_script(webui);
webui->resp_page += "</body>\n";
script();
webua->resp_page += "</body>\n";
}
/* Create the default motionplus page */
void webu_html_page(ctx_webui *webui)
void cls_webu_html::default_page()
{
webui->resp_page += "<!DOCTYPE html>\n"
"<html lang='" + webui->lang + "'>\n";
webu_html_head(webui);
webu_html_body(webui);
webui->resp_page += "</html>\n";
webua->resp_page += "<!DOCTYPE html>\n"
"<html lang='" + webua->lang + "'>\n";
head();
body();
webua->resp_page += "</html>\n";
}
/*Create the bad request page*/
void webu_html_badreq(ctx_webui *webui)
{
webui->resp_page =
"<!DOCTYPE html>\n"
"<html>\n"
"<body>\n"
"<p>Bad Request</p>\n"
"<p>The server did not understand your request.</p>\n"
"</body>\n"
"</html>\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;
}

View File

@@ -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_ */

View File

@@ -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_cam<webui->motapp->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_cam<app->cam_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_cam<webui->motapp->cam_cnt; indx_cam++) {
cam = webui->motapp->cam_list[indx_cam];
for (indx_cam=0; indx_cam<app->cam_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_cam<webui->motapp->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_cam<app->cam_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_cam<webui->motapp->cam_cnt; indx_cam++) {
if (webui->cam->device_id == webui->motapp->cam_list[indx_cam]->device_id){
for (indx_cam=0; indx_cam<app->cam_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, &timestamp_tm);
strftime(buf, sizeof(buf), "%FT%T", &timestamp_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, &timestamp_tm);
strftime(buf, sizeof(buf), "%FT%T", &timestamp_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_cam<webui->motapp->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_cam<app->cam_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;
}

View File

@@ -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_ */

View File

@@ -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;
}
}

View File

@@ -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_ */

View File

@@ -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; indx<webui->motapp->cam_cnt; indx++) {
if (webui->motapp->cam_list[indx]->device_id == webui->device_id) {
webui->camindx = indx;
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->event_stop = true;
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->event_user = true;
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->snapshot = true;
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->pause = true;
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->pause = false;
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
webui->motapp->cam_list[indx]->restart_dev = true;
webui->motapp->cam_list[indx]->finish_dev = true;
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<webui->motapp->cam_cnt; indx++) {
cam = webui->motapp->cam_list[indx];
if (webua->device_id == 0) {
for (indx=0; indx<app->cam_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; indx<post_sz; indx++) {
myfree(&post_info[indx].key_nm);
myfree(&post_info[indx].key_val);
}
myfree(&post_info);
}

View File

@@ -18,7 +18,44 @@
#ifndef _INCLUDE_WEBU_POST_HPP_
#define _INCLUDE_WEBU_POST_HPP_
class cls_webu_post {
public:
cls_webu_post(cls_webu_ans *webua);
~cls_webu_post();
void webu_post_main(ctx_webui *webui);
mhdrslt iterate_post (const char *key, const char *data, size_t datasz);
mhdrslt processor_init();
mhdrslt processor_start(const char *upload_data, size_t *upload_data_size);
private:
ctx_motapp *app;
cls_webu *webu;
cls_webu_ans *webua;
cls_webu_html *webu_html;
std::string post_cmd;
int post_sz; /* The number of entries in the post info */
ctx_key *post_info; /* Structure of the entries provided from the post data */
struct MHD_PostProcessor *post_processor; /* Processor for handling Post method connections */
void cam_add();
void cam_delete();
void parse_cmd();
void iterate_post_append(int indx, const char *data, size_t datasz);
void iterate_post_new(const char *key, const char *data, size_t datasz);
void process_actions();
void action_eventend();
void action_eventstart();
void action_snapshot();
void action_pause();
void action_unpause();
void action_restart();
void action_stop();
void action_user();
void write_config();
void config();
void ptz();
};
#endif /* _INCLUDE_WEBU_POST_HPP_ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */