📄 motion.c
字号:
/* motion.c * * Detect changes in a video stream. * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) * This software is distributed under the GNU public license version 2 * See also the file 'COPYING'. * */#include "ffmpeg.h"#include "motion.h"#if (defined(BSD) && !defined(PWCBSD))#include "video_freebsd.h"#else#include "video.h"#endif /* BSD */#include "conf.h"#include "alg.h"#include "track.h"#include "event.h"#include "picture.h"#include "rotate.h"/* Forward declarations */static int motion_init(struct context *cnt);static void motion_cleanup(struct context *cnt);/** * tls_key_threadnr * * TLS key for storing thread number in thread-local storage. */pthread_key_t tls_key_threadnr;/** * global_lock * * Protects any global variables (like 'threads_running') during updates, * to prevent problems with multiple threads updating at the same time. *///pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t global_lock;/** * cnt_list * * List of context structures, one for each main Motion thread. */struct context **cnt_list=NULL;/** * threads_running * * Keeps track of number of Motion threads currently running. Also used * by 'main' to know when all threads have exited. */volatile int threads_running=0;/* * debug_level is for developers, normally used to control which * types of messages get output. */unsigned short int debug_level;/* Set this when we want main to end or restart */volatile unsigned short int finish=0;/** * restart * * Differentiates between a quit and a restart. When all threads have * finished running, 'main' checks if 'restart' is true and if so starts * up again (instead of just quitting). */unsigned short int restart=0;/** * image_ring_resize * * This routine is called from motion_loop to resize the image precapture ringbuffer * NOTE: This function clears all images in the old ring buffer * Parameters: * * cnt Pointer to the motion context structure * new_size The new size of the ring buffer * * Returns: nothing */static void image_ring_resize(struct context *cnt, int new_size){ /* Only resize if : * Not in an event and * decreasing at last position in new buffer * increasing at last position in old buffer * e.g. at end of smallest buffer */ if (cnt->event_nr != cnt->prev_event) { int smallest; if (new_size < cnt->imgs.image_ring_size) { /* Decreasing */ smallest = new_size; } else { /* Increasing */ smallest = cnt->imgs.image_ring_size; } if (cnt->imgs.image_ring_in == smallest - 1 || smallest == 0) { motion_log(LOG_INFO, 0, "Resizing pre_capture buffer to %d items", new_size); /* Create memory for new ring buffer */ struct image_data *tmp; tmp = mymalloc(new_size * sizeof(struct image_data)); /* Copy all information from old to new * Smallest is 0 at initial init */ if (smallest > 0) { memcpy(tmp, cnt->imgs.image_ring, sizeof(struct image_data) * smallest); } /* In the new buffers, allocate image memory */ { int i; for(i = smallest; i < new_size; i++) { tmp[i].image = mymalloc(cnt->imgs.size); memset(tmp[i].image, 0x80, cnt->imgs.size); /* initialize to grey */ } } /* Free the old ring */ free(cnt->imgs.image_ring); /* Point to the new ring */ cnt->imgs.image_ring = tmp; cnt->imgs.image_ring_size = new_size; } }}/** * image_ring_destroy * * This routine is called when we want to free the ring * * Parameters: * * cnt Pointer to the motion context structure * * Returns: nothing */static void image_ring_destroy(struct context *cnt){ unsigned short int i; /* Exit if don't have any ring */ if (cnt->imgs.image_ring == NULL) return; /* Free all image buffers */ for (i = 0; i < cnt->imgs.image_ring_size; i++) { free(cnt->imgs.image_ring[i].image); } /* Free the ring */ free(cnt->imgs.image_ring); cnt->imgs.image_ring = NULL; cnt->imgs.image_ring_size = 0;}/** * image_save_as_preview * * This routine is called when we detect motion and want to save a image in the preview buffer * * Parameters: * * cnt Pointer to the motion context structure * img Pointer to the image_data structure we want to set as preview image * * Returns: nothing */static void image_save_as_preview(struct context *cnt, struct image_data *img){ void * image; /* Save preview image pointer */ image = cnt->imgs.preview_image.image; /* Copy all info */ memcpy(&cnt->imgs.preview_image.image, img, sizeof(struct image_data)); /* restore image pointer */ cnt->imgs.preview_image.image = image; /* Copy image */ memcpy(cnt->imgs.preview_image.image, img->image, cnt->imgs.size); /* If we set output_all to yes and during the event * there is no image with motion, diffs is 0, we are not going to save the preview event */ if (cnt->imgs.preview_image.diffs == 0) cnt->imgs.preview_image.diffs = 1; /* If we have locate on it is already done */ if (cnt->locate == LOCATE_PREVIEW) { alg_draw_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image, LOCATE_NORMAL); }}/** * context_init * * Initializes a context struct with the default values for all the * variables. * * Parameters: * * cnt - the context struct to destroy * * Returns: nothing */static void context_init (struct context *cnt){ /* * We first clear the entire structure to zero, then fill in any * values which have non-zero default values. Note that this * assumes that a NULL address pointer has a value of binary 0 * (this is also assumed at other places within the code, i.e. * there are instances of "if (ptr)"). Just for possible future * changes to this assumption, any pointers which are intended * to be initialised to NULL are listed within a comment. */ memset(cnt, 0, sizeof(struct context)); cnt->noise = 255; cnt->lastrate = 25; memcpy(&cnt->track, &track_template, sizeof(struct trackoptions)); cnt->pipe = -1; cnt->mpipe = -1;}/** * context_destroy * * Destroys a context struct by freeing allocated memory, calling the * appropriate cleanup functions and finally freeing the struct itself. * * Parameters: * * cnt - the context struct to destroy * * Returns: nothing */static void context_destroy(struct context *cnt){ unsigned short int j; /* Free memory allocated for config parameters */ for (j = 0; config_params[j].param_name != NULL; j++) { if (config_params[j].copy == copy_string) { void **val; val = (void *)((char *)cnt+(int)config_params[j].conf_value); if (*val) { free(*val); *val = NULL; } } } free(cnt);}/** * sig_handler * * Our SIGNAL-Handler. We need this to handle alarms and external signals. */static void sig_handler(int signo){ short int i; switch(signo) { case SIGALRM: /* Somebody (maybe we ourself) wants us to make a snapshot * This feature triggers snapshots on ALL threads that have * snapshot_interval different from 0. */ if (cnt_list) { i = -1; while (cnt_list[++i]) { if (cnt_list[i]->conf.snapshot_interval) { cnt_list[i]->snapshot=1; } } } break; case SIGUSR1: /* Ouch! We have been hit from the outside! Someone wants us to make a movie! */ if (cnt_list) { i = -1; while (cnt_list[++i]) cnt_list[i]->makemovie=1; } break; case SIGHUP: restart = 1; /* Fall through, as the value of 'restart' is the only difference * between SIGHUP and the ones below. */ case SIGINT: case SIGQUIT: case SIGTERM: /* Somebody wants us to quit! We should better finish the actual movie and end up! */ if (cnt_list) { i = -1; while (cnt_list[++i]) { cnt_list[i]->makemovie=1; cnt_list[i]->finish=1; /* don't restart thread when it ends, * all threads restarts if global restart is set */ cnt_list[i]->restart=0; } } /* Set flag we want to quit main check threads loop * if restart is set (above) we start up again */ finish = 1; break; case SIGSEGV: exit(0); }}/** * sigchild_handler * * This function is a POSIX compliant replacement of the commonly used * signal(SIGCHLD, SIG_IGN). */static void sigchild_handler(int signo ATTRIBUTE_UNUSED){#ifdef WNOHANG while (waitpid(-1, NULL, WNOHANG) > 0) {};#endif /* WNOHANG */ return;}/** * motion_remove_pid * * This function remove the process id file ( pid file ) before motion exit. * */static void motion_remove_pid(void){ if ((cnt_list[0]->daemon) && (cnt_list[0]->conf.pid_file) && (restart == 0)) { if (!unlink(cnt_list[0]->conf.pid_file)) motion_log(LOG_INFO, 0, "Removed process id file (pid file)."); else motion_log(LOG_INFO, 1, "Error removing pid file"); }}/** * motion_detected * * Called from 'motion_loop' when motion is detected * Can be called when no motion if output_all is set! * * Parameters: * * cnt - current thread's context struct * dev - video device file descriptor * img - pointer to the captured image_data with detected motion */static void motion_detected(struct context *cnt, int dev, struct image_data *img){ struct config *conf = &cnt->conf; struct images *imgs = &cnt->imgs; struct coord *location = &img->location;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -