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

📄 netcam.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 * We copy the strings out of the url structure into the ftp_context	 * structure.  By setting url->{string} to NULL we effectively "take	 * ownership" of the string away from the URL (i.e. it won't be freed	 * when we cleanup the url structure later).	 */	netcam->ftp->path = url->path;	url->path = NULL;	if (cnt->conf.netcam_userpass != NULL)		ptr = cnt->conf.netcam_userpass;	else {		ptr = url->userpass;  /* don't set this one NULL, gets freed */	}	if (ptr != NULL) {		char *cptr;		if ((cptr = strchr(ptr, ':')) == NULL)			netcam->ftp->user = strdup(ptr);		else {			netcam->ftp->user = mymalloc((cptr - ptr));			memcpy(netcam->ftp->user,ptr,(cptr - ptr));			netcam->ftp->passwd = strdup(cptr + 1);		}	}	netcam_url_free(url);	/*	 * The ftp context should be all ready to attempt a connection with	 * the server, so we try ....	 */	if (ftp_connect(netcam) < 0) {		ftp_free_context(netcam->ftp);		return -1;	}	if (ftp_send_type(netcam->ftp, 'I') < 0) {		motion_log(LOG_ERR, 0, "Error sending TYPE I to ftp server");		return -1;	}	netcam->get_image = netcam_read_ftp_jpeg;	return 0;}/** * netcam_recv * *      This routine receives the next block from the netcam.  It takes care *      of the potential timeouts and interrupt which may occur because of *      the settings from setsockopt. * * Parameters: * *      netcam          Pointer to a netcam context *      buffptr         Pointer to the receive buffer *      buffsize        Length of the buffer * * Returns: *      If successful, the length of the message received, otherwise the *      error reply from the system call. * */ssize_t netcam_recv(netcam_context_ptr netcam, void *buffptr, size_t buffsize) {	ssize_t retval;	fd_set fd_r;	struct timeval selecttime;	FD_ZERO(&fd_r);	FD_SET(netcam->sock, &fd_r);	selecttime = netcam->timeout;	retval = select(FD_SETSIZE, &fd_r, NULL, NULL, &selecttime);	if (retval == 0) {             /* 0 means timeout */		return -1;	}	return recv(netcam->sock, buffptr, buffsize, 0);}/** * netcam_cleanup * *      This routine releases any allocated data within the netcam context, *      then frees the context itself.  Extreme care must be taken to assure *      that the multi-threading nature of the program is correctly *      handled. *      This function is also called from motion_init if first time connection *      fails and we start retrying until we get a valid first frame from the *      camera.  * * Parameters: * *      netcam           Pointer to a netcam context *      init_retry_flag  1 when the function is called because we are retrying *                         making the initial connection with a netcam and we know *                         we do not need to kill a netcam handler thread *                       0 in any other case. * * Returns:              Nothing. * */void netcam_cleanup(netcam_context_ptr netcam, int init_retry_flag){	struct timespec waittime;	if (!netcam)		return;	/*	 * This 'lock' is just a bit of "defensive" programming.  It should	 * only be necessary if the routine is being called from different	 * threads, but in our Motion design, it should only be called from	 * the motion main-loop.	 */	pthread_mutex_lock(&netcam->mutex);	if (netcam->cnt->netcam == NULL) {		return;	}	/*	 * We set the netcam_context pointer in the motion main-loop context	 * to be NULL, so that this routine won't be called a second time	 */	netcam->cnt->netcam = NULL;	/*	 * Next we set 'finish' in order to get the camera-handler thread	 * to stop.	 */	netcam->finish = 1;	/*	 * If the camera is non-streaming, the handler thread could be waiting	 * for a signal, so we send it one.  If it's actually waiting on the	 * condition, it won't actually start yet because we still have	 * netcam->mutex locked.	 */	if (!netcam->caps.streaming) {		pthread_cond_signal(&netcam->cap_cond);	}	/*	 * Once the camera-handler gets to the end of it's loop (probably as	 * soon as we release netcam->mutex), because netcam->finish has been	 * set it will exit it's loop, do anything it needs to do with the	 * netcam context, and then send *us* as signal (netcam->exiting).	 * Note that when we start our wait on netcam->exiting, our lock on	 * netcam->mutex is automatically released, which will allow the	 * handler to complete it's loop, notice that 'finish' is set and exit.	 * This should always work, but again (defensive programming) we	 * use pthread_cond_timedwait and, if our timeout (8 seconds) expires	 * we just do the cleanup the handler would normally have done.  This	 * assures that (even if there is a bug in our code) motion will still	 * be able to exit.	 * If the init_retry_flag is not set the netcam_cleanup code was	 * called while retrying the initial connection to a netcam and then	 * there is no camera-handler started yet and thread_running must	 * not be decremented.	 */	waittime.tv_sec = time(NULL) + 8;   /* Seems that 3 is too small */	waittime.tv_nsec = 0;	if (!init_retry_flag &&	    pthread_cond_timedwait(&netcam->exiting, &netcam->mutex, &waittime) != 0) {		/*		 * Although this shouldn't happen, if it *does* happen we will		 * log it (just for the programmer's information)		 */		motion_log(-1, 0, "No response from camera "		           "handler - it must have already died");		pthread_mutex_lock(&global_lock);		threads_running--;		pthread_mutex_unlock(&global_lock);	}	/* we don't need any lock anymore, so release it */	pthread_mutex_unlock(&netcam->mutex);	/* and cleanup the rest of the netcam_context structure */	if (netcam->connect_host != NULL) {		free(netcam->connect_host);	}	if (netcam->connect_request != NULL) {		free(netcam->connect_request);	}	if (netcam->boundary != NULL) {		free(netcam->boundary);	}	if (netcam->latest != NULL) {		if (netcam->latest->ptr != NULL) {			free(netcam->latest->ptr);		}		free(netcam->latest);	}	if (netcam->receiving != NULL) {		if (netcam->receiving->ptr != NULL) {			free(netcam->receiving->ptr);		}		free(netcam->receiving);	}	if (netcam->jpegbuf != NULL) {		if (netcam->jpegbuf->ptr != NULL) {			free(netcam->jpegbuf->ptr);		}		free(netcam->jpegbuf);	}	if (netcam->ftp != NULL) {		ftp_free_context(netcam->ftp);	} else {		netcam_disconnect(netcam);	}	if (netcam->response != NULL) {		free(netcam->response);	}	pthread_mutex_destroy(&netcam->mutex);	pthread_cond_destroy(&netcam->cap_cond);	pthread_cond_destroy(&netcam->pic_ready);	pthread_cond_destroy(&netcam->exiting);	free(netcam);}/** * netcam_next * *      This routine is called when the main 'motion' thread wants a new *      frame of video.  It fetches the most recent frame available from *      the netcam, converts it to YUV420P, and returns it to motion. * * Parameters: *      cnt             Pointer to the context for this thread *      image           Pointer to a buffer for the returned image * * Returns:             Error code */int netcam_next(struct context *cnt, unsigned char *image){	netcam_context_ptr netcam;	/*	 * Here we have some more "defensive programming".  This check should	 * never be true, but if it is just return with a "fatal error".	 */	if ((!cnt) || (!cnt->netcam))		return NETCAM_FATAL_ERROR;	netcam = cnt->netcam;	if (!netcam->latest->used) {		if (debug_level) {			motion_log(LOG_INFO, 0, "netcam_next called with no data in buffer");		}		return NETCAM_NOTHING_NEW_ERROR;	}	/*	 * If we are controlling a non-streaming camera, we synchronize the	 * motion main-loop with the camera-handling thread through a signal,	 * together with a flag to say "start your next capture".	 */	if (!netcam->caps.streaming) {		pthread_mutex_lock(&netcam->mutex);		netcam->start_capture = 1;		pthread_cond_signal(&netcam->cap_cond);		pthread_mutex_unlock(&netcam->mutex);	}	/*	 * If an error occurs in the JPEG decompression which follows this,	 * jpeglib will return to the code within this 'if'.  Basically, our	 * approach is to just return a NULL (failed) to the caller (an	 * error message has already been produced by the libjpeg routines)	 */	if (setjmp(netcam->setjmp_buffer)) {		return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR;	}	/* If there was no error, process the latest image buffer */	return netcam_proc_jpeg(netcam, image);}/** * netcam_start * *      This routine is called from the main motion thread.  It's job is *      to open up the requested camera device and do any required *      initialisation.  If the camera is a streaming type, then this *      routine must also start up the camera-handling thread to take *      care of it. * * Parameters: * *      cnt     Pointer to the motion context structure for this device * * Returns:     0 on success, -1 on any failure */int netcam_start(struct context *cnt){	netcam_context_ptr netcam;        /* local pointer to our context */	pthread_attr_t handler_attribute; /* attributes of our handler thread */	int retval;                       /* working var */	struct url_t url;                 /* for parsing netcam URL */	if (debug_level > CAMERA_INFO)		motion_log(-1, 0, "entered netcam_start()");	memset(&url, 0, sizeof(url));	if (SETUP)		motion_log(LOG_INFO, 0, "Camera thread starting...");	/*	 * Create a new netcam_context for this camera	 * and clear all the entries.	 */	cnt->netcam = (struct netcam_context *)		      mymalloc(sizeof(struct netcam_context));	memset(cnt->netcam, 0, sizeof(struct netcam_context));	netcam = cnt->netcam;           /* Just for clarity in remaining code */	netcam->cnt = cnt;              /* Fill in the "parent" info */	/*	 * Fill in our new netcam context with all known initial	 * values.	 */	/* Our image buffers */	netcam->receiving = mymalloc(sizeof(netcam_buff));	memset(netcam->receiving, 0, sizeof(netcam_buff));	netcam->receiving->ptr = mymalloc(NETCAM_BUFFSIZE);	netcam->jpegbuf = mymalloc(sizeof(netcam_buff));	memset(netcam->jpegbuf, 0, sizeof(netcam_buff));	netcam->jpegbuf->ptr = mymalloc(NETCAM_BUFFSIZE);	netcam->latest = mymalloc(sizeof(netcam_buff));	memset(netcam->latest, 0, sizeof(netcam_buff));	netcam->latest->ptr = mymalloc(NETCAM_BUFFSIZE);	netcam->timeout.tv_sec = READ_TIMEOUT;	/* Thread control structures */	pthread_mutex_init(&netcam->mutex, NULL);	pthread_cond_init(&netcam->cap_cond, NULL);	pthread_cond_init(&netcam->pic_ready, NULL);	pthread_cond_init(&netcam->exiting, NULL);		/* Initialise the average frame time to the user's value */	netcam->av_frame_time = 1000000.0 / cnt->conf.frame_limit;	/*	 * If a proxy has been specified, parse that URL.	 */	if (cnt->conf.netcam_proxy) {		netcam_url_parse(&url, cnt->conf.netcam_proxy);		if (!url.host) {			motion_log(LOG_ERR, 0, "Invalid netcam_proxy (%s)",			           cnt->conf.netcam_proxy);			netcam_url_free(&url);			return -1;		}		if (url.userpass) {			motion_log(LOG_ERR, 0, "Username/password not allowed on a proxy URL");			netcam_url_free(&url);			return -1;		}		/*		 * A 'proxy' means that our eventual 'connect' to our		 * camera must be sent to the proxy, and that our 'GET' must		 * include the full path to the camera host.		 */		netcam->connect_host = url.host;		url.host = NULL;		netcam->connect_port = url.port;		netcam_url_free(&url);  /* Finished with proxy */	}	/*	 * Parse the URL from the configuration data	 */	netcam_url_parse(&url, cnt->conf.netcam_url);	if (!url.host) {		motion_log(LOG_ERR, 0, "Invalid netcam_url (%s)", cnt->conf.netcam_url);		netcam_url_free(&url);		return -1;	}	if (cnt->conf.netcam_proxy == NULL) {		netcam->connect_host = url.host;		url.host = NULL;		netcam->connect_port = url.port;	}	if ((url.service) && (!strcmp(url.service, "http")) ){		retval = netcam_setup_html(netcam, &url);	} else if ((url.service) && (!strcmp(url.service, "ftp")) ){		retval = netcam_setup_ftp(netcam, &url);	} else {		motion_log(LOG_ERR, 0, "Invalid netcam service  '%s' - "					"must be http or ftp", url.service);		netcam_url_free(&url);		return -1;	}	if (retval < 0)		return -1;	/*	 * We expect that, at this point, we should be positioned to read	 * the first image available from the camera (directly after the	 * applicable header).  We want to decode the image in order to get	 * the dimensions (width and height).  If successful, we will use	 * these to set the required image buffer(s) in our netcam_struct.	 */	if ((retval = netcam->get_image(netcam)) != 0) {		motion_log(LOG_ERR, 0, "Failed trying to read first image");		return -1;	}	/*	 * If an error occurs in the JPEG decompression which follows this,	 * jpeglib will return to the code within this 'if'.  If such an error	 * occurs during startup, we will just abandon this attempt.	 */	if (setjmp(netcam->setjmp_buffer)) {		motion_log(LOG_ERR, 0, "libjpeg decompression failure "		                       "on first frame - giving up!");		return -1;	}	netcam_get_dimensions(netcam);	/* Motion currently requires that image height and width is a	 * multiple of 16. So we check for this.	 */	if (netcam->width % 16) {		motion_log(LOG_ERR, 0, "netcam image width (%d) is not modulo 16",		           netcam->width);		return -1;	}	if (netcam->height % 16) {		motion_log(LOG_ERR, 0, "netcam image height (%d) is not modulo 16",		           netcam->height);		return -1;	}	/* Fill in camera details into context structure */	cnt->imgs.width = netcam->width;	cnt->imgs.height = netcam->height;	cnt->imgs.size = (netcam->width * netcam->height * 3) / 2;	cnt->imgs.motionsize = netcam->width * netcam->height;	cnt->imgs.type = VIDEO_PALETTE_YUV420P;	/*	 * Everything is now ready - start up the	 * "handler thread".	 */	pthread_attr_init(&handler_attribute);	pthread_attr_setdetachstate(&handler_attribute, PTHREAD_CREATE_DETACHED);	pthread_mutex_lock(&global_lock);	netcam->threadnr = ++threads_running;	pthread_mutex_unlock(&global_lock);	if ((retval = pthread_create(&netcam->thread_id, &handler_attribute,	                             &netcam_handler_loop, netcam)) < 0) {		motion_log(LOG_ERR, 1, "Starting camera handler thread [%d]", netcam->threadnr);		return -1;	}	return 0;}

⌨️ 快捷键说明

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