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

📄 motion.c

📁 motion motion
💻 C
📖 第 1 页 / 共 5 页
字号:
					cnt->makemovie = 1;			/* Now test for quiet longer than 'gap' OR make movie as decided in			 * previous statement.			 */			if (((cnt->currenttime - cnt->lasttime >= cnt->conf.gap) && cnt->conf.gap > 0) || cnt->makemovie) {				if (cnt->event_nr == cnt->prev_event || cnt->makemovie) {					/* Flush image buffer */					process_image_ring(cnt, IMAGE_BUFFER_FLUSH);					/* Save preview_shot here at the end of event */					if (cnt->imgs.preview_image.diffs) {						preview_save(cnt);						cnt->imgs.preview_image.diffs = 0;					}					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;					/* Reset post capture */					cnt->postcap = 0;					/* Finally we increase the event number */					cnt->event_nr++;					cnt->lightswitch_framecounter = 0;					/* And we unset the text_event_string to avoid that buffered					 * images get a timestamp from previous event.					 */					cnt->text_event_string[0] = '\0';				}			}			/* Save/send to movie some images */			process_image_ring(cnt, 2);		/***** 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->current_image->diffs);					strcat(msg, part);					if (strchr(cnt->conf.despeckle, 'l')){						sprintf(part, " - labels: %3d", cnt->current_image->total_labels);						strcat(msg, part);					}				}				else{					sprintf(part, "Changes: %5d", cnt->current_image->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, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_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->current_image->timestamp_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->current_image->timestamp_tm.tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm);				}				/* handle the hourly case */				else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) {					event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_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->current_image->timestamp_tm.tm_wday == 0 && cnt->current_image->timestamp_tm.tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_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->current_image->timestamp_tm.tm_wday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_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->current_image->timestamp_tm.tm_mday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0)						event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_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, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_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, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm);			if (!cnt->conf.webcam_motion || cnt->shots == 1)				event(cnt, EVENT_WEBCAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_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;			else if (strcasecmp(cnt->conf.output_normal, "center") == 0)				cnt->new_img = NEWIMG_CENTER;			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);		}	}	/* END OF MOTION MAIN LOOP	 * If code continues here it is because the thread is exiting or restarting	 */err:	if (rolling_average_data)		free(rolling_average_data);	cnt->lost_connection = 1;	motion_log(-1, 0, "Thread exiting");	motion_cleanup(cnt);	pthread_mutex_lock(&global_lock);	threads_running--;	pthread_mutex_unlock(&global_lock);	if (!cnt->restart)		cnt->watchdog=WATCHDOG_OFF;	cnt->running = 0;	cnt->finish = 0;	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);	/* fork */	if (fork()) {		motion_log(-1, 0, "Motion going to daemon mode");		exit(0);	}		/* Create the pid file if defined, if failed exit	 * If we fail we report it. If we succeed we postpone the log entry till	 * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting	 * for an enter.	 */	if (cnt_list[0]->conf.pid_file) {		pidf = fopen(cnt_list[0]->conf.pid_file, "w+");			if ( pidf ) {			(void)fprintf(pidf, "%d\n", getpid());			fclose(pidf);		} else {			motion_log(LOG_ERR, 1, "Exit motion,

⌨️ 快捷键说明

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