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

📄 motion.c

📁 motion motion
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Draw location */	if (cnt->locate == LOCATE_ON)		alg_draw_location(location, imgs, imgs->width, img->image, LOCATE_BOTH);	/* Calculate how centric motion is if configured preview center*/	if (cnt->new_img & NEWIMG_CENTER) {		unsigned int distX = abs((imgs->width/2) - location->x);		unsigned int distY = abs((imgs->height/2) - location->y);		img->cent_dist = distX*distX + distY*distY;	}	/* Do things only if we have got minimum_motion_frames */	if (img->flags & IMAGE_TRIGGER) {		/* Take action if this is a new event and we have a trigger image */		if (cnt->event_nr != cnt->prev_event) {			/* Reset prev_event number to current event and save event time			 * in both time_t and struct tm format.			 */			cnt->prev_event = cnt->event_nr;			cnt->eventtime = img->timestamp;			localtime_r(&cnt->eventtime, cnt->eventtime_tm);			/* Since this is a new event we create the event_text_string used for			 * the %C conversion specifier. We may already need it for			 * on_motion_detected_commend so it must be done now.			 */			mystrftime(cnt, cnt->text_event_string, sizeof(cnt->text_event_string),			           cnt->conf.text_event, cnt->eventtime_tm, NULL, 0);			/* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */			event(cnt, EVENT_FIRSTMOTION, img->image, NULL, NULL, &img->timestamp_tm);			if (cnt->conf.setup_mode)				motion_log(-1, 0, "Motion detected - starting event %d", cnt->event_nr);			/* always save first motion frame as preview-shot, may be changed to an other one later */			if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) {				image_save_as_preview(cnt, img);			}		}		/* EVENT_MOTION triggers event_beep and on_motion_detected_command */		event(cnt, EVENT_MOTION, NULL, NULL, NULL, &img->timestamp_tm);	}	/* Limit framerate */	if (img->shot < conf->frame_limit) {		/* If config option webcam_motion is enabled, send the latest motion detected image		 * to the webcam but only if it is not the first shot within a second. This is to		 * avoid double frames since we already have sent a frame to the webcam.		 * We also disable this in setup_mode.		 */		if (conf->webcam_motion && !conf->setup_mode && img->shot != 1) {			event(cnt, EVENT_WEBCAM, img->image, NULL, NULL, &img->timestamp_tm);		}		/* Save motion jpeg, if configured */		/* Output the image_out (motion) picture. */		if (conf->motion_img) {			event(cnt, EVENT_IMAGEM_DETECTED, NULL, NULL, NULL, &img->timestamp_tm);		}	}	if (cnt->track.type) {		cnt->moved = track_move(cnt, dev, location, imgs, 0);	}}/** * process_image_ring * *   Called from 'motion_loop' to save images / send images to movie * * Parameters: * *   cnt        - current thread's context struct *   max_images - Max number of images to process *                Set to IMAGE_BUFFER_FLUSH to send/save all images in buffer */#define IMAGE_BUFFER_FLUSH ((unsigned int)-1)static void process_image_ring(struct context *cnt, unsigned int max_images){	/* we are going to send an event, in the events there is still	 * some code that use cnt->current_image	 * so set it temporary to our image */	struct image_data *saved_current_image = cnt->current_image;	/* If image is flaged to be saved and not saved yet, process it */	do {		/* Check if we should save/send this image, breakout if not */		if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & (IMAGE_SAVE | IMAGE_SAVED)) != IMAGE_SAVE)			break;		/* Set inte global cotext that we are working with this image */		cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_out];		if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot < cnt->conf.frame_limit) {			/* Output the picture to jpegs and ffmpeg */			event(cnt, EVENT_IMAGE_DETECTED,			      cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, 			      &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm);		}		/* Mark the image as saved */		cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags |= IMAGE_SAVED;		/* Store it as a preview image, only if it have motion */		if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_MOTION)		{			/* Check for most significant preview-shot when output_normal=best */			if (cnt->new_img & NEWIMG_BEST) {				if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].diffs > cnt->imgs.preview_image.diffs) {					image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]);				}			}			/* Check for most significant preview-shot when output_normal=center */			if (cnt->new_img & NEWIMG_CENTER) {				if(cnt->imgs.image_ring[cnt->imgs.image_ring_out].cent_dist < cnt->imgs.preview_image.cent_dist) {					image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]);				}			}		}		/* Increment to image after last sended */		if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size)			cnt->imgs.image_ring_out = 0;		if (max_images != IMAGE_BUFFER_FLUSH) {			max_images--;			/* breakout if we have done max_images */			if (max_images == 0)				break;		}		/* loop until out and in is same e.g. buffer empty */	} while (cnt->imgs.image_ring_out != cnt->imgs.image_ring_in);	/* restore global context values */	cnt->current_image = saved_current_image;}/** * motion_init * * This routine is called from motion_loop (the main thread of the program) to do * all of the initialisation required before starting the actual run. * * Parameters: * *      cnt     Pointer to the motion context structure * * Returns:     0 OK *             -1 Fatal error, open loopback error *             -2 Fatal error, open SQL database error */static int motion_init(struct context *cnt){	int i;	FILE *picture;	/* Store thread number in TLS. */	pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr));	cnt->currenttime_tm = mymalloc(sizeof(struct tm));	cnt->eventtime_tm = mymalloc(sizeof(struct tm));	/* Init frame time */	cnt->currenttime = time(NULL);	localtime_r(&cnt->currenttime, cnt->currenttime_tm);	cnt->smartmask_speed = 0;	/* We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so	 * that certain code below does not run until motion has been detected the first time */	cnt->event_nr = 1;	cnt->prev_event = 0;	cnt->lightswitch_framecounter = 0;	cnt->detecting_motion = 0;	cnt->makemovie = 0;	motion_log(LOG_DEBUG, 0, "Thread %d started", (unsigned long)pthread_getspecific(tls_key_threadnr));	if (!cnt->conf.filepath)		cnt->conf.filepath = strdup(".");	/* set the device settings */	cnt->video_dev = vid_start(cnt);	/* We failed to get an initial image from a camera	 * So we need to guess height and width based on the config	 * file options.	 */	if (cnt->video_dev < 0) {		motion_log(LOG_ERR, 0, "Could not fetch initial image from camera");		motion_log(LOG_ERR, 0, "Motion continues using width and height from config file(s)");		cnt->imgs.width = cnt->conf.width;		cnt->imgs.height = cnt->conf.height;		cnt->imgs.size = cnt->conf.width * cnt->conf.height * 3 / 2;		cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height;		cnt->imgs.type = VIDEO_PALETTE_YUV420P;	}	image_ring_resize(cnt, 1); /* Create a initial precapture ring buffer with 1 frame */	cnt->imgs.ref = mymalloc(cnt->imgs.size);	cnt->imgs.out = mymalloc(cnt->imgs.size);	memset(cnt->imgs.out, 0, cnt->imgs.size);	cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn));  /* contains the moving objects of ref. frame */	cnt->imgs.image_virgin = mymalloc(cnt->imgs.size);	cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize);	cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize);	cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.smartmask_buffer));	cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.labels));	cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(cnt->imgs.labelsize));	/* allocate buffer here for preview buffer */	cnt->imgs.preview_image.image = mymalloc(cnt->imgs.size);	/* Allocate a buffer for temp. usage in some places */	/* Only despeckle & bayer2rgb24() for now for now... */	cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height);	/* Now is a good time to init rotation data. Since vid_start has been	 * called, we know that we have imgs.width and imgs.height. When capturing	 * from a V4L device, these are copied from the corresponding conf values	 * in vid_start. When capturing from a netcam, they get set in netcam_start,	 * which is called from vid_start.	 *	 * rotate_init will set cap_width and cap_height in cnt->rotate_data.	 */	rotate_init(cnt); /* rotate_deinit is called in main */	/* Capture first image, or we will get an alarm on start */	if (cnt->video_dev > 0) {		for (i = 0; i < 5; i++) {			if (vid_next(cnt, cnt->imgs.image_virgin) == 0)				break;			SLEEP(2,0);		}		if (i >= 5) {			memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size);       /* initialize to grey */			draw_text(cnt->imgs.image_virgin, 10, 20, cnt->imgs.width,			          "Error capturing first image", cnt->conf.text_double);			motion_log(LOG_ERR, 0, "Error capturing first image");		}	}	/* create a reference frame */	alg_update_reference_frame(cnt, RESET_REF_FRAME);#ifndef WITHOUT_V4L#if (!defined(BSD))	/* open video loopback devices if enabled */	if (cnt->conf.vidpipe) {		if (cnt->conf.setup_mode)			motion_log(-1, 0, "Opening video loopback device for normal pictures");		/* vid_startpipe should get the output dimensions */		cnt->pipe = vid_startpipe(cnt->conf.vidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type);		if (cnt->pipe < 0) {			motion_log(LOG_ERR, 0, "Failed to open video loopback");			return -1;		}	}	if (cnt->conf.motionvidpipe) {		if (cnt->conf.setup_mode)			motion_log(-1, 0, "Opening video loopback device for motion pictures");		/* vid_startpipe should get the output dimensions */		cnt->mpipe = vid_startpipe(cnt->conf.motionvidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type);		if (cnt->mpipe < 0) {			motion_log(LOG_ERR, 0, "Failed to open video loopback");			return -1;		}	}#endif /* BSD */#endif /*WITHOUT_V4L*/#ifdef HAVE_MYSQL	if(cnt->conf.mysql_db) {		cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL));		mysql_init(cnt->database);		if (!mysql_real_connect(cnt->database, cnt->conf.mysql_host, cnt->conf.mysql_user,		    cnt->conf.mysql_password, cnt->conf.mysql_db, 0, NULL, 0)) {			motion_log(LOG_ERR, 0, "Cannot connect to MySQL database %s on host %s with user %s",			           cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user);			motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database));			return -2;		}		#if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)		my_bool  my_true = TRUE;		mysql_options(cnt->database,MYSQL_OPT_RECONNECT,&my_true);		#endif	}#endif /* HAVE_MYSQL */#ifdef HAVE_PGSQL	if (cnt->conf.pgsql_db) {		char connstring[255];		/* create the connection string.		   Quote the values so we can have null values (blank)*/		snprintf(connstring, 255,		         "dbname='%s' host='%s' user='%s' password='%s' port='%d'",		         cnt->conf.pgsql_db, /* dbname */		         (cnt->conf.pgsql_host ? cnt->conf.pgsql_host : ""), /* host (may be blank) */		         (cnt->conf.pgsql_user ? cnt->conf.pgsql_user : ""), /* user (may be blank) */		         (cnt->conf.pgsql_password ? cnt->conf.pgsql_password : ""), /* password (may be blank) */		          cnt->conf.pgsql_port		);		cnt->database_pg = PQconnectdb(connstring);		if (PQstatus(cnt->database_pg) == CONNECTION_BAD) {			motion_log(LOG_ERR, 0, "Connection to PostgreSQL database '%s' failed: %s",			           cnt->conf.pgsql_db, PQerrorMessage(cnt->database_pg));			return -2;		}	}#endif /* HAVE_PGSQL */#if defined(HAVE_MYSQL) || defined(HAVE_PGSQL)	/* Set the sql mask file according to the SQL config options*/	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) */	/* Load the mask file if any */	if (cnt->conf.mask_file) {		if ((picture = fopen(cnt->conf.mask_file, "r"))) {			/* NOTE: The mask is expected to have the output dimensions. I.e., the mask			 * applies to the already rotated image, not the capture image. Thus, use			 * width and height from imgs.			 */			cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height);			fclose(picture);		} else {			motion_log(LOG_ERR, 1, "Error opening mask file %s", cnt->conf.mask_file);			/* Try to write an empty mask file to make it easier			   for the user to edit it */			put_fixed_mask(cnt, cnt->conf.mask_file);		}		if (!cnt->imgs.mask) {			motion_log(LOG_ERR, 0, "Failed to read mask image. Mask feature disabled.");		} else {			if (cnt->conf.setup_mode)				motion_log(-1, 0, "Maskfile \"%s\" loaded.",cnt->conf.mask_file);		}	} else		cnt->imgs.mask=NULL;	/* Always initialize smart_mask - someone could turn it on later... */	memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize);	memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize);	memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize*sizeof(cnt->imgs.smartmask_buffer));	/* Set noise level */	cnt->noise = cnt->conf.noise;	/* Set threshold value */	cnt->threshold = cnt->conf.max_changes;	/* Initialize webcam server if webcam port is specified to not 0 */	if (cnt->conf.webcam_port) {		if ( webcam_init(cnt) == -1 ) {			motion_log(LOG_ERR, 1, "Problem enabling stream server in port %d", cnt->conf.webcam_port);			cnt->finish = 1;		}else 	motion_log(LOG_DEBUG, 0, "Started stream webcam server in port %d", cnt->conf.webcam_port);	}	/* Prevent first few frames from triggering motion... */	cnt->moved = 8;	/* 2 sec startup delay so FPS is calculated correct */	cnt->startup_frames = cnt->conf.frame_limit * 2;	return 0;}

⌨️ 快捷键说明

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