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

📄 motion.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 5 页
字号:
			*(cnt->imgs.timestamp + cnt->precap_cur) = cnt->currenttime;			/* Store shot number with pre_captured image*/			*(cnt->imgs.shotstamp+cnt->precap_cur) = cnt->shots;			/* newimg now points to the current image. With precap_cur incremented it			 * will be pointing to the position in the buffer for the NEXT image frame			 * not the current!!! So newimg points to current frame about to be loaded			 * and the cnt->precap_cur already have been incremented to point to the			 * next frame.			 */			newimg = cnt->imgs.image_ring_buffer + (cnt->imgs.size * (cnt->precap_cur++));			/* If we are at the end of the ring buffer go to the start */			if (cnt->precap_cur > cnt->precap_nr)				cnt->precap_cur=0;		/***** MOTION LOOP - RETRY INITIALIZING NETCAM SECTION *****/			/* If a network camera is not available we keep on retrying every 10 seconds			 * until it shows up.			 */			if (cnt->video_dev == -1 && cnt->conf.netcam_url &&			    cnt->currenttime % 10 == 0 && cnt->shots == 0) {				motion_log(LOG_ERR, 0,				           "Retrying until successful initial connection with network camera");				netcam_cleanup(cnt->netcam, 1);				cnt->netcam = NULL;				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->imgs.width || cnt->imgs.height != cnt->conf.height) {					motion_log(LOG_ERR, 0, "Network camera has finally become available");					motion_log(LOG_ERR, 0, "Network 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 to reinitialize all "					                       "image buffers to new picture dimensions");					kill(getpid(), 1);					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			 */			vid_return_code = vid_next(cnt, newimg);			if (vid_return_code == 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(newimg, 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, newimg, 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;				}			} else {				if (vid_return_code < 0) {					/* Fatal error - break out of main loop terminating thread */					motion_log(LOG_ERR, 0, "Video device fatal error - terminating camera thread");					break;				} else {       /* Non fatal errors */					if (debug_level)						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 to reinitialize all "						                       "image buffers");						kill(getpid(), 1);						break;					}					/* First missed frame - store timestamp */					if (!cnt->missing_frame_counter)						cnt->connectionlosttime = cnt->currenttime;					/* If we are waiting for first image prevent the					 * cnt->connectionlosttime from being updated each time we come back					 */					if (cnt->video_dev == -1)						cnt->missing_frame_counter = 1;					/* Increase missing_frame_counter					 * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image					 * After 30 seconds we put a grey error image in the buffer					 * Note: at low_cpu the timeout will be longer but we live with that					 * If we still have not yet received the initial image from a camera					 * we go straight for the grey error image.					 */					if (cnt->video_dev != -1 &&					    ++cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)) {						memcpy(newimg, cnt->imgs.image_virgin, cnt->imgs.size);					} else {						char tmpout[80];						char tmpin[] = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T";						struct tm tmptime;						localtime_r(&cnt->connectionlosttime, &tmptime);						memset(newimg, 0x80, cnt->imgs.size);						mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tmptime, NULL, 0);						draw_text(newimg, 10, 20 * text_size_factor, cnt->imgs.width,						          tmpout, cnt->conf.text_double);						/* Write error message only once */						if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) {							motion_log(LOG_ERR, 0, "Video signal lost - Adding grey image");							// Event for lost video signal can be called from here						}					}				}			}		/***** MOTION LOOP - MOTION DETECTION SECTION *****/			/* The actual motion detection takes place in the following			 * diffs is the number of pixels detected as changed			 * Make a differences picture in image_out			 *			 * alg_diff_standard is the slower full feature motion detection algorithm			 * alg_diff first calls a fast detection algorithm which only looks at a			 *   fraction of the pixels. If this detects possible motion alg_diff_standard			 *   is called.			 */			if (cnt->threshold && !cnt->pause) {				/* if we've already detected motion and we want to see if there's				 * still motion, don't bother trying the fast one first. IF there's				 * motion, the alg_diff will trigger alg_diff_standard				 * anyway				 */				if (detecting_motion || cnt->conf.setup_mode)					cnt->diffs = alg_diff_standard(cnt, cnt->imgs.image_virgin);				else					cnt->diffs = alg_diff(cnt, cnt->imgs.image_virgin);				/* Lightswitch feature - has light intensity changed?				 * This can happen due to change of light conditions or due to a sudden change of the camera				 * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next				 * 5 frames to allow the camera to settle.				 */				if (cnt->conf.lightswitch) {					if (alg_lightswitch(cnt, cnt->diffs)) {						if (cnt->conf.setup_mode)							motion_log(-1, 0, "Lightswitch detected");						if (cnt->moved < 5)							cnt->moved = 5;						cnt->diffs = 0;					}				}				/* Switchfilter feature tries to detect a change in the video signal				 * from one camera to the next. This is normally used in the Round				 * Robin feature. The algorithm is not very safe.				 * The algorithm takes a little time so we only call it when needed				 * ie. when feature is enabled and diffs>threshold.				 * We do not suspend motion detection like we did for lightswitch				 * because with Round Robin this is controlled by roundrobin_skip.				 */				if (cnt->conf.switchfilter && cnt->diffs > cnt->threshold) {					cnt->diffs = alg_switchfilter(cnt, cnt->diffs, newimg);					if (cnt->diffs <= cnt->threshold) {						cnt->diffs = 0;						if (cnt->conf.setup_mode)							motion_log(-1, 0, "Switchfilter detected");					}				}				/* Despeckle feature				 * First we run (as given by the despeckle option iterations				 * of erode and dilate algorithms.				 * Finally we run the labelling feature.				 * All this is done in the alg_despeckle code.				 */				cnt->imgs.total_labels = 0;				cnt->imgs.largest_label = 0;				olddiffs = 0;				if (cnt->conf.despeckle && cnt->diffs > 0) {					olddiffs = cnt->diffs;					cnt->diffs = alg_despeckle(cnt, olddiffs);				}else if (cnt->imgs.labelsize_max)					cnt->imgs.labelsize_max = 0; /* Disable labeling if enabled */			} else if (!cnt->conf.setup_mode)				cnt->diffs = 0;			/* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */			if (cnt->smartmask_speed) {				if (!--smartmask_count){					alg_tune_smartmask(cnt);					smartmask_count = smartmask_ratio;				}			}			/* cnt->moved is set by the tracking code when camera has been asked to move.			 * When camera is moving we do not want motion to detect motion or we will			 * get our camera chasing itself like crazy and we will get motion detected			 * which is not really motion. So we pretend there is no motion by setting			 * cnt->diffs = 0.			 * We also pretend to have a moving camera when we start Motion and when light			 * switch has been detected to allow camera to settle.			 */			if (cnt->moved) {				cnt->moved--;				cnt->diffs = 0;			}		/***** MOTION LOOP - TUNING SECTION *****/			/* if noise tuning was selected, do it now. but only when			 * no frames have been recorded and only once per second			 */			if (cnt->conf.noise_tune && cnt->shots == 0) {				if (!detecting_motion && (cnt->diffs <= cnt->threshold))					alg_noise_tune(cnt, cnt->imgs.image_virgin);			}			/* if we are not noise tuning lets make sure that remote controlled			 * changes of noise_level are used.			 */			if (!cnt->conf.noise_tune)				cnt->noise = cnt->conf.noise;			/* threshold tuning if enabled			 * if we are not threshold tuning lets make sure that remote controlled			 * changes of threshold are used.			 */			if (cnt->conf.threshold_tune)				alg_threshold_tune(cnt, cnt->diffs, detecting_motion);			else				cnt->threshold = cnt->conf.max_changes;		/***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/			/* Some overlays on top of the motion image			 * Note that these now modifies the cnt->imgs.out so this buffer			 * can no longer be used for motion detection features until next			 * picture frame is captured.			 */			/* Fixed mask overlay */			if (cnt->imgs.mask && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) )				overlay_fixed_mask(cnt, cnt->imgs.out);			/* Smartmask overlay */			if (cnt->smartmask_speed && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) )				overlay_smartmask(cnt, cnt->imgs.out);			/* Largest labels overlay */			if (cnt->imgs.largest_label && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) )				overlay_largest_label(cnt, cnt->imgs.out);			/* If motion is detected (cnt->diffs > cnt->threshold) and before we add text to the pictures			   we find the center and size coordinates of the motion to be used for text overlays and later			   for adding the locate rectangle */			if (cnt->diffs > cnt->threshold)				 alg_locate_center_size(&cnt->imgs, cnt->imgs.width, cnt->imgs.height, &cnt->location);			/* Initialize the double sized characters if needed. */			if(cnt->conf.text_double && text_size_factor == 1)				text_size_factor = 2;			/* If text_double is set to off, then reset the scaling text_size_factor. */			else if(!cnt->conf.text_double && text_size_factor == 2) {				text_size_factor = 1;			}			/* Add changed pixels in upper right corner of the pictures */			if (cnt->conf.text_changes) {				char tmp[15];				if (!cnt->pause)					sprintf(tmp, "%d", cnt->diffs);				else					sprintf(tmp, "-");				draw_text(newimg, cnt->imgs.width - 10, 10, cnt->imgs.width, tmp, cnt->conf.text_double);			}			/* Add changed pixels to motion-images (for webcam) in setup_mode			   and always overlay smartmask (not only when motion is detected) */			if (cnt->conf.setup_mode) {				char tmp[PATH_MAX];				sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->diffs, cnt->imgs.total_labels, cnt->noise);				draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 30 * text_size_factor,				          cnt->imgs.width, tmp, cnt->conf.text_double);				sprintf(tmp, "THREAD %d SETUP", cnt->threadnr);				draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor,				          cnt->imgs.width, tmp, cnt->conf.text_double);			}			/* Add text in lower left corner of the pictures */			if (cnt->conf.text_left) {				char tmp[PATH_MAX];				mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left, cnt->currenttime_tm, NULL, 0);				draw_text(newimg, 10, cnt->imgs.height - 10 * text_size_factor, cnt->imgs.width,				          tmp, cnt->conf.text_double);			}			/* Add text in lower right corner of the pictures */			if (cnt->conf.text_right) {				char tmp[PATH_MAX];				mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right, cnt->currenttime_tm, NULL, 0);				draw_text(newimg, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor,				          cnt->imgs.width, tmp, cnt->conf.text_double);			}		/***** MOTION LOOP - ACTIONS AND EVENT CONTROL SECTION *****/			/* If motion has been detected we take action and start saving			 * pictures and movies etc by calling motion_detected().			 * Is output_all enabled we always call motion_detected()			 * If post_capture is enabled we also take care of this in the this			 * code section.			 */			if (cnt->conf.output_all) {				detecting_motion = 1;				motion_detected(cnt, 0, cnt->video_dev, newimg);			} else if (cnt->diffs > cnt->threshold) {				/* Did we detect motion (like the cat just walked in :) )?				 * If so, ensure the motion is sustained if minimum_motion_frames				 * is set, and take action by calling motion_detected().				 * pre_capture is handled by motion_detected(), and we handle				 * post_capture here. */				if (!detecting_motion)					detecting_motion = 1;				detecting_motion++;				if (detecting_motion > cnt->conf.minimum_motion_frames) {					motion_detected(cnt, cnt->diffs, cnt->video_dev, newimg);					postcap = cnt->conf.post_capture;				}			} else if (postcap) {				motion_detected(cnt, 0, cnt->video_dev, newimg);				postcap--;			} else {				detecting_motion = 0;			}			/* Is the mpeg movie to long? Then make movies			 * First test for max mpegtime			 */			if (cnt->conf.maxmpegtime && cnt->event_nr == cnt->prev_event)				if (cnt->currenttime - cnt->eventtime >= cnt->conf.maxmpegtime)					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) {					/* When output_normal=best save best preview_shot here at the end of event */					if (cnt->new_img == NEWIMG_BEST && cnt->preview_max) {						preview_best(cnt);						cnt->preview_max = 0;					}

⌨️ 快捷键说明

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