"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/motion.c" (14 Jan 2020, 150994 Bytes) of package /linux/misc/motion-Release-4.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "motion.c" see the Fossies "Dox" file reference documentation.

    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  */
   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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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 
  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 
  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 
  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 
  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 
  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 
  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*/
  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 
  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 
 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             // close database to be sure that we are not leaking
 1043             mysql_close(cnt->database);
 1044             cnt->database_event_id = 0;
 1045 
 1046             cnt->database = mymalloc(sizeof(MYSQL));
 1047             mysql_init(cnt->database);
 1048             if ((cnt->conf.database_port < 0) || (cnt->conf.database_port > 65535)){
 1049                 dbport = 0;
 1050             } else {
 1051                 dbport = cnt->conf.database_port;
 1052             }
 1053             if (!mysql_real_connect(cnt->database, cnt->conf.database_host, cnt->conf.database_user,
 1054                 cnt->conf.database_password, cnt->conf.database_dbname, dbport, NULL, 0)) {
 1055                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
 1056                     ,_("Cannot connect to MySQL database %s on host %s with user %s")
 1057                     ,cnt->conf.database_dbname, cnt->conf.database_host
 1058                     ,cnt->conf.database_user);
 1059                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
 1060                     ,_("MySQL error was %s"), mysql_error(cnt->database));
 1061                 return -2;
 1062             }
 1063             #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)
 1064                 int my_true = TRUE;
 1065                 mysql_options(cnt->database, MYSQL_OPT_RECONNECT, &my_true);
 1066             #endif
 1067         }
 1068     #else
 1069         (void)cnt;  /* Avoid compiler warnings */
 1070     #endif /* HAVE_MYSQL HAVE_MARIADB */
 1071 
 1072     return 0;
 1073 
 1074 }
 1075 
 1076 static int dbse_init_sqlite3(struct context *cnt){
 1077     #ifdef HAVE_SQLITE3
 1078         if (cnt_list[0]->database_sqlite3 != 0) {
 1079             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("SQLite3 using shared handle"));
 1080             cnt->database_sqlite3 = cnt_list[0]->database_sqlite3;
 1081 
 1082         } else if ((!strcmp(cnt->conf.database_type, "sqlite3")) && cnt->conf.database_dbname) {
 1083             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
 1084                 ,_("SQLite3 Database filename %s"), cnt->conf.database_dbname);
 1085             if (sqlite3_open(cnt->conf.database_dbname, &cnt->database_sqlite3) != SQLITE_OK) {
 1086                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
 1087                     ,_("Can't open database %s : %s")
 1088                     ,cnt->conf.database_dbname, sqlite3_errmsg(cnt->database_sqlite3));
 1089                 sqlite3_close(cnt->database_sqlite3);
 1090                 return -2;
 1091             }
 1092             MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
 1093                 ,_("database_busy_timeout %d msec"), cnt->conf.database_busy_timeout);
 1094             if (sqlite3_busy_timeout(cnt->database_sqlite3, cnt->conf.database_busy_timeout) != SQLITE_OK)
 1095                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
 1096                     ,_("database_busy_timeout failed %s")
 1097                     ,sqlite3_errmsg(cnt->database_sqlite3));
 1098         }
 1099     #else
 1100         (void)cnt;  /* Avoid compiler warnings */
 1101     #endif /* HAVE_SQLITE3 */
 1102 
 1103     return 0;
 1104 
 1105 }
 1106 
 1107 static int dbse_init_pgsql(struct context *cnt){
 1108     #ifdef HAVE_PGSQL
 1109         if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) {
 1110             char connstring[255];
 1111 
 1112             /*
 1113              * Create the connection string.
 1114              * Quote the values so we can have null values (blank)
 1115              */
 1116             snprintf(connstring, 255,
 1117                      "dbname='%s' host='%s' user='%s' password='%s' port='%d'",
 1118                       cnt->conf.database_dbname, /* dbname */
 1119                       (cnt->conf.database_host ? cnt->conf.database_host : ""), /* host (may be blank) */
 1120                       (cnt->conf.database_user ? cnt->conf.database_user : ""), /* user (may be blank) */
 1121                       (cnt->conf.database_password ? cnt->conf.database_password : ""), /* password (may be blank) */
 1122                       cnt->conf.database_port
 1123             );
 1124 
 1125             cnt->database_pg = PQconnectdb(connstring);
 1126             if (PQstatus(cnt->database_pg) == CONNECTION_BAD) {
 1127                 MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
 1128                 ,_("Connection to PostgreSQL database '%s' failed: %s")
 1129                 ,cnt->conf.database_dbname, PQerrorMessage(cnt->database_pg));
 1130                 return -2;
 1131             }
 1132         }
 1133     #else
 1134         (void)cnt;  /* Avoid compiler warnings */
 1135     #endif /* HAVE_PGSQL */
 1136 
 1137     return 0;
 1138 }
 1139 
 1140 static int dbse_init(struct context *cnt){
 1141     int retcd = 0;
 1142 
 1143     if (cnt->conf.database_type) {
 1144         MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
 1145             ,_("Database backend %s"), cnt->conf.database_type);
 1146 
 1147         retcd = dbse_init_mysql(cnt);
 1148         if (retcd != 0) return retcd;
 1149 
 1150         retcd = dbse_init_sqlite3(cnt);
 1151         if (retcd != 0) return retcd;
 1152 
 1153         retcd = dbse_init_pgsql(cnt);
 1154         if (retcd != 0) return retcd;
 1155 
 1156         /* Set the sql mask file according to the SQL config options*/
 1157         cnt->sql_mask = cnt->conf.sql_log_picture * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) +
 1158                         cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT +
 1159                         cnt->conf.sql_log_movie * (FTYPE_MPEG + FTYPE_MPEG_MOTION) +
 1160                         cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE;
 1161     }
 1162 
 1163     return retcd;
 1164 }
 1165 
 1166 static void dbse_deinit(struct context *cnt){
 1167     if (cnt->conf.database_type) {
 1168         #if defined(HAVE_MYSQL) || defined(HAVE_MARIADB)
 1169             if ( (!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) {
 1170                 mysql_close(cnt->database);
 1171                 cnt->database_event_id = 0;
 1172             }
 1173         #endif /* HAVE_MYSQL HAVE_MARIADB */
 1174 
 1175         #ifdef HAVE_PGSQL
 1176                 if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) {
 1177                     PQfinish(cnt->database_pg);
 1178                 }
 1179         #endif /* HAVE_PGSQL */
 1180 
 1181         #ifdef HAVE_SQLITE3
 1182                 /* Close the SQLite database */
 1183                 if ((!strcmp(cnt->conf.database_type, "sqlite3")) && (cnt->conf.database_dbname)) {
 1184                     sqlite3_close(cnt->database_sqlite3);
 1185                     cnt->database_sqlite3 = NULL;
 1186                 }
 1187         #endif /* HAVE_SQLITE3 */
 1188         (void)cnt;
 1189     }
 1190 }
 1191 
 1192 static void dbse_sqlmask_update(struct context *cnt){
 1193     /*
 1194     * Set the sql mask file according to the SQL config options
 1195     * We update it for every frame in case the config was updated
 1196     * via remote control.
 1197     */
 1198     cnt->sql_mask = cnt->conf.sql_log_picture * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) +
 1199                     cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT +
 1200                     cnt->conf.sql_log_movie * (FTYPE_MPEG + FTYPE_MPEG_MOTION) +
 1201                     cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE;
 1202 }
 1203 
 1204 /**
 1205  * motion_init
 1206  *
 1207  * This routine is called from motion_loop (the main thread of the program) to do
 1208  * all of the initialization required before starting the actual run.
 1209  *
 1210  * Parameters:
 1211  *
 1212  *      cnt     Pointer to the motion context structure
 1213  *
 1214  * Returns:     0 OK
 1215  *             -1 Fatal error, open loopback error
 1216  *             -2 Fatal error, open SQL database error
 1217  *             -3 Fatal error, image dimensions are not modulo 8
 1218  */
 1219 static int motion_init(struct context *cnt)
 1220 {
 1221     FILE *picture;
 1222     int indx, retcd;
 1223 
 1224     util_threadname_set("ml",cnt->threadnr,cnt->conf.camera_name);
 1225 
 1226     /* Store thread number in TLS. */
 1227     pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr));
 1228 
 1229     cnt->currenttime_tm = mymalloc(sizeof(struct tm));
 1230     cnt->eventtime_tm = mymalloc(sizeof(struct tm));
 1231     /* Init frame time */
 1232     cnt->currenttime = time(NULL);
 1233     localtime_r(&cnt->currenttime, cnt->currenttime_tm);
 1234 
 1235     cnt->smartmask_speed = 0;
 1236 
 1237     /*
 1238      * We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so
 1239      * that certain code below does not run until motion has been detected the first time
 1240      */
 1241     cnt->event_nr = 1;
 1242     cnt->prev_event = 0;
 1243     cnt->lightswitch_framecounter = 0;
 1244     cnt->detecting_motion = 0;
 1245     cnt->event_user = FALSE;
 1246     cnt->event_stop = FALSE;
 1247 
 1248     /* Make sure to default the high res to zero */
 1249     cnt->imgs.width_high = 0;
 1250     cnt->imgs.height_high = 0;
 1251     cnt->imgs.size_high = 0;
 1252     cnt->movie_passthrough = cnt->conf.movie_passthrough;
 1253 
 1254     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 1255         ,_("Camera %d started: motion detection %s"),
 1256         cnt->camera_id, cnt->pause ? _("Disabled"):_("Enabled"));
 1257 
 1258     if (!cnt->conf.target_dir)
 1259         cnt->conf.target_dir = mystrdup(".");
 1260 
 1261     if (init_camera_type(cnt) != 0 ) return -3;
 1262 
 1263     if ((cnt->camera_type != CAMERA_TYPE_RTSP) &&
 1264         (cnt->movie_passthrough)) {
 1265         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Pass-through processing disabled."));
 1266         cnt->movie_passthrough = FALSE;
 1267     }
 1268 
 1269     if ((cnt->conf.height == 0) || (cnt->conf.width == 0)) {
 1270         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 1271             ,_("Invalid configuration dimensions %dx%d"),cnt->conf.height,cnt->conf.width);
 1272         cnt->conf.height = DEF_HEIGHT;
 1273         cnt->conf.width = DEF_WIDTH;
 1274         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 1275             ,_("Using default dimensions %dx%d"),cnt->conf.height,cnt->conf.width);
 1276     }
 1277     if (cnt->conf.width % 8) {
 1278         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1279             ,_("Image width (%d) requested is not modulo 8."), cnt->conf.width);
 1280         cnt->conf.width = cnt->conf.width - (cnt->conf.width % 8) + 8;
 1281         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1282             ,_("Adjusting width to next higher multiple of 8 (%d)."), cnt->conf.width);
 1283     }
 1284     if (cnt->conf.height % 8) {
 1285         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1286             ,_("Image height (%d) requested is not modulo 8."), cnt->conf.height);
 1287         cnt->conf.height = cnt->conf.height - (cnt->conf.height % 8) + 8;
 1288         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1289             ,_("Adjusting height to next higher multiple of 8 (%d)."), cnt->conf.height);
 1290     }
 1291     if (cnt->conf.width  < 64) cnt->conf.width  = 64;
 1292     if (cnt->conf.height < 64) cnt->conf.height = 64;
 1293 
 1294     if (cnt->conf.netcam_decoder != NULL){
 1295         cnt->netcam_decoder = mymalloc(strlen(cnt->conf.netcam_decoder)+1);
 1296         retcd = snprintf(cnt->netcam_decoder,strlen(cnt->conf.netcam_decoder)+1
 1297             ,"%s",cnt->conf.netcam_decoder);
 1298         if (retcd < 0){
 1299             free(cnt->netcam_decoder);
 1300             cnt->netcam_decoder = NULL;
 1301         }
 1302     } else {
 1303         cnt->netcam_decoder = NULL;
 1304     }
 1305 
 1306 
 1307     /* set the device settings */
 1308     cnt->video_dev = vid_start(cnt);
 1309 
 1310     /*
 1311      * We failed to get an initial image from a camera
 1312      * So we need to guess height and width based on the config
 1313      * file options.
 1314      */
 1315     if (cnt->video_dev == -1) {
 1316         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 1317             ,_("Could not fetch initial image from camera "));
 1318         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 1319             ,_("Motion continues using width and height from config file(s)"));
 1320         cnt->imgs.width = cnt->conf.width;
 1321         cnt->imgs.height = cnt->conf.height;
 1322         cnt->imgs.size_norm = cnt->conf.width * cnt->conf.height * 3 / 2;
 1323         cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height;
 1324     } else if (cnt->video_dev == -2) {
 1325         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1326             ,_("Could not fetch initial image from camera "));
 1327         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1328             ,_("Motion only supports width and height modulo 8"));
 1329         return -3;
 1330     }
 1331     /* Revalidate we got a valid image size */
 1332     if ((cnt->imgs.width % 8) || (cnt->imgs.height % 8)) {
 1333         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1334             ,_("Image width (%d) or height(%d) requested is not modulo 8.")
 1335             ,cnt->imgs.width, cnt->imgs.height);
 1336         return -3;
 1337     }
 1338     if ((cnt->imgs.width  < 64) || (cnt->imgs.height < 64)){
 1339         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1340             ,_("Motion only supports width and height greater than or equal to 64 %dx%d")
 1341             ,cnt->imgs.width, cnt->imgs.height);
 1342             return -3;
 1343     }
 1344     /* Substream size notification*/
 1345     if ((cnt->imgs.width % 16) || (cnt->imgs.height % 16)) {
 1346         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1347             ,_("Substream not available.  Image sizes not modulo 16."));
 1348     }
 1349 
 1350 
 1351     /* We set size_high here so that it can be used in the retry function to determine whether
 1352      * we need to break and reallocate buffers
 1353      */
 1354     cnt->imgs.size_high = (cnt->imgs.width_high * cnt->imgs.height_high * 3) / 2;
 1355 
 1356     image_ring_resize(cnt, 1); /* Create a initial precapture ring buffer with 1 frame */
 1357 
 1358     cnt->imgs.ref = mymalloc(cnt->imgs.size_norm);
 1359     cnt->imgs.img_motion.image_norm = mymalloc(cnt->imgs.size_norm);
 1360 
 1361     /* contains the moving objects of ref. frame */
 1362     cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.ref_dyn));
 1363     cnt->imgs.image_virgin.image_norm = mymalloc(cnt->imgs.size_norm);
 1364     cnt->imgs.image_vprvcy.image_norm = mymalloc(cnt->imgs.size_norm);
 1365     cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize);
 1366     cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize);
 1367     cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer));
 1368     cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.labels));
 1369     cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(*cnt->imgs.labelsize));
 1370     cnt->imgs.preview_image.image_norm = mymalloc(cnt->imgs.size_norm);
 1371     cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height);
 1372     if (cnt->imgs.size_high > 0){
 1373         cnt->imgs.image_virgin.image_high = mymalloc(cnt->imgs.size_high);
 1374         cnt->imgs.preview_image.image_high = mymalloc(cnt->imgs.size_high);
 1375     }
 1376 
 1377     mot_stream_init(cnt);
 1378 
 1379     /* Set output picture type */
 1380     if (!strcmp(cnt->conf.picture_type, "ppm"))
 1381         cnt->imgs.picture_type = IMAGE_TYPE_PPM;
 1382     else if (!strcmp(cnt->conf.picture_type, "webp")) {
 1383         #ifdef HAVE_WEBP
 1384                 cnt->imgs.picture_type = IMAGE_TYPE_WEBP;
 1385         #else
 1386                 /* Fallback to jpeg if webp was selected in the config file, but the support for it was not compiled in */
 1387                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1388                 ,_("webp image format is not available, failing back to jpeg"));
 1389                 cnt->imgs.picture_type = IMAGE_TYPE_JPEG;
 1390         #endif /* HAVE_WEBP */
 1391     }
 1392     else
 1393         cnt->imgs.picture_type = IMAGE_TYPE_JPEG;
 1394 
 1395     /*
 1396      * Now is a good time to init rotation data. Since vid_start has been
 1397      * called, we know that we have imgs.width and imgs.height. When capturing
 1398      * from a V4L device, these are copied from the corresponding conf values
 1399      * in vid_start. When capturing from a netcam, they get set in netcam_start,
 1400      * which is called from vid_start.
 1401      *
 1402      * rotate_init will set cap_width and cap_height in cnt->rotate_data.
 1403      */
 1404     rotate_init(cnt); /* rotate_deinit is called in main */
 1405 
 1406     init_text_scale(cnt);   /*Initialize and validate the text_scale */
 1407 
 1408     /* Capture first image, or we will get an alarm on start */
 1409     if (cnt->video_dev >= 0) {
 1410         int i;
 1411 
 1412         for (i = 0; i < 5; i++) {
 1413             if (vid_next(cnt, &cnt->imgs.image_virgin) == 0)
 1414                 break;
 1415             SLEEP(2, 0);
 1416         }
 1417 
 1418         if (i >= 5) {
 1419             memset(cnt->imgs.image_virgin.image_norm, 0x80, cnt->imgs.size_norm);       /* initialize to grey */
 1420             draw_text(cnt->imgs.image_virgin.image_norm, cnt->imgs.width, cnt->imgs.height,
 1421                       10, 20, "Error capturing first image", cnt->text_scale);
 1422             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error capturing first image"));
 1423         }
 1424     }
 1425     cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in];
 1426 
 1427     /* create a reference frame */
 1428     alg_update_reference_frame(cnt, RESET_REF_FRAME);
 1429 
 1430     #if defined(HAVE_V4L2) && !defined(BSD)
 1431         /* open video loopback devices if enabled */
 1432         if (cnt->conf.video_pipe) {
 1433             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 1434                 ,_("Opening video loopback device for normal pictures"));
 1435 
 1436             /* vid_startpipe should get the output dimensions */
 1437             cnt->pipe = vlp_startpipe(cnt->conf.video_pipe, cnt->imgs.width, cnt->imgs.height);
 1438 
 1439             if (cnt->pipe < 0) {
 1440                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1441                     ,_("Failed to open video loopback for normal pictures"));
 1442                 return -1;
 1443             }
 1444         }
 1445 
 1446         if (cnt->conf.video_pipe_motion) {
 1447             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 1448                 ,_("Opening video loopback device for motion pictures"));
 1449 
 1450             /* vid_startpipe should get the output dimensions */
 1451             cnt->mpipe = vlp_startpipe(cnt->conf.video_pipe_motion, cnt->imgs.width, cnt->imgs.height);
 1452 
 1453             if (cnt->mpipe < 0) {
 1454                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1455                     ,_("Failed to open video loopback for motion pictures"));
 1456                 return -1;
 1457             }
 1458         }
 1459     #endif /* HAVE_V4L2 && !BSD */
 1460 
 1461     retcd = dbse_init(cnt);
 1462     if (retcd != 0) return retcd;
 1463 
 1464     /* Load the mask file if any */
 1465     if (cnt->conf.mask_file) {
 1466         if ((picture = myfopen(cnt->conf.mask_file, "r"))) {
 1467             /*
 1468              * NOTE: The mask is expected to have the output dimensions. I.e., the mask
 1469              * applies to the already rotated image, not the capture image. Thus, use
 1470              * width and height from imgs.
 1471              */
 1472             cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height);
 1473             myfclose(picture);
 1474         } else {
 1475             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
 1476                 ,_("Error opening mask file %s")
 1477                 ,cnt->conf.mask_file);
 1478             /*
 1479              * Try to write an empty mask file to make it easier
 1480              * for the user to edit it
 1481              */
 1482             put_fixed_mask(cnt, cnt->conf.mask_file);
 1483         }
 1484 
 1485         if (!cnt->imgs.mask) {
 1486             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 1487                 ,_("Failed to read mask image. Mask feature disabled."));
 1488         } else {
 1489             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO
 1490                 ,_("Maskfile \"%s\" loaded.")
 1491                 ,cnt->conf.mask_file);
 1492         }
 1493     } else {
 1494         cnt->imgs.mask = NULL;
 1495     }
 1496 
 1497     init_mask_privacy(cnt);
 1498 
 1499     /* Always initialize smart_mask - someone could turn it on later... */
 1500     memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);
 1501     memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);
 1502     memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer));
 1503 
 1504     /* Set noise level */
 1505     cnt->noise = cnt->conf.noise_level;
 1506 
 1507     /* Set threshold value */
 1508     cnt->threshold = cnt->conf.threshold;
 1509     if (cnt->conf.threshold_maximum > cnt->conf.threshold ){
 1510         cnt->threshold_maximum = cnt->conf.threshold_maximum;
 1511     } else {
 1512         cnt->threshold_maximum = (cnt->imgs.height * cnt->imgs.width * 3) / 2;
 1513     }
 1514 
 1515     if (cnt->conf.stream_preview_method == 99){
 1516         /* This is the depreciated Stop stream process */
 1517 
 1518         /* Initialize stream server if stream port is specified to not 0 */
 1519 
 1520         if (cnt->conf.stream_port) {
 1521             if (stream_init (&(cnt->stream), cnt->conf.stream_port, cnt->conf.stream_localhost,
 1522                 cnt->conf.webcontrol_ipv6, cnt->conf.stream_cors_header) == -1) {
 1523                 MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
 1524                     ,_("Problem enabling motion-stream server in port %d")
 1525                     ,cnt->conf.stream_port);
 1526                 cnt->conf.stream_port = 0;
 1527                 cnt->finish = 1;
 1528             } else {
 1529                 MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 1530                     ,_("Started motion-stream server on port %d (auth %s)")
 1531                     ,cnt->conf.stream_port
 1532                     ,cnt->conf.stream_auth_method ? _("Enabled"):_("Disabled"));
 1533             }
 1534         }
 1535 
 1536     } /* End of legacy stream methods*/
 1537 
 1538 
 1539     /* Prevent first few frames from triggering motion... */
 1540     cnt->moved = 8;
 1541 
 1542     /* Work out expected frame rate based on config setting */
 1543     if (cnt->conf.framerate < 2)
 1544         cnt->conf.framerate = 2;
 1545 
 1546     /* 2 sec startup delay so FPS is calculated correct */
 1547     cnt->startup_frames = (cnt->conf.framerate * 2) + cnt->conf.pre_capture + cnt->conf.minimum_motion_frames;
 1548 
 1549     cnt->required_frame_time = 1000000L / cnt->conf.framerate;
 1550 
 1551     cnt->frame_delay = cnt->required_frame_time;
 1552 
 1553     /*
 1554      * Reserve enough space for a 10 second timing history buffer. Note that,
 1555      * if there is any problem on the allocation, mymalloc does not return.
 1556      */
 1557     cnt->rolling_average_data = NULL;
 1558     cnt->rolling_average_limit = 10 * cnt->conf.framerate;
 1559     cnt->rolling_average_data = mymalloc(sizeof(cnt->rolling_average_data) * cnt->rolling_average_limit);
 1560 
 1561     /* Preset history buffer with expected frame rate */
 1562     for (indx = 0; indx < cnt->rolling_average_limit; indx++)
 1563         cnt->rolling_average_data[indx] = cnt->required_frame_time;
 1564 
 1565 
 1566     cnt->track_posx = 0;
 1567     cnt->track_posy = 0;
 1568     if (cnt->track.type)
 1569         cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0);
 1570 
 1571     /* Initialize area detection */
 1572     cnt->area_minx[0] = cnt->area_minx[3] = cnt->area_minx[6] = 0;
 1573     cnt->area_miny[0] = cnt->area_miny[1] = cnt->area_miny[2] = 0;
 1574 
 1575     cnt->area_minx[1] = cnt->area_minx[4] = cnt->area_minx[7] = cnt->imgs.width / 3;
 1576     cnt->area_maxx[0] = cnt->area_maxx[3] = cnt->area_maxx[6] = cnt->imgs.width / 3;
 1577 
 1578     cnt->area_minx[2] = cnt->area_minx[5] = cnt->area_minx[8] = cnt->imgs.width / 3 * 2;
 1579     cnt->area_maxx[1] = cnt->area_maxx[4] = cnt->area_maxx[7] = cnt->imgs.width / 3 * 2;
 1580 
 1581     cnt->area_miny[3] = cnt->area_miny[4] = cnt->area_miny[5] = cnt->imgs.height / 3;
 1582     cnt->area_maxy[0] = cnt->area_maxy[1] = cnt->area_maxy[2] = cnt->imgs.height / 3;
 1583 
 1584     cnt->area_miny[6] = cnt->area_miny[7] = cnt->area_miny[8] = cnt->imgs.height / 3 * 2;
 1585     cnt->area_maxy[3] = cnt->area_maxy[4] = cnt->area_maxy[5] = cnt->imgs.height / 3 * 2;
 1586 
 1587     cnt->area_maxx[2] = cnt->area_maxx[5] = cnt->area_maxx[8] = cnt->imgs.width;
 1588     cnt->area_maxy[6] = cnt->area_maxy[7] = cnt->area_maxy[8] = cnt->imgs.height;
 1589 
 1590     cnt->areadetect_eventnbr = 0;
 1591 
 1592     cnt->timenow = 0;
 1593     cnt->timebefore = 0;
 1594     cnt->rate_limit = 0;
 1595     cnt->lastframetime = 0;
 1596     cnt->minimum_frame_time_downcounter = cnt->conf.minimum_frame_time;
 1597     cnt->get_image = 1;
 1598 
 1599     cnt->olddiffs = 0;
 1600     cnt->smartmask_ratio = 0;
 1601     cnt->smartmask_count = 20;
 1602 
 1603     cnt->previous_diffs = 0;
 1604     cnt->previous_location_x = 0;
 1605     cnt->previous_location_y = 0;
 1606 
 1607     cnt->time_last_frame = 1;
 1608     cnt->time_current_frame = 0;
 1609 
 1610     cnt->smartmask_lastrate = 0;
 1611 
 1612     cnt->passflag = 0;  //only purpose to flag first frame
 1613     cnt->rolling_frame = 0;
 1614 
 1615     if (cnt->conf.emulate_motion) {
 1616         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Emulating motion"));
 1617     }
 1618 
 1619     return 0;
 1620 }
 1621 
 1622 /**
 1623  * motion_cleanup
 1624  *
 1625  * This routine is called from motion_loop when thread ends to
 1626  * cleanup all memory etc. that motion_init did.
 1627  *
 1628  * Parameters:
 1629  *
 1630  *      cnt     Pointer to the motion context structure
 1631  *
 1632  * Returns:     nothing
 1633  */
 1634 static void motion_cleanup(struct context *cnt) {
 1635 
 1636     if (cnt->conf.stream_preview_method == 99){
 1637         /* This is the depreciated Stop stream process */
 1638         if ((cnt->conf.stream_port) && (cnt->stream.socket != -1))
 1639             stream_stop(&cnt->stream);
 1640     }
 1641 
 1642     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, NULL);
 1643     event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, NULL);
 1644 
 1645     mot_stream_deinit(cnt);
 1646 
 1647     if (cnt->video_dev >= 0) {
 1648         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Calling vid_close() from motion_cleanup"));
 1649         vid_close(cnt);
 1650     }
 1651 
 1652     free(cnt->imgs.img_motion.image_norm);
 1653     cnt->imgs.img_motion.image_norm = NULL;
 1654 
 1655     free(cnt->imgs.ref);
 1656     cnt->imgs.ref = NULL;
 1657 
 1658     free(cnt->imgs.ref_dyn);
 1659     cnt->imgs.ref_dyn = NULL;
 1660 
 1661     free(cnt->imgs.image_virgin.image_norm);
 1662     cnt->imgs.image_virgin.image_norm = NULL;
 1663 
 1664     free(cnt->imgs.image_vprvcy.image_norm);
 1665     cnt->imgs.image_vprvcy.image_norm = NULL;
 1666 
 1667     free(cnt->imgs.labels);
 1668     cnt->imgs.labels = NULL;
 1669 
 1670     free(cnt->imgs.labelsize);
 1671     cnt->imgs.labelsize = NULL;
 1672 
 1673     free(cnt->imgs.smartmask);
 1674     cnt->imgs.smartmask = NULL;
 1675 
 1676     free(cnt->imgs.smartmask_final);
 1677     cnt->imgs.smartmask_final = NULL;
 1678 
 1679     free(cnt->imgs.smartmask_buffer);
 1680     cnt->imgs.smartmask_buffer = NULL;
 1681 
 1682     if (cnt->imgs.mask) free(cnt->imgs.mask);
 1683     cnt->imgs.mask = NULL;
 1684 
 1685     if (cnt->imgs.mask_privacy) free(cnt->imgs.mask_privacy);
 1686     cnt->imgs.mask_privacy = NULL;
 1687 
 1688     if (cnt->imgs.mask_privacy_uv) free(cnt->imgs.mask_privacy_uv);
 1689     cnt->imgs.mask_privacy_uv = NULL;
 1690 
 1691     if (cnt->imgs.mask_privacy_high) free(cnt->imgs.mask_privacy_high);
 1692     cnt->imgs.mask_privacy_high = NULL;
 1693 
 1694     if (cnt->imgs.mask_privacy_high_uv) free(cnt->imgs.mask_privacy_high_uv);
 1695     cnt->imgs.mask_privacy_high_uv = NULL;
 1696 
 1697     free(cnt->imgs.common_buffer);
 1698     cnt->imgs.common_buffer = NULL;
 1699 
 1700     free(cnt->imgs.preview_image.image_norm);
 1701     cnt->imgs.preview_image.image_norm = NULL;
 1702 
 1703     if (cnt->imgs.size_high > 0){
 1704         free(cnt->imgs.image_virgin.image_high);
 1705         cnt->imgs.image_virgin.image_high = NULL;
 1706 
 1707         free(cnt->imgs.preview_image.image_high);
 1708         cnt->imgs.preview_image.image_high = NULL;
 1709     }
 1710 
 1711     image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */
 1712 
 1713     rotate_deinit(cnt); /* cleanup image rotation data */
 1714 
 1715     if (cnt->pipe != -1) {
 1716         close(cnt->pipe);
 1717         cnt->pipe = -1;
 1718     }
 1719 
 1720     if (cnt->mpipe != -1) {
 1721         close(cnt->mpipe);
 1722         cnt->mpipe = -1;
 1723     }
 1724 
 1725     if (cnt->rolling_average_data != NULL) free(cnt->rolling_average_data);
 1726 
 1727 
 1728     /* Cleanup the current time structure */
 1729     free(cnt->currenttime_tm);
 1730     cnt->currenttime_tm = NULL;
 1731 
 1732     /* Cleanup the event time structure */
 1733     free(cnt->eventtime_tm);
 1734     cnt->eventtime_tm = NULL;
 1735 
 1736     dbse_deinit(cnt);
 1737 
 1738     if (cnt->netcam_decoder){
 1739         free(cnt->netcam_decoder);
 1740         cnt->netcam_decoder = NULL;
 1741     }
 1742 
 1743 }
 1744 
 1745 static void mlp_mask_privacy(struct context *cnt){
 1746 
 1747     if (cnt->imgs.mask_privacy == NULL) return;
 1748 
 1749     /*
 1750     * This function uses long operations to process 4 (32 bit) or 8 (64 bit)
 1751     * bytes at a time, providing a significant boost in performance.
 1752     * Then a trailer loop takes care of any remaining bytes.
 1753     */
 1754     unsigned char *image;
 1755     const unsigned char *mask;
 1756     const unsigned char *maskuv;
 1757 
 1758     int index_y;
 1759     int index_crcb;
 1760     int increment;
 1761     int indx_img;                /* Counter for how many images we need to apply the mask to */
 1762     int indx_max;                /* 1 if we are only doing norm, 2 if we are doing both norm and high */
 1763 
 1764     indx_img = 1;
 1765     indx_max = 1;
 1766     if (cnt->imgs.size_high > 0) indx_max = 2;
 1767     increment = sizeof(unsigned long);
 1768 
 1769     while (indx_img <= indx_max){
 1770         if (indx_img == 1) {
 1771             /* Normal Resolution */
 1772             index_y = cnt->imgs.height * cnt->imgs.width;
 1773             image = cnt->current_image->image_norm;
 1774             mask = cnt->imgs.mask_privacy;
 1775             index_crcb = cnt->imgs.size_norm - index_y;
 1776             maskuv = cnt->imgs.mask_privacy_uv;
 1777         } else {
 1778             /* High Resolution */
 1779             index_y = cnt->imgs.height_high * cnt->imgs.width_high;
 1780             image = cnt->current_image->image_high;
 1781             mask = cnt->imgs.mask_privacy_high;
 1782             index_crcb = cnt->imgs.size_high - index_y;
 1783             maskuv = cnt->imgs.mask_privacy_high_uv;
 1784         }
 1785 
 1786         while (index_y >= increment) {
 1787             *((unsigned long *)image) &= *((unsigned long *)mask);
 1788             image += increment;
 1789             mask += increment;
 1790             index_y -= increment;
 1791         }
 1792         while (--index_y >= 0) {
 1793             *(image++) &= *(mask++);
 1794         }
 1795 
 1796         /* Mask chrominance. */
 1797         while (index_crcb >= increment) {
 1798             index_crcb -= increment;
 1799             /*
 1800             * Replace the masked bytes with 0x080. This is done using two masks:
 1801             * the normal privacy mask is used to clear the masked bits, the
 1802             * "or" privacy mask is used to write 0x80. The benefit of that method
 1803             * is that we process 4 or 8 bytes in just two operations.
 1804             */
 1805             *((unsigned long *)image) &= *((unsigned long *)mask);
 1806             mask += increment;
 1807             *((unsigned long *)image) |= *((unsigned long *)maskuv);
 1808             maskuv += increment;
 1809             image += increment;
 1810         }
 1811 
 1812         while (--index_crcb >= 0) {
 1813             if (*(mask++) == 0x00) *image = 0x80; // Mask last remaining bytes.
 1814             image += 1;
 1815         }
 1816 
 1817         indx_img++;
 1818     }
 1819 }
 1820 
 1821 static void mlp_areadetect(struct context *cnt){
 1822     int i, j, z = 0;
 1823     /*
 1824      * Simple hack to recognize motion in a specific area
 1825      * Do we need a new coversion specifier as well??
 1826      */
 1827     if ((cnt->conf.area_detect) &&
 1828         (cnt->event_nr != cnt->areadetect_eventnbr) &&
 1829         (cnt->current_image->flags & IMAGE_TRIGGER)) {
 1830         j = strlen(cnt->conf.area_detect);
 1831         for (i = 0; i < j; i++) {
 1832             z = cnt->conf.area_detect[i] - 49; /* characters are stored as ascii 48-57 (0-9) */
 1833             if ((z >= 0) && (z < 9)) {
 1834                 if (cnt->current_image->location.x > cnt->area_minx[z] &&
 1835                     cnt->current_image->location.x < cnt->area_maxx[z] &&
 1836                     cnt->current_image->location.y > cnt->area_miny[z] &&
 1837                     cnt->current_image->location.y < cnt->area_maxy[z]) {
 1838                     event(cnt, EVENT_AREA_DETECTED, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 1839                     cnt->areadetect_eventnbr = cnt->event_nr; /* Fire script only once per event */
 1840                     MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO
 1841                         ,_("Motion in area %d detected."), z + 1);
 1842                     break;
 1843                 }
 1844             }
 1845         }
 1846     }
 1847 
 1848 }
 1849 
 1850 static void mlp_prepare(struct context *cnt){
 1851 
 1852     int frame_buffer_size;
 1853     struct timeval tv1;
 1854 
 1855     /***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/
 1856     cnt->watchdog = WATCHDOG_TMO;
 1857 
 1858     /* Get current time and preserver last time for frame interval calc. */
 1859 
 1860     /* This may be better at the end of the loop or moving the part in
 1861      * the end doing elapsed time calc in here
 1862      */
 1863     cnt->timebefore = cnt->timenow;
 1864     gettimeofday(&tv1, NULL);
 1865     cnt->timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;
 1866 
 1867     /*
 1868      * Calculate detection rate limit. Above 5fps we limit the detection
 1869      * rate to 3fps to reduce load at higher framerates.
 1870      */
 1871     cnt->process_thisframe = 0;
 1872     cnt->rate_limit++;
 1873     if (cnt->rate_limit >= (cnt->lastrate / 3)) {
 1874         cnt->rate_limit = 0;
 1875         cnt->process_thisframe = 1;
 1876     }
 1877 
 1878     /*
 1879      * Since we don't have sanity checks done when options are set,
 1880      * this sanity check must go in the main loop :(, before pre_captures
 1881      * are attempted.
 1882      */
 1883     if (cnt->conf.minimum_motion_frames < 1)
 1884         cnt->conf.minimum_motion_frames = 1;
 1885 
 1886     if (cnt->conf.pre_capture < 0)
 1887         cnt->conf.pre_capture = 0;
 1888 
 1889     /*
 1890      * Check if our buffer is still the right size
 1891      * If pre_capture or minimum_motion_frames has been changed
 1892      * via the http remote control we need to re-size the ring buffer
 1893      */
 1894     frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames;
 1895 
 1896     if (cnt->imgs.image_ring_size != frame_buffer_size)
 1897         image_ring_resize(cnt, frame_buffer_size);
 1898 
 1899     /* Get time for current frame */
 1900     cnt->currenttime = time(NULL);
 1901 
 1902     /*
 1903      * localtime returns static data and is not threadsafe
 1904      * so we use localtime_r which is reentrant and threadsafe
 1905      */
 1906     localtime_r(&cnt->currenttime, cnt->currenttime_tm);
 1907 
 1908     /*
 1909      * If we have started on a new second we reset the shots variable
 1910      * lastrate is updated to be the number of the last frame. last rate
 1911      * is used as the ffmpeg framerate when motion is detected.
 1912      */
 1913     if (cnt->lastframetime != cnt->currenttime) {
 1914         cnt->lastrate = cnt->shots + 1;
 1915         cnt->shots = -1;
 1916         cnt->lastframetime = cnt->currenttime;
 1917 
 1918         if (cnt->conf.minimum_frame_time) {
 1919             cnt->minimum_frame_time_downcounter--;
 1920             if (cnt->minimum_frame_time_downcounter == 0)
 1921                 cnt->get_image = 1;
 1922         } else {
 1923             cnt->get_image = 1;
 1924         }
 1925     }
 1926 
 1927 
 1928     /* Increase the shots variable for each frame captured within this second */
 1929     cnt->shots++;
 1930 
 1931     if (cnt->startup_frames > 0)
 1932         cnt->startup_frames--;
 1933 
 1934 
 1935 }
 1936 
 1937 static void mlp_resetimages(struct context *cnt){
 1938 
 1939     struct image_data *old_image;
 1940 
 1941     if (cnt->conf.minimum_frame_time) {
 1942         cnt->minimum_frame_time_downcounter = cnt->conf.minimum_frame_time;
 1943         cnt->get_image = 0;
 1944     }
 1945 
 1946     /* ring_buffer_in is pointing to current pos, update before put in a new image */
 1947     if (++cnt->imgs.image_ring_in >= cnt->imgs.image_ring_size)
 1948         cnt->imgs.image_ring_in = 0;
 1949 
 1950     /* Check if we have filled the ring buffer, throw away last image */
 1951     if (cnt->imgs.image_ring_in == cnt->imgs.image_ring_out) {
 1952         if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size)
 1953             cnt->imgs.image_ring_out = 0;
 1954     }
 1955 
 1956     /* cnt->current_image points to position in ring where to store image, diffs etc. */
 1957     old_image = cnt->current_image;
 1958     cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in];
 1959 
 1960     /* Init/clear current_image */
 1961     if (cnt->process_thisframe) {
 1962         /* set diffs to 0 now, will be written after we calculated diffs in new image */
 1963         cnt->current_image->diffs = 0;
 1964 
 1965         /* Set flags to 0 */
 1966         cnt->current_image->flags = 0;
 1967         cnt->current_image->cent_dist = 0;
 1968 
 1969         /* Clear location data */
 1970         memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location));
 1971         cnt->current_image->total_labels = 0;
 1972     } else if (cnt->current_image && old_image) {
 1973         /* not processing this frame: save some important values for next image */
 1974         cnt->current_image->diffs = old_image->diffs;
 1975         cnt->current_image->timestamp_tv = old_image->timestamp_tv;
 1976         cnt->current_image->shot = old_image->shot;
 1977         cnt->current_image->cent_dist = old_image->cent_dist;
 1978         cnt->current_image->flags = old_image->flags & (~IMAGE_SAVED);
 1979         cnt->current_image->location = old_image->location;
 1980         cnt->current_image->total_labels = old_image->total_labels;
 1981     }
 1982 
 1983     /* Store time with pre_captured image */
 1984     gettimeofday(&cnt->current_image->timestamp_tv, NULL);
 1985 
 1986     /* Store shot number with pre_captured image */
 1987     cnt->current_image->shot = cnt->shots;
 1988 
 1989 }
 1990 
 1991 static int mlp_retry(struct context *cnt){
 1992 
 1993     /*
 1994      * If a camera is not available we keep on retrying every 10 seconds
 1995      * until it shows up.
 1996      */
 1997     int size_high;
 1998 
 1999     if (cnt->video_dev < 0 &&
 2000         cnt->currenttime % 10 == 0 && cnt->shots == 0) {
 2001         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 2002             ,_("Retrying until successful connection with camera"));
 2003         cnt->video_dev = vid_start(cnt);
 2004 
 2005         if (cnt->video_dev < 0) {
 2006             return 1;
 2007         }
 2008 
 2009         if ((cnt->imgs.width % 8) || (cnt->imgs.height % 8)) {
 2010             MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 2011                 ,_("Image width (%d) or height(%d) requested is not modulo 8.")
 2012                 ,cnt->imgs.width, cnt->imgs.height);
 2013             return 1;
 2014         }
 2015 
 2016         if ((cnt->imgs.width  < 64) || (cnt->imgs.height < 64)){
 2017             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 2018                 ,_("Motion only supports width and height greater than or equal to 64 %dx%d")
 2019                 ,cnt->imgs.width, cnt->imgs.height);
 2020                 return 1;
 2021         }
 2022 
 2023         /*
 2024          * If the netcam has different dimensions than in the config file
 2025          * we need to restart Motion to re-allocate all the buffers
 2026          */
 2027         if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) {
 2028             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Camera has finally become available\n"
 2029                        "Camera image has different width and height"
 2030                        "from what is in the config file. You should fix that\n"
 2031                        "Restarting Motion thread to reinitialize all "
 2032                        "image buffers to new picture dimensions"));
 2033             cnt->conf.width = cnt->imgs.width;
 2034             cnt->conf.height = cnt->imgs.height;
 2035             /*
 2036              * Break out of main loop terminating thread
 2037              * watchdog will start us again
 2038              */
 2039             return 1;
 2040         }
 2041         /*
 2042          * For high res, we check the size of buffer to determine whether to break out
 2043          * the init_motion function allocated the buffer for high using the cnt->imgs.size_high
 2044          * and the vid_start ONLY re-populates the height/width so we can check the size here.
 2045          */
 2046         size_high = (cnt->imgs.width_high * cnt->imgs.height_high * 3) / 2;
 2047         if (cnt->imgs.size_high != size_high) return 1;
 2048     }
 2049     return 0;
 2050 }
 2051 
 2052 static int mlp_capture(struct context *cnt){
 2053 
 2054     const char *tmpin;
 2055     char tmpout[80];
 2056     int vid_return_code = 0;        /* Return code used when calling vid_next */
 2057     struct timeval tv1;
 2058 
 2059     /***** MOTION LOOP - IMAGE CAPTURE SECTION *****/
 2060     /*
 2061      * Fetch next frame from camera
 2062      * If vid_next returns 0 all is well and we got a new picture
 2063      * Any non zero value is an error.
 2064      * 0 = OK, valid picture
 2065      * <0 = fatal error - leave the thread by breaking out of the main loop
 2066      * >0 = non fatal error - copy last image or show grey image with message
 2067      */
 2068     if (cnt->video_dev >= 0)
 2069         vid_return_code = vid_next(cnt, cnt->current_image);
 2070     else
 2071         vid_return_code = 1; /* Non fatal error */
 2072 
 2073     // VALID PICTURE
 2074     if (vid_return_code == 0) {
 2075         cnt->lost_connection = 0;
 2076         cnt->connectionlosttime = 0;
 2077 
 2078         /* If all is well reset missing_frame_counter */
 2079         if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.framerate) {
 2080             /* If we previously logged starting a grey image, now log video re-start */
 2081             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Video signal re-acquired"));
 2082             // event for re-acquired video signal can be called here
 2083             event(cnt, EVENT_CAMERA_FOUND, NULL, NULL, NULL, NULL);
 2084         }
 2085         cnt->missing_frame_counter = 0;
 2086 
 2087         /*
 2088          * Save the newly captured still virgin image to a buffer
 2089          * which we will not alter with text and location graphics
 2090          */
 2091         memcpy(cnt->imgs.image_virgin.image_norm, cnt->current_image->image_norm, cnt->imgs.size_norm);
 2092 
 2093         mlp_mask_privacy(cnt);
 2094 
 2095         memcpy(cnt->imgs.image_vprvcy.image_norm, cnt->current_image->image_norm, cnt->imgs.size_norm);
 2096 
 2097         /*
 2098          * If the camera is a netcam we let the camera decide the pace.
 2099          * Otherwise we will keep on adding duplicate frames.
 2100          * By resetting the timer the framerate becomes maximum the rate
 2101          * of the Netcam.
 2102          */
 2103         if (cnt->conf.netcam_url) {
 2104             gettimeofday(&tv1, NULL);
 2105             cnt->timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;
 2106         }
 2107     // FATAL ERROR - leave the thread by breaking out of the main loop
 2108     } else if (vid_return_code < 0) {
 2109         /* Fatal error - Close video device */
 2110         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 2111             ,_("Video device fatal error - Closing video device"));
 2112         vid_close(cnt);
 2113         /*
 2114          * Use virgin image, if we are not able to open it again next loop
 2115          * a gray image with message is applied
 2116          * flag lost_connection
 2117          */
 2118         memcpy(cnt->current_image->image_norm, cnt->imgs.image_virgin.image_norm, cnt->imgs.size_norm);
 2119         cnt->lost_connection = 1;
 2120     /* NO FATAL ERROR -
 2121     *        copy last image or show grey image with message
 2122     *        flag on lost_connection if :
 2123     *               vid_return_code == NETCAM_RESTART_ERROR
 2124     *        cnt->video_dev < 0
 2125     *        cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.framerate)
 2126     */
 2127     } else {
 2128 
 2129         //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "vid_return_code %d",vid_return_code);
 2130 
 2131         /*
 2132          * Netcams that change dimensions while Motion is running will
 2133          * require that Motion restarts to reinitialize all the many
 2134          * buffers inside Motion. It will be a mess to try and recover any
 2135          * other way
 2136          */
 2137         if (vid_return_code == NETCAM_RESTART_ERROR) {
 2138             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 2139                 ,_("Restarting Motion thread to reinitialize all "
 2140                 "image buffers"));
 2141             /*
 2142              * Break out of main loop terminating thread
 2143              * watchdog will start us again
 2144              * Set lost_connection flag on
 2145              */
 2146             cnt->lost_connection = 1;
 2147             return 1;
 2148         }
 2149 
 2150         /*
 2151          * First missed frame - store timestamp
 2152          * Don't reset time when thread restarts
 2153          */
 2154         if (cnt->connectionlosttime == 0){
 2155             cnt->connectionlosttime = cnt->currenttime;
 2156         }
 2157 
 2158 
 2159         /*
 2160          * Increase missing_frame_counter
 2161          * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image
 2162          * After MISSING_FRAMES_TIMEOUT seconds we put a grey error image in the buffer
 2163          * If we still have not yet received the initial image from a camera
 2164          * we go straight for the grey error image.
 2165          */
 2166         ++cnt->missing_frame_counter;
 2167 
 2168         if (cnt->video_dev >= 0 &&
 2169             cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.framerate)) {
 2170             memcpy(cnt->current_image->image_norm, cnt->imgs.image_vprvcy.image_norm, cnt->imgs.size_norm);
 2171         } else {
 2172             cnt->lost_connection = 1;
 2173 
 2174             if (cnt->video_dev >= 0)
 2175                 tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T";
 2176             else
 2177                 tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T";
 2178 
 2179             tv1.tv_sec=cnt->connectionlosttime;
 2180             tv1.tv_usec = 0;
 2181             memset(cnt->current_image->image_norm, 0x80, cnt->imgs.size_norm);
 2182             mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tv1, NULL, 0);
 2183             draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
 2184                       10, 20 * cnt->text_scale, tmpout, cnt->text_scale);
 2185 
 2186             /* Write error message only once */
 2187             if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.framerate) {
 2188                 MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 2189                     ,_("Video signal lost - Adding grey image"));
 2190                 // Event for lost video signal can be called from here
 2191                 event(cnt, EVENT_CAMERA_LOST, NULL, NULL, NULL, &tv1);
 2192             }
 2193 
 2194             /*
 2195              * If we don't get a valid frame for a long time, try to close/reopen device
 2196              * Only try this when a device is open
 2197              */
 2198             if ((cnt->video_dev > 0) &&
 2199                 (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.framerate)) {
 2200                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 2201                     ,_("Video signal still lost - "
 2202                     "Trying to close video device"));
 2203                 vid_close(cnt);
 2204             }
 2205         }
 2206     }
 2207     return 0;
 2208 
 2209 }
 2210 
 2211 static void mlp_detection(struct context *cnt){
 2212 
 2213 
 2214     /***** MOTION LOOP - MOTION DETECTION SECTION *****/
 2215     /*
 2216      * The actual motion detection takes place in the following
 2217      * diffs is the number of pixels detected as changed
 2218      * Make a differences picture in image_out
 2219      *
 2220      * alg_diff_standard is the slower full feature motion detection algorithm
 2221      * alg_diff first calls a fast detection algorithm which only looks at a
 2222      * fraction of the pixels. If this detects possible motion alg_diff_standard
 2223      * is called.
 2224      */
 2225     if (cnt->process_thisframe) {
 2226         if (cnt->threshold && !cnt->pause) {
 2227             /*
 2228              * If we've already detected motion and we want to see if there's
 2229              * still motion, don't bother trying the fast one first. IF there's
 2230              * motion, the alg_diff will trigger alg_diff_standard
 2231              * anyway
 2232              */
 2233             if (cnt->detecting_motion || cnt->conf.setup_mode)
 2234                 cnt->current_image->diffs = alg_diff_standard(cnt, cnt->imgs.image_vprvcy.image_norm);
 2235             else
 2236                 cnt->current_image->diffs = alg_diff(cnt, cnt->imgs.image_vprvcy.image_norm);
 2237 
 2238             /* Lightswitch feature - has light intensity changed?
 2239              * This can happen due to change of light conditions or due to a sudden change of the camera
 2240              * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next
 2241              * 'lightswitch_frames' frames to allow the camera to settle.
 2242              * Don't check if we have lost connection, we detect "Lost signal" frame as lightswitch
 2243              */
 2244             if (cnt->conf.lightswitch_percent > 1 && !cnt->lost_connection) {
 2245                 if (alg_lightswitch(cnt, cnt->current_image->diffs)) {
 2246                     MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Lightswitch detected"));
 2247 
 2248                     if (cnt->conf.lightswitch_frames < 1)
 2249                         cnt->conf.lightswitch_frames = 1;
 2250                     else if (cnt->conf.lightswitch_frames > 1000)
 2251                         cnt->conf.lightswitch_frames = 1000;
 2252 
 2253                     if (cnt->moved < (unsigned int)cnt->conf.lightswitch_frames)
 2254                         cnt->moved = (unsigned int)cnt->conf.lightswitch_frames;
 2255 
 2256                     cnt->current_image->diffs = 0;
 2257                     alg_update_reference_frame(cnt, RESET_REF_FRAME);
 2258                 }
 2259             }
 2260 
 2261             /*
 2262              * Switchfilter feature tries to detect a change in the video signal
 2263              * from one camera to the next. This is normally used in the Round
 2264              * Robin feature. The algorithm is not very safe.
 2265              * The algorithm takes a little time so we only call it when needed
 2266              * ie. when feature is enabled and diffs>threshold.
 2267              * We do not suspend motion detection like we did for lightswitch
 2268              * because with Round Robin this is controlled by roundrobin_skip.
 2269              */
 2270             if (cnt->conf.roundrobin_switchfilter && cnt->current_image->diffs > cnt->threshold) {
 2271                 cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs,
 2272                                                              cnt->current_image->image_norm);
 2273 
 2274                 if ((cnt->current_image->diffs <= cnt->threshold) ||
 2275                     (cnt->current_image->diffs > cnt->threshold_maximum)) {
 2276 
 2277                     cnt->current_image->diffs = 0;
 2278                     MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Switchfilter detected"));
 2279                 }
 2280             }
 2281 
 2282             /*
 2283              * Despeckle feature
 2284              * First we run (as given by the despeckle_filter option iterations
 2285              * of erode and dilate algorithms.
 2286              * Finally we run the labelling feature.
 2287              * All this is done in the alg_despeckle code.
 2288              */
 2289             cnt->current_image->total_labels = 0;
 2290             cnt->imgs.largest_label = 0;
 2291             cnt->olddiffs = 0;
 2292 
 2293             if (cnt->conf.despeckle_filter && cnt->current_image->diffs > 0) {
 2294                 cnt->olddiffs = cnt->current_image->diffs;
 2295                 cnt->current_image->diffs = alg_despeckle(cnt, cnt->olddiffs);
 2296             } else if (cnt->imgs.labelsize_max) {
 2297                 cnt->imgs.labelsize_max = 0; /* Disable labeling if enabled */
 2298             }
 2299 
 2300         } else if (!cnt->conf.setup_mode) {
 2301             cnt->current_image->diffs = 0;
 2302         }
 2303     }
 2304 
 2305     //TODO:  This section needs investigation for purpose, cause and effect
 2306     /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */
 2307     if ((cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) &&
 2308         (!--cnt->smartmask_count)) {
 2309         alg_tune_smartmask(cnt);
 2310         cnt->smartmask_count = cnt->smartmask_ratio;
 2311     }
 2312 
 2313     /*
 2314      * cnt->moved is set by the tracking code when camera has been asked to move.
 2315      * When camera is moving we do not want motion to detect motion or we will
 2316      * get our camera chasing itself like crazy and we will get motion detected
 2317      * which is not really motion. So we pretend there is no motion by setting
 2318      * cnt->diffs = 0.
 2319      * We also pretend to have a moving camera when we start Motion and when light
 2320      * switch has been detected to allow camera to settle.
 2321      */
 2322     if (cnt->moved) {
 2323         cnt->moved--;
 2324         cnt->current_image->diffs = 0;
 2325     }
 2326 
 2327 }
 2328 
 2329 static void mlp_tuning(struct context *cnt){
 2330 
 2331     /***** MOTION LOOP - TUNING SECTION *****/
 2332 
 2333     /*
 2334      * If noise tuning was selected, do it now. but only when
 2335      * no frames have been recorded and only once per second
 2336      */
 2337     if ((cnt->conf.noise_tune && cnt->shots == 0) &&
 2338          (!cnt->detecting_motion && (cnt->current_image->diffs <= cnt->threshold)))
 2339         alg_noise_tune(cnt, cnt->imgs.image_vprvcy.image_norm);
 2340 
 2341 
 2342     /*
 2343      * If we are not noise tuning lets make sure that remote controlled
 2344      * changes of noise_level are used.
 2345      */
 2346     if (cnt->process_thisframe) {
 2347         /*
 2348          * threshold tuning if enabled
 2349          * if we are not threshold tuning lets make sure that remote controlled
 2350          * changes of threshold are used.
 2351          */
 2352         if (cnt->conf.threshold_tune){
 2353             alg_threshold_tune(cnt, cnt->current_image->diffs, cnt->detecting_motion);
 2354         }
 2355 
 2356         /*
 2357          * If motion is detected (cnt->current_image->diffs > cnt->threshold) and before we add text to the pictures
 2358          * we find the center and size coordinates of the motion to be used for text overlays and later
 2359          * for adding the locate rectangle
 2360          */
 2361         if ((cnt->current_image->diffs > cnt->threshold) &&
 2362             (cnt->current_image->diffs < cnt->threshold_maximum)){
 2363 
 2364             alg_locate_center_size(&cnt->imgs
 2365                 , cnt->imgs.width
 2366                 , cnt->imgs.height
 2367                 , &cnt->current_image->location);
 2368             }
 2369 
 2370         /*
 2371          * Update reference frame.
 2372          * micro-lighswitch: trying to auto-detect lightswitch events.
 2373          * frontdoor illumination. Updates are rate-limited to 3 per second at
 2374          * framerates above 5fps to save CPU resources and to keep sensitivity
 2375          * at a constant level.
 2376          */
 2377 
 2378         if ((cnt->current_image->diffs > cnt->threshold) &&
 2379             (cnt->current_image->diffs < cnt->threshold_maximum) &&
 2380             (cnt->conf.lightswitch_percent >= 1) &&
 2381             (cnt->lightswitch_framecounter < (cnt->lastrate * 2)) && /* two seconds window only */
 2382             /* number of changed pixels almost the same in two consecutive frames and */
 2383             ((abs(cnt->previous_diffs - cnt->current_image->diffs)) < (cnt->previous_diffs / 15)) &&
 2384             /* center of motion in about the same place ? */
 2385             ((abs(cnt->current_image->location.x - cnt->previous_location_x)) <= (cnt->imgs.width / 150)) &&
 2386             ((abs(cnt->current_image->location.y - cnt->previous_location_y)) <= (cnt->imgs.height / 150))) {
 2387             alg_update_reference_frame(cnt, RESET_REF_FRAME);
 2388             cnt->current_image->diffs = 0;
 2389             cnt->lightswitch_framecounter = 0;
 2390 
 2391             MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("micro-lightswitch!"));
 2392         } else {
 2393             alg_update_reference_frame(cnt, UPDATE_REF_FRAME);
 2394         }
 2395         cnt->previous_diffs = cnt->current_image->diffs;
 2396         cnt->previous_location_x = cnt->current_image->location.x;
 2397         cnt->previous_location_y = cnt->current_image->location.y;
 2398     }
 2399 
 2400 
 2401 }
 2402 
 2403 static void mlp_overlay(struct context *cnt){
 2404 
 2405     char tmp[PATH_MAX];
 2406 
 2407     /***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/
 2408     /*
 2409      * Some overlays on top of the motion image
 2410      * Note that these now modifies the cnt->imgs.out so this buffer
 2411      * can no longer be used for motion detection features until next
 2412      * picture frame is captured.
 2413      */
 2414 
 2415     /* Smartmask overlay */
 2416     if (cnt->smartmask_speed &&
 2417         (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
 2418          cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
 2419         overlay_smartmask(cnt, cnt->imgs.img_motion.image_norm);
 2420 
 2421     /* Largest labels overlay */
 2422     if (cnt->imgs.largest_label && (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
 2423         cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
 2424         overlay_largest_label(cnt, cnt->imgs.img_motion.image_norm);
 2425 
 2426     /* Fixed mask overlay */
 2427     if (cnt->imgs.mask && (cnt->conf.picture_output_motion || cnt->conf.movie_output_motion ||
 2428         cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)))
 2429         overlay_fixed_mask(cnt, cnt->imgs.img_motion.image_norm);
 2430 
 2431     /* Add changed pixels in upper right corner of the pictures */
 2432     if (cnt->conf.text_changes) {
 2433         if (!cnt->pause)
 2434             sprintf(tmp, "%d", cnt->current_image->diffs);
 2435         else
 2436             sprintf(tmp, "-");
 2437 
 2438         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
 2439                   cnt->imgs.width - 10, 10, tmp, cnt->text_scale);
 2440     }
 2441 
 2442     /*
 2443      * Add changed pixels to motion-images (for stream) in setup_mode
 2444      * and always overlay smartmask (not only when motion is detected)
 2445      */
 2446     if (cnt->conf.setup_mode || (cnt->stream_motion.cnct_count > 0)) {
 2447         sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs,
 2448                 cnt->current_image->total_labels, cnt->noise);
 2449         draw_text(cnt->imgs.img_motion.image_norm, cnt->imgs.width, cnt->imgs.height,
 2450                   cnt->imgs.width - 10, cnt->imgs.height - (30 * cnt->text_scale),
 2451                   tmp, cnt->text_scale);
 2452         sprintf(tmp, "THREAD %d SETUP", cnt->threadnr);
 2453         draw_text(cnt->imgs.img_motion.image_norm, cnt->imgs.width, cnt->imgs.height,
 2454                   cnt->imgs.width - 10, cnt->imgs.height - (10 * cnt->text_scale),
 2455                   tmp, cnt->text_scale);
 2456     }
 2457 
 2458     /* Add text in lower left corner of the pictures */
 2459     if (cnt->conf.text_left) {
 2460         mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left,
 2461                    &cnt->current_image->timestamp_tv, NULL, 0);
 2462         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
 2463                   10, cnt->imgs.height - (10 * cnt->text_scale), tmp, cnt->text_scale);
 2464     }
 2465 
 2466     /* Add text in lower right corner of the pictures */
 2467     if (cnt->conf.text_right) {
 2468         mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right,
 2469                    &cnt->current_image->timestamp_tv, NULL, 0);
 2470         draw_text(cnt->current_image->image_norm, cnt->imgs.width, cnt->imgs.height,
 2471                   cnt->imgs.width - 10, cnt->imgs.height - (10 * cnt->text_scale),
 2472                   tmp, cnt->text_scale);
 2473     }
 2474 
 2475 }
 2476 
 2477 static void mlp_actions(struct context *cnt){
 2478 
 2479     int indx;
 2480 
 2481     /***** MOTION LOOP - ACTIONS AND EVENT CONTROL SECTION *****/
 2482 
 2483     if ((cnt->current_image->diffs > cnt->threshold) &&
 2484         (cnt->current_image->diffs < cnt->threshold_maximum)) {
 2485         /* flag this image, it have motion */
 2486         cnt->current_image->flags |= IMAGE_MOTION;
 2487         cnt->lightswitch_framecounter++; /* micro lightswitch */
 2488     } else {
 2489         cnt->lightswitch_framecounter = 0;
 2490     }
 2491 
 2492     /*
 2493      * If motion has been detected we take action and start saving
 2494      * pictures and movies etc by calling motion_detected().
 2495      * Is emulate_motion enabled we always call motion_detected()
 2496      * If post_capture is enabled we also take care of this in the this
 2497      * code section.
 2498      */
 2499     if ((cnt->conf.emulate_motion || cnt->event_user) && (cnt->startup_frames == 0)) {
 2500         /*  If we were previously detecting motion, started a movie, then got
 2501          *  no motion then we reset the start movie time so that we do not
 2502          *  get a pause in the movie.
 2503         */
 2504         if ( (cnt->detecting_motion == 0) && (cnt->ffmpeg_output != NULL) )
 2505             ffmpeg_reset_movie_start_time(cnt->ffmpeg_output, &cnt->current_image->timestamp_tv);
 2506         cnt->detecting_motion = 1;
 2507         if (cnt->conf.post_capture > 0) {
 2508             /* Setup the postcap counter */
 2509             cnt->postcap = cnt->conf.post_capture;
 2510             // MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "(Em) Init post capture %d", cnt->postcap);
 2511         }
 2512 
 2513         cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE);
 2514         /* Mark all images in image_ring to be saved */
 2515         for (indx = 0; indx < cnt->imgs.image_ring_size; indx++){
 2516             cnt->imgs.image_ring[indx].flags |= IMAGE_SAVE;
 2517         }
 2518 
 2519         motion_detected(cnt, cnt->video_dev, cnt->current_image);
 2520     } else if ((cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0)) {
 2521         /*
 2522          * Did we detect motion (like the cat just walked in :) )?
 2523          * If so, ensure the motion is sustained if minimum_motion_frames
 2524          */
 2525 
 2526         /* Count how many frames with motion there is in the last minimum_motion_frames in precap buffer */
 2527         int frame_count = 0;
 2528         int pos = cnt->imgs.image_ring_in;
 2529 
 2530         for (indx = 0; indx < cnt->conf.minimum_motion_frames; indx++) {
 2531             if (cnt->imgs.image_ring[pos].flags & IMAGE_MOTION)
 2532                 frame_count++;
 2533 
 2534             if (pos == 0)
 2535                 pos = cnt->imgs.image_ring_size-1;
 2536             else
 2537                 pos--;
 2538         }
 2539 
 2540         if (frame_count >= cnt->conf.minimum_motion_frames) {
 2541 
 2542             cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE);
 2543             /*  If we were previously detecting motion, started a movie, then got
 2544              *  no motion then we reset the start movie time so that we do not
 2545              *  get a pause in the movie.
 2546             */
 2547             if ( (cnt->detecting_motion == 0) && (cnt->ffmpeg_output != NULL) )
 2548                 ffmpeg_reset_movie_start_time(cnt->ffmpeg_output, &cnt->current_image->timestamp_tv);
 2549 
 2550             cnt->detecting_motion = 1;
 2551 
 2552             /* Setup the postcap counter */
 2553             cnt->postcap = cnt->conf.post_capture;
 2554             //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "Setup post capture %d", cnt->postcap);
 2555 
 2556             /* Mark all images in image_ring to be saved */
 2557             for (indx = 0; indx < cnt->imgs.image_ring_size; indx++)
 2558                 cnt->imgs.image_ring[indx].flags |= IMAGE_SAVE;
 2559 
 2560         } else if (cnt->postcap > 0) {
 2561            /* we have motion in this frame, but not enought frames for trigger. Check postcap */
 2562             cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE);
 2563             cnt->postcap--;
 2564             //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "post capture %d", cnt->postcap);
 2565         } else {
 2566             cnt->current_image->flags |= IMAGE_PRECAP;
 2567         }
 2568 
 2569         /* Always call motion_detected when we have a motion image */
 2570         motion_detected(cnt, cnt->video_dev, cnt->current_image);
 2571     } else if (cnt->postcap > 0) {
 2572         /* No motion, doing postcap */
 2573         cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE);
 2574         cnt->postcap--;
 2575         //MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "post capture %d", cnt->postcap);
 2576     } else {
 2577         /* Done with postcap, so just have the image in the precap buffer */
 2578         cnt->current_image->flags |= IMAGE_PRECAP;
 2579         /* gapless movie feature */
 2580         if ((cnt->conf.event_gap == 0) && (cnt->detecting_motion == 1))
 2581             cnt->event_stop = TRUE;
 2582         cnt->detecting_motion = 0;
 2583     }
 2584 
 2585     /* Update last frame saved time, so we can end event after gap time */
 2586     if (cnt->current_image->flags & IMAGE_SAVE)
 2587         cnt->lasttime = cnt->current_image->timestamp_tv.tv_sec;
 2588 
 2589 
 2590     mlp_areadetect(cnt);
 2591 
 2592     /*
 2593      * Is the movie too long? Then make movies
 2594      * First test for movie_max_time
 2595      */
 2596     if ((cnt->conf.movie_max_time && cnt->event_nr == cnt->prev_event) &&
 2597         (cnt->currenttime - cnt->eventtime >= cnt->conf.movie_max_time))
 2598         cnt->event_stop = TRUE;
 2599 
 2600     /*
 2601      * Now test for quiet longer than 'gap' OR make movie as decided in
 2602      * previous statement.
 2603      */
 2604     if (((cnt->currenttime - cnt->lasttime >= cnt->conf.event_gap) && cnt->conf.event_gap > 0) ||
 2605           cnt->event_stop) {
 2606         if (cnt->event_nr == cnt->prev_event || cnt->event_stop) {
 2607 
 2608             /* Flush image buffer */
 2609             process_image_ring(cnt, IMAGE_BUFFER_FLUSH);
 2610 
 2611             /* Save preview_shot here at the end of event */
 2612             if (cnt->imgs.preview_image.diffs) {
 2613                 event(cnt, EVENT_IMAGE_PREVIEW, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2614                 cnt->imgs.preview_image.diffs = 0;
 2615             }
 2616 
 2617             event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2618 
 2619             /*
 2620              * If tracking is enabled we center our camera so it does not
 2621              * point to a place where it will miss the next action
 2622              */
 2623             if (cnt->track.type)
 2624                 cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0);
 2625 
 2626             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("End of event %d"), cnt->event_nr);
 2627 
 2628             cnt->event_stop = FALSE;
 2629             cnt->event_user = FALSE;
 2630 
 2631             /* Reset post capture */
 2632             cnt->postcap = 0;
 2633 
 2634             /* Finally we increase the event number */
 2635             cnt->event_nr++;
 2636             cnt->lightswitch_framecounter = 0;
 2637 
 2638             /*
 2639              * And we unset the text_event_string to avoid that buffered
 2640              * images get a timestamp from previous event.
 2641              */
 2642             cnt->text_event_string[0] = '\0';
 2643         }
 2644     }
 2645 
 2646     /* Save/send to movie some images */
 2647     process_image_ring(cnt, 2);
 2648 
 2649 
 2650 }
 2651 
 2652 static void mlp_setupmode(struct context *cnt){
 2653     /***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/
 2654 
 2655     /* If CAMERA_VERBOSE enabled output some numbers to console */
 2656     if (cnt->conf.setup_mode) {
 2657         char msg[1024] = "\0";
 2658         char part[100];
 2659 
 2660         if (cnt->conf.despeckle_filter) {
 2661             snprintf(part, 99, _("Raw changes: %5d - changes after '%s': %5d"),
 2662                      cnt->olddiffs, cnt->conf.despeckle_filter, cnt->current_image->diffs);
 2663             strcat(msg, part);
 2664             if (strchr(cnt->conf.despeckle_filter, 'l')) {
 2665                 snprintf(part, 99,_(" - labels: %3d"), cnt->current_image->total_labels);
 2666                 strcat(msg, part);
 2667             }
 2668         } else {
 2669             snprintf(part, 99,_("Changes: %5d"), cnt->current_image->diffs);
 2670             strcat(msg, part);
 2671         }
 2672 
 2673         if (cnt->conf.noise_tune) {
 2674             snprintf(part, 99,_(" - noise level: %2d"), cnt->noise);
 2675             strcat(msg, part);
 2676         }
 2677 
 2678         if (cnt->conf.threshold_tune) {
 2679             snprintf(part, 99, _(" - threshold: %d"), cnt->threshold);
 2680             strcat(msg, part);
 2681         }
 2682 
 2683         MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s", msg);
 2684     }
 2685 
 2686 }
 2687 
 2688 static void mlp_snapshot(struct context *cnt){
 2689     /***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/
 2690     /*
 2691      * Did we get triggered to make a snapshot from control http? Then shoot a snap
 2692      * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap
 2693      * We actually allow the time to run over the interval in case we have a delay
 2694      * from slow camera.
 2695      * Note: Negative value means SIGALRM snaps are enabled
 2696      * httpd-control snaps are always enabled.
 2697      */
 2698 
 2699     /* time_current_frame is used both for snapshot and timelapse features */
 2700     cnt->time_current_frame = cnt->currenttime;
 2701 
 2702     if ((cnt->conf.snapshot_interval > 0 && cnt->shots == 0 &&
 2703          cnt->time_current_frame % cnt->conf.snapshot_interval <= cnt->time_last_frame % cnt->conf.snapshot_interval) ||
 2704          cnt->snapshot) {
 2705         event(cnt, EVENT_IMAGE_SNAPSHOT, cnt->current_image, NULL, NULL, &cnt->current_image->timestamp_tv);
 2706         cnt->snapshot = 0;
 2707     }
 2708 
 2709 }
 2710 
 2711 static void mlp_timelapse(struct context *cnt){
 2712 
 2713     struct tm timestamp_tm;
 2714 
 2715     if (cnt->conf.timelapse_interval) {
 2716         localtime_r(&cnt->current_image->timestamp_tv.tv_sec, &timestamp_tm);
 2717 
 2718         /*
 2719          * Check to see if we should start a new timelapse file. We start one when
 2720          * we are on the first shot, and and the seconds are zero. We must use the seconds
 2721          * to prevent the timelapse file from getting reset multiple times during the minute.
 2722          */
 2723         if (timestamp_tm.tm_min == 0 &&
 2724             (cnt->time_current_frame % 60 < cnt->time_last_frame % 60) &&
 2725             cnt->shots == 0) {
 2726 
 2727             if (strcasecmp(cnt->conf.timelapse_mode, "manual") == 0) {
 2728                 ;/* No action */
 2729 
 2730             /* If we are daily, raise timelapseend event at midnight */
 2731             } else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) {
 2732                 if (timestamp_tm.tm_hour == 0)
 2733                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2734 
 2735             /* handle the hourly case */
 2736             } else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) {
 2737                 event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2738 
 2739             /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */
 2740             } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) {
 2741                 if (timestamp_tm.tm_wday == 0 &&
 2742                     timestamp_tm.tm_hour == 0)
 2743                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2744             /* If we are weekly-monday, raise timelapseend event at midnight on monday */
 2745             } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) {
 2746                 if (timestamp_tm.tm_wday == 1 &&
 2747                     timestamp_tm.tm_hour == 0)
 2748                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2749             /* If we are monthly, raise timelapseend event at midnight on first day of month */
 2750             } else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) {
 2751                 if (timestamp_tm.tm_mday == 1 &&
 2752                     timestamp_tm.tm_hour == 0)
 2753                     event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2754             /* If invalid we report in syslog once and continue in manual mode */
 2755             } else {
 2756                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 2757                     ,_("Invalid timelapse_mode argument '%s'"), cnt->conf.timelapse_mode);
 2758                 MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 2759                     ,_("%:s Defaulting to manual timelapse mode"));
 2760                 conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual");
 2761             }
 2762         }
 2763 
 2764         /*
 2765          * If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0
 2766          * add a timelapse frame to the timelapse movie.
 2767          */
 2768         if (cnt->shots == 0 && cnt->time_current_frame % cnt->conf.timelapse_interval <=
 2769             cnt->time_last_frame % cnt->conf.timelapse_interval) {
 2770                 event(cnt, EVENT_TIMELAPSE, cnt->current_image, NULL, NULL,
 2771                     &cnt->current_image->timestamp_tv);
 2772         }
 2773     } else if (cnt->ffmpeg_timelapse) {
 2774     /*
 2775      * If timelapse movie is in progress but conf.timelapse_interval is zero then close timelapse file
 2776      * This is an important feature that allows manual roll-over of timelapse file using the http
 2777      * remote control via a cron job.
 2778      */
 2779         event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tv);
 2780     }
 2781 
 2782     cnt->time_last_frame = cnt->time_current_frame;
 2783 
 2784 
 2785 }
 2786 
 2787 static void mlp_loopback(struct context *cnt){
 2788     /*
 2789      * Feed last image and motion image to video device pipes and the stream clients
 2790      * In setup mode we send the special setup mode image to both stream and vloopback pipe
 2791      * In normal mode we feed the latest image to vloopback device and we send
 2792      * the image to the stream. We always send the first image in a second to the stream.
 2793      * Other image are sent only when the config option stream_motion is off
 2794      * The result is that with stream_motion on the stream stream is normally at the minimal
 2795      * 1 frame per second but the minute motion is detected the motion_detected() function
 2796      * sends all detected pictures to the stream except the 1st per second which is already sent.
 2797      */
 2798     if (cnt->conf.setup_mode) {
 2799 
 2800         event(cnt, EVENT_IMAGE, &cnt->imgs.img_motion, NULL, &cnt->pipe, &cnt->current_image->timestamp_tv);
 2801         event(cnt, EVENT_STREAM, &cnt->imgs.img_motion, NULL, NULL, &cnt->current_image->timestamp_tv);
 2802     } else {
 2803         event(cnt, EVENT_IMAGE, cnt->current_image, NULL,
 2804               &cnt->pipe, &cnt->current_image->timestamp_tv);
 2805 
 2806         if (!cnt->conf.stream_motion || cnt->shots == 1)
 2807             event(cnt, EVENT_STREAM, cnt->current_image, NULL, NULL,
 2808                   &cnt->current_image->timestamp_tv);
 2809     }
 2810 
 2811     event(cnt, EVENT_IMAGEM, &cnt->imgs.img_motion, NULL, &cnt->mpipe, &cnt->current_image->timestamp_tv);
 2812 
 2813 }
 2814 
 2815 static void mlp_parmsupdate(struct context *cnt){
 2816     /***** MOTION LOOP - ONCE PER SECOND PARAMETER UPDATE SECTION *****/
 2817 
 2818     /* Check for some config parameter changes but only every second */
 2819     if (cnt->shots != 0) return;
 2820 
 2821     init_text_scale(cnt);  /* Initialize and validate text_scale */
 2822 
 2823     if (strcasecmp(cnt->conf.picture_output, "on") == 0)
 2824         cnt->new_img = NEWIMG_ON;
 2825     else if (strcasecmp(cnt->conf.picture_output, "first") == 0)
 2826         cnt->new_img = NEWIMG_FIRST;
 2827     else if (strcasecmp(cnt->conf.picture_output, "best") == 0)
 2828         cnt->new_img = NEWIMG_BEST;
 2829     else if (strcasecmp(cnt->conf.picture_output, "center") == 0)
 2830         cnt->new_img = NEWIMG_CENTER;
 2831     else
 2832         cnt->new_img = NEWIMG_OFF;
 2833 
 2834     if (strcasecmp(cnt->conf.locate_motion_mode, "on") == 0)
 2835         cnt->locate_motion_mode = LOCATE_ON;
 2836     else if (strcasecmp(cnt->conf.locate_motion_mode, "preview") == 0)
 2837         cnt->locate_motion_mode = LOCATE_PREVIEW;
 2838     else
 2839         cnt->locate_motion_mode = LOCATE_OFF;
 2840 
 2841     if (strcasecmp(cnt->conf.locate_motion_style, "box") == 0)
 2842         cnt->locate_motion_style = LOCATE_BOX;
 2843     else if (strcasecmp(cnt->conf.locate_motion_style, "redbox") == 0)
 2844         cnt->locate_motion_style = LOCATE_REDBOX;
 2845     else if (strcasecmp(cnt->conf.locate_motion_style, "cross") == 0)
 2846         cnt->locate_motion_style = LOCATE_CROSS;
 2847     else if (strcasecmp(cnt->conf.locate_motion_style, "redcross") == 0)
 2848         cnt->locate_motion_style = LOCATE_REDCROSS;
 2849     else
 2850         cnt->locate_motion_style = LOCATE_BOX;
 2851 
 2852     /* Sanity check for smart_mask_speed, silly value disables smart mask */
 2853     if (cnt->conf.smart_mask_speed < 0 || cnt->conf.smart_mask_speed > 10)
 2854         cnt->conf.smart_mask_speed = 0;
 2855 
 2856     /* Has someone changed smart_mask_speed or framerate? */
 2857     if (cnt->conf.smart_mask_speed != cnt->smartmask_speed ||
 2858         cnt->smartmask_lastrate != cnt->lastrate) {
 2859         if (cnt->conf.smart_mask_speed == 0) {
 2860             memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);
 2861             memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);
 2862         }
 2863 
 2864         cnt->smartmask_lastrate = cnt->lastrate;
 2865         cnt->smartmask_speed = cnt->conf.smart_mask_speed;
 2866         /*
 2867             * Decay delay - based on smart_mask_speed (framerate independent)
 2868             * This is always 5*smartmask_speed seconds
 2869             */
 2870         cnt->smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed);
 2871     }
 2872 
 2873     dbse_sqlmask_update(cnt);
 2874 
 2875     cnt->threshold = cnt->conf.threshold;
 2876     if (cnt->conf.threshold_maximum > cnt->conf.threshold ){
 2877         cnt->threshold_maximum = cnt->conf.threshold_maximum;
 2878     } else {
 2879         cnt->threshold_maximum = (cnt->imgs.height * cnt->imgs.width * 3) / 2;
 2880     }
 2881 
 2882     if (!cnt->conf.noise_tune){
 2883         cnt->noise = cnt->conf.noise_level;
 2884     }
 2885 
 2886 }
 2887 
 2888 static void mlp_frametiming(struct context *cnt){
 2889 
 2890     int indx;
 2891     struct timeval tv2;
 2892     unsigned long int elapsedtime;  //TODO: Need to evaluate logic for needing this.
 2893     long int delay_time_nsec;
 2894 
 2895     /***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/
 2896     /*
 2897      * Work out expected frame rate based on config setting which may
 2898      * have changed from http-control
 2899      */
 2900     if (cnt->conf.framerate)
 2901         cnt->required_frame_time = 1000000L / cnt->conf.framerate;
 2902     else
 2903         cnt->required_frame_time = 0;
 2904 
 2905     /* Get latest time to calculate time taken to process video data */
 2906     gettimeofday(&tv2, NULL);
 2907     elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - cnt->timenow;
 2908 
 2909     /*
 2910      * Update history buffer but ignore first pass as timebefore
 2911      * variable will be inaccurate
 2912      */
 2913     if (cnt->passflag)
 2914         cnt->rolling_average_data[cnt->rolling_frame] = cnt->timenow - cnt->timebefore;
 2915     else
 2916         cnt->passflag = 1;
 2917 
 2918     cnt->rolling_frame++;
 2919     if (cnt->rolling_frame >= cnt->rolling_average_limit)
 2920         cnt->rolling_frame = 0;
 2921 
 2922     /* Calculate 10 second average and use deviation in delay calculation */
 2923     cnt->rolling_average = 0L;
 2924 
 2925     for (indx = 0; indx < cnt->rolling_average_limit; indx++)
 2926         cnt->rolling_average += cnt->rolling_average_data[indx];
 2927 
 2928     cnt->rolling_average /= cnt->rolling_average_limit;
 2929     cnt->frame_delay = cnt->required_frame_time - elapsedtime - (cnt->rolling_average - cnt->required_frame_time);
 2930 
 2931     if (cnt->frame_delay > 0) {
 2932         /* Apply delay to meet frame time */
 2933         if (cnt->frame_delay > cnt->required_frame_time)
 2934             cnt->frame_delay = cnt->required_frame_time;
 2935 
 2936         /* Delay time in nanoseconds for SLEEP */
 2937         delay_time_nsec = cnt->frame_delay * 1000;
 2938 
 2939         if (delay_time_nsec > 999999999)
 2940             delay_time_nsec = 999999999;
 2941 
 2942         /* SLEEP as defined in motion.h  A safe sleep using nanosleep */
 2943         SLEEP(0, delay_time_nsec);
 2944     }
 2945 
 2946 }
 2947 
 2948 /**
 2949  * motion_loop
 2950  *
 2951  *   Thread function for the motion handling threads.
 2952  *
 2953  */
 2954 static void *motion_loop(void *arg)
 2955 {
 2956     struct context *cnt = arg;
 2957 
 2958     if (motion_init(cnt) == 0){
 2959         while (!cnt->finish || cnt->event_stop) {
 2960             mlp_prepare(cnt);
 2961             if (cnt->get_image) {
 2962                 mlp_resetimages(cnt);
 2963                 if (mlp_retry(cnt) == 1)  break;
 2964                 if (mlp_capture(cnt) == 1)  break;
 2965                 mlp_detection(cnt);
 2966                 mlp_tuning(cnt);
 2967                 mlp_overlay(cnt);
 2968                 mlp_actions(cnt);
 2969                 mlp_setupmode(cnt);
 2970             }
 2971             mlp_snapshot(cnt);
 2972             mlp_timelapse(cnt);
 2973             mlp_loopback(cnt);
 2974             mlp_parmsupdate(cnt);
 2975             mlp_frametiming(cnt);
 2976         }
 2977     }
 2978 
 2979     cnt->lost_connection = 1;
 2980     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Thread exiting"));
 2981 
 2982     motion_cleanup(cnt);
 2983 
 2984     pthread_mutex_lock(&global_lock);
 2985         threads_running--;
 2986     pthread_mutex_unlock(&global_lock);
 2987 
 2988     cnt->running = 0;
 2989     cnt->finish = 0;
 2990 
 2991     pthread_exit(NULL);
 2992 }
 2993 
 2994 /**
 2995  * become_daemon
 2996  *
 2997  *   Turns Motion into a daemon through forking. The parent process (i.e. the
 2998  *   one initially calling this function) will exit inside this function, while
 2999  *   control will be returned to the child process. Standard input/output are
 3000  *   released properly, and the current directory is set to / in order to not
 3001  *   lock up any file system.
 3002  *
 3003  * Parameters:
 3004  *
 3005  *   cnt - current thread's context struct
 3006  *
 3007  * Returns: nothing
 3008  */
 3009 static void become_daemon(void)
 3010 {
 3011     int i;
 3012     FILE *pidf = NULL;
 3013     struct sigaction sig_ign_action;
 3014 
 3015     /* Setup sig_ign_action */
 3016 #ifdef SA_RESTART
 3017     sig_ign_action.sa_flags = SA_RESTART;
 3018 #else
 3019     sig_ign_action.sa_flags = 0;
 3020 #endif
 3021     sig_ign_action.sa_handler = SIG_IGN;
 3022     sigemptyset(&sig_ign_action.sa_mask);
 3023 
 3024     /* fork */
 3025     if (fork()) {
 3026         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion going to daemon mode"));
 3027         exit(0);
 3028     }
 3029 
 3030     /*
 3031      * Create the pid file if defined, if failed exit
 3032      * If we fail we report it. If we succeed we postpone the log entry till
 3033      * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting
 3034      * for an enter.
 3035      */
 3036     if (cnt_list[0]->conf.pid_file) {
 3037         pidf = myfopen(cnt_list[0]->conf.pid_file, "w+");
 3038 
 3039         if (pidf) {
 3040             (void)fprintf(pidf, "%d\n", getpid());
 3041             myfclose(pidf);
 3042         } else {
 3043             MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO
 3044                 ,_("Exit motion, cannot create process"
 3045                 " id file (pid file) %s"), cnt_list[0]->conf.pid_file);
 3046             if (ptr_logfile)
 3047                 myfclose(ptr_logfile);
 3048             exit(0);
 3049         }
 3050     }
 3051 
 3052     /*
 3053      * Changing dir to root enables people to unmount a disk
 3054      * without having to stop Motion
 3055      */
 3056     if (chdir("/"))
 3057         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Could not change directory"));
 3058 
 3059 
 3060 #if (defined(BSD) && !defined(__APPLE__))
 3061     setpgrp(0, getpid());
 3062 #else
 3063     setpgrp();
 3064 #endif
 3065 
 3066 
 3067     if ((i = open("/dev/tty", O_RDWR)) >= 0) {
 3068         ioctl(i, TIOCNOTTY, NULL);
 3069         close(i);
 3070     }
 3071 
 3072     setsid();
 3073     i = open("/dev/null", O_RDONLY);
 3074 
 3075     if (i != -1) {
 3076         dup2(i, STDIN_FILENO);
 3077         close(i);
 3078     }
 3079 
 3080     i = open("/dev/null", O_WRONLY);
 3081 
 3082     if (i != -1) {
 3083         dup2(i, STDOUT_FILENO);
 3084         dup2(i, STDERR_FILENO);
 3085         close(i);
 3086     }
 3087 
 3088     /* Now it is safe to add the PID creation to the logs */
 3089     if (pidf)
 3090         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 3091             ,_("Created process id file %s. Process ID is %d")
 3092             ,cnt_list[0]->conf.pid_file, getpid());
 3093 
 3094     sigaction(SIGTTOU, &sig_ign_action, NULL);
 3095     sigaction(SIGTTIN, &sig_ign_action, NULL);
 3096     sigaction(SIGTSTP, &sig_ign_action, NULL);
 3097 }
 3098 
 3099 static void cntlist_create(int argc, char *argv[]){
 3100     /*
 3101      * cnt_list is an array of pointers to the context structures cnt for each thread.
 3102      * First we reserve room for a pointer to thread 0's context structure
 3103      * and a NULL pointer which indicates that end of the array of pointers to
 3104      * thread context structures.
 3105      */
 3106     cnt_list = mymalloc(sizeof(struct context *) * 2);
 3107 
 3108     /* Now we reserve room for thread 0's context structure and let cnt_list[0] point to it */
 3109     cnt_list[0] = mymalloc(sizeof(struct context));
 3110 
 3111     /* Populate context structure with start/default values */
 3112     context_init(cnt_list[0]);
 3113 
 3114     /* Initialize some static and global string variables */
 3115     gethostname (cnt_list[0]->hostname, PATH_MAX);
 3116     cnt_list[0]->hostname[PATH_MAX-1] = '\0';
 3117     /* end of variables */
 3118 
 3119     /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */
 3120     cnt_list[1] = NULL;
 3121 
 3122     /*
 3123      * Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads
 3124      * the config options from motion.conf, thread config files and the command line.
 3125      */
 3126     cnt_list[0]->conf.argv = argv;
 3127     cnt_list[0]->conf.argc = argc;
 3128     cnt_list = conf_load(cnt_list);
 3129 }
 3130 
 3131 static void motion_shutdown(void){
 3132     int i = -1;
 3133 
 3134     motion_remove_pid();
 3135 
 3136     webu_stop(cnt_list);
 3137 
 3138     while (cnt_list[++i])
 3139         context_destroy(cnt_list[i]);
 3140 
 3141     free(cnt_list);
 3142     cnt_list = NULL;
 3143 
 3144     vid_mutex_destroy();
 3145 }
 3146 
 3147 static void motion_camera_ids(void){
 3148     /* Set the camera id's on the context.  They must be unique */
 3149     int indx, indx2, invalid_ids;
 3150 
 3151     /* Set defaults */
 3152     indx = 0;
 3153     while (cnt_list[indx] != NULL){
 3154         if (cnt_list[indx]->conf.camera_id > 0){
 3155             cnt_list[indx]->camera_id = cnt_list[indx]->conf.camera_id;
 3156         } else {
 3157             cnt_list[indx]->camera_id = indx;
 3158         }
 3159         indx++;
 3160     }
 3161 
 3162     invalid_ids = FALSE;
 3163     indx = 0;
 3164     while (cnt_list[indx] != NULL){
 3165         if (cnt_list[indx]->camera_id > 32000) invalid_ids = TRUE;
 3166         indx2 = indx + 1;
 3167         while (cnt_list[indx2] != NULL){
 3168             if (cnt_list[indx]->camera_id == cnt_list[indx2]->camera_id) invalid_ids = TRUE;
 3169 
 3170             indx2++;
 3171         }
 3172         indx++;
 3173     }
 3174     if (invalid_ids){
 3175         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 3176             ,_("Camara IDs are not unique or have values over 32,000.  Falling back to thread numbers"));
 3177         indx = 0;
 3178         while (cnt_list[indx] != NULL){
 3179             cnt_list[indx]->camera_id = indx;
 3180             indx++;
 3181         }
 3182     }
 3183 }
 3184 
 3185 static void motion_ntc(void){
 3186 
 3187     #ifdef HAVE_V4L2
 3188         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("v4l2   : available"));
 3189     #else
 3190         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("v4l2   : not available"));
 3191     #endif
 3192 
 3193     #ifdef HAVE_BKTR
 3194         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("bktr   : available"));
 3195     #else
 3196         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("bktr   : not available"));
 3197     #endif
 3198 
 3199     #ifdef HAVE_WEBP
 3200         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("webp   : available"));
 3201     #else
 3202         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("webp   : not available"));
 3203     #endif
 3204 
 3205     #ifdef HAVE_MMAL
 3206         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("mmal   : available"));
 3207     #else
 3208         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("mmal   : not available"));
 3209     #endif
 3210 
 3211     #ifdef HAVE_FFMPEG
 3212         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("ffmpeg : available"));
 3213     #else
 3214         MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,_("ffmpeg : not available"));
 3215     #endif
 3216 
 3217     #ifdef HAVE_MYSQL
 3218         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("mysql  : available"));
 3219     #else
 3220         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("mysql  : not available"));
 3221     #endif
 3222 
 3223     #ifdef HAVE_MARIADB
 3224         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("MariaDB: available"));
 3225     #else
 3226         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("MariaDB: not available"));
 3227     #endif
 3228 
 3229     #ifdef HAVE_SQLITE3
 3230         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("sqlite3: available"));
 3231     #else
 3232         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("sqlite3: not available"));
 3233     #endif
 3234 
 3235     #ifdef HAVE_PGSQL
 3236         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("pgsql  : available"));
 3237     #else
 3238         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("pgsql  : not available"));
 3239     #endif
 3240 
 3241     #ifdef HAVE_GETTEXT
 3242         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("nls    : available"));
 3243     #else
 3244         MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("nls    : not available"));
 3245     #endif
 3246 
 3247 
 3248 }
 3249 
 3250 
 3251 /**
 3252  * motion_startup
 3253  *
 3254  *   Responsible for initializing stuff when Motion starts up or is restarted,
 3255  *   including daemon initialization and creating the context struct list.
 3256  *
 3257  * Parameters:
 3258  *
 3259  *   daemonize - non-zero to do daemon init (if the config parameters says so),
 3260  *               or 0 to skip it
 3261  *   argc      - size of argv
 3262  *   argv      - command-line options, passed initially from 'main'
 3263  *
 3264  * Returns: nothing
 3265  */
 3266 static void motion_startup(int daemonize, int argc, char *argv[])
 3267 {
 3268     /* Initialize our global mutex */
 3269     pthread_mutex_init(&global_lock, NULL);
 3270 
 3271     /*
 3272      * Create the list of context structures and load the
 3273      * configuration.
 3274      */
 3275     cntlist_create(argc, argv);
 3276 
 3277     if ((cnt_list[0]->conf.log_level > ALL) ||
 3278         (cnt_list[0]->conf.log_level == 0)) {
 3279         cnt_list[0]->conf.log_level = LEVEL_DEFAULT;
 3280         cnt_list[0]->log_level = cnt_list[0]->conf.log_level;
 3281         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 3282             ,_("Using default log level (%s) (%d)")
 3283             ,get_log_level_str(cnt_list[0]->log_level)
 3284             ,SHOW_LEVEL_VALUE(cnt_list[0]->log_level));
 3285     } else {
 3286         cnt_list[0]->log_level = cnt_list[0]->conf.log_level - 1; // Let's make syslog compatible
 3287     }
 3288 
 3289 
 3290     if ((cnt_list[0]->conf.log_file) && (strncmp(cnt_list[0]->conf.log_file, "syslog", 6))) {
 3291         set_log_mode(LOGMODE_FILE);
 3292         ptr_logfile = set_logfile(cnt_list[0]->conf.log_file);
 3293 
 3294         if (ptr_logfile) {
 3295             set_log_mode(LOGMODE_SYSLOG);
 3296             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 3297                 ,_("Logging to file (%s)"),cnt_list[0]->conf.log_file);
 3298             set_log_mode(LOGMODE_FILE);
 3299         } else {
 3300             MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO
 3301                 ,_("Exit motion, cannot create log file %s")
 3302                 ,cnt_list[0]->conf.log_file);
 3303             exit(0);
 3304         }
 3305     } else {
 3306         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Logging to syslog"));
 3307     }
 3308 
 3309     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion %s Started"),VERSION);
 3310 
 3311     if ((cnt_list[0]->conf.log_type == NULL) ||
 3312         !(cnt_list[0]->log_type = get_log_type(cnt_list[0]->conf.log_type))) {
 3313         cnt_list[0]->log_type = TYPE_DEFAULT;
 3314         cnt_list[0]->conf.log_type = mystrcpy(cnt_list[0]->conf.log_type, "ALL");
 3315         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Using default log type (%s)"),
 3316                    get_log_type_str(cnt_list[0]->log_type));
 3317     }
 3318 
 3319     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Using log type (%s) log level (%s)"),
 3320                get_log_type_str(cnt_list[0]->log_type), get_log_level_str(cnt_list[0]->log_level));
 3321 
 3322     set_log_level(cnt_list[0]->log_level);
 3323     set_log_type(cnt_list[0]->log_type);
 3324 
 3325 
 3326     if (daemonize) {
 3327         /*
 3328          * If daemon mode is requested, and we're not going into setup mode,
 3329          * become daemon.
 3330          */
 3331         if (cnt_list[0]->daemon && cnt_list[0]->conf.setup_mode == 0) {
 3332             become_daemon();
 3333             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion running as daemon process"));
 3334         }
 3335     }
 3336 
 3337     if (cnt_list[0]->conf.setup_mode)
 3338         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Motion running in setup mode."));
 3339 
 3340     conf_output_parms(cnt_list);
 3341 
 3342     motion_ntc();
 3343 
 3344     motion_camera_ids();
 3345 
 3346     initialize_chars();
 3347 
 3348     webu_start(cnt_list);
 3349 
 3350     vid_mutex_init();
 3351 
 3352 }
 3353 
 3354 /**
 3355  * motion_start_thread
 3356  *
 3357  *   Called from main when start a motion thread
 3358  *
 3359  * Parameters:
 3360  *
 3361  *   cnt - Thread context pointer
 3362  *   thread_attr - pointer to thread attributes
 3363  *
 3364  * Returns: nothing
 3365  */
 3366 static void motion_start_thread(struct context *cnt){
 3367     int i;
 3368     char service[6];
 3369     pthread_attr_t thread_attr;
 3370 
 3371     if (strcmp(cnt->conf_filename, "")){
 3372         cnt->conf_filename[sizeof(cnt->conf_filename) - 1] = '\0';
 3373         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Camera ID: %d is from %s")
 3374             ,cnt->camera_id, cnt->conf_filename);
 3375     }
 3376 
 3377     if (cnt->conf.netcam_url){
 3378         snprintf(service,6,"%s",cnt->conf.netcam_url);
 3379         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Camera ID: %d Camera Name: %s Service: %s")
 3380             ,cnt->camera_id, cnt->conf.camera_name,service);
 3381     } else {
 3382         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Camera ID: %d Camera Name: %s Device: %s")
 3383             ,cnt->camera_id, cnt->conf.camera_name,cnt->conf.video_device);
 3384     }
 3385 
 3386     /*
 3387      * Check the stream port number for conflicts.
 3388      * First we check for conflict with the control port.
 3389      * Second we check for that two threads does not use the same port number
 3390      * for the stream. If a duplicate port is found the stream feature gets disabled (port = 0)
 3391      * for this thread and a warning is written to console and syslog.
 3392      */
 3393 
 3394     if (cnt->conf.stream_port != 0) {
 3395         /* Compare against the control port. */
 3396         if (cnt_list[0]->conf.webcontrol_port == cnt->conf.stream_port) {
 3397             MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 3398                 ,_("Stream port number %d for thread %d conflicts with the control port")
 3399                 ,cnt->conf.stream_port, cnt->threadnr);
 3400             MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 3401                 ,_("Stream feature for thread %d is disabled.")
 3402                 ,cnt->threadnr);
 3403             cnt->conf.stream_port = 0;
 3404         }
 3405         /* Compare against stream ports of other threads. */
 3406         for (i = 1; cnt_list[i]; i++) {
 3407             if (cnt_list[i] == cnt) continue;
 3408 
 3409             if (cnt_list[i]->conf.stream_port == cnt->conf.stream_port) {
 3410                 MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 3411                     ,_("Stream port number %d for thread %d conflicts with thread %d")
 3412                     ,cnt->conf.stream_port, cnt->threadnr, cnt_list[i]->threadnr);
 3413                 MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 3414                     ,_("Stream feature for thread %d is disabled.")
 3415                     ,cnt->threadnr);
 3416                 cnt->conf.stream_port = 0;
 3417             }
 3418         }
 3419     }
 3420 
 3421     /*
 3422      * Update how many threads we have running. This is done within a
 3423      * mutex lock to prevent multiple simultaneous updates to
 3424      * 'threads_running'.
 3425      */
 3426     pthread_mutex_lock(&global_lock);
 3427     threads_running++;
 3428     pthread_mutex_unlock(&global_lock);
 3429 
 3430     /* Set a flag that we want this thread running */
 3431     cnt->restart = 1;
 3432 
 3433     /* Give the thread WATCHDOG_TMO to start */
 3434     cnt->watchdog = WATCHDOG_TMO;
 3435 
 3436     /* Flag it as running outside of the thread, otherwise if the main loop
 3437      * checked if it is was running before the thread set it to 1, it would
 3438      * start another thread for this device. */
 3439     cnt->running = 1;
 3440 
 3441     pthread_attr_init(&thread_attr);
 3442     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
 3443 
 3444     if (pthread_create(&cnt->thread_id, &thread_attr, &motion_loop, cnt)) {
 3445         /* thread create failed, undo running state */
 3446         cnt->running = 0;
 3447         pthread_mutex_lock(&global_lock);
 3448         threads_running--;
 3449         pthread_mutex_unlock(&global_lock);
 3450     }
 3451     pthread_attr_destroy(&thread_attr);
 3452 
 3453 }
 3454 
 3455 static void motion_restart(int argc, char **argv){
 3456     /*
 3457     * Handle the restart situation. Currently the approach is to
 3458     * cleanup everything, and then initialize everything again
 3459     * (including re-reading the config file(s)).
 3460     */
 3461     MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Restarting motion."));
 3462     motion_shutdown();
 3463 
 3464     SLEEP(2, 0);
 3465 
 3466     motion_startup(0, argc, argv); /* 0 = skip daemon init */
 3467     MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO,_("Motion restarted"));
 3468 
 3469     restart = 0;
 3470 }
 3471 
 3472 static void motion_watchdog(int indx){
 3473 
 3474     /* Notes:
 3475      * To test scenarios, just double lock a mutex in a spawned thread.
 3476      * We use detached threads because pthread_join would lock the main thread
 3477      * If we only call the first pthread_cancel when we reach the watchdog_kill
 3478      *   it does not break us out of the mutex lock.
 3479      * We keep sending VTAlarms so the pthread_cancel queued can be caught.
 3480      * The calls to pthread_kill 'may' not work or cause crashes
 3481      *   The cancel could finish and then the pthread_kill could be called
 3482      *   on the invalid thread_id which could cause undefined results
 3483      * Even if the cancel finishes it is not clean since memory is not cleaned.
 3484      * The other option instead of cancel would be to exit(1) and terminate everything
 3485      * Best to just not get into a watchdog situation...
 3486      */
 3487 
 3488     if (!cnt_list[indx]->running) return;
 3489 
 3490     cnt_list[indx]->watchdog--;
 3491     if (cnt_list[indx]->watchdog == 0) {
 3492         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 3493             ,_("Thread %d - Watchdog timeout. Trying to do a graceful restart")
 3494             , cnt_list[indx]->threadnr);
 3495         cnt_list[indx]->event_stop = TRUE; /* Trigger end of event */
 3496         cnt_list[indx]->finish = 1;
 3497     }
 3498 
 3499     if (cnt_list[indx]->watchdog == WATCHDOG_KILL) {
 3500         MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
 3501             ,_("Thread %d - Watchdog timeout did NOT restart, killing it!")
 3502             , cnt_list[indx]->threadnr);
 3503         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_RTSP) &&
 3504             (cnt_list[indx]->rtsp != NULL)){
 3505             pthread_cancel(cnt_list[indx]->rtsp->thread_id);
 3506         }
 3507         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_RTSP) &&
 3508             (cnt_list[indx]->rtsp_high != NULL)){
 3509             pthread_cancel(cnt_list[indx]->rtsp_high->thread_id);
 3510         }
 3511         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
 3512             (cnt_list[indx]->netcam != NULL)){
 3513             pthread_cancel(cnt_list[indx]->netcam->thread_id);
 3514         }
 3515         pthread_cancel(cnt_list[indx]->thread_id);
 3516     }
 3517 
 3518     if (cnt_list[indx]->watchdog < WATCHDOG_KILL) {
 3519         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
 3520             (cnt_list[indx]->rtsp != NULL)){
 3521             if (!cnt_list[indx]->rtsp->handler_finished &&
 3522                 pthread_kill(cnt_list[indx]->rtsp->thread_id, 0) == ESRCH) {
 3523                 cnt_list[indx]->rtsp->handler_finished = TRUE;
 3524                 pthread_mutex_lock(&global_lock);
 3525                     threads_running--;
 3526                 pthread_mutex_unlock(&global_lock);
 3527                 netcam_rtsp_cleanup(cnt_list[indx],FALSE);
 3528             } else {
 3529                 pthread_kill(cnt_list[indx]->rtsp->thread_id, SIGVTALRM);
 3530             }
 3531         }
 3532         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
 3533             (cnt_list[indx]->rtsp_high != NULL)){
 3534             if (!cnt_list[indx]->rtsp_high->handler_finished &&
 3535                 pthread_kill(cnt_list[indx]->rtsp_high->thread_id, 0) == ESRCH) {
 3536                 cnt_list[indx]->rtsp_high->handler_finished = TRUE;
 3537                 pthread_mutex_lock(&global_lock);
 3538                     threads_running--;
 3539                 pthread_mutex_unlock(&global_lock);
 3540                 netcam_rtsp_cleanup(cnt_list[indx],FALSE);
 3541             } else {
 3542                 pthread_kill(cnt_list[indx]->rtsp_high->thread_id, SIGVTALRM);
 3543             }
 3544         }
 3545         if ((cnt_list[indx]->camera_type == CAMERA_TYPE_NETCAM) &&
 3546             (cnt_list[indx]->netcam != NULL)){
 3547             if (!cnt_list[indx]->netcam->handler_finished &&
 3548                 pthread_kill(cnt_list[indx]->netcam->thread_id, 0) == ESRCH) {
 3549                 pthread_mutex_lock(&global_lock);
 3550                     threads_running--;
 3551                 pthread_mutex_unlock(&global_lock);
 3552                 cnt_list[indx]->netcam->handler_finished = TRUE;
 3553                 cnt_list[indx]->netcam->finish = FALSE;
 3554             } else {
 3555                 pthread_kill(cnt_list[indx]->netcam->thread_id, SIGVTALRM);
 3556             }
 3557         }
 3558         if (cnt_list[indx]->running &&
 3559             pthread_kill(cnt_list[indx]->thread_id, 0) == ESRCH){
 3560             MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO
 3561                 ,_("Thread %d - Cleaning thread.")
 3562                 , cnt_list[indx]->threadnr);
 3563             pthread_mutex_lock(&global_lock);
 3564                 threads_running--;
 3565             pthread_mutex_unlock(&global_lock);
 3566             motion_cleanup(cnt_list[indx]);
 3567             cnt_list[indx]->running = 0;
 3568             cnt_list[indx]->finish = 0;
 3569         } else {
 3570             pthread_kill(cnt_list[indx]->thread_id,SIGVTALRM);
 3571         }
 3572     }
 3573 }
 3574 
 3575 static int motion_check_threadcount(void){
 3576     /* Return 1 if we should break out of loop */
 3577 
 3578     /* It has been observed that this is not counting every
 3579      * thread running.  The netcams spawn handler threads which are not
 3580      * counted here.  This is only counting context threads and when they
 3581      * all get to zero, then we are done.
 3582      */
 3583 
 3584     int motion_threads_running, indx;
 3585 
 3586     motion_threads_running = 0;
 3587 
 3588     for (indx = (cnt_list[1] != NULL ? 1 : 0); cnt_list[indx]; indx++) {
 3589         if (cnt_list[indx]->running || cnt_list[indx]->restart)
 3590             motion_threads_running++;
 3591     }
 3592 
 3593     /* If the web control/streams are in finish/shutdown, we
 3594      * do not want to count them.  They will be completely closed
 3595      * by the process outside of loop that is checking the counts
 3596      * of threads.  If the webcontrol is not in a finish / shutdown
 3597      * then we want to keep them in the tread count to allow user
 3598      * to restart the cameras and keep Motion running.
 3599      */
 3600     indx = 0;
 3601     while (cnt_list[indx] != NULL){
 3602         if ((cnt_list[indx]->webcontrol_finish == FALSE) &&
 3603             ((cnt_list[indx]->webcontrol_daemon != NULL) ||
 3604              (cnt_list[indx]->webstream_daemon != NULL))) {
 3605             motion_threads_running++;
 3606         }
 3607         indx++;
 3608     }
 3609 
 3610 
 3611     if (((motion_threads_running == 0) && finish) ||
 3612         ((motion_threads_running == 0) && (threads_running == 0))) {
 3613         MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO
 3614             ,_("DEBUG-1 threads_running %d motion_threads_running %d , finish %d")
 3615             ,threads_running, motion_threads_running, finish);
 3616         return 1;
 3617     } else {
 3618         return 0;
 3619     }
 3620 }
 3621 
 3622 /**
 3623  * main
 3624  *
 3625  *   Main entry point of Motion. Launches all the motion threads and contains
 3626  *   the logic for starting up, restarting and cleaning up everything.
 3627  *
 3628  * Parameters:
 3629  *
 3630  *   argc - size of argv
 3631  *   argv - command-line options
 3632  *
 3633  * Returns: Motion exit status = 0 always
 3634  */
 3635 int main (int argc, char **argv)
 3636 {
 3637     int i;
 3638 
 3639     /* Create the TLS key for thread number. */
 3640     pthread_key_create(&tls_key_threadnr, NULL);
 3641     pthread_setspecific(tls_key_threadnr, (void *)(0));
 3642 
 3643     setup_signals();
 3644 
 3645     motion_startup(1, argc, argv);
 3646 
 3647     ffmpeg_global_init();
 3648 
 3649     dbse_global_init();
 3650 
 3651     translate_init();
 3652 
 3653     do {
 3654         if (restart) motion_restart(argc, argv);
 3655 
 3656         for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) {
 3657             cnt_list[i]->threadnr = i ? i : 1;
 3658             motion_start_thread(cnt_list[i]);
 3659         }
 3660 
 3661         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 3662             ,_("Waiting for threads to finish, pid: %d"), getpid());
 3663 
 3664         while (1) {
 3665             SLEEP(1, 0);
 3666             if (motion_check_threadcount()) break;
 3667 
 3668             for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) {
 3669                 /* Check if threads wants to be restarted */
 3670                 if ((!cnt_list[i]->running) && (cnt_list[i]->restart)) {
 3671                     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO
 3672                         ,_("Motion thread %d restart"), cnt_list[i]->threadnr);
 3673                     motion_start_thread(cnt_list[i]);
 3674                 }
 3675                 motion_watchdog(i);
 3676             }
 3677         }
 3678 
 3679         /* Reset end main loop flag */
 3680         finish = 0;
 3681 
 3682         MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Threads finished"));
 3683 
 3684         /* Rest for a while if we're supposed to restart. */
 3685         if (restart) SLEEP(1, 0);
 3686 
 3687     } while (restart); /* loop if we're supposed to restart */
 3688 
 3689 
 3690     MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion terminating"));
 3691 
 3692     ffmpeg_global_deinit();
 3693 
 3694     dbse_global_deinit();
 3695 
 3696     motion_shutdown();
 3697 
 3698     /* Perform final cleanup. */
 3699     pthread_key_delete(tls_key_threadnr);
 3700     pthread_mutex_destroy(&global_lock);
 3701 
 3702     return 0;
 3703 }
 3704 
 3705 /**
 3706  * mymalloc
 3707  *
 3708  *   Allocates some memory and checks if that succeeded or not. If it failed,
 3709  *   do some errorlogging and bail out.
 3710  *
 3711  *   NOTE: Kenneth Lavrsen changed printing of size_t types so instead of using
 3712  *   conversion specifier %zd I changed it to %llu and casted the size_t
 3713  *   variable to unsigned long long. The reason for this nonsense is that older
 3714  *   versions of gcc like 2.95 uses %Zd and does not understand %zd. So to avoid
 3715  *   this mess I used a more generic way. Long long should have enough bits for
 3716  *   64-bit machines with large memory areas.
 3717  *
 3718  * Parameters:
 3719  *
 3720  *   nbytes - no. of bytes to allocate
 3721  *
 3722  * Returns: a pointer to the allocated memory
 3723  */
 3724 void * mymalloc(size_t nbytes)
 3725 {
 3726     void *dummy = calloc(nbytes, 1);
 3727 
 3728     if (!dummy) {
 3729         MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO, _("Could not allocate %llu bytes of memory!")
 3730             ,(unsigned long long)nbytes);
 3731         motion_remove_pid();
 3732         exit(1);
 3733     }
 3734 
 3735     return dummy;
 3736 }
 3737 
 3738 /**
 3739  * myrealloc
 3740  *
 3741  *   Re-allocate (i.e., resize) some memory and check if that succeeded or not.
 3742  *   If it failed, do some errorlogging and bail out. If the new memory size
 3743  *   is 0, the memory is freed.
 3744  *
 3745  * Parameters:
 3746  *
 3747  *   ptr  - pointer to the memory to resize/reallocate
 3748  *   size - new memory size
 3749  *   desc - name of the calling function
 3750  *
 3751  * Returns: a pointer to the reallocated memory, or NULL if the memory was
 3752  *          freed
 3753  */
 3754 void *myrealloc(void *ptr, size_t size, const char *desc)
 3755 {
 3756     void *dummy = NULL;
 3757 
 3758     if (size == 0) {
 3759         free(ptr);
 3760         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
 3761             ,_("Warning! Function %s tries to resize memoryblock at %p to 0 bytes!")
 3762             ,desc, ptr);
 3763     } else {
 3764         dummy = realloc(ptr, size);
 3765         if (!dummy) {
 3766             MOTION_LOG(EMG, TYPE_ALL, NO_ERRNO
 3767                 ,_("Could not resize memory-block at offset %p to %llu bytes (function %s)!")
 3768                 ,ptr, (unsigned long long)size, desc);
 3769             motion_remove_pid();
 3770             exit(1);
 3771         }
 3772     }
 3773 
 3774     return dummy;
 3775 }
 3776 
 3777 
 3778 /**
 3779  * create_path
 3780  *
 3781  *   This function creates a whole path, like mkdir -p. Example paths:
 3782  *      this/is/an/example/
 3783  *      /this/is/an/example/
 3784  *   Warning: a path *must* end with a slash!
 3785  *
 3786  * Parameters:
 3787  *
 3788  *   cnt  - current thread's context structure (for logging)
 3789  *   path - the path to create
 3790  *
 3791  * Returns: 0 on success, -1 on failure
 3792  */
 3793 int create_path(const char *path)
 3794 {
 3795     char *start;
 3796     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 3797 
 3798     if (path[0] == '/')
 3799         start = strchr(path + 1, '/');
 3800     else
 3801         start = strchr(path, '/');
 3802 
 3803     while (start) {
 3804         char *buffer = mystrdup(path);
 3805         buffer[start-path] = 0x00;
 3806 
 3807         if (mkdir(buffer, mode) == -1 && errno != EEXIST) {
 3808             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
 3809                 ,_("Problem creating directory %s"), buffer);
 3810             free(buffer);
 3811             return -1;
 3812         }
 3813 
 3814         start = strchr(start + 1, '/');
 3815 
 3816         if (!start)
 3817             MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("creating directory %s"), buffer);
 3818 
 3819         free(buffer);
 3820     }
 3821 
 3822     return 0;
 3823 }
 3824 
 3825 /**
 3826  * myfopen
 3827  *
 3828  *   This function opens a file, if that failed because of an ENOENT error
 3829  *   (which is: path does not exist), the path is created and then things are
 3830  *   tried again. This is faster then trying to create that path over and over
 3831  *   again. If someone removes the path after it was created, myfopen will
 3832  *   recreate the path automatically.
 3833  *
 3834  * Parameters:
 3835  *
 3836  *   path - path to the file to open
 3837  *   mode - open mode
 3838  *
 3839  * Returns: the file stream object
 3840  */
 3841 FILE * myfopen(const char *path, const char *mode)
 3842 {
 3843     /* first, just try to open the file */
 3844     FILE *dummy = fopen(path, mode);
 3845     if (dummy) return dummy;
 3846 
 3847     /* could not open file... */
 3848     /* path did not exist? */
 3849     if (errno == ENOENT) {
 3850 
 3851         /* create path for file... */
 3852         if (create_path(path) == -1)
 3853             return NULL;
 3854 
 3855         /* and retry opening the file */
 3856         dummy = fopen(path, mode);
 3857     }
 3858     if (!dummy) {
 3859         /*
 3860          * Two possibilities
 3861          * 1: there was an other error while trying to open the file for the
 3862          * first time
 3863          * 2: could still not open the file after the path was created
 3864          */
 3865         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
 3866             ,_("Error opening file %s with mode %s"), path, mode);
 3867         return NULL;
 3868     }
 3869 
 3870     return dummy;
 3871 }
 3872 
 3873 /**
 3874  * myfclose
 3875  *
 3876  *  Motion-specific variant of fclose()
 3877  *
 3878  * Returns: fclose() return value
 3879  */
 3880 int myfclose(FILE* fh)
 3881 {
 3882     int rval = fclose(fh);
 3883 
 3884     if (rval != 0)
 3885         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error closing file"));
 3886 
 3887     return rval;
 3888 }
 3889 
 3890 /**
 3891  * mystrftime_long
 3892  *
 3893  *   Motion-specific long form of format specifiers.
 3894  *
 3895  * Parameters:
 3896  *
 3897  *   cnt        - current thread's context structure.
 3898  *   width      - width associated with the format specifier.
 3899  *   word       - beginning of the format specifier's word.
 3900  *   l          - length of the format specifier's word.
 3901  *   out        - output buffer where to store the result. Size: PATH_MAX.
 3902  *
 3903  * This is called if a format specifier with the format below was found:
 3904  *
 3905  *   % { word }
 3906  *
 3907  * As a special edge case, an incomplete format at the end of the string
 3908  * is processed as well:
 3909  *
 3910  *   % { word \0
 3911  *
 3912  * Any valid format specified width is supported, e.g. "%12{host}".
 3913  *
 3914  * The following specifier keywords are currently supported:
 3915  *
 3916  * host    Replaced with the name of the local machine (see gethostname(2)).
 3917  * fps     Equivalent to %fps.
 3918  */
 3919 static void mystrftime_long (const struct context *cnt,
 3920                              int width, const char *word, int l, char *out)
 3921 {
 3922 #define SPECIFIERWORD(k) ((strlen(k)==l) && (!strncmp (k, word, l)))
 3923 
 3924     if (SPECIFIERWORD("host")) {
 3925         snprintf (out, PATH_MAX, "%*s", width, cnt->hostname);
 3926         return;
 3927     }
 3928     if (SPECIFIERWORD("fps")) {
 3929         sprintf(out, "%*d", width, cnt->movie_fps);
 3930         return;
 3931     }
 3932     if (SPECIFIERWORD("dbeventid")) {
 3933         sprintf(out, "%*llu", width, cnt->database_event_id);
 3934         return;
 3935     }
 3936     if (SPECIFIERWORD("ver")) {
 3937         sprintf(out, "%*s", width, VERSION);
 3938         return;
 3939     }
 3940 
 3941     // Not a valid modifier keyword. Log the error and ignore.
 3942     MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO,
 3943         _("invalid format specifier keyword %*.*s"), l, l, word);
 3944 
 3945     // Do not let the output buffer empty, or else where to restart the
 3946     // interpretation of the user string will become dependent to far too
 3947     // many conditions. Maybe change loop to "if (*pos_userformat == '%') {
 3948     // ...} __else__ ..."?
 3949     out[0] = '~'; out[1] = 0;
 3950 }
 3951 
 3952 /**
 3953  * mystrftime
 3954  *
 3955  *   Motion-specific variant of strftime(3) that supports additional format
 3956  *   specifiers in the format string.
 3957  *
 3958  * Parameters:
 3959  *
 3960  *   cnt        - current thread's context structure
 3961  *   s          - destination string
 3962  *   max        - max number of bytes to write
 3963  *   userformat - format string
 3964  *   tm         - time information
 3965  *   filename   - string containing full path of filename
 3966  *                set this to NULL if not relevant
 3967  *   sqltype    - Filetype as used in SQL feature, set to 0 if not relevant
 3968  *
 3969  * Returns: number of bytes written to the string s
 3970  */
 3971 size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *userformat,
 3972                   const struct timeval *tv1, const char *filename, int sqltype)
 3973 {
 3974     char formatstring[PATH_MAX] = "";
 3975     char tempstring[PATH_MAX] = "";
 3976     char *format, *tempstr;
 3977     const char *pos_userformat;
 3978     int width;
 3979     struct tm timestamp_tm;
 3980 
 3981     localtime_r(&tv1->tv_sec, &timestamp_tm);
 3982 
 3983     format = formatstring;
 3984 
 3985     /* if mystrftime is called with userformat = NULL we return a zero length string */
 3986     if (userformat == NULL) {
 3987         *s = '\0';
 3988         return 0;
 3989     }
 3990 
 3991     for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) {
 3992 
 3993         if (*pos_userformat == '%') {
 3994             /*
 3995              * Reset 'tempstr' to point to the beginning of 'tempstring',
 3996              * otherwise we will eat up tempstring if there are many
 3997              * format specifiers.
 3998              */
 3999             tempstr = tempstring;
 4000             tempstr[0] = '\0';
 4001             width = 0;
 4002             while ('0' <= pos_userformat[1] && pos_userformat[1] <= '9') {
 4003                 width *= 10;
 4004                 width += pos_userformat[1] - '0';
 4005                 ++pos_userformat;
 4006             }
 4007 
 4008             switch (*++pos_userformat) {
 4009             case '\0': // end of string
 4010                 --pos_userformat;
 4011                 break;
 4012 
 4013             case 'v': // event
 4014                 sprintf(tempstr, "%0*d", width ? width : 2, cnt->event_nr);
 4015                 break;
 4016 
 4017             case 'q': // shots
 4018                 sprintf(tempstr, "%0*d", width ? width : 2,
 4019                     cnt->current_image->shot);
 4020                 break;
 4021 
 4022             case 'D': // diffs
 4023                 sprintf(tempstr, "%*d", width, cnt->current_image->diffs);
 4024                 break;
 4025 
 4026             case 'N': // noise
 4027                 sprintf(tempstr, "%*d", width, cnt->noise);
 4028                 break;
 4029 
 4030             case 'i': // motion width
 4031                 sprintf(tempstr, "%*d", width,
 4032                     cnt->current_image->location.width);
 4033                 break;
 4034 
 4035             case 'J': // motion height
 4036                 sprintf(tempstr, "%*d", width,
 4037                     cnt->current_image->location.height);
 4038                 break;
 4039 
 4040             case 'K': // motion center x
 4041                 sprintf(tempstr, "%*d", width, cnt->current_image->location.x);
 4042                 break;
 4043 
 4044             case 'L': // motion center y
 4045                 sprintf(tempstr, "%*d", width, cnt->current_image->location.y);
 4046                 break;
 4047 
 4048             case 'o': // threshold
 4049                 sprintf(tempstr, "%*d", width, cnt->threshold);
 4050                 break;
 4051 
 4052             case 'Q': // number of labels
 4053                 sprintf(tempstr, "%*d", width,
 4054                     cnt->current_image->total_labels);
 4055                 break;
 4056 
 4057             case 't': // camera id
 4058                 sprintf(tempstr, "%*d", width, cnt->camera_id);
 4059                 break;
 4060 
 4061             case 'C': // text_event
 4062                 if (cnt->text_event_string[0])
 4063                     snprintf(tempstr, PATH_MAX, "%*s", width,
 4064                         cnt->text_event_string);
 4065                 else
 4066                     ++pos_userformat;
 4067                 break;
 4068 
 4069             case 'w': // picture width
 4070                 sprintf(tempstr, "%*d", width, cnt->imgs.width);
 4071                 break;
 4072 
 4073             case 'h': // picture height
 4074                 sprintf(tempstr, "%*d", width, cnt->imgs.height);
 4075                 break;
 4076 
 4077             case 'f': // filename -- or %fps
 4078                 if ((*(pos_userformat+1) == 'p') && (*(pos_userformat+2) == 's')) {
 4079                     sprintf(tempstr, "%*d", width, cnt->movie_fps);
 4080                     pos_userformat += 2;
 4081                     break;
 4082                 }
 4083 
 4084                 if (filename)
 4085                     snprintf(tempstr, PATH_MAX, "%*s", width, filename);
 4086                 else
 4087                     ++pos_userformat;
 4088                 break;
 4089 
 4090             case 'n': // sqltype
 4091                 if (sqltype)
 4092                     sprintf(tempstr, "%*d", width, sqltype);
 4093                 else
 4094                     ++pos_userformat;
 4095                 break;
 4096 
 4097             case '{': // long format specifier word.
 4098                 {
 4099                     const char *word = ++pos_userformat;
 4100                     while ((*pos_userformat != '}') && (*pos_userformat != 0))
 4101                         ++pos_userformat;
 4102                     mystrftime_long (cnt, width, word, (int)(pos_userformat-word), tempstr);
 4103                     if (*pos_userformat == '\0') --pos_userformat;
 4104                 }
 4105                 break;
 4106 
 4107             case '$': // thread name
 4108                 if (cnt->conf.camera_name && cnt->conf.camera_name[0])
 4109                     snprintf(tempstr, PATH_MAX, "%s", cnt->conf.camera_name);
 4110                 else
 4111                     ++pos_userformat;
 4112                 break;
 4113 
 4114             default: // Any other code is copied with the %-sign
 4115                 *format++ = '%';
 4116                 *format++ = *pos_userformat;
 4117                 continue;
 4118             }
 4119 
 4120             /*
 4121              * If a format specifier was found and used, copy the result from
 4122              * 'tempstr' to 'format'.
 4123              */
 4124             if (tempstr[0]) {
 4125                 while ((*format = *tempstr++) != '\0')
 4126                     ++format;
 4127                 continue;
 4128             }
 4129         }
 4130 
 4131         /* For any other character than % we just simply copy the character */
 4132         *format++ = *pos_userformat;
 4133     }
 4134 
 4135     *format = '\0';
 4136     format = formatstring;
 4137 
 4138     return strftime(s, max, format, &timestamp_tm);
 4139 }
 4140 /* This is a temporary location for these util functions.  All the generic utility
 4141  * functions will be collected here and ultimately moved into a new common "util" module
 4142  */
 4143 void util_threadname_set(const char *abbr, int threadnbr, const char *threadname){
 4144     /* When the abbreviation is sent in as null, that means we are being
 4145      * provided a fully filled out thread name (usually obtained from a
 4146      * previously called get_threadname so we set it without additional
 4147      *  formatting.
 4148      */
 4149 
 4150     char tname[16];
 4151     if (abbr != NULL){
 4152         snprintf(tname, sizeof(tname), "%s%d%s%s",abbr,threadnbr,
 4153              threadname ? ":" : "",
 4154              threadname ? threadname : "");
 4155     } else {
 4156         snprintf(tname, sizeof(tname), "%s",threadname);
 4157     }
 4158 
 4159 #ifdef __APPLE__
 4160     pthread_setname_np(tname);
 4161 #elif defined(BSD)
 4162     pthread_set_name_np(pthread_self(), tname);
 4163 #elif HAVE_PTHREAD_SETNAME_NP
 4164     pthread_setname_np(pthread_self(), tname);
 4165 #else
 4166     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Unable to set thread name %s"), tname);
 4167 #endif
 4168 
 4169 }
 4170 
 4171 void util_threadname_get(char *threadname){
 4172 
 4173 #if ((!defined(BSD) && HAVE_PTHREAD_GETNAME_NP) || defined(__APPLE__))
 4174     char currname[16];
 4175     pthread_getname_np(pthread_self(), currname, sizeof(currname));
 4176     snprintf(threadname, sizeof(currname), "%s",currname);
 4177 #else
 4178     snprintf(threadname, 8, "%s","Unknown");
 4179 #endif
 4180 
 4181 }
 4182 int util_check_passthrough(struct context *cnt){
 4183 #if (HAVE_FFMPEG && LIBAVFORMAT_VERSION_MAJOR < 55)
 4184     if (cnt->movie_passthrough)
 4185         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 4186             ,_("FFMPEG version too old. Disabling pass-through processing."));
 4187     return 0;
 4188 #else
 4189     if (cnt->movie_passthrough){
 4190         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 4191             ,_("pass-through is enabled but is still experimental."));
 4192         return 1;
 4193     } else {
 4194         return 0;
 4195     }
 4196 #endif
 4197 
 4198 }