From 7bd179c0850115c51474caa5d6bcd4784f6b8d65 Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sun, 9 Dec 2018 11:52:25 -0700 Subject: [PATCH 01/10] Update Version number to 4.2.1+git --- version.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/version.sh b/version.sh index 6a4b855c3..e08deebe2 100755 --- a/version.sh +++ b/version.sh @@ -13,5 +13,6 @@ if [ -d .git ]; then else GIT_COMMIT="gitUNKNOWN" fi -printf "$BASE_VERSION" -#printf "$BASE_VERSION+$GIT_COMMIT" +#printf "$BASE_VERSION" +printf "$BASE_VERSION+$GIT_COMMIT" + From 1faacf12bed29c954ef05dbf5f5f9caddb10345c Mon Sep 17 00:00:00 2001 From: Martin Pollard Date: Mon, 14 Jan 2019 05:03:04 +0000 Subject: [PATCH 02/10] Fix webu_hostname to handle IPv6 [] colons (#885) webu_hostname currently incorrectly parses IPv6 [] style IP addresses in hostnames because it misinterprets the colons within them as the port delimiting colon. --- webu.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/webu.c b/webu.c index 1d9a55ffc..9976081a2 100644 --- a/webu.c +++ b/webu.c @@ -831,10 +831,19 @@ static void webu_hostname(struct webui_ctx *webui, int ctrl) { hdr = MHD_lookup_connection_value (webui->connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST); if (hdr != NULL){ snprintf(webui->hostname, WEBUI_LEN_PARM, "%s", hdr); - en_pos = strstr(webui->hostname, ":"); - if (en_pos != NULL){ - host_len = en_pos - webui->hostname + 1; - snprintf(webui->hostname, host_len, "%s", hdr); + /* IPv6 addresses have :'s in them so special case them */ + if (webui->hostname[0] == '['){ + en_pos = strstr(webui->hostname, "]"); + if (en_pos != NULL){ + host_len = en_pos - webui->hostname + 2; + snprintf(webui->hostname, host_len, "%s", hdr); + } + } else { + en_pos = strstr(webui->hostname, ":"); + if (en_pos != NULL){ + host_len = en_pos - webui->hostname + 1; + snprintf(webui->hostname, host_len, "%s", hdr); + } } } else { gethostname(webui->hostname, WEBUI_LEN_PARM - 1); From 5508eb0c5ac56ecc8fcfc2f989edf55abf482cfb Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sat, 19 Jan 2019 20:35:10 -0700 Subject: [PATCH 03/10] Initialize for track type 4 Closes #877 --- motion.c | 1 + 1 file changed, 1 insertion(+) diff --git a/motion.c b/motion.c index b5e3bfcf9..aa7dab2e9 100644 --- a/motion.c +++ b/motion.c @@ -1389,6 +1389,7 @@ static int motion_init(struct context *cnt) MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error capturing first image")); } } + cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in]; /* create a reference frame */ alg_update_reference_frame(cnt, RESET_REF_FRAME); From b550370585cde6e5241ac602bb97104d9b41acd2 Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sat, 19 Jan 2019 20:36:22 -0700 Subject: [PATCH 04/10] Save preview on emulate Closes #876 --- motion.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/motion.c b/motion.c index aa7dab2e9..e42c254bb 100644 --- a/motion.c +++ b/motion.c @@ -2467,6 +2467,11 @@ static void mlp_actions(struct context *cnt){ } cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); + /* Mark all images in image_ring to be saved */ + for (indx = 0; indx < cnt->imgs.image_ring_size; indx++){ + cnt->imgs.image_ring[indx].flags |= IMAGE_SAVE; + } + motion_detected(cnt, cnt->video_dev, cnt->current_image); } else if ((cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0)) { /* From f40b46f331016fb8241de54ebfc556e696cc450b Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sat, 19 Jan 2019 20:38:31 -0700 Subject: [PATCH 05/10] Answer stream only after first pass of motion loop closes #883 --- webu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webu.c b/webu.c index 9976081a2..5386634b6 100644 --- a/webu.c +++ b/webu.c @@ -1264,6 +1264,9 @@ static int webu_answer_strm(void *cls return MHD_YES; } + /* Do not answer a request until the motion loop has completed at least once */ + if (webui->cnt->passflag == 0) return MHD_NO; + if (strcmp (method, "GET") != 0){ MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO ,_("Invalid Method requested: %s"),method); return MHD_NO; From 1d6556289b30cc6ca2775277b1062dbcc94b4929 Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sat, 19 Jan 2019 20:39:13 -0700 Subject: [PATCH 06/10] Revise stream rate --- webu.c | 1 + webu.h | 1 + webu_stream.c | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/webu.c b/webu.c index 5386634b6..728c1108a 100644 --- a/webu.c +++ b/webu.c @@ -86,6 +86,7 @@ static void webu_context_init(struct context **cntlst, struct context *cnt, stru webui->resp_size = WEBUI_LEN_RESP * 10; /* The size of the resp_page buffer. May get adjusted */ webui->resp_used = 0; /* How many bytes used so far in resp_page*/ webui->stream_pos = 0; /* Stream position of image being sent */ + webui->stream_fps = 1; /* Stream rate */ webui->resp_page = mymalloc(webui->resp_size); /* The response being constructed */ webui->cntlst = cntlst; /* The list of context's for all cameras */ webui->cnt = cnt; /* The context pointer for a single camera */ diff --git a/webu.h b/webu.h index 7ea018696..d542eeca2 100644 --- a/webu.h +++ b/webu.h @@ -60,6 +60,7 @@ struct webui_ctx { size_t resp_size; /* The allocated size of the response */ size_t resp_used; /* The amount of the response page used */ uint64_t stream_pos; /* Stream position of sent image */ + int stream_fps; /* Stream rate per second */ struct timeval time_last; /* Keep track of processing time for stream thread*/ int mhd_first; /* Boolean for whether it is the first connection*/ diff --git a/webu_stream.c b/webu_stream.c index 21e9af4e7..74663a239 100644 --- a/webu_stream.c +++ b/webu_stream.c @@ -49,8 +49,8 @@ static void webu_stream_mjpeg_delay(struct webui_ctx *webui) { if (stream_delay < 0) stream_delay = 0; if (stream_delay > 1000000000 ) stream_delay = 1000000000; - if (webui->cnt->conf.stream_maxrate >= 1){ - stream_rate = ( (1000000000 / webui->cnt->conf.stream_maxrate) - stream_delay); + if (webui->stream_fps >= 1){ + stream_rate = ( (1000000000 / webui->stream_fps) - stream_delay); if ((stream_rate > 0) && (stream_rate < 1000000000)){ SLEEP(0,stream_rate); } else if (stream_rate == 1000000000) { @@ -88,6 +88,11 @@ static void webu_stream_mjpeg_getimg(struct webui_ctx *webui) { /* Copy jpg from the motion loop thread */ pthread_mutex_lock(&webui->cnt->mutex_stream); + if ((!webui->cnt->detecting_motion) && (webui->cnt->conf.stream_motion)){ + webui->stream_fps = 1; + } else { + webui->stream_fps = webui->cnt->conf.stream_maxrate; + } if (local_stream->jpeg_data == NULL) { pthread_mutex_unlock(&webui->cnt->mutex_stream); return; From 503af40f1db2b9178cb51ad1843a684e1188e0aa Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sat, 19 Jan 2019 20:40:59 -0700 Subject: [PATCH 07/10] Set packet stream_index for pass through Closes #889 --- ffmpeg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ffmpeg.c b/ffmpeg.c index dc2666a3c..a8afa6e6e 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -989,6 +989,8 @@ static void ffmpeg_passthru_write(struct ffmpeg *ffmpeg, int indx){ return; } + ffmpeg->pkt.stream_index = 0; + retcd = av_write_frame(ffmpeg->oc, &ffmpeg->pkt); my_packet_unref(ffmpeg->pkt); if (retcd < 0) { From cf1582967c5aa819821d1c7dd40f8130c83677cd Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sun, 3 Feb 2019 10:16:59 -0700 Subject: [PATCH 08/10] Webcontrol Actions (#900) * Update Webcontrol Actions and Resolve Compiler Warnings --- conf.c | 6 ++-- event.c | 84 +++++++++++++++++++++++++++++++++++++--------- motion.1 | 15 ++++++++- motion.c | 22 +++++++++++- motion_config.html | 55 ++++++++++++++++++++++++------ picture.c | 9 ++++- video_common.c | 38 ++------------------- webu.c | 61 ++++++++++++++++++++++++++++----- webu_html.c | 6 ++-- webu_text.c | 30 ++++++++--------- 10 files changed, 234 insertions(+), 92 deletions(-) diff --git a/conf.c b/conf.c index 19f92f69e..1e8ff1a46 100644 --- a/conf.c +++ b/conf.c @@ -2359,7 +2359,9 @@ struct context **conf_load(struct context **cnt) exit(-1); } - snprintf(filename, PATH_MAX, "%s/motion.conf", path); + snprintf(filename, PATH_MAX, "%.*s/motion.conf" + , (int)(PATH_MAX-1-strlen("/motion.conf")) + , path); fp = fopen (filename, "r"); } @@ -3120,7 +3122,7 @@ static struct context **config_camera(struct context **cnt, const char *str, */ static void usage() { - printf("motion Version "VERSION", Copyright 2000-2018 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen/Motion-Project maintainers\n"); + printf("motion Version "VERSION", Copyright 2000-2019 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen/Motion-Project maintainers\n"); printf("\nHome page :\t https://motion-project.github.io/ \n"); printf("\nusage:\tmotion [options]\n"); printf("\n\n"); diff --git a/event.c b/event.c index bcf2a3e2e..78b3a95a7 100644 --- a/event.c +++ b/event.c @@ -521,7 +521,11 @@ static void event_image_detect(struct context *cnt, imagepath = DEF_IMAGEPATH; mystrftime(cnt, filename, sizeof(filename), imagepath, currenttime_tv, NULL, 0); - snprintf(fullfilename, PATH_MAX, "%s/%s.%s", cnt->conf.target_dir, filename, imageext(cnt)); + snprintf(fullfilename, PATH_MAX, "%.*s/%.*s.%s" + , (int)(PATH_MAX-2-strlen(filename)-strlen(imageext(cnt))) + , cnt->conf.target_dir + , (int)(PATH_MAX-2-strlen(cnt->conf.target_dir)-strlen(imageext(cnt))) + , filename, imageext(cnt)); passthrough = util_check_passthrough(cnt); if ((cnt->imgs.size_high > 0) && (!passthrough)) { @@ -558,9 +562,14 @@ static void event_imagem_detect(struct context *cnt, mystrftime(cnt, filename, sizeof(filename), imagepath, currenttime_tv, NULL, 0); /* motion images gets same name as normal images plus an appended 'm' */ - snprintf(filenamem, PATH_MAX, "%sm", filename); - snprintf(fullfilenamem, PATH_MAX, "%s/%s.%s", cnt->conf.target_dir, filenamem, imageext(cnt)); - + snprintf(filenamem, PATH_MAX, "%.*sm" + , (int)(PATH_MAX-1-strlen(filename)) + , filename); + snprintf(fullfilenamem, PATH_MAX, "%.*s/%.*s.%s" + , (int)(PATH_MAX-2-strlen(filenamem)-strlen(imageext(cnt))) + , cnt->conf.target_dir + , (int)(PATH_MAX-2-strlen(cnt->conf.target_dir)-strlen(imageext(cnt))) + , filenamem, imageext(cnt)); put_picture(cnt, fullfilenamem, cnt->imgs.img_motion.image_norm, FTYPE_IMAGE_MOTION); event(cnt, EVENT_FILECREATE, NULL, fullfilenamem, (void *)FTYPE_IMAGE, currenttime_tv); } @@ -593,8 +602,14 @@ static void event_image_snapshot(struct context *cnt, snappath = DEF_SNAPPATH; mystrftime(cnt, filepath, sizeof(filepath), snappath, currenttime_tv, NULL, 0); - snprintf(filename, PATH_MAX, "%s.%s", filepath, imageext(cnt)); - snprintf(fullfilename, PATH_MAX, "%s/%s", cnt->conf.target_dir, filename); + snprintf(filename, PATH_MAX, "%.*s.%s" + , (int)(PATH_MAX-1-strlen(filepath)-strlen(imageext(cnt))) + , filepath, imageext(cnt)); + snprintf(fullfilename, PATH_MAX, "%.*s/%.*s" + , (int)(PATH_MAX-1-strlen(filename)) + , cnt->conf.target_dir + , (int)(PATH_MAX-1-strlen(cnt->conf.target_dir)) + , filename); put_picture(cnt, fullfilename, img_data->image_norm, FTYPE_IMAGE_SNAPSHOT); event(cnt, EVENT_FILECREATE, NULL, fullfilename, (void *)FTYPE_IMAGE, currenttime_tv); @@ -602,7 +617,10 @@ static void event_image_snapshot(struct context *cnt, * Update symbolic link *after* image has been written so that * the link always points to a valid file. */ - snprintf(linkpath, PATH_MAX, "%s/lastsnap.%s", cnt->conf.target_dir, imageext(cnt)); + snprintf(linkpath, PATH_MAX, "%.*s/lastsnap.%s" + , (int)(PATH_MAX-strlen("/lastsnap.")-strlen(imageext(cnt))) + , cnt->conf.target_dir, imageext(cnt)); + remove(linkpath); if (symlink(filename, linkpath)) { @@ -612,8 +630,14 @@ static void event_image_snapshot(struct context *cnt, } } else { mystrftime(cnt, filepath, sizeof(filepath), cnt->conf.snapshot_filename, currenttime_tv, NULL, 0); - snprintf(filename, PATH_MAX, "%s.%s", filepath, imageext(cnt)); - snprintf(fullfilename, PATH_MAX, "%s/%s", cnt->conf.target_dir, filename); + snprintf(filename, PATH_MAX, "%.*s.%s" + , (int)(PATH_MAX-1-strlen(imageext(cnt))) + , filepath, imageext(cnt)); + snprintf(fullfilename, PATH_MAX, "%.*s/%.*s" + , (int)(PATH_MAX-1-strlen(filename)) + , cnt->conf.target_dir + , (int)(PATH_MAX-1-strlen(cnt->conf.target_dir)) + , filename); remove(fullfilename); put_picture(cnt, fullfilename, img_data->image_norm, FTYPE_IMAGE_SNAPSHOT); event(cnt, EVENT_FILECREATE, NULL, fullfilename, (void *)FTYPE_IMAGE, currenttime_tv); @@ -687,7 +711,11 @@ static void event_image_preview(struct context *cnt, imagepath = (char *)DEF_IMAGEPATH; mystrftime(cnt, filename, sizeof(filename), imagepath, &cnt->imgs.preview_image.timestamp_tv, NULL, 0); - snprintf(previewname, PATH_MAX, "%s/%s.%s", cnt->conf.target_dir, filename, imageext(cnt)); + snprintf(previewname, PATH_MAX, "%.*s/%.*s.%s" + , (int)(PATH_MAX-2-strlen(filename)-strlen(imageext(cnt))) + , cnt->conf.target_dir + , (int)(PATH_MAX-2-strlen(cnt->conf.target_dir)-strlen(imageext(cnt))) + , filename, imageext(cnt)); passthrough = util_check_passthrough(cnt); if ((cnt->imgs.size_high > 0) && (!passthrough)) { @@ -771,7 +799,11 @@ static void event_create_extpipe(struct context *cnt, } mystrftime(cnt, stamp, sizeof(stamp), moviepath, currenttime_tv, NULL, 0); - snprintf(cnt->extpipefilename, PATH_MAX - 4, "%s/%s", cnt->conf.target_dir, stamp); + snprintf(cnt->extpipefilename, PATH_MAX - 4, "%.*s/%.*s" + , (int)(PATH_MAX-5-strlen(stamp)) + , cnt->conf.target_dir + , (int)(PATH_MAX-5-strlen(cnt->conf.target_dir)) + , stamp); if (access(cnt->conf.target_dir, W_OK)!= 0) { /* Permission denied */ @@ -943,11 +975,27 @@ static void event_ffmpeg_newfile(struct context *cnt, codec = "msmpeg4"; break; } - snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%s_%sm", cnt->conf.target_dir, codec, stamp); - snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s_%s", cnt->conf.target_dir, codec, stamp); + snprintf(cnt->motionfilename, PATH_MAX - 4, "%.*s/%s_%.*sm" + , (int)(PATH_MAX-7-strlen(stamp)-strlen(codec)) + , cnt->conf.target_dir, codec + , (int)(PATH_MAX-7-strlen(cnt->conf.target_dir)-strlen(codec)) + , stamp); + snprintf(cnt->newfilename, PATH_MAX - 4, "%.*s/%s_%.*s" + , (int)(PATH_MAX-6-strlen(stamp)-strlen(codec)) + , cnt->conf.target_dir, codec + , (int)(PATH_MAX-6-strlen(cnt->conf.target_dir)-strlen(codec)) + , stamp); } else { - snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%sm", cnt->conf.target_dir, stamp); - snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s", cnt->conf.target_dir, stamp); + snprintf(cnt->motionfilename, PATH_MAX - 4, "%.*s/%.*sm" + , (int)(PATH_MAX-6-strlen(stamp)) + , cnt->conf.target_dir + , (int)(PATH_MAX-6-strlen(cnt->conf.target_dir)) + , stamp); + snprintf(cnt->newfilename, PATH_MAX - 4, "%.*s/%.*s" + , (int)(PATH_MAX-5-strlen(stamp)) + , cnt->conf.target_dir + , (int)(PATH_MAX-5-strlen(cnt->conf.target_dir)) + , stamp); } if (cnt->conf.movie_output) { cnt->ffmpeg_output = mymalloc(sizeof(struct ffmpeg)); @@ -1056,7 +1104,11 @@ static void event_ffmpeg_timelapse(struct context *cnt, mystrftime(cnt, tmp, sizeof(tmp), timepath, currenttime_tv, NULL, 0); /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */ - snprintf(cnt->timelapsefilename, PATH_MAX - 4, "%s/%s", cnt->conf.target_dir, tmp); + snprintf(cnt->timelapsefilename, PATH_MAX - 4, "%.*s/%.*s" + , (int)(PATH_MAX-5-strlen(tmp)) + , cnt->conf.target_dir + , (int)(PATH_MAX-5-strlen(cnt->conf.target_dir)) + , tmp); passthrough = util_check_passthrough(cnt); cnt->ffmpeg_timelapse = mymalloc(sizeof(struct ffmpeg)); if ((cnt->imgs.size_high > 0) && (!passthrough)){ diff --git a/motion.1 b/motion.1 index 926b4b373..65a8878a6 100644 --- a/motion.1 +++ b/motion.1 @@ -1,4 +1,4 @@ -.TH MOTION 1 2018-10-20 "Motion" "Motion Options and Config Files" +.TH MOTION 1 2019-02-02 "Motion" "Motion Options and Config Files" .SH NAME motion \- Detect motion using a video4linux device or network camera .SH SYNOPSIS @@ -1803,6 +1803,19 @@ Maximum frame rate to send to stream .RE .RE +.TP +.B stream_motion +.RS +.nf +Values: on,off +Default: off +Description: +.fi +.RS +Limit stream to 1 fps when no motion is being detected. +.RE +.RE + .TP .B database_type .RS diff --git a/motion.c b/motion.c index e42c254bb..66ebdcefa 100644 --- a/motion.c +++ b/motion.c @@ -364,7 +364,7 @@ static void sig_handler(int signo) if (cnt_list) { i = -1; while (cnt_list[++i]) { - cnt_list[i]->webcontrol_finish = 1; + cnt_list[i]->webcontrol_finish = TRUE; cnt_list[i]->event_stop = TRUE; cnt_list[i]->finish = 1; /* @@ -3435,6 +3435,8 @@ static void motion_watchdog(int indx){ * Best to just not get into a watchdog situation... */ + if (!cnt_list[indx]->running) return; + cnt_list[indx]->watchdog--; if (cnt_list[indx]->watchdog == 0) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO @@ -3538,6 +3540,24 @@ static int motion_check_threadcount(void){ motion_threads_running++; } + /* If the web control/streams are in finish/shutdown, we + * do not want to count them. They will be completely closed + * by the process outside of loop that is checking the counts + * of threads. If the webcontrol is not in a finish / shutdown + * then we want to keep them in the tread count to allow user + * to restart the cameras and keep Motion running. + */ + indx = 0; + while (cnt_list[indx] != NULL){ + if ((cnt_list[indx]->webcontrol_finish == FALSE) && + ((cnt_list[indx]->webcontrol_daemon != NULL) || + (cnt_list[indx]->webstream_daemon != NULL))) { + motion_threads_running++; + } + indx++; + } + + if (((motion_threads_running == 0) && finish) || ((motion_threads_running == 0) && (threads_running == 0))) { MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO diff --git a/motion_config.html b/motion_config.html index 615a7592b..130e90ccb 100644 --- a/motion_config.html +++ b/motion_config.html @@ -1173,6 +1173,12 @@

Configuration Options-Listed Alph stream_maxrate stream_maxrate + + webcam_motion + stream_motion + stream_motion + stream_motion + webcam_port stream_port @@ -1527,12 +1533,6 @@

Configuration Options-Listed Alph stream_limit -Depreciated - - webcam_motion - stream_motion - stream_motion - -Depreciated - @@ -1958,7 +1958,10 @@

Configuration Options-Listed by T stream_grey stream_maxrate - + + stream_motion + +

@@ -4750,13 +4753,33 @@

Web Control

  • {IP}:{port}/{camid}/action/eventend Trigger the end of a event.
  • {IP}:{port}/{camid}/action/snapshot Create a snapshot
  • {IP}:{port}/{camid}/action/restart Shutdown and restart Motion
  • -
  • {IP}:{port}/{camid}/action/quit Shutdown Motion
  • +
  • {IP}:{port}/{camid}/action/quit Close all connections to the camera
  • +
  • {IP}:{port}/{camid}/action/end Entirely shutdown the Motion application
  • {IP}:{port}/{camid}/track/center Send command to center PTZ camera
  • {IP}:{port}/{camid}/track/set?x={value1}&y={value2} Send command to PTZ camera to move to location specified by x and y
  • {IP}:{port}/{camid}/track/set?pan={value1}&tilt={value2} Send command to PTZ camera to pan to value1 and tilt to value2
  • +

    + As a general rule, when the {camid} references the camera_id in the main motion.conf file, the webcontrol + actions referenced above are going to be applied to every camera that is connected to Motion. This camera_id + is usually specified as 0 (zero). So issuing a command of {IP}:{port}/0/detection/pause is + going to pause all the cameras. +

    + A point of clarification with respect to the differences between pause, quit, + and end. When the action of pause is executed, Motion will stop the motion detection + processing and of course all events but will continue to process and decode images from the camera. This allows + for a faster transition when the user executes a start The quit action conversely not + only stops the motion detection but also disconnects from the camera and decoding of images. To start motion + detection after a quit, the user must execute a restart which will reinitialize the + connection to the camera. And since the camera was completely disconnect, it can take more than a few seconds + for Motion to fully start and have the camera available for processing or viewing. Finally, there is an + option for end. This option completely terminates the Motion application. It closes all connections + to all the cameras and terminates the application. This may be required when running Motion in daemon mode. + Note that there is no way to restart the Motion application from the webcontrol interface after processing + a end request. +

    If the item above is available via the HTML/CSS interface, it is also possible to see the exact URL sent to Motion in the log. Change the log level to 8 (debug), then open up the Motion webcontrol interface and @@ -5196,6 +5219,18 @@

    stream_maxrate

    Don't set this parameter too high unless you only use it on the localhost or on an internal LAN.

    +

    stream_motion

    +

    +
      +
    • Type: boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    + Limit the framerate to 1 frame per second when there is no motion being detected and increase + it to the stream_maxrate when there is motion. +

    + @@ -5388,8 +5423,8 @@

    sql_query_stop

  • Default: Not defined
  • - SQL query that executes on a event where a file is closed after a event of motion. - This can be used to for example update the events table with an end timestamp for the recordings. + SQL query that executes after a movie has finished. + This can be used to for example update the events table with an end timestamp for the recording.

    You can use Conversion Specifiers within the query. diff --git a/picture.c b/picture.c index 4b82913a0..6710dda95 100644 --- a/picture.c +++ b/picture.c @@ -235,6 +235,7 @@ static unsigned prepare_exif(unsigned char **exif, */ char *description, *datetime, *subtime; char datetime_buf[22]; + char tmpbuf[45]; struct tm timestamp_tm; struct timeval tv1; @@ -246,13 +247,19 @@ static unsigned prepare_exif(unsigned char **exif, localtime_r(&tv1.tv_sec, ×tamp_tm); /* Exif requires this exact format */ - snprintf(datetime_buf, 21, "%04d:%02d:%02d %02d:%02d:%02d", + /* The compiler is twitchy on truncating formats and the exif is twitchy + * on the length of the whole string. So we do it in two steps of printing + * into a large buffer which compiler wants, then print that into the smaller + * buffer that exif wants..TODO Find better method + */ + snprintf(tmpbuf, 45, "%04d:%02d:%02d %02d:%02d:%02d", timestamp_tm.tm_year + 1900, timestamp_tm.tm_mon + 1, timestamp_tm.tm_mday, timestamp_tm.tm_hour, timestamp_tm.tm_min, timestamp_tm.tm_sec); + snprintf(datetime_buf, 22,"%.21s",tmpbuf); datetime = datetime_buf; // TODO: Extract subsecond timestamp from somewhere, but only diff --git a/video_common.c b/video_common.c index 7068f0589..c285eca01 100644 --- a/video_common.c +++ b/video_common.c @@ -477,43 +477,9 @@ void vid_y10torgb24(unsigned char *map, unsigned char *cap_map, int width, int h void vid_greytoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height) { - /* This is a adaptation of the rgb to yuv. - * For grey, we use just a single color - */ - - unsigned char *y, *u, *v; - unsigned char *r; - int i, loop; - r = cap_map; - - y = map; - u = y + width * height; - v = u + (width * height) / 4; - memset(u, 0, width * height / 4); - memset(v, 0, width * height / 4); - - for (loop = 0; loop < height; loop++) { - for (i = 0; i < width; i += 2) { - *y++ = (9796 ** r + 19235 ** r + 3736 ** r) >> 15; - *u += ((-4784 ** r - 9437 ** r + 14221 ** r) >> 17) + 32; - *v += ((20218 ** r - 16941 ** r - 3277 ** r) >> 17) + 32; - r++; - - *y++ = (9796 ** r + 19235 ** r + 3736 ** r) >> 15; - *u += ((-4784 ** r - 9437 ** r + 14221 ** r) >> 17) + 32; - *v += ((20218 ** r - 16941 ** r - 3277 ** r) >> 17) + 32; - r ++; - - u++; - v++; - } - - if ((loop & 1) == 0) { - u -= width / 2; - v -= width / 2; - } - } + memcpy(map, cap_map, (width*height)); + memset(map+(width*height), 128, (width * height) / 2); } diff --git a/webu.c b/webu.c index 728c1108a..3e0cae2bf 100644 --- a/webu.c +++ b/webu.c @@ -576,20 +576,52 @@ void webu_process_action(struct webui_ctx *webui) { } else if (!strcmp(webui->uri_cmd2,"restart")){ - /* This is the legacy method...(we can do better than signals..).*/ if (webui->thread_nbr == 0) { - MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("httpd is going to restart")); - kill(getpid(),SIGHUP); + MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Restarting all threads")); webui->cntlst[0]->webcontrol_finish = TRUE; + kill(getpid(),SIGHUP); } else { MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, - _("httpd is going to restart thread %d"),webui->thread_nbr); + _("Restarting thread %d"),webui->thread_nbr); + webui->cnt->restart = TRUE; if (webui->cnt->running) { webui->cnt->event_stop = TRUE; - webui->cnt->finish = 1; + webui->cnt->finish = TRUE; } - webui->cnt->restart = 1; + } + + } else if (!strcmp(webui->uri_cmd2,"quit")){ + if (webui->thread_nbr == 0 && webui->cam_threads > 1) { + while (webui->cntlst[++indx]){ + MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, + _("Quitting thread %d"),webui->thread_nbr); + webui->cntlst[indx]->restart = FALSE; + webui->cntlst[indx]->event_stop = TRUE; + webui->cntlst[indx]->event_user = TRUE; + webui->cntlst[indx]->finish = TRUE; + } + } else { + MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, + _("Quitting thread %d"),webui->thread_nbr); + webui->cnt->restart = FALSE; + webui->cnt->event_stop = TRUE; + webui->cnt->event_user = TRUE; + webui->cnt->finish = TRUE; + } + + } else if (!strcmp(webui->uri_cmd2,"end")){ + MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("Motion terminating")); + while (webui->cntlst[indx]){ + webui->cntlst[indx]->webcontrol_finish = TRUE; + webui->cntlst[indx]->restart = FALSE; + webui->cntlst[indx]->event_stop = TRUE; + webui->cntlst[indx]->event_user = TRUE; + webui->cntlst[indx]->finish = TRUE; + indx++; + } + + } else if (!strcmp(webui->uri_cmd2,"start")){ if (webui->thread_nbr == 0 && webui->cam_threads > 1) { do { @@ -2017,16 +2049,19 @@ void webu_stop(struct context **cnt) { int indxthrd; if (cnt[0]->webcontrol_daemon != NULL){ - cnt[0]->webcontrol_finish = 1; + cnt[0]->webcontrol_finish = TRUE; MHD_stop_daemon (cnt[0]->webcontrol_daemon); } + indxthrd = 0; while (cnt[indxthrd] != NULL){ if (cnt[indxthrd]->webstream_daemon != NULL){ - cnt[indxthrd]->webcontrol_finish = 1; + cnt[indxthrd]->webcontrol_finish = TRUE; MHD_stop_daemon (cnt[indxthrd]->webstream_daemon); } + cnt[indxthrd]->webstream_daemon = NULL; + cnt[indxthrd]->webcontrol_daemon = NULL; indxthrd++; } } @@ -2037,6 +2072,7 @@ void webu_start(struct context **cnt) { * will not function correctly. */ struct sigaction act; + int indxthrd; /* set signal handlers TO IGNORE */ memset(&act, 0, sizeof(act)); @@ -2045,6 +2081,15 @@ void webu_start(struct context **cnt) { sigaction(SIGPIPE, &act, NULL); sigaction(SIGCHLD, &act, NULL); + + indxthrd = 0; + while (cnt[indxthrd] != NULL){ + cnt[indxthrd]->webstream_daemon = NULL; + cnt[indxthrd]->webcontrol_daemon = NULL; + cnt[indxthrd]->webcontrol_finish = FALSE; + indxthrd++; + } + if (cnt[0]->conf.stream_preview_method != 99){ webu_start_ports(cnt); diff --git a/webu_html.c b/webu_html.c index 0a18a8f66..e2ad9f8b3 100644 --- a/webu_html.c +++ b/webu_html.c @@ -324,6 +324,7 @@ static void webu_html_navbar_action(struct webui_ctx *webui) { " %s\n" " %s\n" " %s\n" + " %s\n" " \n" " \n" ,_("Action") @@ -335,7 +336,8 @@ static void webu_html_navbar_action(struct webui_ctx *webui) { ,_("Tracking") ,_("Pause") ,_("Start") - ,_("Restart")); + ,_("Restart") + ,_("Quit")); webu_write(webui, response); } @@ -491,7 +493,7 @@ static void webu_html_config(struct webui_ctx *webui) { ,webui->cntlst[indx]->camera_id); webu_write(webui, response); if (val_thread != NULL){ - snprintf(response, sizeof (response),"%s%s", response, val_thread); + snprintf(response, sizeof (response),"%s", val_thread); webu_write(webui, response); } } diff --git a/webu_text.c b/webu_text.c index 489710d78..f87595d6c 100644 --- a/webu_text.c +++ b/webu_text.c @@ -435,22 +435,13 @@ static void webu_text_get_menu(struct webui_ctx *webui) { } -static void webu_text_quit(struct webui_ctx *webui) { +static void webu_text_action_quit(struct webui_ctx *webui) { /* Shut down motion or the associated thread */ char response[WEBUI_LEN_RESP]; - /* This is the legacy method...(we can do better than signals..).*/ - if (webui->thread_nbr == 0) { - MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, _("httpd quits")); - kill(getpid(),SIGQUIT); - webui->cntlst[0]->webcontrol_finish = TRUE; - } else { - MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, - _("httpd quits thread %d"),webui->thread_nbr); - webui->cnt->restart = 0; - webui->cnt->event_stop = TRUE; - webui->cnt->finish = 1; - } + webu_process_action(webui); + + webu_text_back(webui,"/action"); webu_text_header(webui); snprintf(response,sizeof(response), @@ -661,6 +652,10 @@ static void webu_text_action(struct webui_ctx *webui) { } else if (!strcmp(webui->uri_cmd2,"pause")){ webu_text_action_pause(webui); + } else if ((!strcmp(webui->uri_cmd2,"quit")) || + (!strcmp(webui->uri_cmd2,"end"))){ + webu_text_action_quit(webui); + } else if ((!strcmp(webui->uri_cmd2,"write")) || (!strcmp(webui->uri_cmd2,"writeyes"))){ webu_text_action_write(webui); @@ -789,8 +784,9 @@ static void webu_text_menu_action(struct webui_ctx *webui) { "snapshot
    " "restart
    " "quit
    " + "end
    " + ,webui->uri_camid, webui->uri_camid, webui->uri_camid ,webui->uri_camid, webui->uri_camid, webui->uri_camid - ,webui->uri_camid, webui->uri_camid ); webu_write(webui, response); webu_text_trailer(webui); @@ -1102,7 +1098,11 @@ void webu_text_main(struct webui_ctx *webui) { } else if ((strcmp(webui->uri_cmd1,"action") == 0) && (strcmp(webui->uri_cmd2,"quit") == 0)){ - webu_text_quit(webui); + webu_text_action(webui); + + } else if ((strcmp(webui->uri_cmd1,"action") == 0) && + (strcmp(webui->uri_cmd2,"end") == 0)){ + webu_text_action(webui); } else if (!strcmp(webui->uri_cmd1,"action")) { webu_text_action(webui); From b5b8496492e8624daec7225bcee440dc6c5ba386 Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sun, 3 Feb 2019 10:40:17 -0700 Subject: [PATCH 09/10] OpenBSD compile --- motion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/motion.h b/motion.h index 585ea5194..2a4dbe9a3 100644 --- a/motion.h +++ b/motion.h @@ -53,7 +53,7 @@ struct image_data; #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) #include #endif From c43a56095e78a41e337010f8a1e016a4bf57014f Mon Sep 17 00:00:00 2001 From: Mr-DaveDev Date: Sun, 3 Feb 2019 11:51:34 -0700 Subject: [PATCH 10/10] Version 4.2.2 --- CHANGELOG | 12 ++++++++++++ version.sh | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 18c590e1e..9bc25aa28 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,15 @@ +Summary of changes for version 4.2.2 are below + * Update version number to 4.2.2/Changelog + * Resolve compile problem for OpenBSD + * Resolve compiler warnings for 18.10 + * Guide/Manual updates + * Add the quit/end webcontrol actions to interface 0 + * Set the stream index on passthrough + * Revise the webcontrol stream rate + * Answer webcontrol stream only after completing first loop + * Save the preview images when triggering emulate + * Fix startup problem when using track_type 4 + * Fix hostname for webcontrol when using IPV6 Summary of changes for version 4.2.1 are below * Update version number to 4.2.1 / Changelog * Report to log options included in build diff --git a/version.sh b/version.sh index e08deebe2..1a9b9422b 100755 --- a/version.sh +++ b/version.sh @@ -1,5 +1,5 @@ #!/bin/sh -BASE_VERSION="4.2.1" +BASE_VERSION="4.2.2" if [ -d .git ]; then if test "`git diff --name-only`" = "" ; then GIT_COMMIT="git" @@ -13,6 +13,6 @@ if [ -d .git ]; then else GIT_COMMIT="gitUNKNOWN" fi -#printf "$BASE_VERSION" -printf "$BASE_VERSION+$GIT_COMMIT" +printf "$BASE_VERSION" +#printf "$BASE_VERSION+$GIT_COMMIT"