1 /*    motion.c
2  *
3  *    Detect changes in a video stream.
4  *    Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org)
5  *    This software is distributed under the GNU public license version 2
6  *    See also the file 'COPYING'.
7  *
8  */
9 #include "translate.h"
10 #include "motion.h"
11 #include "ffmpeg.h"
12 #include "video_common.h"
13 #include "video_v4l2.h"
14 #include "video_loopback.h"
15 #include "conf.h"
16 #include "alg.h"
17 #include "track.h"
18 #include "event.h"
19 #include "picture.h"
20 #include "rotate.h"
21 #include "webu.h"
22 
23 
24 #define IMAGE_BUFFER_FLUSH ((unsigned int)-1)
25 
26 /**
27  * tls_key_threadnr
28  *
29  *   TLS key for storing thread number in thread-local storage.
30  */
31 pthread_key_t tls_key_threadnr;
32 
33 /**
34  * global_lock
35  *
36  *   Protects any global variables (like 'threads_running') during updates,
37  *   to prevent problems with multiple threads updating at the same time.
38  */
39 //pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
40 pthread_mutex_t global_lock;
41 
42 /**
43  * cnt_list
44  *
45  *   List of context structures, one for each main Motion thread.
46  */
47 struct context **cnt_list = NULL;
48 
49 /**
50  * threads_running
51  *
52  *   Keeps track of number of Motion threads currently running. Also used
53  *   by 'main' to know when all threads have exited.
54  */
55 volatile int threads_running = 0;
56 
57 /* Set this when we want main to end or restart */
58 volatile unsigned int finish = 0;
59 
60 /* Log file used instead of stderr and syslog */
61 FILE *ptr_logfile = NULL;
62 
63 /**
64  * restart
65  *
66  *   Differentiates between a quit and a restart. When all threads have
67  *   finished running, 'main' checks if 'restart' is true and if so starts
68  *   up again (instead of just quitting).
69  */
70 unsigned int restart = 0;
71 
72 
73 /**
74  * image_ring_resize
75  *
76  * This routine is called from motion_loop to resize the image precapture ringbuffer
77  * NOTE: This function clears all images in the old ring buffer
78 
79  * Parameters:
80  *
81  *      cnt      Pointer to the motion context structure
82  *      new_size The new size of the ring buffer
83  *
84  * Returns:     nothing
85  */
image_ring_resize(struct context * cnt,int new_size)86 static void image_ring_resize(struct context *cnt, int new_size)
87 {
88     /*
89      * Only resize if :
90      * Not in an event and
91      * decreasing at last position in new buffer
92      * increasing at last position in old buffer
93      * e.g. at end of smallest buffer
94      */
95     if (cnt->event_nr != cnt->prev_event) {
96         int smallest;
97 
98         if (new_size < cnt->imgs.image_ring_size)  /* Decreasing */
99             smallest = new_size;
100         else  /* Increasing */
101             smallest = cnt->imgs.image_ring_size;
102 
103         if (cnt->imgs.image_ring_in == smallest - 1 || smallest == 0) {
104             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
105                 ,_("Resizing pre_capture buffer to %d items"), new_size);
106 
107             /* Create memory for new ring buffer */
108             struct image_data *tmp;
109             tmp = mymalloc(new_size * sizeof(struct image_data));
110 
111             /*
112              * Copy all information from old to new
113              * Smallest is 0 at initial init
114              */
115             if (smallest > 0)
116                 memcpy(tmp, cnt->imgs.image_ring, sizeof(struct image_data) * smallest);
117 
118 
119             /* In the new buffers, allocate image memory */
120             {
121                 int i;
122                 for(i = smallest; i < new_size; i++) {
123                     tmp[i].image_norm = mymalloc(cnt->imgs.size_norm);
124                     memset(tmp[i].image_norm, 0x80, cnt->imgs.size_norm);  /* initialize to grey */
125                     if (cnt->imgs.size_high > 0){
126                         tmp[i].image_high = mymalloc(cnt->imgs.size_high);
127                         memset(tmp[i].image_high, 0x80, cnt->imgs.size_high);
128                     }
129                 }
130             }
131 
132             /* Free the old ring */
133             free(cnt->imgs.image_ring);
134 
135             /* Point to the new ring */
136             cnt->imgs.image_ring = tmp;
137             cnt->current_image = NULL;
138 
139             cnt->imgs.image_ring_size = new_size;
140 
141             cnt->imgs.image_ring_in = 0;
142             cnt->imgs.image_ring_out = 0;
143         }
144     }
145 }
146 
147 /**
148  * image_ring_destroy
149  *
150  * This routine is called when we want to free the ring
151  *
152  * Parameters:
153  *
154  *      cnt      Pointer to the motion context structure
155  *
156  * Returns:     nothing
157  */
image_ring_destroy(struct context * cnt)158 static void image_ring_destroy(struct context *cnt)
159 {
160     int i;
161 
162     /* Exit if don't have any ring */
163     if (cnt->imgs.image_ring == NULL)
164         return;
165 
166     /* Free all image buffers */
167     for (i = 0; i < cnt->imgs.image_ring_size; i++){
168         free(cnt->imgs.image_ring[i].image_norm);
169         if (cnt->imgs.size_high >0 ) free(cnt->imgs.image_ring[i].image_high);
170     }
171 
172     /* Free the ring */
173     free(cnt->imgs.image_ring);
174 
175     cnt->imgs.image_ring = NULL;
176     cnt->current_image = NULL;
177     cnt->imgs.image_ring_size = 0;
178 }
179 
180 /**
181  * image_save_as_preview
182  *
183  * This routine is called when we detect motion and want to save an image in the preview buffer
184  *
185  * Parameters:
186  *
187  *      cnt      Pointer to the motion context structure
188  *      img      Pointer to the image_data structure we want to set as preview image
189  *
190  * Returns:     nothing
191  */
image_save_as_preview(struct context * cnt,struct image_data * img)192 static void image_save_as_preview(struct context *cnt, struct image_data *img)
193 {
194     void *image_norm, *image_high;
195 
196     /* Save our pointers to our memory locations for images*/
197     image_norm = cnt->imgs.preview_image.image_norm;
198     image_high = cnt->imgs.preview_image.image_high;
199 
200     /* Copy over the meta data from the img into preview */
201     memcpy(&cnt->imgs.preview_image, img, sizeof(struct image_data));
202 
203     /* Restore the pointers to the memory locations for images*/
204     cnt->imgs.preview_image.image_norm = image_norm;
205     cnt->imgs.preview_image.image_high = image_high;
206 
207     /* Copy the actual images for norm and high */
208     memcpy(cnt->imgs.preview_image.image_norm, img->image_norm, cnt->imgs.size_norm);
209     if (cnt->imgs.size_high > 0){
210         memcpy(cnt->imgs.preview_image.image_high, img->image_high, cnt->imgs.size_high);
211     }
212 
213     /*
214      * If we set output_all to yes and during the event
215      * there is no image with motion, diffs is 0, we are not going to save the preview event
216      */
217     if (cnt->imgs.preview_image.diffs == 0)
218         cnt->imgs.preview_image.diffs = 1;
219 
220     /* draw locate box here when mode = LOCATE_PREVIEW */
221     if (cnt->locate_motion_mode == LOCATE_PREVIEW) {
222 
223         if (cnt->locate_motion_style == LOCATE_BOX) {
224             alg_draw_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image_norm,
225                               LOCATE_BOX, LOCATE_NORMAL, cnt->process_thisframe);
226         } else if (cnt->locate_motion_style == LOCATE_REDBOX) {
227             alg_draw_red_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image_norm,
228                                   LOCATE_REDBOX, LOCATE_NORMAL, cnt->process_thisframe);
229         } else if (cnt->locate_motion_style == LOCATE_CROSS) {
230             alg_draw_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image_norm,
231                               LOCATE_CROSS, LOCATE_NORMAL, cnt->process_thisframe);
232         } else if (cnt->locate_motion_style == LOCATE_REDCROSS) {
233             alg_draw_red_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image_norm,
234                                   LOCATE_REDCROSS, LOCATE_NORMAL, cnt->process_thisframe);
235         }
236     }
237 }
238 
239 /**
240  * context_init
241  *
242  *   Initializes a context struct with the default values for all the
243  *   variables.
244  *
245  * Parameters:
246  *
247  *   cnt - the context struct to destroy
248  *
249  * Returns: nothing
250  */
context_init(struct context * cnt)251 static void context_init(struct context *cnt)
252 {
253    /*
254     * We first clear the entire structure to zero, then fill in any
255     * values which have non-zero default values.  Note that this
256     * assumes that a NULL address pointer has a value of binary 0
257     * (this is also assumed at other places within the code, i.e.
258     * there are instances of "if (ptr)").  Just for possible future
259     * changes to this assumption, any pointers which are intended
260     * to be initialised to NULL are listed within a comment.
261     */
262 
263     memset(cnt, 0, sizeof(struct context));
264     cnt->noise = 255;
265     cnt->lastrate = 25;
266 
267     memcpy(&cnt->track, &track_template, sizeof(struct trackoptions));
268 
269     cnt->pipe = -1;
270     cnt->mpipe = -1;
271 
272     cnt->vdev = NULL;    /*Init to NULL to check loading parms vs web updates*/
273     cnt->netcam = NULL;
274     cnt->rtsp = NULL;
275     cnt->rtsp_high = NULL;
276 
277 }
278 
279 /**
280  * context_destroy
281  *
282  *   Destroys a context struct by freeing allocated memory, calling the
283  *   appropriate cleanup functions and finally freeing the struct itself.
284  *
285  * Parameters:
286  *
287  *   cnt - the context struct to destroy
288  *
289  * Returns: nothing
290  */
context_destroy(struct context * cnt)291 static void context_destroy(struct context *cnt)
292 {
293     unsigned int j;
294 
295     /* Free memory allocated for config parameters */
296     for (j = 0; config_params[j].param_name != NULL; j++) {
297         if (config_params[j].copy == copy_string ||
298             config_params[j].copy == copy_uri ||
299             config_params[j].copy == read_camera_dir) {
300             void **val;
301             val = (void *)((char *)cnt+(int)config_params[j].conf_value);
302             if (*val) {
303                 free(*val);
304                 *val = NULL;
305             }
306         }
307     }
308 
309     free(cnt);
310 }
311 
312 /**
313  * sig_handler
314  *
315  *  Our SIGNAL-Handler. We need this to handle alarms and external signals.
316  */
sig_handler(int signo)317 static void sig_handler(int signo)
318 {
319     int i;
320 
321     /*The FALLTHROUGH is a special comment required by compiler.  Do not edit it*/
322     switch(signo) {
323     case SIGALRM:
324         /*
325          * Somebody (maybe we ourself) wants us to make a snapshot
326          * This feature triggers snapshots on ALL threads that have
327          * snapshot_interval different from 0.
328          */
329         if (cnt_list) {
330             i = -1;
331             while (cnt_list[++i]) {
332                 if (cnt_list[i]->conf.snapshot_interval)
333                     cnt_list[i]->snapshot = 1;
334 
335             }
336         }
337         break;
338     case SIGUSR1:
339         /* Trigger the end of a event */
340         if (cnt_list) {
341             i = -1;
342             while (cnt_list[++i]){
343                 cnt_list[i]->event_stop = TRUE;
344             }
345         }
346         break;
347     case SIGHUP:
348         restart = 1;
349         /*
350          * Fall through, as the value of 'restart' is the only difference
351          * between SIGHUP and the ones below.
352          */
353          /*FALLTHROUGH*/
354     case SIGINT:
355         /*FALLTHROUGH*/
356     case SIGQUIT:
357         /*FALLTHROUGH*/
358     case SIGTERM:
359         /*
360          * Somebody wants us to quit! We should finish the actual
361          * movie and end up!
362          */
363 
364         if (cnt_list) {
365             i = -1;
366             while (cnt_list[++i]) {
367                 cnt_list[i]->webcontrol_finish = TRUE;
368                 cnt_list[i]->event_stop = TRUE;
369                 cnt_list[i]->finish = 1;
370                 /*
371                  * Don't restart thread when it ends,
372                  * all threads restarts if global restart is set
373                  */
374                  cnt_list[i]->restart = 0;
375             }
376         }
377         /*
378          * Set flag we want to quit main check threads loop
379          * if restart is set (above) we start up again
380          */
381         finish = 1;
382         break;
383     case SIGSEGV:
384         exit(0);
385     case SIGVTALRM:
386         printf("SIGVTALRM went off\n");
387         break;
388     }
389 }
390 
391 /**
392  * sigchild_handler
393  *
394  *   This function is a POSIX compliant replacement of the commonly used
395  *   signal(SIGCHLD, SIG_IGN).
396  */
sigchild_handler(int signo ATTRIBUTE_UNUSED)397 static void sigchild_handler(int signo ATTRIBUTE_UNUSED)
398 {
399 #ifdef WNOHANG
400     while (waitpid(-1, NULL, WNOHANG) > 0) {};
401 #endif /* WNOHANG */
402     return;
403 }
404 
405 /**
406  * setup_signals
407  *   Attaches handlers to a number of signals that Motion need to catch.
408  */
setup_signals(void)409 static void setup_signals(void){
410     /*
411      * Setup signals and do some initialization. 1 in the call to
412      * 'motion_startup' means that Motion will become a daemon if so has been
413      * requested, and argc and argc are necessary for reading the command
414      * line options.
415      */
416     struct sigaction sig_handler_action;
417     struct sigaction sigchild_action;
418 
419 #ifdef SA_NOCLDWAIT
420     sigchild_action.sa_flags = SA_NOCLDWAIT;
421 #else
422     sigchild_action.sa_flags = 0;
423 #endif
424     sigchild_action.sa_handler = sigchild_handler;
425     sigemptyset(&sigchild_action.sa_mask);
426 #ifdef SA_RESTART
427     sig_handler_action.sa_flags = SA_RESTART;
428 #else
429     sig_handler_action.sa_flags = 0;
430 #endif
431     sig_handler_action.sa_handler = sig_handler;
432     sigemptyset(&sig_handler_action.sa_mask);
433 
434     /* Enable automatic zombie reaping */
435     sigaction(SIGCHLD, &sigchild_action, NULL);
436     sigaction(SIGPIPE, &sigchild_action, NULL);
437     sigaction(SIGALRM, &sig_handler_action, NULL);
438     sigaction(SIGHUP, &sig_handler_action, NULL);
439     sigaction(SIGINT, &sig_handler_action, NULL);
440     sigaction(SIGQUIT, &sig_handler_action, NULL);
441     sigaction(SIGTERM, &sig_handler_action, NULL);
442     sigaction(SIGUSR1, &sig_handler_action, NULL);
443 
444     /* use SIGVTALRM as a way to break out of the ioctl, don't restart */
445     sig_handler_action.sa_flags = 0;
446     sigaction(SIGVTALRM, &sig_handler_action, NULL);
447 }
448 
449 /**
450  * motion_remove_pid
451  *   This function remove the process id file ( pid file ) before motion exit.
452  */
motion_remove_pid(void)453 static void motion_remove_pid(void)
454 {
455     if ((cnt_list[0]->daemon) && (cnt_list[0]->conf.pid_file) && (restart == 0)) {
456         if (!unlink(cnt_list[0]->conf.pid_file))
457             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Removed process id file (pid file)."));
458         else
459             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error removing pid file"));
460     }
461 
462     if (ptr_logfile) {
463         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Closing logfile (%s)."),
464                    cnt_list[0]->conf.log_file);
465         myfclose(ptr_logfile);
466         set_log_mode(LOGMODE_NONE);
467         ptr_logfile = NULL;
468     }
469 
470 }
471 
472 /**
473  * motion_detected
474  *
475  *   Called from 'motion_loop' when motion is detected
476  *   Can be called when no motion if emulate_motion is set!
477  *
478  * Parameters:
479  *
480  *   cnt      - current thread's context struct
481  *   dev      - video device file descriptor
482  *   img      - pointer to the captured image_data with detected motion
483  */
motion_detected(struct context * cnt,int dev,struct image_data * img)484 static void motion_detected(struct context *cnt, int dev, struct image_data *img)
485 {
486     struct config *conf = &cnt->conf;
487     struct images *imgs = &cnt->imgs;
488     struct coord *location = &img->location;
489     int indx;
490 
491     /* Draw location */
492     if (cnt->locate_motion_mode == LOCATE_ON) {
493 
494         if (cnt->locate_motion_style == LOCATE_BOX) {
495             alg_draw_location(location, imgs, imgs->width, img->image_norm, LOCATE_BOX,
496                               LOCATE_BOTH, cnt->process_thisframe);
497         } else if (cnt->locate_motion_style == LOCATE_REDBOX) {
498             alg_draw_red_location(location, imgs, imgs->width, img->image_norm, LOCATE_REDBOX,
499                                   LOCATE_BOTH, cnt->process_thisframe);
500         } else if (cnt->locate_motion_style == LOCATE_CROSS) {
501             alg_draw_location(location, imgs, imgs->width, img->image_norm, LOCATE_CROSS,
502                               LOCATE_BOTH, cnt->process_thisframe);
503         } else if (cnt->locate_motion_style == LOCATE_REDCROSS) {
504             alg_draw_red_location(location, imgs, imgs->width, img->image_norm, LOCATE_REDCROSS,
505                                   LOCATE_BOTH, cnt->process_thisframe);
506         }
507     }
508 
509     /* Calculate how centric motion is if configured preview center*/
510     if (cnt->new_img & NEWIMG_CENTER) {
511         unsigned int distX = abs((imgs->width / 2) - location->x);
512         unsigned int distY = abs((imgs->height / 2) - location->y);
513 
514         img->cent_dist = distX * distX + distY * distY;
515     }
516 
517 
518     /* Do things only if we have got minimum_motion_frames */
519     if (img->flags & IMAGE_TRIGGER) {
520         /* Take action if this is a new event and we have a trigger image */
521         if (cnt->event_nr != cnt->prev_event) {
522             /*
523              * Reset prev_event number to current event and save event time
524              * in both time_t and struct tm format.
525              */
526             cnt->prev_event = cnt->event_nr;
527             cnt->eventtime = img->timestamp_tv.tv_sec;
528             localtime_r(&cnt->eventtime, cnt->eventtime_tm);
529 
530             /*
531              * Since this is a new event we create the event_text_string used for
532              * the %C conversion specifier. We may already need it for
533              * on_motion_detected_commend so it must be done now.
534              */
535             mystrftime(cnt, cnt->text_event_string, sizeof(cnt->text_event_string),
536                        cnt->conf.text_event, &img->timestamp_tv, NULL, 0);
537 
538             /* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */
539 
540             indx = cnt->imgs.image_ring_out-1;
541             do {
542                 indx++;
543                 if (indx == cnt->imgs.image_ring_size) indx = 0;
544                 if ((cnt->imgs.image_ring[indx].flags & (IMAGE_SAVE | IMAGE_SAVED)) == IMAGE_SAVE){
545                     event(cnt, EVENT_FIRSTMOTION, img, NULL, NULL, &cnt->imgs.image_ring[indx].timestamp_tv);
546                     indx = cnt->imgs.image_ring_in;
547                 }
548             } while (indx != cnt->imgs.image_ring_in);
549 
550             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion detected - starting event %d"),
551                        cnt->event_nr);
552 
553             /* always save first motion frame as preview-shot, may be changed to an other one later */
554             if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER))
555                 image_save_as_preview(cnt, img);
556 
557         }
558 
559         /* EVENT_MOTION triggers event_beep and on_motion_detected_command */
560         event(cnt, EVENT_MOTION, NULL, NULL, NULL, &img->timestamp_tv);
561     }
562 
563     /* Limit framerate */
564     if (img->shot < conf->framerate) {
565         /*
566          * If config option stream_motion is enabled, send the latest motion detected image
567          * to the stream but only if it is not the first shot within a second. This is to
568          * avoid double frames since we already have sent a frame to the stream.
569          * We also disable this in setup_mode.
570          */
571         if (conf->stream_motion && !conf->setup_mode && img->shot != 1)
572             event(cnt, EVENT_STREAM, img, NULL, NULL, &img->timestamp_tv);
573 
574         /*
575          * Save motion jpeg, if configured
576          * Output the image_out (motion) picture.
577          */
578         if (conf->picture_output_motion)
579             event(cnt, EVENT_IMAGEM_DETECTED, NULL, NULL, NULL, &img->timestamp_tv);
580     }
581 
582     /* if track enabled and auto track on */
583     if (cnt->track.type && cnt->track.active)
584         cnt->moved = track_move(cnt, dev, location, imgs, 0);
585 
586 }
587 
588 /**
589  * process_image_ring
590  *
591  *   Called from 'motion_loop' to save images / send images to movie
592  *
593  * Parameters:
594  *
595  *   cnt        - current thread's context struct
596  *   max_images - Max number of images to process
597  *                Set to IMAGE_BUFFER_FLUSH to send/save all images in buffer
598  */
599 
process_image_ring(struct context * cnt,unsigned int max_images)600 static void process_image_ring(struct context *cnt, unsigned int max_images)
601 {
602     /*
603      * We are going to send an event, in the events there is still
604      * some code that use cnt->current_image
605      * so set it temporary to our image
606      */
607     struct image_data *saved_current_image = cnt->current_image;
608 
609     /* If image is flaged to be saved and not saved yet, process it */
610     do {
611         /* Check if we should save/send this image, breakout if not */
612         assert(cnt->imgs.image_ring_out < cnt->imgs.image_ring_size);
613         if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & (IMAGE_SAVE | IMAGE_SAVED)) != IMAGE_SAVE)
614             break;
615 
616         /* Set inte global context that we are working with this image */
617         cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_out];
618 
619         if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot < cnt->conf.framerate) {
620             if (cnt->log_level >= DBG) {
621                 char tmp[32];
622                 const char *t;
623 
624                 if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_TRIGGER)
625                     t = "Trigger";
626                 else if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_MOTION)
627                     t = "Motion";
628                 else if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_PRECAP)
629                     t = "Precap";
630                 else if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_POSTCAP)
631                     t = "Postcap";
632                 else
633                     t = "Other";
634 
635                 mystrftime(cnt, tmp, sizeof(tmp), "%H%M%S-%q",
636                            &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tv, NULL, 0);
637                 draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image_norm,
638                           cnt->imgs.width, cnt->imgs.height, 10, 20, tmp, cnt->text_scale);
639                 draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image_norm,
640                           cnt->imgs.width, cnt->imgs.height, 10, 30, t, cnt->text_scale);
641             }
642 
643             /* Output the picture to jpegs and ffmpeg */
644             event(cnt, EVENT_IMAGE_DETECTED,
645               &cnt->imgs.image_ring[cnt->imgs.image_ring_out], NULL, NULL,
646               &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tv);
647 
648 
649             /*
650              * Check if we must add any "filler" frames into movie to keep up fps
651              * Only if we are recording videos ( ffmpeg or extenal pipe )
652              * While the overall elapsed time might be correct, if there are
653              * many duplicated frames, say 10 fps, 5 duplicated, the video will
654              * look like it is frozen every second for half a second.
655              */
656             if (!cnt->conf.movie_duplicate_frames) {
657                 /* don't duplicate frames */
658             } else if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot == 0) &&
659                 (cnt->ffmpeg_output || (cnt->conf.movie_extpipe_use && cnt->extpipe))) {
660                 /*
661                  * movie_last_shoot is -1 when file is created,
662                  * we don't know how many frames there is in first sec
663                  */
664                 if (cnt->movie_last_shot >= 0) {
665                     if (cnt_list[0]->log_level >= DBG) {
666                         int frames = cnt->movie_fps - (cnt->movie_last_shot + 1);
667                         if (frames > 0) {
668                             char tmp[25];
669                             MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO
670                             ,_("Added %d fillerframes into movie"), frames);
671                             sprintf(tmp, "Fillerframes %d", frames);
672                             draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image_norm,
673                                       cnt->imgs.width, cnt->imgs.height, 10, 40, tmp, cnt->text_scale);
674                         }
675                     }
676                     /* Check how many frames it was last sec */
677                     while ((cnt->movie_last_shot + 1) < cnt->movie_fps) {
678                         /* Add a filler frame into encoder */
679                         event(cnt, EVENT_FFMPEG_PUT,
680                           &cnt->imgs.image_ring[cnt->imgs.image_ring_out], NULL, NULL,
681                           &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tv);
682 
683                         cnt->movie_last_shot++;
684                     }
685                 }
686                 cnt->movie_last_shot = 0;
687             } else if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot != (cnt->movie_last_shot + 1)) {
688                 /* We are out of sync! Propably we got motion - no motion - motion */
689                 cnt->movie_last_shot = -1;
690             }
691 
692             /*
693              * Save last shot added to movie
694              * only when we not are within first sec
695              */
696             if (cnt->movie_last_shot >= 0)
697                 cnt->movie_last_shot = cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot;
698         }
699 
700         /* Mark the image as saved */
701         cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags |= IMAGE_SAVED;
702 
703         /* Store it as a preview image, only if it has motion */
704         if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_MOTION) {
705             /* Check for most significant preview-shot when picture_output=best */
706             if (cnt->new_img & NEWIMG_BEST) {
707                 if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].diffs > cnt->imgs.preview_image.diffs) {
708                     image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]);
709                 }
710             }
711             /* Check for most significant preview-shot when picture_output=center */
712             if (cnt->new_img & NEWIMG_CENTER) {
713                 if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].cent_dist < cnt->imgs.preview_image.cent_dist) {
714                     image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]);
715                 }
716             }
717         }
718 
719         /* Increment to image after last sended */
720         if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size)
721             cnt->imgs.image_ring_out = 0;
722 
723         if (max_images != IMAGE_BUFFER_FLUSH) {
724             max_images--;
725             /* breakout if we have done max_images */
726             if (max_images == 0)
727                 break;
728         }
729 
730         /* loop until out and in is same e.g. buffer empty */
731     } while (cnt->imgs.image_ring_out != cnt->imgs.image_ring_in);
732 
733     /* restore global context values */
734     cnt->current_image = saved_current_image;
735 }
736 
init_camera_type(struct context * cnt)737 static int init_camera_type(struct context *cnt){
738 
739     cnt->camera_type = CAMERA_TYPE_UNKNOWN;
740 
741     #ifdef HAVE_MMAL
742         if (cnt->conf.mmalcam_name) {
743             cnt->camera_type = CAMERA_TYPE_MMAL;
744             return 0;
745         }
746     #endif // HAVE_MMAL
747 
748     if (cnt->conf.netcam_url) {
749         if ((strncmp(cnt->conf.netcam_url,"mjpeg",5) == 0) ||
750             (strncmp(cnt->conf.netcam_url,"v4l2" ,4) == 0) ||
751             (strncmp(cnt->conf.netcam_url,"file" ,4) == 0) ||
752             (strncmp(cnt->conf.netcam_url,"rtmp" ,4) == 0) ||
753             (strncmp(cnt->conf.netcam_url,"rtsp" ,4) == 0)) {
754             cnt->camera_type = CAMERA_TYPE_RTSP;
755         } else {
756             cnt->camera_type = CAMERA_TYPE_NETCAM;
757         }
758         return 0;
759     }
760 
761     #ifdef HAVE_BKTR
762         if (strncmp(cnt->conf.video_device,"/dev/bktr",9) == 0) {
763             cnt->camera_type = CAMERA_TYPE_BKTR;
764             return 0;
765         }
766     #endif // HAVE_BKTR
767 
768     #ifdef HAVE_V4L2
769         if (cnt->conf.video_device) {
770             cnt->camera_type = CAMERA_TYPE_V4L2;
771             return 0;
772         }
773     #endif // HAVE_V4L2
774 
775 
776     MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
777         , _("Unable to determine camera type (MMAL, Netcam, V4L2, BKTR)"));
778     return -1;
779 
780 }
781 
init_mask_privacy(struct context * cnt)782 static void init_mask_privacy(struct context *cnt){
783 
784     int indxrow, indxcol;
785     int start_cr, offset_cb, start_cb;
786     int y_index, uv_index;
787     int indx_img, indx_max;         /* Counter and max for norm/high */
788     int indx_width, indx_height;
789     unsigned char *img_temp, *img_temp_uv;
790 
791 
792     FILE *picture;
793 
794     /* Load the privacy file if any */
795     cnt->imgs.mask_privacy = NULL;
796     cnt->imgs.mask_privacy_uv = NULL;
797     cnt->imgs.mask_privacy_high = NULL;
798     cnt->imgs.mask_privacy_high_uv = NULL;
799 
800     if (cnt->conf.mask_privacy) {
801         if ((picture = myfopen(cnt->conf.mask_privacy, "r"))) {
802             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Opening privacy mask file"));
803             /*
804              * NOTE: The mask is expected to have the output dimensions. I.e., the mask
805              * applies to the already rotated image, not the capture image. Thus, use
806              * width and height from imgs.
807              */
808             cnt->imgs.mask_privacy = get_pgm(picture, cnt->imgs.width, cnt->imgs.height);
809 
810             /* We only need the "or" mask for the U & V chrominance area.  */
811             cnt->imgs.mask_privacy_uv = mymalloc((cnt->imgs.height * cnt->imgs.width) / 2);
812             if (cnt->imgs.size_high > 0){
813                 MOTION_LOG(INF, TYPE_ALL, NO_ERRNO
814                     ,_("Opening high resolution privacy mask file"));
815                 rewind(picture);
816                 cnt->imgs.mask_privacy_high = get_pgm(picture, cnt->imgs.width_high, cnt->imgs.height_high);
817                 cnt->imgs.mask_privacy_high_uv = mymalloc((cnt->imgs.height_high * cnt->imgs.width_high) / 2);
818             }
819 
820             myfclose(picture);
821         } else {
822             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
823                 ,_("Error opening mask file %s"), cnt->conf.mask_privacy);
824             /* Try to write an empty mask file to make it easier for the user to edit it */
825             put_fixed_mask(cnt, cnt->conf.mask_privacy);
826         }
827 
828         if (!cnt->imgs.mask_privacy) {
829             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
830                 ,_("Failed to read mask privacy image. Mask privacy feature disabled."));
831         } else {
832             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO
833             ,_("Mask privacy file \"%s\" loaded."), cnt->conf.mask_privacy);
834 
835             indx_img = 1;
836             indx_max = 1;
837             if (cnt->imgs.size_high > 0) indx_max = 2;
838 
839             while (indx_img <= indx_max){
840                 if (indx_img == 1){
841                     start_cr = (cnt->imgs.height * cnt->imgs.width);
842                     offset_cb = ((cnt->imgs.height * cnt->imgs.width)/4);
843                     start_cb = start_cr + offset_cb;
844                     indx_width = cnt->imgs.width;
845                     indx_height = cnt->imgs.height;
846                     img_temp = cnt->imgs.mask_privacy;
847                     img_temp_uv = cnt->imgs.mask_privacy_uv;
848                 } else {
849                     start_cr = (cnt->imgs.height_high * cnt->imgs.width_high);
850                     offset_cb = ((cnt->imgs.height_high * cnt->imgs.width_high)/4);
851                     start_cb = start_cr + offset_cb;
852                     indx_width = cnt->imgs.width_high;
853                     indx_height = cnt->imgs.height_high;
854                     img_temp = cnt->imgs.mask_privacy_high;
855                     img_temp_uv = cnt->imgs.mask_privacy_high_uv;
856                 }
857 
858                 for (indxrow = 0; indxrow < indx_height; indxrow++) {
859                     for (indxcol = 0; indxcol < indx_width; indxcol++) {
860                         y_index = indxcol + (indxrow * indx_width);
861                         if (img_temp[y_index] == 0xff) {
862                             if ((indxcol % 2 == 0) && (indxrow % 2 == 0) ){
863                                 uv_index = (indxcol/2) + ((indxrow * indx_width)/4);
864                                 img_temp[start_cr + uv_index] = 0xff;
865                                 img_temp[start_cb + uv_index] = 0xff;
866                                 img_temp_uv[uv_index] = 0x00;
867                                 img_temp_uv[offset_cb + uv_index] = 0x00;
868                             }
869                         } else {
870                             img_temp[y_index] = 0x00;
871                             if ((indxcol % 2 == 0) && (indxrow % 2 == 0) ){
872                                 uv_index = (indxcol/2) + ((indxrow * indx_width)/4);
873                                 img_temp[start_cr + uv_index] = 0x00;
874                                 img_temp[start_cb + uv_index] = 0x00;
875                                 img_temp_uv[uv_index] = 0x80;
876                                 img_temp_uv[offset_cb + uv_index] = 0x80;
877                             }
878                         }
879                     }
880                 }
881                 indx_img++;
882             }
883         }
884     }
885 
886 }
887 
init_text_scale(struct context * cnt)888 static void init_text_scale(struct context *cnt){
889 
890     /* Consider that web interface may change conf values at any moment.
891      * The below can put two sections in the image so make sure that after
892      * scaling does not occupy more than 1/4 of image (10 pixels * 2 lines)
893      */
894 
895     cnt->text_scale = cnt->conf.text_scale;
896     if (cnt->text_scale <= 0) cnt->text_scale = 1;
897 
898     if ((cnt->text_scale * 10 * 2) > (cnt->imgs.width / 4)) {
899         cnt->text_scale = (cnt->imgs.width / (4 * 10 * 2));
900         if (cnt->text_scale <= 0) cnt->text_scale = 1;
901         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
902             ,_("Invalid text scale.  Adjusted to %d"), cnt->text_scale);
903     }
904 
905     if ((cnt->text_scale * 10 * 2) > (cnt->imgs.height / 4)) {
906         cnt->text_scale = (cnt->imgs.height / (4 * 10 * 2));
907         if (cnt->text_scale <= 0) cnt->text_scale = 1;
908         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
909             ,_("Invalid text scale.  Adjusted to %d"), cnt->text_scale);
910     }
911 
912     /* If we had to modify the scale, change conf so we don't get another message */
913     cnt->conf.text_scale = cnt->text_scale;
914 
915 }
916 
mot_stream_init(struct context * cnt)917 static void mot_stream_init(struct context *cnt){
918 
919     /* The image buffers are allocated in event_stream_put if needed*/
920     pthread_mutex_init(&cnt->mutex_stream, NULL);
921 
922     cnt->imgs.substream_image = NULL;
923 
924     cnt->stream_norm.jpeg_size = 0;
925     cnt->stream_norm.jpeg_data = NULL;
926     cnt->stream_norm.cnct_count = 0;
927 
928     cnt->stream_sub.jpeg_size = 0;
929     cnt->stream_sub.jpeg_data = NULL;
930     cnt->stream_sub.cnct_count = 0;
931 
932     cnt->stream_motion.jpeg_size = 0;
933     cnt->stream_motion.jpeg_data = NULL;
934     cnt->stream_motion.cnct_count = 0;
935 
936     cnt->stream_source.jpeg_size = 0;
937     cnt->stream_source.jpeg_data = NULL;
938     cnt->stream_source.cnct_count = 0;
939 
940 }
941 
mot_stream_deinit(struct context * cnt)942 static void mot_stream_deinit(struct context *cnt){
943 
944     /* Need to check whether buffers were allocated since init
945      * function defers the allocations to event_stream_put
946     */
947 
948     pthread_mutex_destroy(&cnt->mutex_stream);
949 
950     if (cnt->imgs.substream_image != NULL){
951         free(cnt->imgs.substream_image);
952         cnt->imgs.substream_image = NULL;
953     }
954 
955     if (cnt->stream_norm.jpeg_data != NULL){
956         free(cnt->stream_norm.jpeg_data);
957         cnt->stream_norm.jpeg_data = NULL;
958     }
959 
960     if (cnt->stream_sub.jpeg_data != NULL){
961         free(cnt->stream_sub.jpeg_data);
962         cnt->stream_sub.jpeg_data = NULL;
963     }
964 
965     if (cnt->stream_motion.jpeg_data != NULL){
966         free(cnt->stream_motion.jpeg_data);
967         cnt->stream_motion.jpeg_data = NULL;
968     }
969 
970     if (cnt->stream_source.jpeg_data != NULL){
971         free(cnt->stream_source.jpeg_data);
972         cnt->stream_source.jpeg_data = NULL;
973     }
974 }
975 
976 /* TODO: dbse functions are to be moved to separate module in future change*/
dbse_global_deinit(void)977 static void dbse_global_deinit(void){
978     MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL"));
979     #if defined(HAVE_MYSQL) || defined(HAVE_MARIADB)
980         mysql_library_end();
981     #endif /* HAVE_MYSQL HAVE_MARIADB */
982 
983 }
984 
dbse_global_init(void)985 static void dbse_global_init(void){
986 
987     MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("Initializing database"));
988    /* Initialize all the database items */
989     #if defined(HAVE_MYSQL) || defined(HAVE_MARIADB)
990         if (mysql_library_init(0, NULL, NULL)) {
991             fprintf(stderr, "could not initialize MySQL library\n");
992             exit(1);
993         }
994     #endif /* HAVE_MYSQL HAVE_MARIADB */
995 
996     #ifdef HAVE_SQLITE3
997         int indx;
998         /* database_sqlite3 == NULL if not changed causes each thread to create their own
999         * sqlite3 connection this will only happens when using a non-threaded sqlite version */
1000         cnt_list[0]->database_sqlite3=NULL;
1001         if (cnt_list[0]->conf.database_type && ((!strcmp(cnt_list[0]->conf.database_type, "sqlite3")) && cnt_list[0]->conf.database_dbname)) {
1002             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
1003                 ,_("SQLite3 Database filename %s")
1004                 ,cnt_list[0]->conf.database_dbname);
1005 
1006             int thread_safe = sqlite3_threadsafe();
1007             if (thread_safe > 0) {
1008                 MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("SQLite3 is threadsafe"));
1009                 MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("SQLite3 serialized %s")
1010                     ,(sqlite3_config(SQLITE_CONFIG_SERIALIZED)?_("FAILED"):_("SUCCESS")));
1011                 if (sqlite3_open( cnt_list[0]->conf.database_dbname, &cnt_list[0]->database_sqlite3) != SQLITE_OK) {
1012                     MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1013                         ,_("Can't open database %s : %s")
1014                         ,cnt_list[0]->conf.database_dbname
1015                         ,sqlite3_errmsg( cnt_list[0]->database_sqlite3));
1016                     sqlite3_close( cnt_list[0]->database_sqlite3);
1017                     exit(1);
1018                 }
1019                 MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("database_busy_timeout %d msec"),
1020                         cnt_list[0]->conf.database_busy_timeout);
1021                 if (sqlite3_busy_timeout( cnt_list[0]->database_sqlite3,  cnt_list[0]->conf.database_busy_timeout) != SQLITE_OK)
1022                     MOTION_LOG(ERR, TYPE_DB, NO_ERRNO,_("database_busy_timeout failed %s")
1023                         ,sqlite3_errmsg( cnt_list[0]->database_sqlite3));
1024             }
1025         }
1026         /* Cascade to all threads */
1027         indx = 1;
1028         while (cnt_list[indx] != NULL) {
1029             cnt_list[indx]->database_sqlite3 = cnt_list[0]->database_sqlite3;
1030             indx++;
1031         }
1032 
1033     #endif /* HAVE_SQLITE3 */
1034 
1035 }
1036 
dbse_init_mysql(struct context * cnt)1037 static int dbse_init_mysql(struct context *cnt){
1038 
1039     #if defined(HAVE_MYSQL) || defined(HAVE_MARIADB)
1040         int dbport;
1041         if ((!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) {
1042             cnt->database_event_id = 0;
1043             cnt->database = mymalloc(sizeof(MYSQL));
1044             mysql_init(cnt->database);
1045             if ((cnt->conf.database_port < 0) || (cnt->conf.database_port > 65535)){
1046                 dbport = 0;
1047             } else {
1048                 dbport = cnt->conf.database_port;
1049             }
1050             if (!mysql_real_connect(cnt->database, cnt->conf.database_host, cnt->conf.database_user,
1051                 cnt->conf.database_password, cnt->conf.database_dbname, dbport, NULL, 0)) {
1052                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1053                     ,_("Cannot connect to MySQL database %s on host %s with user %s")
1054                     ,cnt->conf.database_dbname, cnt->conf.database_host
1055                     ,cnt->conf.database_user);
1056                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1057                     ,_("MySQL error was %s"), mysql_error(cnt->database));
1058                 return -2;
1059             }
1060             #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)
1061                 int my_true = TRUE;
1062                 mysql_options(cnt->database, MYSQL_OPT_RECONNECT, &my_true);
1063             #endif
1064         }
1065     #else
1066         (void)cnt;  /* Avoid compiler warnings */
1067     #endif /* HAVE_MYSQL HAVE_MARIADB */
1068 
1069     return 0;
1070 
1071 }
1072 
dbse_init_sqlite3(struct context * cnt)1073 static int dbse_init_sqlite3(struct context *cnt){
1074     #ifdef HAVE_SQLITE3
1075         if (cnt_list[0]->database_sqlite3 != 0) {
1076             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("SQLite3 using shared handle"));
1077             cnt->database_sqlite3 = cnt_list[0]->database_sqlite3;
1078 
1079         } else if ((!strcmp(cnt->conf.database_type, "sqlite3")) && cnt->conf.database_dbname) {
1080             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
1081                 ,_("SQLite3 Database filename %s"), cnt->conf.database_dbname);
1082             if (sqlite3_open(cnt->conf.database_dbname, &cnt->database_sqlite3) != SQLITE_OK) {
1083                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1084                     ,_("Can't open database %s : %s")
1085                     ,cnt->conf.database_dbname, sqlite3_errmsg(cnt->database_sqlite3));
1086                 sqlite3_close(cnt->database_sqlite3);
1087                 return -2;
1088             }
1089             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
1090                 ,_("database_busy_timeout %d msec"), cnt->conf.database_busy_timeout);
1091             if (sqlite3_busy_timeout(cnt->database_sqlite3, cnt->conf.database_busy_timeout) != SQLITE_OK)
1092                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1093                     ,_("database_busy_timeout failed %s")
1094                     ,sqlite3_errmsg(cnt->database_sqlite3));
1095         }
1096     #else
1097         (void)cnt;  /* Avoid compiler warnings */
1098     #endif /* HAVE_SQLITE3 */
1099 
1100     return 0;
1101 
1102 }
1103 
dbse_init_pgsql(struct context * cnt)1104 static int dbse_init_pgsql(struct context *cnt){
1105     #ifdef HAVE_PGSQL
1106         if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) {
1107             char connstring[255];
1108 
1109             /*
1110              * Create the connection string.
1111              * Quote the values so we can have null values (blank)
1112              */
1113             snprintf(connstring, 255,
1114                      "dbname='%s' host='%s' user='%s' password='%s' port='%d'",
1115                       cnt->conf.database_dbname, /* dbname */
1116                       (cnt->conf.database_host ? cnt->conf.database_host : ""), /* host (may be blank) */
1117                       (cnt->conf.database_user ? cnt->conf.database_user : ""), /* user (may be blank) */
1118                       (cnt->conf.database_password ? cnt->conf.database_password : ""), /* password (may be blank) */
1119                       cnt->conf.database_port
1120             );
1121 
1122             cnt->database_pg = PQconnectdb(connstring);
1123             if (PQstatus(cnt->database_pg) == CONNECTION_BAD) {
1124                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
1125                 ,_("Connection to PostgreSQL database '%s' failed: %s")
1126                 ,cnt->conf.database_dbname, PQerrorMessage(cnt->database_pg));
1127                 return -2;
1128             }
1129         }
1130     #else
1131         (void)cnt;  /* Avoid compiler warnings */
1132     #endif /* HAVE_PGSQL */
1133 
1134     return 0;
1135 }
1136 
dbse_init(struct context * cnt)1137 static int dbse_init(struct context *cnt){
1138     int retcd = 0;
1139 
1140     if (cnt->conf.database_type) {
1141         MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
1142             ,_("Database backend %s"), cnt->conf.database_type);
1143 
1144         retcd = dbse_init_mysql(cnt);
1145         if (retcd != 0) return retcd;
1146 
1147         retcd = dbse_init_sqlite3(cnt);
1148         if (retcd != 0) return retcd;
1149 
1150         retcd = dbse_init_pgsql(cnt);
1151         if (retcd != 0) return retcd;
1152 
1153         /* Set the sql mask file according to the SQL config options*/
1154         cnt->sql_mask = cnt->conf.sql_log_picture * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) +
1155                         cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT +
1156                         cnt->conf.sql_log_movie * (FTYPE_MPEG + FTYPE_MPEG_MOTION) +
1157                         cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE;
1158     }
1159 
1160     return retcd;
1161 }
1162 
dbse_deinit(struct context * cnt)1163 static void dbse_deinit(struct context *cnt){
1164     if (cnt->conf.database_type) {
1165         #if defined(HAVE_MYSQL) || defined(HAVE_MARIADB)
1166             if ( (!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) {
1167                 mysql_thread_end();
1168                 mysql_close(cnt->database);
1169                 cnt->database_event_id = 0;
1170             }
1171         #endif /* HAVE_MYSQL HAVE_MARIADB */
1172 
1173         #ifdef HAVE_PGSQL
1174                 if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) {
1175                     PQfinish(cnt->database_pg);
1176                 }
1177         #endif /* HAVE_PGSQL */
1178 
1179         #ifdef HAVE_SQLITE3
1180                 /* Close the SQLite database */
1181                 if ((!strcmp(cnt->conf.database_type, "sqlite3")) && (cnt->conf.database_dbname)) {
1182                     sqlite3_close(cnt->database_sqlite3);
1183                     cnt->database_sqlite3 = NULL;
1184                 }
1185         #endif /* HAVE_SQLITE3 */
1186         (void)cnt;
1187     }
1188 }
1189 
dbse_sqlmask_update(struct context * cnt)1190 static void dbse_sqlmask_update(struct context *cnt){
1191     /*
1192     * Set the sql mask file according to the SQL config options
1193     * We update it for every frame in case the config was updated
1194     * via remote control.
1195     */
1196     cnt->sql_mask = cnt->conf.sql_log_picture * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) +
1197                     cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT +
1198                     cnt->conf.sql_log_movie * (FTYPE_MPEG + FTYPE_MPEG_MOTION) +
1199                     cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE;
1200 }
1201 
1202 /**
1203  * motion_init
1204  *
1205  * This routine is called from motion_loop (the main thread of the program) to do
1206  * all of the initialization required before starting the actual run.
1207  *
1208  * Parameters:
1209  *
1210  *      cnt     Pointer to the motion context structure
1211  *
1212  * Returns:     0 OK
1213  *             -1 Fatal error, open loopback error
1214  *             -2 Fatal error, open SQL database error
1215  *             -3 Fatal error, image dimensions are not modulo 8
1216  */
motion_init(struct context * cnt)1217 static int motion_init(struct context *cnt)
1218 {
1219     FILE *picture;
1220     int indx, retcd;
1221 
1222     util_threadname_set("ml",cnt->threadnr,cnt->conf.camera_name);
1223 
1224     /* Store thread number in TLS. */
1225     pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr));
1226 
1227     cnt->currenttime_tm = mymalloc(sizeof(struct tm));
1228     cnt->eventtime_tm = mymalloc(sizeof(struct tm));
1229     /* Init frame time */
1230     cnt->currenttime = time(NULL);
1231     localtime_r(&cnt->currenttime, cnt->currenttime_tm);
1232 
1233     cnt->smartmask_speed = 0;
1234 
1235     /*
1236      * We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so
1237      * that certain code below does not run until motion has been detected the first time
1238      */
1239     cnt->event_nr = 1;
1240     cnt->prev_event = 0;
1241     cnt->lightswitch_framecounter = 0;
1242     cnt->detecting_motion = 0;
1243     cnt->event_user = FALSE;
1244     cnt->event_stop = FALSE;
1245 
1246     /* Make sure to default the high res to zero */
1247     cnt->imgs.width_high = 0;
1248     cnt->imgs.height_high = 0;
1249     cnt->imgs.size_high = 0;
1250     cnt->movie_passthrough = cnt->conf.movie_passthrough;
1251 
1252     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
1253         ,_("Camera %d started: motion detection %s"),
1254         cnt->camera_id, cnt->pause ? _("Disabled"):_("Enabled"));
1255 
1256     if (!cnt->conf.target_dir)
1257         cnt->conf.target_dir = mystrdup(".");
1258 
1259     if (init_camera_type(cnt) != 0 ) return -3;
1260 
1261     if ((cnt->camera_type != CAMERA_TYPE_RTSP) &&
1262         (cnt->movie_passthrough)) {
1263         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Pass-through processing disabled."));
1264         cnt->movie_passthrough = FALSE;
1265     }
1266 
1267     if ((cnt->conf.height == 0) || (cnt->conf.width == 0)) {
1268         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
1269             ,_("Invalid configuration dimensions %dx%d"),cnt->conf.height,cnt->conf.width);
1270         cnt->conf.height = DEF_HEIGHT;
1271         cnt->conf.width = DEF_WIDTH;
1272         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
1273             ,_("Using default dimensions %dx%d"),cnt->conf.height,cnt->conf.width);
1274     }
1275     if (cnt->conf.width % 8) {
1276         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1277             ,_("Image width (%d) requested is not modulo 8."), cnt->conf.width);
1278         cnt->conf.width = cnt->conf.width - (cnt->conf.width % 8) + 8;
1279         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1280             ,_("Adjusting width to next higher multiple of 8 (%d)."), cnt->conf.width);
1281     }
1282     if (cnt->conf.height % 8) {
1283         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1284             ,_("Image height (%d) requested is not modulo 8."), cnt->conf.height);
1285         cnt->conf.height = cnt->conf.height - (cnt->conf.height % 8) + 8;
1286         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1287             ,_("Adjusting height to next higher multiple of 8 (%d)."), cnt->conf.height);
1288     }
1289     if (cnt->conf.width  < 64) cnt->conf.width  = 64;
1290     if (cnt->conf.height < 64) cnt->conf.height = 64;
1291 
1292     if (cnt->conf.netcam_decoder != NULL){
1293         cnt->netcam_decoder = mymalloc(strlen(cnt->conf.netcam_decoder)+1);
1294         retcd = snprintf(cnt->netcam_decoder,strlen(cnt->conf.netcam_decoder)+1
1295             ,"%s",cnt->conf.netcam_decoder);
1296         if (retcd < 0){
1297             free(cnt->netcam_decoder);
1298             cnt->netcam_decoder = NULL;
1299         }
1300     } else {
1301         cnt->netcam_decoder = NULL;
1302     }
1303 
1304 
1305     /* set the device settings */
1306     cnt->video_dev = vid_start(cnt);
1307 
1308     /*
1309      * We failed to get an initial image from a camera
1310      * So we need to guess height and width based on the config
1311      * file options.
1312      */
1313     if (cnt->video_dev == -1) {
1314         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
1315             ,_("Could not fetch initial image from camera "));
1316         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
1317             ,_("Motion continues using width and height from config file(s)"));
1318         cnt->imgs.width = cnt->conf.width;
1319         cnt->imgs.height = cnt->conf.height;
1320         cnt->imgs.size_norm = cnt->conf.width * cnt->conf.height * 3 / 2;
1321         cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height;
1322     } else if (cnt->video_dev == -2) {
1323         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1324             ,_("Could not fetch initial image from camera "));
1325         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1326             ,_("Motion only supports width and height modulo 8"));
1327         return -3;
1328     }
1329     /* Revalidate we got a valid image size */
1330     if ((cnt->imgs.width % 8) || (cnt->imgs.height % 8)) {
1331         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1332             ,_("Image width (%d) or height(%d) requested is not modulo 8.")
1333             ,cnt->imgs.width, cnt->imgs.height);
1334         return -3;
1335     }
1336     if ((cnt->imgs.width  < 64) || (cnt->imgs.height < 64)){
1337         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1338             ,_("Motion only supports width and height greater than or equal to 64 %dx%d")
1339             ,cnt->imgs.width, cnt->imgs.height);
1340             return -3;
1341     }
1342     /* Substream size notification*/
1343     if ((cnt->imgs.width % 16) || (cnt->imgs.height % 16)) {
1344         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
1345             ,_("Substream not available.  Image sizes not modulo 16."));
1346     }
1347 
1348 
1349     /* We set size_high here so that it can be used in the retry function to determine whether
1350      * we need to break and reallocate buffers
1351      */
1352     cnt->imgs.size_high = (cnt->imgs.width_high * cnt->imgs.height_high * 3) / 2;
1353 
1354     image_ring_resize(cnt, 1); /* Create a initial precapture ring buffer with 1 frame */
1355 
1356     cnt->imgs.ref = mymalloc(cnt->imgs.size_norm);
1357     cnt->imgs.img_motion.image_norm = mymalloc(cnt->imgs.size_norm);
1358 
1359     /* contains the moving objects of ref. frame */
1360     cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.ref_dyn));
1361     cnt->imgs.image_virgin.image_norm = mymalloc(cnt->imgs.size_norm);
1362     cnt->imgs.image_vprvcy.image_norm = mymalloc(cnt->imgs.size_norm);
1363     cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize);
1364     cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize);
1365     cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer));
1366     cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.labels));
1367     cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(*cnt->imgs.labelsize));
1368     cnt->imgs.preview_image.image_norm = mymalloc(cnt->imgs.size_norm);
1369     cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height);
1370     if (cnt->imgs.size_high > 0){
1371         cnt->imgs.image_virgin.image_high = mymalloc(cnt->imgs.size_high);
1372         cnt->imgs.preview_image.image_high = mymalloc(cnt->imgs.size_high);
1373     }
1374 
1375     mot_stream_init(cnt);
1376 
1377     /* Set output picture type */
1378     if (!strcmp(cnt->conf.picture_type, "ppm"))
1379         cnt->imgs.picture_type = IMAGE_TYPE_PPM;
1380     else if (!strcmp(cnt->conf.picture_type, "webp")) {
1381         #ifdef HAVE_WEBP
1382                 cnt->imgs.picture_type = IMAGE_TYPE_WEBP;
1383         #else
1384                 /* Fallback to jpeg if webp was selected in the config file, but the support for it was not compiled in */
1385                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1386                 ,_("webp image format is not available, failing back to jpeg"));
1387                 cnt->imgs.picture_type = IMAGE_TYPE_JPEG;
1388         #endif /* HAVE_WEBP */
1389     }
1390     else
1391         cnt->imgs.picture_type = IMAGE_TYPE_JPEG;
1392 
1393     /*
1394      * Now is a good time to init rotation data. Since vid_start has been
1395      * called, we know that we have imgs.width and imgs.height. When capturing
1396      * from a V4L device, these are copied from the corresponding conf values
1397      * in vid_start. When capturing from a netcam, they get set in netcam_start,
1398      * which is called from vid_start.
1399      *
1400      * rotate_init will set cap_width and cap_height in cnt->rotate_data.
1401      */
1402     rotate_init(cnt); /* rotate_deinit is called in main */
1403 
1404     init_text_scale(cnt);   /*Initialize and validate the text_scale */
1405 
1406     /* Capture first image, or we will get an alarm on start */
1407     if (cnt->video_dev >= 0) {
1408         int i;
1409 
1410         for (i = 0; i < 5; i++) {
1411             if (vid_next(cnt, &cnt->imgs.image_virgin) == 0)
1412                 break;
1413             SLEEP(2, 0);
1414         }
1415 
1416         if (i >= 5) {
1417             memset(cnt->imgs.image_virgin.image_norm, 0x80, cnt->imgs.size_norm);       /* initialize to grey */
1418             draw_text(cnt->imgs.image_virgin.image_norm, cnt->imgs.width, cnt->imgs.height,
1419                       10, 20, "Error capturing first image", cnt->text_scale);
1420             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error capturing first image"));
1421         }
1422     }
1423     cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in];
1424 
1425     /* create a reference frame */
1426     alg_update_reference_frame(cnt, RESET_REF_FRAME);
1427 
1428     #if defined(HAVE_V4L2) && !defined(BSD)
1429         /* open video loopback devices if enabled */
1430         if (cnt->conf.video_pipe) {
1431             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
1432                 ,_("Opening video loopback device for normal pictures"));
1433 
1434             /* vid_startpipe should get the output dimensions */
1435             cnt->pipe = vlp_startpipe(cnt->conf.video_pipe, cnt->imgs.width, cnt->imgs.height);
1436 
1437             if (cnt->pipe < 0) {
1438                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1439                     ,_("Failed to open video loopback for normal pictures"));
1440                 return -1;
1441             }
1442         }
1443 
1444         if (cnt->conf.video_pipe_motion) {
1445             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
1446                 ,_("Opening video loopback device for motion pictures"));
1447 
1448             /* vid_startpipe should get the output dimensions */
1449             cnt->mpipe = vlp_startpipe(cnt->conf.video_pipe_motion, cnt->imgs.width, cnt->imgs.height);
1450 
1451             if (cnt->mpipe < 0) {
1452                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1453                     ,_("Failed to open video loopback for motion pictures"));
1454                 return -1;
1455             }
1456         }
1457     #endif /* HAVE_V4L2 && !BSD */
1458 
1459     retcd = dbse_init(cnt);
1460     if (retcd != 0) return retcd;
1461 
1462     /* Load the mask file if any */
1463     if (cnt->conf.mask_file) {
1464         if ((picture = myfopen(cnt->conf.mask_file, "r"))) {
1465             /*
1466              * NOTE: The mask is expected to have the output dimensions. I.e., the mask
1467              * applies to the already rotated image, not the capture image. Thus, use
1468              * width and height from imgs.
1469              */
1470             cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height);
1471             myfclose(picture);
1472         } else {
1473             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
1474                 ,_("Error opening mask file %s")
1475                 ,cnt->conf.mask_file);
1476             /*
1477              * Try to write an empty mask file to make it easier
1478              * for the user to edit it
1479              */
1480             put_fixed_mask(cnt, cnt->conf.mask_file);
1481         }
1482 
1483         if (!cnt->imgs.mask) {
1484             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
1485                 ,_("Failed to read mask image. Mask feature disabled."));
1486         } else {
1487             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO
1488                 ,_("Maskfile \"%s\" loaded.")
1489                 ,cnt->conf.mask_file);
1490         }
1491     } else {
1492         cnt->imgs.mask = NULL;
1493     }
1494 
1495     init_mask_privacy(cnt);
1496 
1497     /* Always initialize smart_mask - someone could turn it on later... */
1498     memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);
1499     memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);
1500     memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer));
1501 
1502     /* Set noise level */
1503     cnt->noise = cnt->conf.noise_level;
1504 
1505     /* Set threshold value */
1506     cnt->threshold = cnt->conf.threshold;
1507     if (cnt->conf.threshold_maximum > cnt->conf.threshold ){
1508         cnt->threshold_maximum = cnt->conf.threshold_maximum;
1509     } else {
1510         cnt->threshold_maximum = (cnt->imgs.height * cnt->imgs.width * 3) / 2;
1511     }
1512 
1513     if (cnt->conf.stream_preview_method == 99){
1514         /* This is the depreciated Stop stream process */
1515 
1516         /* Initialize stream server if stream port is specified to not 0 */
1517 
1518         if (cnt->conf.stream_port) {
1519             if (stream_init (&(cnt->stream), cnt->conf.stream_port, cnt->conf.stream_localhost,
1520                 cnt->conf.webcontrol_ipv6, cnt->conf.stream_cors_header) == -1) {
1521                 MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
1522                     ,_("Problem enabling motion-stream server in port %d")
1523                     ,cnt->conf.stream_port);
1524                 cnt->conf.stream_port = 0;
1525                 cnt->finish = 1;
1526             } else {
1527                 MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
1528                     ,_("Started motion-stream server on port %d (auth %s)")
1529                     ,cnt->conf.stream_port
1530                     ,cnt->conf.stream_auth_method ? _("Enabled"):_("Disabled"));
1531             }
1532         }
1533 
1534     } /* End of legacy stream methods*/
1535 
1536 
1537     /* Prevent first few frames from triggering motion... */
1538     cnt->moved = 8;
1539 
1540     /* Work out expected frame rate based on config setting */
1541     if (cnt->conf.framerate < 2)
1542         cnt->conf.framerate = 2;
1543 
1544     /* 2 sec startup delay so FPS is calculated correct */
1545     cnt->startup_frames = (cnt->conf.framerate * 2) + cnt->conf.pre_capture + cnt->conf.minimum_motion_frames;
1546 
1547     cnt->required_frame_time = 1000000L / cnt->conf.framerate;
1548 
1549     cnt->frame_delay = cnt->required_frame_time;
1550 
1551     /*
1552      * Reserve enough space for a 10 second timing history buffer. Note that,
1553      * if there is any problem on the allocation, mymalloc does not return.
1554      */
1555     cnt->rolling_average_data = NULL;
1556     cnt->rolling_average_limit = 10 * cnt->conf.framerate;
1557     cnt->rolling_average_data = mymalloc(sizeof(cnt->rolling_average_data) * cnt->rolling_average_limit);
1558 
1559     /* Preset history buffer with expected frame rate */
1560     for (indx = 0; indx < cnt->rolling_average_limit; indx++)
1561         cnt->rolling_average_data[indx] = cnt->required_frame_time;
1562 
1563 
1564     cnt->track_posx = 0;
1565     cnt->track_posy = 0;
1566     if (cnt->track.type)
1567         cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0);
1568 
1569     /* Initialize area detection */
1570     cnt->area_minx[0] = cnt->area_minx[3] = cnt->area_minx[6] = 0;
1571     cnt->area_miny[0] = cnt->area_miny[1] = cnt->area_miny[2] = 0;
1572 
1573     cnt->area_minx[1] = cnt->area_minx[4] = cnt->area_minx[7] = cnt->imgs.width / 3;
1574     cnt->area_maxx[0] = cnt->area_maxx[3] = cnt->area_maxx[6] = cnt->imgs.width / 3;
1575 
1576     cnt->area_minx[2] = cnt->area_minx[5] = cnt->area_minx[8] = cnt->imgs.width / 3 * 2;
1577     cnt->area_maxx[1] = cnt->area_maxx[4] = cnt->area_maxx[7] = cnt->imgs.width / 3 * 2;
1578 
1579     cnt->area_miny[3] = cnt->area_miny[4] = cnt->area_miny[5] = cnt->imgs.height / 3;
1580     cnt->area_maxy[0] = cnt->area_maxy[1] = cnt->area_maxy[2] = cnt->imgs.height / 3;
1581 
1582     cnt->area_miny[6] = cnt->area_miny[7] = cnt->area_miny[8] = cnt->imgs.height / 3 * 2;
1583     cnt->area_maxy[3] = cnt->area_maxy[4] = cnt->area_maxy[5] = cnt->imgs.height / 3 * 2;
1584 
1585     cnt->area_maxx[2] = cnt->area_maxx[5] = cnt->area_maxx[8] = cnt->imgs.width;
1586     cnt->area_maxy[6] = cnt->area_maxy[7] = cnt->area_maxy[8] = cnt->imgs.height;
1587 
1588     cnt->areadetect_eventnbr = 0;
1589 
1590     cnt->timenow = 0;
1591     cnt->timebefore = 0;
1592     cnt->rate_limit = 0;
1593     cnt->lastframetime = 0;
1594     cnt->minimum_frame_time_downcounter = cnt->conf.minimum_frame_time;
1595     cnt->get_image = 1;
1596 
1597     cnt->olddiffs = 0;
1598     cnt->smartmask_ratio = 0;
1599     cnt->smartmask_count = 20;
1600 
1601     cnt->previous_diffs = 0;
1602     cnt->previous_location_x = 0;
1603     cnt->previous_location_y = 0;
1604 
1605     cnt->time_last_frame = 1;
1606     cnt->time_current_frame = 0;
1607 
1608     cnt->smartmask_lastrate = 0;
1609 
1610     cnt->passflag = 0;  //only purpose to flag first frame
1611     cnt->rolling_frame = 0;
1612 
1613     if (cnt->conf.emulate_motion) {
1614         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Emulating motion"));
1615     }
1616 
1617     return 0;
1618 }
1619 
1620 /**
1621  * motion_cleanup
1622  *
1623  * This routine is called from motion_loop when thread ends to
1624  * cleanup all memory etc. that motion_init did.
1625  *
1626  * Parameters:
1627  *
1628  *      cnt     Pointer to the motion context structure
1629  *
1630  * Returns:     nothing
1631  */
motion_cleanup(struct context * cnt)1632 static void motion_cleanup(struct context *cnt) {
1633 
1634     if (cnt->conf.stream_preview_method == 99){
1635         /* This is the depreciated Stop stream process */
1636         if ((cnt->conf.stream_port) && (cnt->stream.socket != -1))
1637             stream_stop(&cnt->stream);
1638     }
1639 
1640     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, NULL);
1641     event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, NULL);
1642 
1643     mot_stream_deinit(cnt);
1644 
1645     if (cnt->video_dev >= 0) {
1646         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Calling vid_close() from motion_cleanup"));
1647         vid_close(cnt);
1648     }
1649 
1650     free(cnt->imgs.img_motion.image_norm);
1651     cnt->imgs.img_motion.image_norm = NULL;
1652 
1653     free(cnt->imgs.ref);
1654     cnt->imgs.ref = NULL;
1655 
1656     free(cnt->imgs.ref_dyn);
1657     cnt->imgs.ref_dyn = NULL;
1658 
1659     free(cnt->imgs.image_virgin.image_norm);
1660     cnt->imgs.image_virgin.image_norm = NULL;
1661 
1662     free(cnt->imgs.image_vprvcy.image_norm);
1663     cnt->imgs.image_vprvcy.image_norm = NULL;
1664 
1665     free(cnt->imgs.labels);
1666     cnt->imgs.labels = NULL;
1667 
1668     free(cnt->imgs.labelsize);
1669     cnt->imgs.labelsize = NULL;
1670 
1671     free(cnt->imgs.smartmask);
1672     cnt->imgs.smartmask = NULL;
1673 
1674     free(cnt->imgs.smartmask_final);
1675     cnt->imgs.smartmask_final = NULL;
1676 
1677     free(cnt->imgs.smartmask_buffer);
1678     cnt->imgs.smartmask_buffer = NULL;
1679 
1680     if (cnt->imgs.mask) free(cnt->imgs.mask);
1681     cnt->imgs.mask = NULL;
1682 
1683     if (cnt->imgs.mask_privacy) free(cnt->imgs.mask_privacy);
1684     cnt->imgs.mask_privacy = NULL;
1685 
1686     if (cnt->imgs.mask_privacy_uv) free(cnt->imgs.mask_privacy_uv);
1687     cnt->imgs.mask_privacy_uv = NULL;
1688 
1689     if (cnt->imgs.mask_privacy_high) free(cnt->imgs.mask_privacy_high);
1690     cnt->imgs.mask_privacy_high = NULL;
1691 
1692     if (cnt->imgs.mask_privacy_high_uv) free(cnt->imgs.mask_privacy_high_uv);
1693     cnt->imgs.mask_privacy_high_uv = NULL;
1694 
1695     free(cnt->imgs.common_buffer);
1696     cnt->imgs.common_buffer = NULL;
1697 
1698     free(cnt->imgs.preview_image.image_norm);
1699     cnt->imgs.preview_image.image_norm = NULL;
1700 
1701     if (cnt->imgs.size_high > 0){
1702         free(cnt->imgs.image_virgin.image_high);
1703         cnt->imgs.image_virgin.image_high = NULL;
1704 
1705         free(cnt->imgs.preview_image.image_high);
1706         cnt->imgs.preview_image.image_high = NULL;
1707     }
1708 
1709     image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */
1710 
1711     rotate_deinit(cnt); /* cleanup image rotation data */
1712 
1713     if (cnt->pipe != -1) {
1714         close(cnt->pipe);
1715         cnt->pipe = -1;
1716     }
1717 
1718     if (cnt->mpipe != -1) {
1719         close(cnt->mpipe);
1720         cnt->mpipe = -1;
1721     }
1722 
1723     if (cnt->rolling_average_data != NULL) free(cnt->rolling_average_data);
1724 
1725 
1726     /* Cleanup the current time structure */
1727     free(cnt->currenttime_tm);
1728     cnt->currenttime_tm = NULL;
1729 
1730     /* Cleanup the event time structure */
1731     free(cnt->eventtime_tm);
1732     cnt->eventtime_tm = NULL;
1733 
1734     dbse_deinit(cnt);
1735 
1736     if (cnt->netcam_decoder){
1737         free(cnt->netcam_decoder);
1738         cnt->netcam_decoder = NULL;
1739     }
1740 
1741 }
1742 
mlp_mask_privacy(struct context * cnt)1743 static void mlp_mask_privacy(struct context *cnt){
1744 
1745     if (cnt->imgs.mask_privacy == NULL) return;
1746 
1747     /*
1748     * This function uses long operations to process 4 (32 bit) or 8 (64 bit)
1749     * bytes at a time, providing a significant boost in performance.
1750     * Then a trailer loop takes care of any remaining bytes.
1751     */
1752     unsigned char *image;
1753     const unsigned char *mask;
1754     const unsigned char *maskuv;
1755 
1756     int index_y;
1757     int index_crcb;
1758     int increment;
1759     int indx_img;                /* Counter for how many images we need to apply the mask to */
1760     int indx_max;                /* 1 if we are only doing norm, 2 if we are doing both norm and high */
1761 
1762     indx_img = 1;
1763     indx_max = 1;
1764     if (cnt->imgs.size_high > 0) indx_max = 2;
1765     increment = sizeof(unsigned long);
1766 
1767     while (indx_img <= indx_max){
1768         if (indx_img == 1) {
1769             /* Normal Resolution */
1770             index_y = cnt->imgs.height * cnt->imgs.width;
1771             image = cnt->current_image->image_norm;
1772             mask = cnt->imgs.mask_privacy;
1773             index_crcb = cnt->imgs.size_norm - index_y;
1774             maskuv = cnt->imgs.mask_privacy_uv;
1775         } else {
1776             /* High Resolution */
1777             index_y = cnt->imgs.height_high * cnt->imgs.width_high;
1778             image = cnt->current_image->image_high;
1779             mask = cnt->imgs.mask_privacy_high;
1780             index_crcb = cnt->imgs.size_high - index_y;
1781             maskuv = cnt->imgs.mask_privacy_high_uv;
1782         }
1783 
1784         while (index_y >= increment) {
1785             *((unsigned long *)image) &= *((unsigned long *)mask);
1786             image += increment;
1787             mask += increment;
1788             index_y -= increment;
1789         }
1790         while (--index_y >= 0) {
1791             *(image++) &= *(mask++);
1792         }
1793 
1794         /* Mask chrominance. */
1795         while (index_crcb >= increment) {
1796             index_crcb -= increment;
1797             /*
1798             * Replace the masked bytes with 0x080. This is done using two masks:
1799             * the normal privacy mask is used to clear the masked bits, the
1800             * "or" privacy mask is used to write 0x80. The benefit of that method
1801             * is that we process 4 or 8 bytes in just two operations.
1802             */
1803             *((unsigned long *)image) &= *((unsigned long *)mask);
1804             mask += increment;
1805             *((unsigned long *)image) |= *((unsigned long *)maskuv);
1806             maskuv += increment;
1807             image += increment;
1808         }
1809 
1810         while (--index_crcb >= 0) {
1811             if (*(mask++) == 0x00) *image = 0x80; // Mask last remaining bytes.
1812             image += 1;
1813         }
1814 
1815         indx_img++;
1816     }
1817 }
1818 
mlp_areadetect(struct context * cnt)1819 static void mlp_areadetect(struct context *cnt){
1820     int i, j, z = 0;
1821     /*
1822      * Simple hack to recognize motion in a specific area
1823      * Do we need a new coversion specifier as well??
1824      */
1825     if ((cnt->conf.area_detect) &&
1826         (cnt->event_nr != cnt->areadetect_eventnbr) &&
1827         (cnt->current_image->flags & IMAGE_TRIGGER)) {
1828         j = strlen(cnt->conf.area_detect);
1829         for (i = 0; i < j; i++) {
1830             z = cnt->conf.area_detect[i] - 49; /* characters are stored as ascii 48-57 (0-9) */
1831             if ((z >= 0) && (z < 9)) {
1832                 if (cnt->current_image->location.x > cnt->area_minx[z] &&
1833                     cnt->current_image->location.x < cnt->area_maxx[z] &&
1834                     cnt->current_image->location.y > cnt->area_miny[z] &&
1835                     cnt->current_image->location.y < cnt->area_maxy[z]) {
1836                     event(cnt, EVENT_AREA_DETECTED, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
1837                     cnt->areadetect_eventnbr = cnt->event_nr; /* Fire script only once per event */
1838                     MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO
1839                         ,_("Motion in area %d detected."), z + 1);
1840                     break;
1841                 }
1842             }
1843         }
1844     }
1845 
1846 }
1847 
mlp_prepare(struct context * cnt)1848 static void mlp_prepare(struct context *cnt){
1849 
1850     int frame_buffer_size;
1851     struct timeval tv1;
1852 
1853     /***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/
1854     cnt->watchdog = WATCHDOG_TMO;
1855 
1856     /* Get current time and preserver last time for frame interval calc. */
1857 
1858     /* This may be better at the end of the loop or moving the part in
1859      * the end doing elapsed time calc in here
1860      */
1861     cnt->timebefore = cnt->timenow;
1862     gettimeofday(&tv1, NULL);
1863     cnt->timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;
1864 
1865     /*
1866      * Calculate detection rate limit. Above 5fps we limit the detection
1867      * rate to 3fps to reduce load at higher framerates.
1868      */
1869     cnt->process_thisframe = 0;
1870     cnt->rate_limit++;
1871     if (cnt->rate_limit >= (cnt->lastrate / 3)) {
1872         cnt->rate_limit = 0;
1873         cnt->process_thisframe = 1;
1874     }
1875 
1876     /*
1877      * Since we don't have sanity checks done when options are set,
1878      * this sanity check must go in the main loop :(, before pre_captures
1879      * are attempted.
1880      */
1881     if (cnt->conf.minimum_motion_frames < 1)
1882         cnt->conf.minimum_motion_frames = 1;
1883 
1884     if (cnt->conf.pre_capture < 0)
1885         cnt->conf.pre_capture = 0;
1886 
1887     /*
1888      * Check if our buffer is still the right size
1889      * If pre_capture or minimum_motion_frames has been changed
1890      * via the http remote control we need to re-size the ring buffer
1891      */
1892     frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames;
1893 
1894     if (cnt->imgs.image_ring_size != frame_buffer_size)
1895         image_ring_resize(cnt, frame_buffer_size);
1896 
1897     /* Get time for current frame */
1898     cnt->currenttime = time(NULL);
1899 
1900     /*
1901      * localtime returns static data and is not threadsafe
1902      * so we use localtime_r which is reentrant and threadsafe
1903      */
1904     localtime_r(&cnt->currenttime, cnt->currenttime_tm);
1905 
1906     /*
1907      * If we have started on a new second we reset the shots variable
1908      * lastrate is updated to be the number of the last frame. last rate
1909      * is used as the ffmpeg framerate when motion is detected.
1910      */
1911     if (cnt->lastframetime != cnt->currenttime) {
1912         cnt->lastrate = cnt->shots + 1;
1913         cnt->shots = -1;
1914         cnt->lastframetime = cnt->currenttime;
1915 
1916         if (cnt->conf.minimum_frame_time) {
1917             cnt->minimum_frame_time_downcounter--;
1918             if (cnt->minimum_frame_time_downcounter == 0)
1919                 cnt->get_image = 1;
1920         } else {
1921             cnt->get_image = 1;
1922         }
1923     }
1924 
1925 
1926     /* Increase the shots variable for each frame captured within this second */
1927     cnt->shots++;
1928 
1929     if (cnt->startup_frames > 0)
1930         cnt->startup_frames--;
1931 
1932 
1933 }
1934 
mlp_resetimages(struct context * cnt)1935 static void mlp_resetimages(struct context *cnt){
1936 
1937     struct image_data *old_image;
1938 
1939     if (cnt->conf.minimum_frame_time) {
1940         cnt->minimum_frame_time_downcounter = cnt->conf.minimum_frame_time;
1941         cnt->get_image = 0;
1942     }
1943 
1944     /* ring_buffer_in is pointing to current pos, update before put in a new image */
1945     if (++cnt->imgs.image_ring_in >= cnt->imgs.image_ring_size)
1946         cnt->imgs.image_ring_in = 0;
1947 
1948     /* Check if we have filled the ring buffer, throw away last image */
1949     if (cnt->imgs.image_ring_in == cnt->imgs.image_ring_out) {
1950         if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size)
1951             cnt->imgs.image_ring_out = 0;
1952     }
1953 
1954     /* cnt->current_image points to position in ring where to store image, diffs etc. */
1955     old_image = cnt->current_image;
1956     cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in];
1957 
1958     /* Init/clear current_image */
1959     if (cnt->process_thisframe) {
1960         /* set diffs to 0 now, will be written after we calculated diffs in new image */
1961         cnt->current_image->diffs = 0;
1962 
1963         /* Set flags to 0 */
1964         cnt->current_image->flags = 0;
1965         cnt->current_image->cent_dist = 0;
1966 
1967         /* Clear location data */
1968         memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location));
1969         cnt->current_image->total_labels = 0;
1970     } else if (cnt->current_image && old_image) {
1971         /* not processing this frame: save some important values for next image */
1972         cnt->current_image->diffs = old_image->diffs;
1973         cnt->current_image->timestamp_tv = old_image->timestamp_tv;
1974         cnt->current_image->shot = old_image->shot;
1975         cnt->current_image->cent_dist = old_image->cent_dist;
1976         cnt->current_image->flags = old_image->flags & (~IMAGE_SAVED);
1977         cnt->current_image->location = old_image->location;
1978         cnt->current_image->total_labels = old_image->total_labels;
1979     }
1980 
1981     /* Store time with pre_captured image */
1982     gettimeofday(&cnt->current_image->timestamp_tv, NULL);
1983 
1984     /* Store shot number with pre_captured image */
1985     cnt->current_image->shot = cnt->shots;
1986 
1987 }
1988 
mlp_retry(struct context * cnt)1989 static int mlp_retry(struct context *cnt){
1990 
1991     /*
1992      * If a camera is not available we keep on retrying every 10 seconds
1993      * until it shows up.
1994      */
1995     int size_high;
1996 
1997     if (cnt->video_dev < 0 &&
1998         cnt->currenttime % 10 == 0 && cnt->shots == 0) {
1999         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
2000             ,_("Retrying until successful connection with camera"));
2001         cnt->video_dev = vid_start(cnt);
2002 
2003         if (cnt->video_dev < 0) {
2004             return 1;
2005         }
2006 
2007         if ((cnt->imgs.width % 8) || (cnt->imgs.height % 8)) {
2008             MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
2009                 ,_("Image width (%d) or height(%d) requested is not modulo 8.")
2010                 ,cnt->imgs.width, cnt->imgs.height);
2011             return 1;
2012         }
2013 
2014         if ((cnt->imgs.width  < 64) || (cnt->imgs.height < 64)){
2015             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
2016                 ,_("Motion only supports width and height greater than or equal to 64 %dx%d")
2017                 ,cnt->imgs.width, cnt->imgs.height);
2018                 return 1;
2019         }
2020 
2021         /*
2022          * If the netcam has different dimensions than in the config file
2023          * we need to restart Motion to re-allocate all the buffers
2024          */
2025         if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) {
2026             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Camera has finally become available\n"
2027                        "Camera image has different width and height"
2028                        "from what is in the config file. You should fix that\n"
2029                        "Restarting Motion thread to reinitialize all "
2030                        "image buffers to new picture dimensions"));
2031             cnt->conf.width = cnt->imgs.width;
2032             cnt->conf.height = cnt->imgs.height;
2033             /*
2034              * Break out of main loop terminating thread
2035              * watchdog will start us again
2036              */
2037             return 1;
2038         }
2039         /*
2040          * For high res, we check the size of buffer to determine whether to break out
2041          * the init_motion function allocated the buffer for high using the cnt->imgs.size_high
2042          * and the vid_start ONLY re-populates the height/width so we can check the size here.
2043          */
2044         size_high = (cnt->imgs.width_high * cnt->imgs.height_high * 3) / 2;
2045         if (cnt->imgs.size_high != size_high) return 1;
2046     }
2047     return 0;
2048 }
2049 
mlp_capture(struct context * cnt)2050 static int mlp_capture(struct context *cnt){
2051 
2052     const char *tmpin;
2053     char tmpout[80];
2054     int vid_return_code = 0;        /* Return code used when calling vid_next */
2055     struct timeval tv1;
2056 
2057     /***** MOTION LOOP - IMAGE CAPTURE SECTION *****/
2058     /*
2059      * Fetch next frame from camera
2060      * If vid_next returns 0 all is well and we got a new picture
2061      * Any non zero value is an error.
2062      * 0 = OK, valid picture
2063      * <0 = fatal error - leave the thread by breaking out of the main loop
2064      * >0 = non fatal error - copy last image or show grey image with message
2065      */
2066     if (cnt->video_dev >= 0)
2067         vid_return_code = vid_next(cnt, cnt->current_image);
2068     else
2069         vid_return_code = 1; /* Non fatal error */
2070 
2071     // VALID PICTURE
2072     if (vid_return_code == 0) {
2073         cnt->lost_connection = 0;
2074         cnt->connectionlosttime = 0;
2075 
2076         /* If all is well reset missing_frame_counter */
2077         if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.framerate) {
2078             /* If we previously logged starting a grey image, now log video re-start */
2079             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Video signal re-acquired"));
2080             // event for re-acquired video signal can be called here
2081             event(cnt, EVENT_CAMERA_FOUND, NULL, NULL, NULL, NULL);
2082         }
2083         cnt->missing_frame_counter = 0;
2084 
2085         /*
2086          * Save the newly captured still virgin image to a buffer
2087          * which we will not alter with text and location graphics
2088          */
2089         memcpy(cnt->imgs.image_virgin.image_norm, cnt->current_image->image_norm, cnt->imgs.size_norm);
2090 
2091         mlp_mask_privacy(cnt);
2092 
2093         memcpy(cnt->imgs.image_vprvcy.image_norm, cnt->current_image->image_norm, cnt->imgs.size_norm);
2094 
2095         /*
2096          * If the camera is a netcam we let the camera decide the pace.
2097          * Otherwise we will keep on adding duplicate frames.
2098          * By resetting the timer the framerate becomes maximum the rate
2099          * of the Netcam.
2100          */
2101         if (cnt->conf.netcam_url) {
2102             gettimeofday(&tv1, NULL);
2103             cnt->timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;
2104         }
2105     // FATAL ERROR - leave the thread by breaking out of the main loop
2106     } else if (vid_return_code < 0) {
2107         /* Fatal error - Close video device */
2108         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
2109             ,_("Video device fatal error - Closing video device"));
2110         vid_close(cnt);
2111         /*
2112          * Use virgin image, if we are not able to open it again next loop
2113          * a gray image with message is applied
2114          * flag lost_connection
2115          */
2116         memcpy(cnt->current_image->image_norm, cnt->imgs.image_virgin.image_norm, cnt->imgs.size_norm);
2117         cnt->lost_connection = 1;
2118     /* NO FATAL ERROR -
2119     *        copy last image or show grey image with message
2120     *        flag on lost_connection if :
2121     *               vid_return_code == NETCAM_RESTART_ERROR
2122     *        cnt->video_dev < 0
2123     *        cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.framerate)
2124     */
2125     } else {
2126 
2127         //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "vid_return_code %d",vid_return_code);
2128 
2129         /*
2130          * Netcams that change dimensions while Motion is running will
2131          * require that Motion restarts to reinitialize all the many
2132          * buffers inside Motion. It will be a mess to try and recover any
2133          * other way
2134          */
2135         if (vid_return_code == NETCAM_RESTART_ERROR) {
2136             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
2137                 ,_("Restarting Motion thread to reinitialize all "
2138                 "image buffers"));
2139             /*
2140              * Break out of main loop terminating thread
2141              * watchdog will start us again
2142              * Set lost_connection flag on
2143              */
2144             cnt->lost_connection = 1;
2145             return 1;
2146         }
2147 
2148         /*
2149          * First missed frame - store timestamp
2150          * Don't reset time when thread restarts
2151          */
2152         if (cnt->connectionlosttime == 0){
2153             cnt->connectionlosttime = cnt->currenttime;
2154         }
2155 
2156 
2157         /*
2158          * Increase missing_frame_counter
2159          * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image
2160          * After MISSING_FRAMES_TIMEOUT seconds we put a grey error image in the buffer
2161          * If we still have not yet received the initial image from a camera
2162          * we go straight for the grey error image.
2163          */
2164         ++cnt->missing_frame_counter;
2165 
2166         if (cnt->video_dev >= 0 &&
2167             cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.framerate)) {
2168             memcpy(cnt->current_image->image_norm, cnt->imgs.image_vprvcy.image_norm, cnt->imgs.size_norm);
2169         } else {
2170             cnt->lost_connection = 1;
2171 
2172             if (cnt->video_dev >= 0)
2173                 tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T";
2174             else
2175                 tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T";
2176 
2177             tv1.tv_sec=cnt->connectionlosttime;
2178             tv1.tv_usec = 0;
2179             memset(cnt->current_image->image_norm, 0x80, cnt->imgs.size_norm);
2180             mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tv1, NULL, 0);
2181             draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
2182                       10, 20 * cnt->text_scale, tmpout, cnt->text_scale);
2183 
2184             /* Write error message only once */
2185             if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.framerate) {
2186                 MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
2187                     ,_("Video signal lost - Adding grey image"));
2188                 // Event for lost video signal can be called from here
2189                 event(cnt, EVENT_CAMERA_LOST, NULL, NULL, NULL, &tv1);
2190             }
2191 
2192             /*
2193              * If we don't get a valid frame for a long time, try to close/reopen device
2194              * Only try this when a device is open
2195              */
2196             if ((cnt->video_dev > 0) &&
2197                 (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.framerate)) {
2198                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
2199                     ,_("Video signal still lost - "
2200                     "Trying to close video device"));
2201                 vid_close(cnt);
2202             }
2203         }
2204     }
2205     return 0;
2206 
2207 }
2208 
mlp_detection(struct context * cnt)2209 static void mlp_detection(struct context *cnt){
2210 
2211 
2212     /***** MOTION LOOP - MOTION DETECTION SECTION *****/
2213     /*
2214      * The actual motion detection takes place in the following
2215      * diffs is the number of pixels detected as changed
2216      * Make a differences picture in image_out
2217      *
2218      * alg_diff_standard is the slower full feature motion detection algorithm
2219      * alg_diff first calls a fast detection algorithm which only looks at a
2220      * fraction of the pixels. If this detects possible motion alg_diff_standard
2221      * is called.
2222      */
2223     if (cnt->process_thisframe) {
2224         if (cnt->threshold && !cnt->pause) {
2225             /*
2226              * If we've already detected motion and we want to see if there's
2227              * still motion, don't bother trying the fast one first. IF there's
2228              * motion, the alg_diff will trigger alg_diff_standard
2229              * anyway
2230              */
2231             if (cnt->detecting_motion || cnt->conf.setup_mode)
2232                 cnt->current_image->diffs = alg_diff_standard(cnt, cnt->imgs.image_vprvcy.image_norm);
2233             else
2234                 cnt->current_image->diffs = alg_diff(cnt, cnt->imgs.image_vprvcy.image_norm);
2235 
2236             /* Lightswitch feature - has light intensity changed?
2237              * This can happen due to change of light conditions or due to a sudden change of the camera
2238              * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next
2239              * 'lightswitch_frames' frames to allow the camera to settle.
2240              * Don't check if we have lost connection, we detect "Lost signal" frame as lightswitch
2241              */
2242             if (cnt->conf.lightswitch_percent > 1 && !cnt->lost_connection) {
2243                 if (alg_lightswitch(cnt, cnt->current_image->diffs)) {
2244                     MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Lightswitch detected"));
2245 
2246                     if (cnt->conf.lightswitch_frames < 1)
2247                         cnt->conf.lightswitch_frames = 1;
2248                     else if (cnt->conf.lightswitch_frames > 1000)
2249                         cnt->conf.lightswitch_frames = 1000;
2250 
2251                     if (cnt->moved < (unsigned int)cnt->conf.lightswitch_frames)
2252                         cnt->moved = (unsigned int)cnt->conf.lightswitch_frames;
2253 
2254                     cnt->current_image->diffs = 0;
2255                     alg_update_reference_frame(cnt, RESET_REF_FRAME);
2256                 }
2257             }
2258 
2259             /*
2260              * Switchfilter feature tries to detect a change in the video signal
2261              * from one camera to the next. This is normally used in the Round
2262              * Robin feature. The algorithm is not very safe.
2263              * The algorithm takes a little time so we only call it when needed
2264              * ie. when feature is enabled and diffs>threshold.
2265              * We do not suspend motion detection like we did for lightswitch
2266              * because with Round Robin this is controlled by roundrobin_skip.
2267              */
2268             if (cnt->conf.roundrobin_switchfilter && cnt->current_image->diffs > cnt->threshold) {
2269                 cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs,
2270                                                              cnt->current_image->image_norm);
2271 
2272                 if ((cnt->current_image->diffs <= cnt->threshold) ||
2273                     (cnt->current_image->diffs > cnt->threshold_maximum)) {
2274 
2275                     cnt->current_image->diffs = 0;
2276                     MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Switchfilter detected"));
2277                 }
2278             }
2279 
2280             /*
2281              * Despeckle feature
2282              * First we run (as given by the despeckle_filter option iterations
2283              * of erode and dilate algorithms.
2284              * Finally we run the labelling feature.
2285              * All this is done in the alg_despeckle code.
2286              */
2287             cnt->current_image->total_labels = 0;
2288             cnt->imgs.largest_label = 0;
2289             cnt->olddiffs = 0;
2290 
2291             if (cnt->conf.despeckle_filter && cnt->current_image->diffs > 0) {
2292                 cnt->olddiffs = cnt->current_image->diffs;
2293                 cnt->current_image->diffs = alg_despeckle(cnt, cnt->olddiffs);
2294             } else if (cnt->imgs.labelsize_max) {
2295                 cnt->imgs.labelsize_max = 0; /* Disable labeling if enabled */
2296             }
2297 
2298         } else if (!cnt->conf.setup_mode) {
2299             cnt->current_image->diffs = 0;
2300         }
2301     }
2302 
2303     //TODO:  This section needs investigation for purpose, cause and effect
2304     /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */
2305     if ((cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) &&
2306         (!--cnt->smartmask_count)) {
2307         alg_tune_smartmask(cnt);
2308         cnt->smartmask_count = cnt->smartmask_ratio;
2309     }
2310 
2311     /*
2312      * cnt->moved is set by the tracking code when camera has been asked to move.
2313      * When camera is moving we do not want motion to detect motion or we will
2314      * get our camera chasing itself like crazy and we will get motion detected
2315      * which is not really motion. So we pretend there is no motion by setting
2316      * cnt->diffs = 0.
2317      * We also pretend to have a moving camera when we start Motion and when light
2318      * switch has been detected to allow camera to settle.
2319      */
2320     if (cnt->moved) {
2321         cnt->moved--;
2322         cnt->current_image->diffs = 0;
2323     }
2324 
2325 }
2326 
mlp_tuning(struct context * cnt)2327 static void mlp_tuning(struct context *cnt){
2328 
2329     /***** MOTION LOOP - TUNING SECTION *****/
2330 
2331     /*
2332      * If noise tuning was selected, do it now. but only when
2333      * no frames have been recorded and only once per second
2334      */
2335     if ((cnt->conf.noise_tune && cnt->shots == 0) &&
2336          (!cnt->detecting_motion && (cnt->current_image->diffs <= cnt->threshold)))
2337         alg_noise_tune(cnt, cnt->imgs.image_vprvcy.image_norm);
2338 
2339 
2340     /*
2341      * If we are not noise tuning lets make sure that remote controlled
2342      * changes of noise_level are used.
2343      */
2344     if (cnt->process_thisframe) {
2345         /*
2346          * threshold tuning if enabled
2347          * if we are not threshold tuning lets make sure that remote controlled
2348          * changes of threshold are used.
2349          */
2350         if (cnt->conf.threshold_tune){
2351             alg_threshold_tune(cnt, cnt->current_image->diffs, cnt->detecting_motion);
2352         }
2353 
2354         /*
2355          * If motion is detected (cnt->current_image->diffs > cnt->threshold) and before we add text to the pictures
2356          * we find the center and size coordinates of the motion to be used for text overlays and later
2357          * for adding the locate rectangle
2358          */
2359         if ((cnt->current_image->diffs > cnt->threshold) &&
2360             (cnt->current_image->diffs < cnt->threshold_maximum)){
2361 
2362             alg_locate_center_size(&cnt->imgs
2363                 , cnt->imgs.width
2364                 , cnt->imgs.height
2365                 , &cnt->current_image->location);
2366             }
2367 
2368         /*
2369          * Update reference frame.
2370          * micro-lighswitch: trying to auto-detect lightswitch events.
2371          * frontdoor illumination. Updates are rate-limited to 3 per second at
2372          * framerates above 5fps to save CPU resources and to keep sensitivity
2373          * at a constant level.
2374          */
2375 
2376         if ((cnt->current_image->diffs > cnt->threshold) &&
2377             (cnt->current_image->diffs < cnt->threshold_maximum) &&
2378             (cnt->conf.lightswitch_percent >= 1) &&
2379             (cnt->lightswitch_framecounter < (cnt->lastrate * 2)) && /* two seconds window only */
2380             /* number of changed pixels almost the same in two consecutive frames and */
2381             ((abs(cnt->previous_diffs - cnt->current_image->diffs)) < (cnt->previous_diffs / 15)) &&
2382             /* center of motion in about the same place ? */
2383             ((abs(cnt->current_image->location.x - cnt->previous_location_x)) <= (cnt->imgs.width / 150)) &&
2384             ((abs(cnt->current_image->location.y - cnt->previous_location_y)) <= (cnt->imgs.height / 150))) {
2385             alg_update_reference_frame(cnt, RESET_REF_FRAME);
2386             cnt->current_image->diffs = 0;
2387             cnt->lightswitch_framecounter = 0;
2388 
2389             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("micro-lightswitch!"));
2390         } else {
2391             alg_update_reference_frame(cnt, UPDATE_REF_FRAME);
2392         }
2393         cnt->previous_diffs = cnt->current_image->diffs;
2394         cnt->previous_location_x = cnt->current_image->location.x;
2395         cnt->previous_location_y = cnt->current_image->location.y;
2396     }
2397 
2398 
2399 }
2400 
mlp_overlay(struct context * cnt)2401 static void mlp_overlay(struct context *cnt){
2402 
2403     char tmp[PATH_MAX];
2404 
2405     /***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/
2406     /*
2407      * Some overlays on top of the motion image
2408      * Note that these now modifies the cnt->imgs.out so this buffer
2409      * can no longer be used for motion detection features until next
2410      * picture frame is captured.
2411      */
2412 
2413     /* Smartmask overlay */
2414     if (cnt->smartmask_speed &&
2415         (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
2416          cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
2417         overlay_smartmask(cnt, cnt->imgs.img_motion.image_norm);
2418 
2419     /* Largest labels overlay */
2420     if (cnt->imgs.largest_label && (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
2421         cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
2422         overlay_largest_label(cnt, cnt->imgs.img_motion.image_norm);
2423 
2424     /* Fixed mask overlay */
2425     if (cnt->imgs.mask && (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
2426         cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
2427         overlay_fixed_mask(cnt, cnt->imgs.img_motion.image_norm);
2428 
2429     /* Add changed pixels in upper right corner of the pictures */
2430     if (cnt->conf.text_changes) {
2431         if (!cnt->pause)
2432             sprintf(tmp, "%d", cnt->current_image->diffs);
2433         else
2434             sprintf(tmp, "-");
2435 
2436         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
2437                   cnt->imgs.width - 10, 10, tmp, cnt->text_scale);
2438     }
2439 
2440     /*
2441      * Add changed pixels to motion-images (for stream) in setup_mode
2442      * and always overlay smartmask (not only when motion is detected)
2443      */
2444     if (cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)) {
2445         sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs,
2446                 cnt->current_image->total_labels, cnt->noise);
2447         draw_text(cnt->imgs.img_motion.image_norm, cnt->imgs.width, cnt->imgs.height,
2448                   cnt->imgs.width - 10, cnt->imgs.height - (30 * cnt->text_scale),
2449                   tmp, cnt->text_scale);
2450         sprintf(tmp, "THREAD %d SETUP", cnt->threadnr);
2451         draw_text(cnt->imgs.img_motion.image_norm, cnt->imgs.width, cnt->imgs.height,
2452                   cnt->imgs.width - 10, cnt->imgs.height - (10 * cnt->text_scale),
2453                   tmp, cnt->text_scale);
2454     }
2455 
2456     /* Add text in lower left corner of the pictures */
2457     if (cnt->conf.text_left) {
2458         mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left,
2459                    &cnt->current_image->timestamp_tv, NULL, 0);
2460         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
2461                   10, cnt->imgs.height - (10 * cnt->text_scale), tmp, cnt->text_scale);
2462     }
2463 
2464     /* Add text in lower right corner of the pictures */
2465     if (cnt->conf.text_right) {
2466         mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right,
2467                    &cnt->current_image->timestamp_tv, NULL, 0);
2468         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
2469                   cnt->imgs.width - 10, cnt->imgs.height - (10 * cnt->text_scale),
2470                   tmp, cnt->text_scale);
2471     }
2472 
2473 }
2474 
mlp_actions(struct context * cnt)2475 static void mlp_actions(struct context *cnt){
2476 
2477     int indx;
2478 
2479     /***** MOTION LOOP - ACTIONS AND EVENT CONTROL SECTION *****/
2480 
2481     if ((cnt->current_image->diffs > cnt->threshold) &&
2482         (cnt->current_image->diffs < cnt->threshold_maximum)) {
2483         /* flag this image, it have motion */
2484         cnt->current_image->flags |= IMAGE_MOTION;
2485         cnt->lightswitch_framecounter++; /* micro lightswitch */
2486     } else {
2487         cnt->lightswitch_framecounter = 0;
2488     }
2489 
2490     /*
2491      * If motion has been detected we take action and start saving
2492      * pictures and movies etc by calling motion_detected().
2493      * Is emulate_motion enabled we always call motion_detected()
2494      * If post_capture is enabled we also take care of this in the this
2495      * code section.
2496      */
2497     if ((cnt->conf.emulate_motion || cnt->event_user) && (cnt->startup_frames == 0)) {
2498         /*  If we were previously detecting motion, started a movie, then got
2499          *  no motion then we reset the start movie time so that we do not
2500          *  get a pause in the movie.
2501         */
2502         if ( (cnt->detecting_motion == 0) && (cnt->ffmpeg_output != NULL) )
2503             ffmpeg_reset_movie_start_time(cnt->ffmpeg_output, &cnt->current_image->timestamp_tv);
2504         cnt->detecting_motion = 1;
2505         if (cnt->conf.post_capture > 0) {
2506             /* Setup the postcap counter */
2507             cnt->postcap = cnt->conf.post_capture;
2508             // MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "(Em) Init post capture %d", cnt->postcap);
2509         }
2510 
2511         cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE);
2512         /* Mark all images in image_ring to be saved */
2513         for (indx = 0; indx < cnt->imgs.image_ring_size; indx++){
2514             cnt->imgs.image_ring[indx].flags |= IMAGE_SAVE;
2515         }
2516 
2517         motion_detected(cnt, cnt->video_dev, cnt->current_image);
2518     } else if ((cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0)) {
2519         /*
2520          * Did we detect motion (like the cat just walked in :) )?
2521          * If so, ensure the motion is sustained if minimum_motion_frames
2522          */
2523 
2524         /* Count how many frames with motion there is in the last minimum_motion_frames in precap buffer */
2525         int frame_count = 0;
2526         int pos = cnt->imgs.image_ring_in;
2527 
2528         for (indx = 0; indx < cnt->conf.minimum_motion_frames; indx++) {
2529             if (cnt->imgs.image_ring[pos].flags & IMAGE_MOTION)
2530                 frame_count++;
2531 
2532             if (pos == 0)
2533                 pos = cnt->imgs.image_ring_size-1;
2534             else
2535                 pos--;
2536         }
2537 
2538         if (frame_count >= cnt->conf.minimum_motion_frames) {
2539 
2540             cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE);
2541             /*  If we were previously detecting motion, started a movie, then got
2542              *  no motion then we reset the start movie time so that we do not
2543              *  get a pause in the movie.
2544             */
2545             if ( (cnt->detecting_motion == 0) && (cnt->ffmpeg_output != NULL) )
2546                 ffmpeg_reset_movie_start_time(cnt->ffmpeg_output, &cnt->current_image->timestamp_tv);
2547 
2548             cnt->detecting_motion = 1;
2549 
2550             /* Setup the postcap counter */
2551             cnt->postcap = cnt->conf.post_capture;
2552             //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "Setup post capture %d", cnt->postcap);
2553 
2554             /* Mark all images in image_ring to be saved */
2555             for (indx = 0; indx < cnt->imgs.image_ring_size; indx++)
2556                 cnt->imgs.image_ring[indx].flags |= IMAGE_SAVE;
2557 
2558         } else if (cnt->postcap > 0) {
2559            /* we have motion in this frame, but not enought frames for trigger. Check postcap */
2560             cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE);
2561             cnt->postcap--;
2562             //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "post capture %d", cnt->postcap);
2563         } else {
2564             cnt->current_image->flags |= IMAGE_PRECAP;
2565         }
2566 
2567         /* Always call motion_detected when we have a motion image */
2568         motion_detected(cnt, cnt->video_dev, cnt->current_image);
2569     } else if (cnt->postcap > 0) {
2570         /* No motion, doing postcap */
2571         cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE);
2572         cnt->postcap--;
2573         //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "post capture %d", cnt->postcap);
2574     } else {
2575         /* Done with postcap, so just have the image in the precap buffer */
2576         cnt->current_image->flags |= IMAGE_PRECAP;
2577         /* gapless movie feature */
2578         if ((cnt->conf.event_gap == 0) && (cnt->detecting_motion == 1))
2579             cnt->event_stop = TRUE;
2580         cnt->detecting_motion = 0;
2581     }
2582 
2583     /* Update last frame saved time, so we can end event after gap time */
2584     if (cnt->current_image->flags & IMAGE_SAVE)
2585         cnt->lasttime = cnt->current_image->timestamp_tv.tv_sec;
2586 
2587 
2588     mlp_areadetect(cnt);
2589 
2590     /*
2591      * Is the movie too long? Then make movies
2592      * First test for movie_max_time
2593      */
2594     if ((cnt->conf.movie_max_time && cnt->event_nr == cnt->prev_event) &&
2595         (cnt->currenttime - cnt->eventtime >= cnt->conf.movie_max_time))
2596         cnt->event_stop = TRUE;
2597 
2598     /*
2599      * Now test for quiet longer than 'gap' OR make movie as decided in
2600      * previous statement.
2601      */
2602     if (((cnt->currenttime - cnt->lasttime >= cnt->conf.event_gap) && cnt->conf.event_gap > 0) ||
2603           cnt->event_stop) {
2604         if (cnt->event_nr == cnt->prev_event || cnt->event_stop) {
2605 
2606             /* Flush image buffer */
2607             process_image_ring(cnt, IMAGE_BUFFER_FLUSH);
2608 
2609             /* Save preview_shot here at the end of event */
2610             if (cnt->imgs.preview_image.diffs) {
2611                 event(cnt, EVENT_IMAGE_PREVIEW, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2612                 cnt->imgs.preview_image.diffs = 0;
2613             }
2614 
2615             event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2616 
2617             /*
2618              * If tracking is enabled we center our camera so it does not
2619              * point to a place where it will miss the next action
2620              */
2621             if (cnt->track.type)
2622                 cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0);
2623 
2624             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("End of event %d"), cnt->event_nr);
2625 
2626             cnt->event_stop = FALSE;
2627             cnt->event_user = FALSE;
2628 
2629             /* Reset post capture */
2630             cnt->postcap = 0;
2631 
2632             /* Finally we increase the event number */
2633             cnt->event_nr++;
2634             cnt->lightswitch_framecounter = 0;
2635 
2636             /*
2637              * And we unset the text_event_string to avoid that buffered
2638              * images get a timestamp from previous event.
2639              */
2640             cnt->text_event_string[0] = '\0';
2641         }
2642     }
2643 
2644     /* Save/send to movie some images */
2645     process_image_ring(cnt, 2);
2646 
2647 
2648 }
2649 
mlp_setupmode(struct context * cnt)2650 static void mlp_setupmode(struct context *cnt){
2651     /***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/
2652 
2653     /* If CAMERA_VERBOSE enabled output some numbers to console */
2654     if (cnt->conf.setup_mode) {
2655         char msg[1024] = "\0";
2656         char part[100];
2657 
2658         if (cnt->conf.despeckle_filter) {
2659             snprintf(part, 99, _("Raw changes: %5d - changes after '%s': %5d"),
2660                      cnt->olddiffs, cnt->conf.despeckle_filter, cnt->current_image->diffs);
2661             strcat(msg, part);
2662             if (strchr(cnt->conf.despeckle_filter, 'l')) {
2663                 snprintf(part, 99,_(" - labels: %3d"), cnt->current_image->total_labels);
2664                 strcat(msg, part);
2665             }
2666         } else {
2667             snprintf(part, 99,_("Changes: %5d"), cnt->current_image->diffs);
2668             strcat(msg, part);
2669         }
2670 
2671         if (cnt->conf.noise_tune) {
2672             snprintf(part, 99,_(" - noise level: %2d"), cnt->noise);
2673             strcat(msg, part);
2674         }
2675 
2676         if (cnt->conf.threshold_tune) {
2677             snprintf(part, 99, _(" - threshold: %d"), cnt->threshold);
2678             strcat(msg, part);
2679         }
2680 
2681         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s", msg);
2682     }
2683 
2684 }
2685 
mlp_snapshot(struct context * cnt)2686 static void mlp_snapshot(struct context *cnt){
2687     /***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/
2688     /*
2689      * Did we get triggered to make a snapshot from control http? Then shoot a snap
2690      * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap
2691      * We actually allow the time to run over the interval in case we have a delay
2692      * from slow camera.
2693      * Note: Negative value means SIGALRM snaps are enabled
2694      * httpd-control snaps are always enabled.
2695      */
2696 
2697     /* time_current_frame is used both for snapshot and timelapse features */
2698     cnt->time_current_frame = cnt->currenttime;
2699 
2700     if ((cnt->conf.snapshot_interval > 0 && cnt->shots == 0 &&
2701          cnt->time_current_frame % cnt->conf.snapshot_interval <= cnt->time_last_frame % cnt->conf.snapshot_interval) ||
2702          cnt->snapshot) {
2703         event(cnt, EVENT_IMAGE_SNAPSHOT, cnt->current_image, NULL, NULL, &cnt->current_image->timestamp_tv);
2704         cnt->snapshot = 0;
2705     }
2706 
2707 }
2708 
mlp_timelapse(struct context * cnt)2709 static void mlp_timelapse(struct context *cnt){
2710 
2711     struct tm timestamp_tm;
2712 
2713     if (cnt->conf.timelapse_interval) {
2714         localtime_r(&cnt->current_image->timestamp_tv.tv_sec, &timestamp_tm);
2715 
2716         /*
2717          * Check to see if we should start a new timelapse file. We start one when
2718          * we are on the first shot, and and the seconds are zero. We must use the seconds
2719          * to prevent the timelapse file from getting reset multiple times during the minute.
2720          */
2721         if (timestamp_tm.tm_min == 0 &&
2722             (cnt->time_current_frame % 60 < cnt->time_last_frame % 60) &&
2723             cnt->shots == 0) {
2724 
2725             if (strcasecmp(cnt->conf.timelapse_mode, "manual") == 0) {
2726                 ;/* No action */
2727 
2728             /* If we are daily, raise timelapseend event at midnight */
2729             } else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) {
2730                 if (timestamp_tm.tm_hour == 0)
2731                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2732 
2733             /* handle the hourly case */
2734             } else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) {
2735                 event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2736 
2737             /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */
2738             } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) {
2739                 if (timestamp_tm.tm_wday == 0 &&
2740                     timestamp_tm.tm_hour == 0)
2741                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2742             /* If we are weekly-monday, raise timelapseend event at midnight on monday */
2743             } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) {
2744                 if (timestamp_tm.tm_wday == 1 &&
2745                     timestamp_tm.tm_hour == 0)
2746                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2747             /* If we are monthly, raise timelapseend event at midnight on first day of month */
2748             } else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) {
2749                 if (timestamp_tm.tm_mday == 1 &&
2750                     timestamp_tm.tm_hour == 0)
2751                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2752             /* If invalid we report in syslog once and continue in manual mode */
2753             } else {
2754                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
2755                     ,_("Invalid timelapse_mode argument '%s'"), cnt->conf.timelapse_mode);
2756                 MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
2757                     ,_("%:s Defaulting to manual timelapse mode"));
2758                 conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual");
2759             }
2760         }
2761 
2762         /*
2763          * If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0
2764          * add a timelapse frame to the timelapse movie.
2765          */
2766         if (cnt->shots == 0 && cnt->time_current_frame % cnt->conf.timelapse_interval <=
2767             cnt->time_last_frame % cnt->conf.timelapse_interval) {
2768                 event(cnt, EVENT_TIMELAPSE, cnt->current_image, NULL, NULL,
2769                     &cnt->current_image->timestamp_tv);
2770         }
2771     } else if (cnt->ffmpeg_timelapse) {
2772     /*
2773      * If timelapse movie is in progress but conf.timelapse_interval is zero then close timelapse file
2774      * This is an important feature that allows manual roll-over of timelapse file using the http
2775      * remote control via a cron job.
2776      */
2777         event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
2778     }
2779 
2780     cnt->time_last_frame = cnt->time_current_frame;
2781 
2782 
2783 }
2784 
mlp_loopback(struct context * cnt)2785 static void mlp_loopback(struct context *cnt){
2786     /*
2787      * Feed last image and motion image to video device pipes and the stream clients
2788      * In setup mode we send the special setup mode image to both stream and vloopback pipe
2789      * In normal mode we feed the latest image to vloopback device and we send
2790      * the image to the stream. We always send the first image in a second to the stream.
2791      * Other image are sent only when the config option stream_motion is off
2792      * The result is that with stream_motion on the stream stream is normally at the minimal
2793      * 1 frame per second but the minute motion is detected the motion_detected() function
2794      * sends all detected pictures to the stream except the 1st per second which is already sent.
2795      */
2796     if (cnt->conf.setup_mode) {
2797 
2798         event(cnt, EVENT_IMAGE, &cnt->imgs.img_motion, NULL, &cnt->pipe, &cnt->current_image->timestamp_tv);
2799         event(cnt, EVENT_STREAM, &cnt->imgs.img_motion, NULL, NULL, &cnt->current_image->timestamp_tv);
2800     } else {
2801         event(cnt, EVENT_IMAGE, cnt->current_image, NULL,
2802               &cnt->pipe, &cnt->current_image->timestamp_tv);
2803 
2804         if (!cnt->conf.stream_motion || cnt->shots == 1)
2805             event(cnt, EVENT_STREAM, cnt->current_image, NULL, NULL,
2806                   &cnt->current_image->timestamp_tv);
2807     }
2808 
2809     event(cnt, EVENT_IMAGEM, &cnt->imgs.img_motion, NULL, &cnt->mpipe, &cnt->current_image->timestamp_tv);
2810 
2811 }
2812 
mlp_parmsupdate(struct context * cnt)2813 static void mlp_parmsupdate(struct context *cnt){
2814     /***** MOTION LOOP - ONCE PER SECOND PARAMETER UPDATE SECTION *****/
2815 
2816     /* Check for some config parameter changes but only every second */
2817     if (cnt->shots != 0) return;
2818 
2819     init_text_scale(cnt);  /* Initialize and validate text_scale */
2820 
2821     if (strcasecmp(cnt->conf.picture_output, "on") == 0)
2822         cnt->new_img = NEWIMG_ON;
2823     else if (strcasecmp(cnt->conf.picture_output, "first") == 0)
2824         cnt->new_img = NEWIMG_FIRST;
2825     else if (strcasecmp(cnt->conf.picture_output, "best") == 0)
2826         cnt->new_img = NEWIMG_BEST;
2827     else if (strcasecmp(cnt->conf.picture_output, "center") == 0)
2828         cnt->new_img = NEWIMG_CENTER;
2829     else
2830         cnt->new_img = NEWIMG_OFF;
2831 
2832     if (strcasecmp(cnt->conf.locate_motion_mode, "on") == 0)
2833         cnt->locate_motion_mode = LOCATE_ON;
2834     else if (strcasecmp(cnt->conf.locate_motion_mode, "preview") == 0)
2835         cnt->locate_motion_mode = LOCATE_PREVIEW;
2836     else
2837         cnt->locate_motion_mode = LOCATE_OFF;
2838 
2839     if (strcasecmp(cnt->conf.locate_motion_style, "box") == 0)
2840         cnt->locate_motion_style = LOCATE_BOX;
2841     else if (strcasecmp(cnt->conf.locate_motion_style, "redbox") == 0)
2842         cnt->locate_motion_style = LOCATE_REDBOX;
2843     else if (strcasecmp(cnt->conf.locate_motion_style, "cross") == 0)
2844         cnt->locate_motion_style = LOCATE_CROSS;
2845     else if (strcasecmp(cnt->conf.locate_motion_style, "redcross") == 0)
2846         cnt->locate_motion_style = LOCATE_REDCROSS;
2847     else
2848         cnt->locate_motion_style = LOCATE_BOX;
2849 
2850     /* Sanity check for smart_mask_speed, silly value disables smart mask */
2851     if (cnt->conf.smart_mask_speed < 0 || cnt->conf.smart_mask_speed > 10)
2852         cnt->conf.smart_mask_speed = 0;
2853 
2854     /* Has someone changed smart_mask_speed or framerate? */
2855     if (cnt->conf.smart_mask_speed != cnt->smartmask_speed ||
2856         cnt->smartmask_lastrate != cnt->lastrate) {
2857         if (cnt->conf.smart_mask_speed == 0) {
2858             memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);
2859             memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);
2860         }
2861 
2862         cnt->smartmask_lastrate = cnt->lastrate;
2863         cnt->smartmask_speed = cnt->conf.smart_mask_speed;
2864         /*
2865             * Decay delay - based on smart_mask_speed (framerate independent)
2866             * This is always 5*smartmask_speed seconds
2867             */
2868         cnt->smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed);
2869     }
2870 
2871     dbse_sqlmask_update(cnt);
2872 
2873     cnt->threshold = cnt->conf.threshold;
2874     if (cnt->conf.threshold_maximum > cnt->conf.threshold ){
2875         cnt->threshold_maximum = cnt->conf.threshold_maximum;
2876     } else {
2877         cnt->threshold_maximum = (cnt->imgs.height * cnt->imgs.width * 3) / 2;
2878     }
2879 
2880     if (!cnt->conf.noise_tune){
2881         cnt->noise = cnt->conf.noise_level;
2882     }
2883 
2884 }
2885 
mlp_frametiming(struct context * cnt)2886 static void mlp_frametiming(struct context *cnt){
2887 
2888     int indx;
2889     struct timeval tv2;
2890     unsigned long int elapsedtime;  //TODO: Need to evaluate logic for needing this.
2891     long int delay_time_nsec;
2892 
2893     /***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/
2894     /*
2895      * Work out expected frame rate based on config setting which may
2896      * have changed from http-control
2897      */
2898     if (cnt->conf.framerate)
2899         cnt->required_frame_time = 1000000L / cnt->conf.framerate;
2900     else
2901         cnt->required_frame_time = 0;
2902 
2903     /* Get latest time to calculate time taken to process video data */
2904     gettimeofday(&tv2, NULL);
2905     elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - cnt->timenow;
2906 
2907     /*
2908      * Update history buffer but ignore first pass as timebefore
2909      * variable will be inaccurate
2910      */
2911     if (cnt->passflag)
2912         cnt->rolling_average_data[cnt->rolling_frame] = cnt->timenow - cnt->timebefore;
2913     else
2914         cnt->passflag = 1;
2915 
2916     cnt->rolling_frame++;
2917     if (cnt->rolling_frame >= cnt->rolling_average_limit)
2918         cnt->rolling_frame = 0;
2919 
2920     /* Calculate 10 second average and use deviation in delay calculation */
2921     cnt->rolling_average = 0L;
2922 
2923     for (indx = 0; indx < cnt->rolling_average_limit; indx++)
2924         cnt->rolling_average += cnt->rolling_average_data[indx];
2925 
2926     cnt->rolling_average /= cnt->rolling_average_limit;
2927     cnt->frame_delay = cnt->required_frame_time - elapsedtime - (cnt->rolling_average - cnt->required_frame_time);
2928 
2929     if (cnt->frame_delay > 0) {
2930         /* Apply delay to meet frame time */
2931         if (cnt->frame_delay > cnt->required_frame_time)
2932             cnt->frame_delay = cnt->required_frame_time;
2933 
2934         /* Delay time in nanoseconds for SLEEP */
2935         delay_time_nsec = cnt->frame_delay * 1000;
2936 
2937         if (delay_time_nsec > 999999999)
2938             delay_time_nsec = 999999999;
2939 
2940         /* SLEEP as defined in motion.h  A safe sleep using nanosleep */
2941         SLEEP(0, delay_time_nsec);
2942     }
2943 
2944 }
2945 
2946 /**
2947  * motion_loop
2948  *
2949  *   Thread function for the motion handling threads.
2950  *
2951  */
motion_loop(void * arg)2952 static void *motion_loop(void *arg)
2953 {
2954     struct context *cnt = arg;
2955 
2956     if (motion_init(cnt) == 0){
2957         while (!cnt->finish || cnt->event_stop) {
2958             mlp_prepare(cnt);
2959             if (cnt->get_image) {
2960                 mlp_resetimages(cnt);
2961                 if (mlp_retry(cnt) == 1)  break;
2962                 if (mlp_capture(cnt) == 1)  break;
2963                 mlp_detection(cnt);
2964                 mlp_tuning(cnt);
2965                 mlp_overlay(cnt);
2966                 mlp_actions(cnt);
2967                 mlp_setupmode(cnt);
2968             }
2969             mlp_snapshot(cnt);
2970             mlp_timelapse(cnt);
2971             mlp_loopback(cnt);
2972             mlp_parmsupdate(cnt);
2973             mlp_frametiming(cnt);
2974         }
2975     }
2976 
2977     cnt->lost_connection = 1;
2978     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Thread exiting"));
2979 
2980     motion_cleanup(cnt);
2981 
2982     pthread_mutex_lock(&global_lock);
2983         threads_running--;
2984     pthread_mutex_unlock(&global_lock);
2985 
2986     cnt->running = 0;
2987     cnt->finish = 0;
2988 
2989     pthread_exit(NULL);
2990 }
2991 
2992 /**
2993  * become_daemon
2994  *
2995  *   Turns Motion into a daemon through forking. The parent process (i.e. the
2996  *   one initially calling this function) will exit inside this function, while
2997  *   control will be returned to the child process. Standard input/output are
2998  *   released properly, and the current directory is set to / in order to not
2999  *   lock up any file system.
3000  *
3001  * Parameters:
3002  *
3003  *   cnt - current thread's context struct
3004  *
3005  * Returns: nothing
3006  */
become_daemon(void)3007 static void become_daemon(void)
3008 {
3009     int i;
3010     FILE *pidf = NULL;
3011     struct sigaction sig_ign_action;
3012 
3013     /* Setup sig_ign_action */
3014 #ifdef SA_RESTART
3015     sig_ign_action.sa_flags = SA_RESTART;
3016 #else
3017     sig_ign_action.sa_flags = 0;
3018 #endif
3019     sig_ign_action.sa_handler = SIG_IGN;
3020     sigemptyset(&sig_ign_action.sa_mask);
3021 
3022     /* fork */
3023     if (fork()) {
3024         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion going to daemon mode"));
3025         exit(0);
3026     }
3027 
3028     /*
3029      * Create the pid file if defined, if failed exit
3030      * If we fail we report it. If we succeed we postpone the log entry till
3031      * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting
3032      * for an enter.
3033      */
3034     if (cnt_list[0]->conf.pid_file) {
3035         pidf = myfopen(cnt_list[0]->conf.pid_file, "w+");
3036 
3037         if (pidf) {
3038             (void)fprintf(pidf, "%d\n", getpid());
3039             myfclose(pidf);
3040         } else {
3041             MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO
3042                 ,_("Exit motion, cannot create process"
3043                 " id file (pid file) %s"), cnt_list[0]->conf.pid_file);
3044             if (ptr_logfile)
3045                 myfclose(ptr_logfile);
3046             exit(0);
3047         }
3048     }
3049 
3050     /*
3051      * Changing dir to root enables people to unmount a disk
3052      * without having to stop Motion
3053      */
3054     if (chdir("/"))
3055         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Could not change directory"));
3056 
3057 
3058 #if (defined(BSD) && !defined(__APPLE__))
3059     setpgrp(0, getpid());
3060 #else
3061     setpgrp();
3062 #endif
3063 
3064 
3065     if ((i = open("/dev/tty", O_RDWR)) >= 0) {
3066         ioctl(i, TIOCNOTTY, NULL);
3067         close(i);
3068     }
3069 
3070     setsid();
3071     i = open("/dev/null", O_RDONLY);
3072 
3073     if (i != -1) {
3074         dup2(i, STDIN_FILENO);
3075         close(i);
3076     }
3077 
3078     i = open("/dev/null", O_WRONLY);
3079 
3080     if (i != -1) {
3081         dup2(i, STDOUT_FILENO);
3082         dup2(i, STDERR_FILENO);
3083         close(i);
3084     }
3085 
3086     /* Now it is safe to add the PID creation to the logs */
3087     if (pidf)
3088         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
3089             ,_("Created process id file %s. Process ID is %d")
3090             ,cnt_list[0]->conf.pid_file, getpid());
3091 
3092     sigaction(SIGTTOU, &sig_ign_action, NULL);
3093     sigaction(SIGTTIN, &sig_ign_action, NULL);
3094     sigaction(SIGTSTP, &sig_ign_action, NULL);
3095 }
3096 
cntlist_create(int argc,char * argv[])3097 static void cntlist_create(int argc, char *argv[]){
3098     /*
3099      * cnt_list is an array of pointers to the context structures cnt for each thread.
3100      * First we reserve room for a pointer to thread 0's context structure
3101      * and a NULL pointer which indicates that end of the array of pointers to
3102      * thread context structures.
3103      */
3104     cnt_list = mymalloc(sizeof(struct context *) * 2);
3105 
3106     /* Now we reserve room for thread 0's context structure and let cnt_list[0] point to it */
3107     cnt_list[0] = mymalloc(sizeof(struct context));
3108 
3109     /* Populate context structure with start/default values */
3110     context_init(cnt_list[0]);
3111 
3112     /* Initialize some static and global string variables */
3113     gethostname (cnt_list[0]->hostname, PATH_MAX);
3114     cnt_list[0]->hostname[PATH_MAX-1] = '\0';
3115     /* end of variables */
3116 
3117     /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */
3118     cnt_list[1] = NULL;
3119 
3120     /*
3121      * Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads
3122      * the config options from motion.conf, thread config files and the command line.
3123      */
3124     cnt_list[0]->conf.argv = argv;
3125     cnt_list[0]->conf.argc = argc;
3126     cnt_list = conf_load(cnt_list);
3127 }
3128 
motion_shutdown(void)3129 static void motion_shutdown(void){
3130     int i = -1;
3131 
3132     motion_remove_pid();
3133 
3134     webu_stop(cnt_list);
3135 
3136     while (cnt_list[++i])
3137         context_destroy(cnt_list[i]);
3138 
3139     free(cnt_list);
3140     cnt_list = NULL;
3141 
3142     vid_mutex_destroy();
3143 }
3144 
motion_camera_ids(void)3145 static void motion_camera_ids(void){
3146     /* Set the camera id's on the context.  They must be unique */
3147     int indx, indx2, invalid_ids;
3148 
3149     /* Set defaults */
3150     indx = 0;
3151     while (cnt_list[indx] != NULL){
3152         if (cnt_list[indx]->conf.camera_id > 0){
3153             cnt_list[indx]->camera_id = cnt_list[indx]->conf.camera_id;
3154         } else {
3155             cnt_list[indx]->camera_id = indx;
3156         }
3157         indx++;
3158     }
3159 
3160     invalid_ids = FALSE;
3161     indx = 0;
3162     while (cnt_list[indx] != NULL){
3163         if (cnt_list[indx]->camera_id > 32000) invalid_ids = TRUE;
3164         indx2 = indx + 1;
3165         while (cnt_list[indx2] != NULL){
3166             if (cnt_list[indx]->camera_id == cnt_list[indx2]->camera_id) invalid_ids = TRUE;
3167 
3168             indx2++;
3169         }
3170         indx++;
3171     }
3172     if (invalid_ids){
3173         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
3174             ,_("Camara IDs are not unique or have values over 32,000.  Falling back to thread numbers"));
3175         indx = 0;
3176         while (cnt_list[indx] != NULL){
3177             cnt_list[indx]->camera_id = indx;
3178             indx++;
3179         }
3180     }
3181 }
3182 
motion_ntc(void)3183 static void motion_ntc(void){
3184 
3185     #ifdef HAVE_V4L2
3186         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("v4l2   : available"));
3187     #else
3188         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("v4l2   : not available"));
3189     #endif
3190 
3191     #ifdef HAVE_BKTR
3192         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("bktr   : available"));
3193     #else
3194         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("bktr   : not available"));
3195     #endif
3196 
3197     #ifdef HAVE_WEBP
3198         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("webp   : available"));
3199     #else
3200         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("webp   : not available"));
3201     #endif
3202 
3203     #ifdef HAVE_MMAL
3204         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("mmal   : available"));
3205     #else
3206         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("mmal   : not available"));
3207     #endif
3208 
3209     #ifdef HAVE_FFMPEG
3210         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("ffmpeg : available"));
3211     #else
3212         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("ffmpeg : not available"));
3213     #endif
3214 
3215     #ifdef HAVE_MYSQL
3216         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("mysql  : available"));
3217     #else
3218         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("mysql  : not available"));
3219     #endif
3220 
3221     #ifdef HAVE_MARIADB
3222         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("MariaDB: available"));
3223     #else
3224         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("MariaDB: not available"));
3225     #endif
3226 
3227     #ifdef HAVE_SQLITE3
3228         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("sqlite3: available"));
3229     #else
3230         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("sqlite3: not available"));
3231     #endif
3232 
3233     #ifdef HAVE_PGSQL
3234         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("pgsql  : available"));
3235     #else
3236         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("pgsql  : not available"));
3237     #endif
3238 
3239     #ifdef HAVE_GETTEXT
3240         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("nls    : available"));
3241     #else
3242         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("nls    : not available"));
3243     #endif
3244 
3245 
3246 }
3247 
3248 
3249 /**
3250  * motion_startup
3251  *
3252  *   Responsible for initializing stuff when Motion starts up or is restarted,
3253  *   including daemon initialization and creating the context struct list.
3254  *
3255  * Parameters:
3256  *
3257  *   daemonize - non-zero to do daemon init (if the config parameters says so),
3258  *               or 0 to skip it
3259  *   argc      - size of argv
3260  *   argv      - command-line options, passed initially from 'main'
3261  *
3262  * Returns: nothing
3263  */
motion_startup(int daemonize,int argc,char * argv[])3264 static void motion_startup(int daemonize, int argc, char *argv[])
3265 {
3266     /* Initialize our global mutex */
3267     pthread_mutex_init(&global_lock, NULL);
3268 
3269     /*
3270      * Create the list of context structures and load the
3271      * configuration.
3272      */
3273     cntlist_create(argc, argv);
3274 
3275     if ((cnt_list[0]->conf.log_level > ALL) ||
3276         (cnt_list[0]->conf.log_level == 0)) {
3277         cnt_list[0]->conf.log_level = LEVEL_DEFAULT;
3278         cnt_list[0]->log_level = cnt_list[0]->conf.log_level;
3279         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
3280             ,_("Using default log level (%s) (%d)")
3281             ,get_log_level_str(cnt_list[0]->log_level)
3282             ,SHOW_LEVEL_VALUE(cnt_list[0]->log_level));
3283     } else {
3284         cnt_list[0]->log_level = cnt_list[0]->conf.log_level - 1; // Let's make syslog compatible
3285     }
3286 
3287 
3288     if ((cnt_list[0]->conf.log_file) && (strncmp(cnt_list[0]->conf.log_file, "syslog", 6))) {
3289         set_log_mode(LOGMODE_FILE);
3290         ptr_logfile = set_logfile(cnt_list[0]->conf.log_file);
3291 
3292         if (ptr_logfile) {
3293             set_log_mode(LOGMODE_SYSLOG);
3294             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
3295                 ,_("Logging to file (%s)"),cnt_list[0]->conf.log_file);
3296             set_log_mode(LOGMODE_FILE);
3297         } else {
3298             MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO
3299                 ,_("Exit motion, cannot create log file %s")
3300                 ,cnt_list[0]->conf.log_file);
3301             exit(0);
3302         }
3303     } else {
3304         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Logging to syslog"));
3305     }
3306 
3307     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion %s Started"),VERSION);
3308 
3309     if ((cnt_list[0]->conf.log_type == NULL) ||
3310         !(cnt_list[0]->log_type = get_log_type(cnt_list[0]->conf.log_type))) {
3311         cnt_list[0]->log_type = TYPE_DEFAULT;
3312         cnt_list[0]->conf.log_type = mystrcpy(cnt_list[0]->conf.log_type, "ALL");
3313         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Using default log type (%s)"),
3314                    get_log_type_str(cnt_list[0]->log_type));
3315     }
3316 
3317     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Using log type (%s) log level (%s)"),
3318                get_log_type_str(cnt_list[0]->log_type), get_log_level_str(cnt_list[0]->log_level));
3319 
3320     set_log_level(cnt_list[0]->log_level);
3321     set_log_type(cnt_list[0]->log_type);
3322 
3323 
3324     if (daemonize) {
3325         /*
3326          * If daemon mode is requested, and we're not going into setup mode,
3327          * become daemon.
3328          */
3329         if (cnt_list[0]->daemon && cnt_list[0]->conf.setup_mode == 0) {
3330             become_daemon();
3331             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion running as daemon process"));
3332         }
3333     }
3334 
3335     if (cnt_list[0]->conf.setup_mode)
3336         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Motion running in setup mode."));
3337 
3338     conf_output_parms(cnt_list);
3339 
3340     motion_ntc();
3341 
3342     motion_camera_ids();
3343 
3344     initialize_chars();
3345 
3346     webu_start(cnt_list);
3347 
3348     vid_mutex_init();
3349 
3350 }
3351 
3352 /**
3353  * motion_start_thread
3354  *
3355  *   Called from main when start a motion thread
3356  *
3357  * Parameters:
3358  *
3359  *   cnt - Thread context pointer
3360  *   thread_attr - pointer to thread attributes
3361  *
3362  * Returns: nothing
3363  */
motion_start_thread(struct context * cnt)3364 static void motion_start_thread(struct context *cnt){
3365     int i;
3366     char service[6];
3367     pthread_attr_t thread_attr;
3368 
3369     if (strcmp(cnt->conf_filename, "")){
3370         cnt->conf_filename[sizeof(cnt->conf_filename) - 1] = '\0';
3371         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Camera ID: %d is from %s")
3372             ,cnt->camera_id, cnt->conf_filename);
3373     }
3374 
3375     if (cnt->conf.netcam_url){
3376         snprintf(service,6,"%s",cnt->conf.netcam_url);
3377         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Camera ID: %d Camera Name: %s Service: %s")
3378             ,cnt->camera_id, cnt->conf.camera_name,service);
3379     } else {
3380         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Camera ID: %d Camera Name: %s Device: %s")
3381             ,cnt->camera_id, cnt->conf.camera_name,cnt->conf.video_device);
3382     }
3383 
3384     /*
3385      * Check the stream port number for conflicts.
3386      * First we check for conflict with the control port.
3387      * Second we check for that two threads does not use the same port number
3388      * for the stream. If a duplicate port is found the stream feature gets disabled (port = 0)
3389      * for this thread and a warning is written to console and syslog.
3390      */
3391 
3392     if (cnt->conf.stream_port != 0) {
3393         /* Compare against the control port. */
3394         if (cnt_list[0]->conf.webcontrol_port == cnt->conf.stream_port) {
3395             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
3396                 ,_("Stream port number %d for thread %d conflicts with the control port")
3397                 ,cnt->conf.stream_port, cnt->threadnr);
3398             MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
3399                 ,_("Stream feature for thread %d is disabled.")
3400                 ,cnt->threadnr);
3401             cnt->conf.stream_port = 0;
3402         }
3403         /* Compare against stream ports of other threads. */
3404         for (i = 1; cnt_list[i]; i++) {
3405             if (cnt_list[i] == cnt) continue;
3406 
3407             if (cnt_list[i]->conf.stream_port == cnt->conf.stream_port) {
3408                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
3409                     ,_("Stream port number %d for thread %d conflicts with thread %d")
3410                     ,cnt->conf.stream_port, cnt->threadnr, cnt_list[i]->threadnr);
3411                 MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
3412                     ,_("Stream feature for thread %d is disabled.")
3413                     ,cnt->threadnr);
3414                 cnt->conf.stream_port = 0;
3415             }
3416         }
3417     }
3418 
3419     /*
3420      * Update how many threads we have running. This is done within a
3421      * mutex lock to prevent multiple simultaneous updates to
3422      * 'threads_running'.
3423      */
3424     pthread_mutex_lock(&global_lock);
3425     threads_running++;
3426     pthread_mutex_unlock(&global_lock);
3427 
3428     /* Set a flag that we want this thread running */
3429     cnt->restart = 1;
3430 
3431     /* Give the thread WATCHDOG_TMO to start */
3432     cnt->watchdog = WATCHDOG_TMO;
3433 
3434     /* Flag it as running outside of the thread, otherwise if the main loop
3435      * checked if it is was running before the thread set it to 1, it would
3436      * start another thread for this device. */
3437     cnt->running = 1;
3438 
3439     pthread_attr_init(&thread_attr);
3440     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
3441 
3442     if (pthread_create(&cnt->thread_id, &thread_attr, &motion_loop, cnt)) {
3443         /* thread create failed, undo running state */
3444         cnt->running = 0;
3445         pthread_mutex_lock(&global_lock);
3446         threads_running--;
3447         pthread_mutex_unlock(&global_lock);
3448     }
3449     pthread_attr_destroy(&thread_attr);
3450 
3451 }
3452 
motion_restart(int argc,char ** argv)3453 static void motion_restart(int argc, char **argv){
3454     /*
3455     * Handle the restart situation. Currently the approach is to
3456     * cleanup everything, and then initialize everything again
3457     * (including re-reading the config file(s)).
3458     */
3459     MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Restarting motion."));
3460     motion_shutdown();
3461 
3462     SLEEP(2, 0);
3463 
3464     motion_startup(0, argc, argv); /* 0 = skip daemon init */
3465     MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Motion restarted"));
3466 
3467     restart = 0;
3468 }
3469 
motion_watchdog(int indx)3470 static void motion_watchdog(int indx){
3471 
3472     /* Notes:
3473      * To test scenarios, just double lock a mutex in a spawned thread.
3474      * We use detached threads because pthread_join would lock the main thread
3475      * If we only call the first pthread_cancel when we reach the watchdog_kill
3476      *   it does not break us out of the mutex lock.
3477      * We keep sending VTAlarms so the pthread_cancel queued can be caught.
3478      * The calls to pthread_kill 'may' not work or cause crashes
3479      *   The cancel could finish and then the pthread_kill could be called
3480      *   on the invalid thread_id which could cause undefined results
3481      * Even if the cancel finishes it is not clean since memory is not cleaned.
3482      * The other option instead of cancel would be to exit(1) and terminate everything
3483      * Best to just not get into a watchdog situation...
3484      */
3485 
3486     if (!cnt_list[indx]->running) return;
3487 
3488     cnt_list[indx]->watchdog--;
3489     if (cnt_list[indx]->watchdog == 0) {
3490         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
3491             ,_("Thread %d - Watchdog timeout. Trying to do a graceful restart")
3492             , cnt_list[indx]->threadnr);
3493         cnt_list[indx]->event_stop = TRUE; /* Trigger end of event */
3494         cnt_list[indx]->finish = 1;
3495     }
3496 
3497     if (cnt_list[indx]->watchdog == WATCHDOG_KILL) {
3498         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
3499             ,_("Thread %d - Watchdog timeout did NOT restart, killing it!")
3500             , cnt_list[indx]->threadnr);
3501         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_RTSP) &&
3502             (cnt_list[indx]->rtsp != NULL)){
3503             pthread_cancel(cnt_list[indx]->rtsp->thread_id);
3504         }
3505         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_RTSP) &&
3506             (cnt_list[indx]->rtsp_high != NULL)){
3507             pthread_cancel(cnt_list[indx]->rtsp_high->thread_id);
3508         }
3509         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
3510             (cnt_list[indx]->netcam != NULL)){
3511             pthread_cancel(cnt_list[indx]->netcam->thread_id);
3512         }
3513         pthread_cancel(cnt_list[indx]->thread_id);
3514     }
3515 
3516     if (cnt_list[indx]->watchdog < WATCHDOG_KILL) {
3517         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
3518             (cnt_list[indx]->rtsp != NULL)){
3519             if (!cnt_list[indx]->rtsp->handler_finished &&
3520                 pthread_kill(cnt_list[indx]->rtsp->thread_id, 0) == ESRCH) {
3521                 cnt_list[indx]->rtsp->handler_finished = TRUE;
3522                 pthread_mutex_lock(&global_lock);
3523                     threads_running--;
3524                 pthread_mutex_unlock(&global_lock);
3525                 netcam_rtsp_cleanup(cnt_list[indx],FALSE);
3526             } else {
3527                 pthread_kill(cnt_list[indx]->rtsp->thread_id, SIGVTALRM);
3528             }
3529         }
3530         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
3531             (cnt_list[indx]->rtsp_high != NULL)){
3532             if (!cnt_list[indx]->rtsp_high->handler_finished &&
3533                 pthread_kill(cnt_list[indx]->rtsp_high->thread_id, 0) == ESRCH) {
3534                 cnt_list[indx]->rtsp_high->handler_finished = TRUE;
3535                 pthread_mutex_lock(&global_lock);
3536                     threads_running--;
3537                 pthread_mutex_unlock(&global_lock);
3538                 netcam_rtsp_cleanup(cnt_list[indx],FALSE);
3539             } else {
3540                 pthread_kill(cnt_list[indx]->rtsp_high->thread_id, SIGVTALRM);
3541             }
3542         }
3543         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
3544             (cnt_list[indx]->netcam != NULL)){
3545             if (!cnt_list[indx]->netcam->handler_finished &&
3546                 pthread_kill(cnt_list[indx]->netcam->thread_id, 0) == ESRCH) {
3547                 pthread_mutex_lock(&global_lock);
3548                     threads_running--;
3549                 pthread_mutex_unlock(&global_lock);
3550                 cnt_list[indx]->netcam->handler_finished = TRUE;
3551                 cnt_list[indx]->netcam->finish = FALSE;
3552             } else {
3553                 pthread_kill(cnt_list[indx]->netcam->thread_id, SIGVTALRM);
3554             }
3555         }
3556         if (cnt_list[indx]->running &&
3557             pthread_kill(cnt_list[indx]->thread_id, 0) == ESRCH){
3558             MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO
3559                 ,_("Thread %d - Cleaning thread.")
3560                 , cnt_list[indx]->threadnr);
3561             pthread_mutex_lock(&global_lock);
3562                 threads_running--;
3563             pthread_mutex_unlock(&global_lock);
3564             motion_cleanup(cnt_list[indx]);
3565             cnt_list[indx]->running = 0;
3566             cnt_list[indx]->finish = 0;
3567         } else {
3568             pthread_kill(cnt_list[indx]->thread_id,SIGVTALRM);
3569         }
3570     }
3571 }
3572 
motion_check_threadcount(void)3573 static int motion_check_threadcount(void){
3574     /* Return 1 if we should break out of loop */
3575 
3576     /* It has been observed that this is not counting every
3577      * thread running.  The netcams spawn handler threads which are not
3578      * counted here.  This is only counting context threads and when they
3579      * all get to zero, then we are done.
3580      */
3581 
3582     int motion_threads_running, indx;
3583 
3584     motion_threads_running = 0;
3585 
3586     for (indx = (cnt_list[1] != NULL ? 1 : 0); cnt_list[indx]; indx++) {
3587         if (cnt_list[indx]->running || cnt_list[indx]->restart)
3588             motion_threads_running++;
3589     }
3590 
3591     /* If the web control/streams are in finish/shutdown, we
3592      * do not want to count them.  They will be completely closed
3593      * by the process outside of loop that is checking the counts
3594      * of threads.  If the webcontrol is not in a finish / shutdown
3595      * then we want to keep them in the tread count to allow user
3596      * to restart the cameras and keep Motion running.
3597      */
3598     indx = 0;
3599     while (cnt_list[indx] != NULL){
3600         if ((cnt_list[indx]->webcontrol_finish == FALSE) &&
3601             ((cnt_list[indx]->webcontrol_daemon != NULL) ||
3602              (cnt_list[indx]->webstream_daemon != NULL))) {
3603             motion_threads_running++;
3604         }
3605         indx++;
3606     }
3607 
3608 
3609     if (((motion_threads_running == 0) && finish) ||
3610         ((motion_threads_running == 0) && (threads_running == 0))) {
3611         MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO
3612             ,_("DEBUG-1 threads_running %d motion_threads_running %d , finish %d")
3613             ,threads_running, motion_threads_running, finish);
3614         return 1;
3615     } else {
3616         return 0;
3617     }
3618 }
3619 
3620 /**
3621  * main
3622  *
3623  *   Main entry point of Motion. Launches all the motion threads and contains
3624  *   the logic for starting up, restarting and cleaning up everything.
3625  *
3626  * Parameters:
3627  *
3628  *   argc - size of argv
3629  *   argv - command-line options
3630  *
3631  * Returns: Motion exit status = 0 always
3632  */
main(int argc,char ** argv)3633 int main (int argc, char **argv)
3634 {
3635     int i;
3636 
3637     /* Create the TLS key for thread number. */
3638     pthread_key_create(&tls_key_threadnr, NULL);
3639     pthread_setspecific(tls_key_threadnr, (void *)(0));
3640 
3641     setup_signals();
3642 
3643     motion_startup(1, argc, argv);
3644 
3645     ffmpeg_global_init();
3646 
3647     dbse_global_init();
3648 
3649     translate_init();
3650 
3651     do {
3652         if (restart) motion_restart(argc, argv);
3653 
3654         for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) {
3655             cnt_list[i]->threadnr = i ? i : 1;
3656             motion_start_thread(cnt_list[i]);
3657         }
3658 
3659         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
3660             ,_("Waiting for threads to finish, pid: %d"), getpid());
3661 
3662         while (1) {
3663             SLEEP(1, 0);
3664             if (motion_check_threadcount()) break;
3665 
3666             for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) {
3667                 /* Check if threads wants to be restarted */
3668                 if ((!cnt_list[i]->running) && (cnt_list[i]->restart)) {
3669                     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
3670                         ,_("Motion thread %d restart"), cnt_list[i]->threadnr);
3671                     motion_start_thread(cnt_list[i]);
3672                 }
3673                 motion_watchdog(i);
3674             }
3675         }
3676 
3677         /* Reset end main loop flag */
3678         finish = 0;
3679 
3680         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Threads finished"));
3681 
3682         /* Rest for a while if we're supposed to restart. */
3683         if (restart) SLEEP(1, 0);
3684 
3685     } while (restart); /* loop if we're supposed to restart */
3686 
3687 
3688     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion terminating"));
3689 
3690     ffmpeg_global_deinit();
3691 
3692     dbse_global_deinit();
3693 
3694     motion_shutdown();
3695 
3696     /* Perform final cleanup. */
3697     pthread_key_delete(tls_key_threadnr);
3698     pthread_mutex_destroy(&global_lock);
3699 
3700     return 0;
3701 }
3702 
3703 /**
3704  * mymalloc
3705  *
3706  *   Allocates some memory and checks if that succeeded or not. If it failed,
3707  *   do some errorlogging and bail out.
3708  *
3709  *   NOTE: Kenneth Lavrsen changed printing of size_t types so instead of using
3710  *   conversion specifier %zd I changed it to %llu and casted the size_t
3711  *   variable to unsigned long long. The reason for this nonsense is that older
3712  *   versions of gcc like 2.95 uses %Zd and does not understand %zd. So to avoid
3713  *   this mess I used a more generic way. Long long should have enough bits for
3714  *   64-bit machines with large memory areas.
3715  *
3716  * Parameters:
3717  *
3718  *   nbytes - no. of bytes to allocate
3719  *
3720  * Returns: a pointer to the allocated memory
3721  */
mymalloc(size_t nbytes)3722 void * mymalloc(size_t nbytes)
3723 {
3724     void *dummy = calloc(nbytes, 1);
3725 
3726     if (!dummy) {
3727         MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO, _("Could not allocate %llu bytes of memory!")
3728             ,(unsigned long long)nbytes);
3729         motion_remove_pid();
3730         exit(1);
3731     }
3732 
3733     return dummy;
3734 }
3735 
3736 /**
3737  * myrealloc
3738  *
3739  *   Re-allocate (i.e., resize) some memory and check if that succeeded or not.
3740  *   If it failed, do some errorlogging and bail out. If the new memory size
3741  *   is 0, the memory is freed.
3742  *
3743  * Parameters:
3744  *
3745  *   ptr  - pointer to the memory to resize/reallocate
3746  *   size - new memory size
3747  *   desc - name of the calling function
3748  *
3749  * Returns: a pointer to the reallocated memory, or NULL if the memory was
3750  *          freed
3751  */
myrealloc(void * ptr,size_t size,const char * desc)3752 void *myrealloc(void *ptr, size_t size, const char *desc)
3753 {
3754     void *dummy = NULL;
3755 
3756     if (size == 0) {
3757         free(ptr);
3758         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
3759             ,_("Warning! Function %s tries to resize memoryblock at %p to 0 bytes!")
3760             ,desc, ptr);
3761     } else {
3762         dummy = realloc(ptr, size);
3763         if (!dummy) {
3764             MOTION_LOG(EMG, TYPE_ALL, NO_ERRNO
3765                 ,_("Could not resize memory-block at offset %p to %llu bytes (function %s)!")
3766                 ,ptr, (unsigned long long)size, desc);
3767             motion_remove_pid();
3768             exit(1);
3769         }
3770     }
3771 
3772     return dummy;
3773 }
3774 
3775 
3776 /**
3777  * create_path
3778  *
3779  *   This function creates a whole path, like mkdir -p. Example paths:
3780  *      this/is/an/example/
3781  *      /this/is/an/example/
3782  *   Warning: a path *must* end with a slash!
3783  *
3784  * Parameters:
3785  *
3786  *   cnt  - current thread's context structure (for logging)
3787  *   path - the path to create
3788  *
3789  * Returns: 0 on success, -1 on failure
3790  */
create_path(const char * path)3791 int create_path(const char *path)
3792 {
3793     char *start;
3794     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
3795 
3796     if (path[0] == '/')
3797         start = strchr(path + 1, '/');
3798     else
3799         start = strchr(path, '/');
3800 
3801     while (start) {
3802         char *buffer = mystrdup(path);
3803         buffer[start-path] = 0x00;
3804 
3805         if (mkdir(buffer, mode) == -1 && errno != EEXIST) {
3806             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
3807                 ,_("Problem creating directory %s"), buffer);
3808             free(buffer);
3809             return -1;
3810         }
3811 
3812         start = strchr(start + 1, '/');
3813 
3814         if (!start)
3815             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("creating directory %s"), buffer);
3816 
3817         free(buffer);
3818     }
3819 
3820     return 0;
3821 }
3822 
3823 /**
3824  * myfopen
3825  *
3826  *   This function opens a file, if that failed because of an ENOENT error
3827  *   (which is: path does not exist), the path is created and then things are
3828  *   tried again. This is faster then trying to create that path over and over
3829  *   again. If someone removes the path after it was created, myfopen will
3830  *   recreate the path automatically.
3831  *
3832  * Parameters:
3833  *
3834  *   path - path to the file to open
3835  *   mode - open mode
3836  *
3837  * Returns: the file stream object
3838  */
myfopen(const char * path,const char * mode)3839 FILE * myfopen(const char *path, const char *mode)
3840 {
3841     /* first, just try to open the file */
3842     FILE *dummy = fopen(path, mode);
3843     if (dummy) return dummy;
3844 
3845     /* could not open file... */
3846     /* path did not exist? */
3847     if (errno == ENOENT) {
3848 
3849         /* create path for file... */
3850         if (create_path(path) == -1)
3851             return NULL;
3852 
3853         /* and retry opening the file */
3854         dummy = fopen(path, mode);
3855     }
3856     if (!dummy) {
3857         /*
3858          * Two possibilities
3859          * 1: there was an other error while trying to open the file for the
3860          * first time
3861          * 2: could still not open the file after the path was created
3862          */
3863         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
3864             ,_("Error opening file %s with mode %s"), path, mode);
3865         return NULL;
3866     }
3867 
3868     return dummy;
3869 }
3870 
3871 /**
3872  * myfclose
3873  *
3874  *  Motion-specific variant of fclose()
3875  *
3876  * Returns: fclose() return value
3877  */
myfclose(FILE * fh)3878 int myfclose(FILE* fh)
3879 {
3880     int rval = fclose(fh);
3881 
3882     if (rval != 0)
3883         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error closing file"));
3884 
3885     return rval;
3886 }
3887 
3888 /**
3889  * mystrftime_long
3890  *
3891  *   Motion-specific long form of format specifiers.
3892  *
3893  * Parameters:
3894  *
3895  *   cnt        - current thread's context structure.
3896  *   width      - width associated with the format specifier.
3897  *   word       - beginning of the format specifier's word.
3898  *   l          - length of the format specifier's word.
3899  *   out        - output buffer where to store the result. Size: PATH_MAX.
3900  *
3901  * This is called if a format specifier with the format below was found:
3902  *
3903  *   % { word }
3904  *
3905  * As a special edge case, an incomplete format at the end of the string
3906  * is processed as well:
3907  *
3908  *   % { word \0
3909  *
3910  * Any valid format specified width is supported, e.g. "%12{host}".
3911  *
3912  * The following specifier keywords are currently supported:
3913  *
3914  * host    Replaced with the name of the local machine (see gethostname(2)).
3915  * fps     Equivalent to %fps.
3916  */
mystrftime_long(const struct context * cnt,int width,const char * word,int l,char * out)3917 static void mystrftime_long (const struct context *cnt,
3918                              int width, const char *word, int l, char *out)
3919 {
3920 #define SPECIFIERWORD(k) ((strlen(k)==l) && (!strncmp (k, word, l)))
3921 
3922     if (SPECIFIERWORD("host")) {
3923         snprintf (out, PATH_MAX, "%*s", width, cnt->hostname);
3924         return;
3925     }
3926     if (SPECIFIERWORD("fps")) {
3927         sprintf(out, "%*d", width, cnt->movie_fps);
3928         return;
3929     }
3930     if (SPECIFIERWORD("dbeventid")) {
3931         sprintf(out, "%*llu", width, cnt->database_event_id);
3932         return;
3933     }
3934     if (SPECIFIERWORD("ver")) {
3935         sprintf(out, "%*s", width, VERSION);
3936         return;
3937     }
3938 
3939     // Not a valid modifier keyword. Log the error and ignore.
3940     MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO,
3941         _("invalid format specifier keyword %*.*s"), l, l, word);
3942 
3943     // Do not let the output buffer empty, or else where to restart the
3944     // interpretation of the user string will become dependent to far too
3945     // many conditions. Maybe change loop to "if (*pos_userformat == '%') {
3946     // ...} __else__ ..."?
3947     out[0] = '~'; out[1] = 0;
3948 }
3949 
3950 /**
3951  * mystrftime
3952  *
3953  *   Motion-specific variant of strftime(3) that supports additional format
3954  *   specifiers in the format string.
3955  *
3956  * Parameters:
3957  *
3958  *   cnt        - current thread's context structure
3959  *   s          - destination string
3960  *   max        - max number of bytes to write
3961  *   userformat - format string
3962  *   tm         - time information
3963  *   filename   - string containing full path of filename
3964  *                set this to NULL if not relevant
3965  *   sqltype    - Filetype as used in SQL feature, set to 0 if not relevant
3966  *
3967  * Returns: number of bytes written to the string s
3968  */
mystrftime(const struct context * cnt,char * s,size_t max,const char * userformat,const struct timeval * tv1,const char * filename,int sqltype)3969 size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *userformat,
3970                   const struct timeval *tv1, const char *filename, int sqltype)
3971 {
3972     char formatstring[PATH_MAX] = "";
3973     char tempstring[PATH_MAX] = "";
3974     char *format, *tempstr;
3975     const char *pos_userformat;
3976     int width;
3977     struct tm timestamp_tm;
3978 
3979     localtime_r(&tv1->tv_sec, &timestamp_tm);
3980 
3981     format = formatstring;
3982 
3983     /* if mystrftime is called with userformat = NULL we return a zero length string */
3984     if (userformat == NULL) {
3985         *s = '\0';
3986         return 0;
3987     }
3988 
3989     for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) {
3990 
3991         if (*pos_userformat == '%') {
3992             /*
3993              * Reset 'tempstr' to point to the beginning of 'tempstring',
3994              * otherwise we will eat up tempstring if there are many
3995              * format specifiers.
3996              */
3997             tempstr = tempstring;
3998             tempstr[0] = '\0';
3999             width = 0;
4000             while ('0' <= pos_userformat[1] && pos_userformat[1] <= '9') {
4001                 width *= 10;
4002                 width += pos_userformat[1] - '0';
4003                 ++pos_userformat;
4004             }
4005 
4006             switch (*++pos_userformat) {
4007             case '\0': // end of string
4008                 --pos_userformat;
4009                 break;
4010 
4011             case 'v': // event
4012                 sprintf(tempstr, "%0*d", width ? width : 2, cnt->event_nr);
4013                 break;
4014 
4015             case 'q': // shots
4016                 sprintf(tempstr, "%0*d", width ? width : 2,
4017                     cnt->current_image->shot);
4018                 break;
4019 
4020             case 'D': // diffs
4021                 sprintf(tempstr, "%*d", width, cnt->current_image->diffs);
4022                 break;
4023 
4024             case 'N': // noise
4025                 sprintf(tempstr, "%*d", width, cnt->noise);
4026                 break;
4027 
4028             case 'i': // motion width
4029                 sprintf(tempstr, "%*d", width,
4030                     cnt->current_image->location.width);
4031                 break;
4032 
4033             case 'J': // motion height
4034                 sprintf(tempstr, "%*d", width,
4035                     cnt->current_image->location.height);
4036                 break;
4037 
4038             case 'K': // motion center x
4039                 sprintf(tempstr, "%*d", width, cnt->current_image->location.x);
4040                 break;
4041 
4042             case 'L': // motion center y
4043                 sprintf(tempstr, "%*d", width, cnt->current_image->location.y);
4044                 break;
4045 
4046             case 'o': // threshold
4047                 sprintf(tempstr, "%*d", width, cnt->threshold);
4048                 break;
4049 
4050             case 'Q': // number of labels
4051                 sprintf(tempstr, "%*d", width,
4052                     cnt->current_image->total_labels);
4053                 break;
4054 
4055             case 't': // camera id
4056                 sprintf(tempstr, "%*d", width, cnt->camera_id);
4057                 break;
4058 
4059             case 'C': // text_event
4060                 if (cnt->text_event_string[0])
4061                     snprintf(tempstr, PATH_MAX, "%*s", width,
4062                         cnt->text_event_string);
4063                 else
4064                     ++pos_userformat;
4065                 break;
4066 
4067             case 'w': // picture width
4068                 sprintf(tempstr, "%*d", width, cnt->imgs.width);
4069                 break;
4070 
4071             case 'h': // picture height
4072                 sprintf(tempstr, "%*d", width, cnt->imgs.height);
4073                 break;
4074 
4075             case 'f': // filename -- or %fps
4076                 if ((*(pos_userformat+1) == 'p') && (*(pos_userformat+2) == 's')) {
4077                     sprintf(tempstr, "%*d", width, cnt->movie_fps);
4078                     pos_userformat += 2;
4079                     break;
4080                 }
4081 
4082                 if (filename)
4083                     snprintf(tempstr, PATH_MAX, "%*s", width, filename);
4084                 else
4085                     ++pos_userformat;
4086                 break;
4087 
4088             case 'n': // sqltype
4089                 if (sqltype)
4090                     sprintf(tempstr, "%*d", width, sqltype);
4091                 else
4092                     ++pos_userformat;
4093                 break;
4094 
4095             case '{': // long format specifier word.
4096                 {
4097                     const char *word = ++pos_userformat;
4098                     while ((*pos_userformat != '}') && (*pos_userformat != 0))
4099                         ++pos_userformat;
4100                     mystrftime_long (cnt, width, word, (int)(pos_userformat-word), tempstr);
4101                     if (*pos_userformat == '\0') --pos_userformat;
4102                 }
4103                 break;
4104 
4105             case '$': // thread name
4106                 if (cnt->conf.camera_name && cnt->conf.camera_name[0])
4107                     snprintf(tempstr, PATH_MAX, "%s", cnt->conf.camera_name);
4108                 else
4109                     ++pos_userformat;
4110                 break;
4111 
4112             default: // Any other code is copied with the %-sign
4113                 *format++ = '%';
4114                 *format++ = *pos_userformat;
4115                 continue;
4116             }
4117 
4118             /*
4119              * If a format specifier was found and used, copy the result from
4120              * 'tempstr' to 'format'.
4121              */
4122             if (tempstr[0]) {
4123                 while ((*format = *tempstr++) != '\0')
4124                     ++format;
4125                 continue;
4126             }
4127         }
4128 
4129         /* For any other character than % we just simply copy the character */
4130         *format++ = *pos_userformat;
4131     }
4132 
4133     *format = '\0';
4134     format = formatstring;
4135 
4136     return strftime(s, max, format, &timestamp_tm);
4137 }
4138 /* This is a temporary location for these util functions.  All the generic utility
4139  * functions will be collected here and ultimately moved into a new common "util" module
4140  */
util_threadname_set(const char * abbr,int threadnbr,const char * threadname)4141 void util_threadname_set(const char *abbr, int threadnbr, const char *threadname){
4142     /* When the abbreviation is sent in as null, that means we are being
4143      * provided a fully filled out thread name (usually obtained from a
4144      * previously called get_threadname so we set it without additional
4145      *  formatting.
4146      */
4147 
4148     char tname[16];
4149     if (abbr != NULL){
4150         snprintf(tname, sizeof(tname), "%s%d%s%s",abbr,threadnbr,
4151              threadname ? ":" : "",
4152              threadname ? threadname : "");
4153     } else {
4154         snprintf(tname, sizeof(tname), "%s",threadname);
4155     }
4156 
4157 #ifdef __APPLE__
4158     pthread_setname_np(tname);
4159 #elif defined(BSD)
4160     pthread_set_name_np(pthread_self(), tname);
4161 #elif HAVE_PTHREAD_SETNAME_NP
4162     pthread_setname_np(pthread_self(), tname);
4163 #else
4164     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Unable to set thread name %s"), tname);
4165 #endif
4166 
4167 }
4168 
util_threadname_get(char * threadname)4169 void util_threadname_get(char *threadname){
4170 
4171 #if ((!defined(BSD) && HAVE_PTHREAD_GETNAME_NP) || defined(__APPLE__))
4172     char currname[16];
4173     pthread_getname_np(pthread_self(), currname, sizeof(currname));
4174     snprintf(threadname, sizeof(currname), "%s",currname);
4175 #else
4176     snprintf(threadname, 8, "%s","Unknown");
4177 #endif
4178 
4179 }
util_check_passthrough(struct context * cnt)4180 int util_check_passthrough(struct context *cnt){
4181 #if (HAVE_FFMPEG && LIBAVFORMAT_VERSION_MAJOR < 55)
4182     if (cnt->movie_passthrough)
4183         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
4184             ,_("FFMPEG version too old. Disabling pass-through processing."));
4185     return 0;
4186 #else
4187     if (cnt->movie_passthrough){
4188         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
4189             ,_("pass-through is enabled but is still experimental."));
4190         return 1;
4191     } else {
4192         return 0;
4193     }
4194 #endif
4195 
4196 }
4197