⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 motion.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 5 页
字号:
					event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, cnt->currenttime_tm);					/* if tracking is enabled we center our camera so it does not					 * point to a place where it will miss the next action					 */					if (cnt->track.type)						cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0);					if (cnt->conf.setup_mode)						motion_log(-1, 0, "End of event %d", cnt->event_nr);					cnt->makemovie = 0;					/* Finally we increase the event number */					cnt->event_nr++;					/* And we unset the text_event_string to avoid that buffered					 * images get a timestamp from previous event.					 */					cnt->text_event_string[0] = '\0';				}			}		/***** MOTION LOOP - REFERENCE FRAME SECTION *****/			/* Update reference frame */			if ((cnt->diffs > cnt->threshold * 2) ||			    (cnt->moved && (cnt->track.type || cnt->conf.lightswitch))) {				/* Prevent the motion created by moving camera or sudden light intensity				 * being detected by creating a fresh reference frame. Decaying is also				 * disabled when motion is above a certain threshold to make tracking				 * more accurate.				 */				memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size);			} else if (cnt->threshold) {				/* Old image slowly decays, this will make it even harder on			 	 * a slow moving object to stay undetected			 	 */				unsigned char *imgs_ref_ptr = cnt->imgs.ref;				unsigned char *newimg_ptr = cnt->imgs.image_virgin;				for (i=cnt->imgs.size-1; i>=0; i--) {					*imgs_ref_ptr = (*imgs_ref_ptr + *newimg_ptr)/2;					imgs_ref_ptr++;					newimg_ptr++;				}			}		/***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/			/* If setup_mode enabled output some numbers to console */			if (cnt->conf.setup_mode){				char msg[1024] = "\0";				char part[100];				if (cnt->conf.despeckle) {					snprintf(part, 99, "Raw changes: %5d - changes after '%s': %5d",					         olddiffs, cnt->conf.despeckle, cnt->diffs);					strcat(msg, part);					if (strchr(cnt->conf.despeckle, 'l')){						sprintf(part, " - labels: %3d", cnt->imgs.total_labels);						strcat(msg, part);					}				}				else{					sprintf(part, "Changes: %5d", cnt->diffs);					strcat(msg, part);				}				if (cnt->conf.noise_tune){					sprintf(part, " - noise level: %2d", cnt->noise);					strcat(msg, part);				}				if (cnt->conf.threshold_tune){					sprintf(part, " - threshold: %d", cnt->threshold);					strcat(msg, part);				}				motion_log(-1, 0, "%s", msg);			}		} /* get_image end */	/***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/		/* Did we get triggered to make a snapshot from control http? Then shoot a snap		 * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap		 * We actually allow the time to run over the interval in case we have a delay		 * from slow camera.		 * Note: Negative value means SIGALRM snaps are enabled		 * httpd-control snaps are always enabled.		 */		/* time_current_frame is used both for snapshot and timelapse features */		time_current_frame = cnt->currenttime;		if ( (cnt->conf.snapshot_interval > 0 && cnt->shots == 0 &&		      time_current_frame % cnt->conf.snapshot_interval <= time_last_frame % cnt->conf.snapshot_interval) ||		    cnt->snapshot) {			event(cnt, EVENT_IMAGE_SNAPSHOT, newimg, NULL, NULL, cnt->currenttime_tm);			cnt->snapshot = 0;		}	/***** MOTION LOOP - TIMELAPSE FEATURE SECTION *****/#ifdef HAVE_FFMPEG		if (cnt->conf.timelapse) {			/* Check to see if we should start a new timelapse file. We start one when			 * we are on the first shot, and and the seconds are zero. We must use the seconds			 * to prevent the timelapse file from getting reset multiple times during the minute.			 */			if (cnt->currenttime_tm->tm_min == 0 &&			    (time_current_frame % 60 < time_last_frame % 60) &&			    cnt->shots == 0) {				if (strcasecmp(cnt->conf.timelapse_mode,"manual") == 0)				;/* No action */				/* If we are daily, raise timelapseend event at midnight */				else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) {					if (cnt->currenttime_tm->tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);				}				/* handle the hourly case */				else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) {					event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);				}				/* If we are weekly-sunday, raise timelapseend event at midnight on sunday */				else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) {					if (cnt->currenttime_tm->tm_wday == 0 && cnt->currenttime_tm->tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);				}				/* If we are weekly-monday, raise timelapseend event at midnight on monday */				else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) {					if (cnt->currenttime_tm->tm_wday == 1 && cnt->currenttime_tm->tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);				}				/* If we are monthly, raise timelapseend event at midnight on first day of month */				else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) {					if (cnt->currenttime_tm->tm_mday == 1 && cnt->currenttime_tm->tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);				}				/* If invalid we report in syslog once and continue in manual mode */				else {					motion_log(LOG_ERR, 0, "Invalid timelapse_mode argument '%s'",					           cnt->conf.timelapse_mode);					motion_log(LOG_ERR, 0, "Defaulting to manual timelapse mode");					conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual");				}			}			/* If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0			 * add a timelapse frame to the timelapse mpeg.			 */			if (cnt->shots == 0 &&				time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse)				event(cnt, EVENT_TIMELAPSE, newimg, NULL, NULL, cnt->currenttime_tm);		}		/* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file		 * This is an important feature that allows manual roll-over of timelapse file using the http		 * remote control via a cron job.		 */		else if (cnt->ffmpeg_timelapse)			event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm);#endif /* HAVE_FFMPEG */		time_last_frame = time_current_frame;	/***** MOTION LOOP - VIDEO LOOPBACK SECTION *****/		/* feed last image and motion image to video device pipes and the webcam clients		 * In setup mode we send the special setup mode image to both webcam and vloopback pipe		 * In normal mode we feed the latest image to vloopback device and we send		 * the image to the webcam. We always send the first image in a second to the webcam.		 * Other image are sent only when the config option webcam_motion is off		 * The result is that with webcam_motion on the webcam stream is normally at the minimal		 * 1 frame per second but the minute motion is detected the motion_detected() function		 * sends all detected pictures to the webcam except the 1st per second which is already sent.		 */		if (cnt->conf.setup_mode) {			event(cnt, EVENT_IMAGE, cnt->imgs.out, NULL, &cnt->pipe, cnt->currenttime_tm);			event(cnt, EVENT_WEBCAM, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm);		} else {			event(cnt, EVENT_IMAGE, newimg, NULL, &cnt->pipe, cnt->currenttime_tm);			if (!cnt->conf.webcam_motion || cnt->shots == 1)				event(cnt, EVENT_WEBCAM, newimg, NULL, NULL, cnt->currenttime_tm);		}		event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm);	/***** MOTION LOOP - ONCE PER SECOND PARAMETER UPDATE SECTION *****/		/* Check for some config parameter changes but only every second */		if (cnt->shots == 0){			if (strcasecmp(cnt->conf.output_normal, "on") == 0)				cnt->new_img=NEWIMG_ON;			else if (strcasecmp(cnt->conf.output_normal, "first") == 0)				cnt->new_img=NEWIMG_FIRST;			else if (strcasecmp(cnt->conf.output_normal, "best") == 0){				cnt->new_img=NEWIMG_BEST;				/* allocate buffer here when not yet done */				if (!cnt->imgs.preview_buffer){					cnt->imgs.preview_buffer = mymalloc(cnt->imgs.size);					if (cnt->conf.setup_mode)						motion_log(-1, 0, "Preview buffer allocated");				}			}			else				cnt->new_img = NEWIMG_OFF;			if (strcasecmp(cnt->conf.locate, "on") == 0)				cnt->locate = LOCATE_ON;			else if (strcasecmp(cnt->conf.locate, "preview") == 0)				cnt->locate = LOCATE_PREVIEW;			else				cnt->locate = LOCATE_OFF;			/* Sanity check for smart_mask_speed, silly value disables smart mask */			if (cnt->conf.smart_mask_speed < 0 || cnt->conf.smart_mask_speed > 10)				cnt->conf.smart_mask_speed = 0;			/* Has someone changed smart_mask_speed or framerate? */			if (cnt->conf.smart_mask_speed != cnt->smartmask_speed || smartmask_lastrate != cnt->lastrate){				if (cnt->conf.smart_mask_speed == 0){					memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);					memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);				}				smartmask_lastrate = cnt->lastrate;				cnt->smartmask_speed = cnt->conf.smart_mask_speed;				/* Decay delay - based on smart_mask_speed (framerate independent)				   This is always 5*smartmask_speed seconds */				smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed);			}#if defined(HAVE_MYSQL) || defined(HAVE_PGSQL)			/* Set the sql mask file according to the SQL config options			 * We update it for every frame in case the config was updated			 * via remote control.			 */			cnt->sql_mask = cnt->conf.sql_log_image * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) +			                cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT +			                cnt->conf.sql_log_mpeg * (FTYPE_MPEG + FTYPE_MPEG_MOTION) +			                cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE;#endif /* defined(HAVE_MYSQL) || defined(HAVE_PGSQL) */		}	/***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/		/* Work out expected frame rate based on config setting which may		   have changed from http-control */		if (cnt->conf.frame_limit)			required_frame_time = 1000000L / cnt->conf.frame_limit;		else			required_frame_time = 0;		/* Get latest time to calculate time taken to process video data */		gettimeofday(&tv2, NULL);		elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - timenow;		/* Update history buffer but ignore first pass as timebefore		   variable will be inaccurate		 */		if (passflag)			rolling_average_data[rolling_frame] = timenow-timebefore;		else			passflag = 1;		rolling_frame++;		if (rolling_frame >= rolling_average_limit)			rolling_frame = 0;		/* Calculate 10 second average and use deviation in delay calculation */		rolling_average = 0L;		for (j=0; j < rolling_average_limit; j++)			rolling_average += rolling_average_data[j];		rolling_average /= rolling_average_limit;		frame_delay = required_frame_time-elapsedtime - (rolling_average - required_frame_time);		if (frame_delay > 0) {			/* Apply delay to meet frame time */			if (frame_delay > required_frame_time)				frame_delay = required_frame_time;			/* Delay time in nanoseconds for SLEEP */			delay_time_nsec = frame_delay * 1000;			if (delay_time_nsec > 999999999)				delay_time_nsec = 999999999;			/* SLEEP as defined in motion.h  A safe sleep using nanosleep */			SLEEP(0, delay_time_nsec);		}		/* This will limit the framerate to 1 frame while not detecting		   motion. Using a different motion flag to allow for multiple frames per second		 */		if (cnt->conf.low_cpu && !detecting_motion) {			/* Recalculate remaining time to delay for a total of 1/low_cpu seconds */			if (frame_delay + elapsedtime < (1000000L / cnt->conf.low_cpu)) {				frame_delay = (1000000L / cnt->conf.low_cpu) - frame_delay - elapsedtime;				/* Delay time in nanoseconds for SLEEP */				delay_time_nsec = frame_delay * 1000;				if (delay_time_nsec > 999999999)					delay_time_nsec = 999999999;				/* SLEEP as defined in motion.h  A safe sleep using nanosleep */				SLEEP(0, delay_time_nsec);				/* Correct frame times to ensure required_frame_time is maintained				 * This is done by taking the time NOW and subtract the time				 * required_frame_time. This way we pretend that timenow was set				 * one frame ago.				 */				gettimeofday(&tv1, NULL);				timenow = tv1.tv_usec + 1000000L * tv1.tv_sec - required_frame_time;			}		}	}	/* END OF MOTION MAIN LOOP	 * If code continues here it is because the thread is exiting or restarting	 */	if (cnt->netcam) {		netcam_cleanup(cnt->netcam, 0);		cnt->netcam = NULL;	}	if (rolling_average_data)		free(rolling_average_data);	motion_log(-1, 0, "Thread exiting");	if (!cnt->finish)		motion_log(LOG_ERR, 1, "Somebody stole the video device, lets hope we got his picture");	event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL);	pthread_mutex_lock(&global_lock);	threads_running--;	pthread_mutex_unlock(&global_lock);	pthread_exit(NULL);}/** * become_daemon * *   Turns Motion into a daemon through forking. The parent process (i.e. the *   one initially calling this function) will exit inside this function, while *   control will be returned to the child process. Standard input/output are *   released properly, and the current directory is set to / in order to not *   lock up any file system. * * Parameters: * *   cnt - current thread's context struct * * Returns: nothing */static void become_daemon(void){	int i;	FILE *pidf = NULL;		struct sigaction sig_ign_action;	/* Setup sig_ign_action */#ifdef SA_RESTART	sig_ign_action.sa_flags = SA_RESTART;#else	sig_ign_action.sa_flags = 0;#endif	sig_ign_action.sa_handler = SIG_IGN;	sigemptyset(&sig_ign_action.sa_mask);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -