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

📄 motion.c

📁 motion motion
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * motion_cleanup * * This routine is called from motion_loop when thread ends to * cleanup all memory etc. that motion_init did. * * Parameters: * *      cnt     Pointer to the motion context structure * * Returns:     nothing */static void motion_cleanup(struct context *cnt){	/* Stop webcam */	event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL);	if (cnt->video_dev >= 0){		motion_log(LOG_DEBUG, 0, "Calling vid_close() from motion_cleanup");				vid_close(cnt);	}	if (cnt->imgs.out) {		free(cnt->imgs.out);		cnt->imgs.out = NULL;	}	if (cnt->imgs.ref) {		free(cnt->imgs.ref);		cnt->imgs.ref = NULL;	}	if (cnt->imgs.ref_dyn) {		free(cnt->imgs.ref_dyn);		cnt->imgs.ref_dyn = NULL;	}	if (cnt->imgs.image_virgin) {		free(cnt->imgs.image_virgin);		cnt->imgs.image_virgin = NULL;	}	if (cnt->imgs.labels) {		free(cnt->imgs.labels);		cnt->imgs.labels = NULL;	}	if (cnt->imgs.labelsize) {		free(cnt->imgs.labelsize);		cnt->imgs.labelsize = NULL;	}	if (cnt->imgs.smartmask) {		free(cnt->imgs.smartmask);		cnt->imgs.smartmask = NULL;	}	if (cnt->imgs.smartmask_final) {		free(cnt->imgs.smartmask_final);		cnt->imgs.smartmask_final = NULL;	}	if (cnt->imgs.smartmask_buffer) {		free(cnt->imgs.smartmask_buffer);		cnt->imgs.smartmask_buffer = NULL;	}	if (cnt->imgs.common_buffer) {		free(cnt->imgs.common_buffer);		cnt->imgs.common_buffer = NULL;	}	if (cnt->imgs.preview_image.image) {		free(cnt->imgs.preview_image.image);		cnt->imgs.preview_image.image = NULL;	}	image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */	rotate_deinit(cnt); /* cleanup image rotation data */	if(cnt->pipe != -1) {		close(cnt->pipe);		cnt->pipe = -1;	}	if(cnt->mpipe != -1) {		close(cnt->mpipe);		cnt->mpipe = -1;	}	/* Cleanup the current time structure */	if (cnt->currenttime_tm) {		free(cnt->currenttime_tm);		cnt->currenttime_tm = NULL;	}	/* Cleanup the event time structure */	if (cnt->eventtime_tm) {		free(cnt->eventtime_tm);		cnt->eventtime_tm = NULL;	}}/** * motion_loop * *   Thread function for the motion handling threads. * */static void *motion_loop(void *arg){	struct context *cnt = arg;	int i, j, z = 0;	time_t lastframetime = 0;	int frame_buffer_size;	unsigned short int ref_frame_limit = 0; 	int area_once = 0; 	int area_minx[9], area_miny[9], area_maxx[9], area_maxy[9];	int smartmask_ratio = 0;	int smartmask_count = 20;	int smartmask_lastrate = 0;	int olddiffs = 0;	int previous_diffs = 0, previous_location_x = 0, previous_location_y = 0;	unsigned short int text_size_factor;	unsigned short int passflag = 0;	long int *rolling_average_data = NULL;	long int rolling_average_limit, required_frame_time, frame_delay, delay_time_nsec;	int rolling_frame = 0;	struct timeval tv1, tv2;	unsigned long int rolling_average, elapsedtime;	unsigned long long int timenow = 0, timebefore = 0;	int vid_return_code = 0;		/* Return code used when calling vid_next */	int minimum_frame_time_downcounter = cnt->conf.minimum_frame_time; /* time in seconds to skip between capturing images */	unsigned short int get_image = 1;	/* Flag used to signal that we capture new image when we run the loop */	/* Next two variables are used for snapshot and timelapse feature	 * time_last_frame is set to 1 so that first coming timelapse or second=0	 * is acted upon.	 */	unsigned long int time_last_frame=1, time_current_frame;	cnt->running = 1;		if (motion_init(cnt) < 0) {		goto err;	}	/* Initialize the double sized characters if needed. */	if(cnt->conf.text_double)		text_size_factor = 2;	else		text_size_factor = 1;	/* Initialize area detection */	area_minx[0] = area_minx[3] = area_minx[6] = area_miny[0] = area_miny[1] = area_miny[2] = 0;	area_minx[1] = area_minx[4] = area_minx[7] = area_maxx[0] = area_maxx[3] = area_maxx[6] = cnt->imgs.width / 3;	area_minx[2] = area_minx[5] = area_minx[8] = area_maxx[1] = area_maxx[4] = area_maxx[7] = cnt->imgs.width / 3 * 2;	area_miny[3] = area_miny[4] = area_miny[5] = area_maxy[0] = area_maxy[1] = area_maxy[2] = cnt->imgs.height / 3;	area_miny[6] = area_miny[7] = area_miny[8] = area_maxy[3] = area_maxy[4] = area_maxy[5] = cnt->imgs.height / 3 * 2;	area_maxx[2] = area_maxx[5] = area_maxx[8] = cnt->imgs.width;	area_maxy[6] = area_maxy[7] = area_maxy[8] = cnt->imgs.height;		/* Work out expected frame rate based on config setting */	if (cnt->conf.frame_limit < 2) cnt->conf.frame_limit = 2;	required_frame_time = 1000000L / cnt->conf.frame_limit;	frame_delay = required_frame_time;	/*	 * Reserve enough space for a 10 second timing history buffer. Note that,	 * if there is any problem on the allocation, mymalloc does not return.	 */	rolling_average_limit = 10 * cnt->conf.frame_limit;	rolling_average_data = mymalloc(sizeof(rolling_average_data) * rolling_average_limit);	/* Preset history buffer with expected frame rate */	for (j=0; j< rolling_average_limit; j++)		rolling_average_data[j]=required_frame_time;	/* MAIN MOTION LOOP BEGINS HERE */	/* Should go on forever... unless you bought vaporware :) */	while (!cnt->finish || cnt->makemovie) {	/***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/		cnt->watchdog = WATCHDOG_TMO;		/* Get current time and preserver last time for frame interval calc. */		timebefore = timenow;		gettimeofday(&tv1, NULL);		timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;		/* since we don't have sanity checks done when options are set,		 * this sanity check must go in the main loop :(, before pre_captures		 * are attempted. */		if (cnt->conf.minimum_motion_frames < 1)			cnt->conf.minimum_motion_frames = 1;		if (cnt->conf.pre_capture < 0)			cnt->conf.pre_capture = 0;		/* Check if our buffer is still the right size		 * If pre_capture or minimum_motion_frames has been changed		 * via the http remote control we need to re-size the ring buffer		 */		frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames;		if (cnt->imgs.image_ring_size != frame_buffer_size) {			image_ring_resize(cnt, frame_buffer_size);		}		/* Get time for current frame */		cnt->currenttime = time(NULL);		/* localtime returns static data and is not threadsafe		 * so we use localtime_r which is reentrant and threadsafe		 */		localtime_r(&cnt->currenttime, cnt->currenttime_tm);		/* If we have started on a new second we reset the shots variable		 * lastrate is updated to be the number of the last frame. last rate		 * is used as the ffmpeg framerate when motion is detected.		 */		if (lastframetime != cnt->currenttime) {			cnt->lastrate = cnt->shots + 1;			cnt->shots = -1;			lastframetime = cnt->currenttime;			if (cnt->conf.minimum_frame_time) {				minimum_frame_time_downcounter--;				if (minimum_frame_time_downcounter == 0)					get_image = 1;			}			else				get_image = 1;		}		/* Increase the shots variable for each frame captured within this second */		cnt->shots++;		if (cnt->startup_frames > 0)			cnt->startup_frames--;		if (get_image){			if (cnt->conf.minimum_frame_time) {				minimum_frame_time_downcounter = cnt->conf.minimum_frame_time;				get_image = 0;			}			/* ring_buffer_in is pointing to current pos, update before put in a new image */			if (++cnt->imgs.image_ring_in >= cnt->imgs.image_ring_size)				cnt->imgs.image_ring_in = 0;			/* Check if we have filled the ring buffer, throw away last image */			if (cnt->imgs.image_ring_in == cnt->imgs.image_ring_out) {				if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size)					cnt->imgs.image_ring_out = 0;			}			/* cnt->current_image points to position in ring where to store image, diffs etc. */			cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in];			/* Init/clear current_image */			{				/* Store time with pre_captured image */				cnt->current_image->timestamp = cnt->currenttime;				localtime_r(&cnt->current_image->timestamp, &cnt->current_image->timestamp_tm);				/* Store shot number with pre_captured image */				cnt->current_image->shot = cnt->shots;				/* set diffs to 0 now, will be written after we calculated diffs in new image */				cnt->current_image->diffs = 0;				/* Set flags to 0 */				cnt->current_image->flags = 0;				cnt->current_image->cent_dist = 0;				/* Clear location data */				memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location));				cnt->current_image->total_labels = 0;			}		/***** MOTION LOOP - RETRY INITIALIZING SECTION *****/			/* If a camera is not available we keep on retrying every 10 seconds			 * until it shows up.			 */			if (cnt->video_dev < 0 &&			    cnt->currenttime % 10 == 0 && cnt->shots == 0) {				motion_log(LOG_ERR, 0,				           "Retrying until successful connection with camera");				cnt->video_dev = vid_start(cnt);				/* if the netcam has different dimensions than in the config file				 * we need to restart Motion to re-allocate all the buffers				 */				if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) {					motion_log(LOG_ERR, 0, "Camera has finally become available");					motion_log(LOG_ERR, 0, "Camera image has different width and height "					                       "from what is in the config file. You should fix that");					motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all "					                       "image buffers to new picture dimensions");					cnt->conf.width = cnt->imgs.width;					cnt->conf.height = cnt->imgs.height;					/* Break out of main loop terminating thread 					 * watchdog will start us again */					break;				}			}		/***** MOTION LOOP - IMAGE CAPTURE SECTION *****/			/* Fetch next frame from camera			 * If vid_next returns 0 all is well and we got a new picture			 * Any non zero value is an error.			 * 0 = OK, valid picture			 * <0 = fatal error - leave the thread by breaking out of the main loop			 * >0 = non fatal error - copy last image or show grey image with message			 */			if (cnt->video_dev >= 0)				vid_return_code = vid_next(cnt, cnt->current_image->image);			else				vid_return_code = 1; /* Non fatal error */			// VALID PICTURE			if (vid_return_code == 0) {				cnt->lost_connection = 0;				cnt->connectionlosttime = 0;				/* If all is well reset missing_frame_counter */				if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) {					/* If we previously logged starting a grey image, now log video re-start */					motion_log(LOG_ERR, 0, "Video signal re-acquired");					// event for re-acquired video signal can be called here				}				cnt->missing_frame_counter = 0;#ifdef HAVE_FFMPEG				/* Deinterlace the image with ffmpeg, before the image is modified. */				if(cnt->conf.ffmpeg_deinterlace) {					ffmpeg_deinterlace(cnt->current_image->image, cnt->imgs.width, cnt->imgs.height);				}#endif				/* save the newly captured still virgin image to a buffer				 * which we will not alter with text and location graphics				 */				memcpy(cnt->imgs.image_virgin, cnt->current_image->image, cnt->imgs.size);				/* If the camera is a netcam we let the camera decide the pace.				 * Otherwise we will keep on adding duplicate frames.				 * By resetting the timer the framerate becomes maximum the rate				 * of the Netcam.				 */				if (cnt->conf.netcam_url) {					gettimeofday(&tv1, NULL);					timenow = tv1.tv_usec + 1000000L * tv1.tv_sec;				}			// FATAL ERROR - leave the thread by breaking out of the main loop				} else if (vid_return_code < 0) {				/* Fatal error - Close video device */				motion_log(LOG_ERR, 0, "Video device fatal error - Closing video device");				vid_close(cnt);				/* Use virgin image, if we are not able to open it again next loop				 * a gray image with message is applied				 * flag lost_connection				 */				memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size);				cnt->lost_connection = 1;			/* NO FATAL ERROR -  			*		copy last image or show grey image with message 			*		flag on lost_connection if :			*               vid_return_code == NETCAM_RESTART_ERROR  			*		cnt->video_dev < 0			*		cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)			*/						} else { 				if (debug_level >= CAMERA_VERBOSE)					motion_log(-1, 0, "vid_return_code %d", vid_return_code);				/* Netcams that change dimensions while Motion is running will				 * require that Motion restarts to reinitialize all the many				 * buffers inside Motion. It will be a mess to try and recover any				 * other way				 */				if (vid_return_code == NETCAM_RESTART_ERROR) {					motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all "					                       "image buffers");					/* Break out of main loop terminating thread 

⌨️ 快捷键说明

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