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

📄 netcam.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 4 页
字号:
			return -1;		}		if (firstflag) {			if ((ret = http_result_code(header)) != 200) {				if (debug_level > 5)					motion_log(-1, 0, "HTTP Result code %d", ret);				free(header);				return ret;			}			firstflag = 0;			free(header);			continue;		}		if (*header == 0)                  /* blank line received */			break;		if (SETUP)			motion_log(LOG_DEBUG, 0, "Received first header");		/* Check if this line is the content type */		if ((ret = netcam_check_content_type(header)) >= 0) {			retval = ret;			/*			 * We are expecting to find one of three types:			 * 'multipart/x-mixed-replace', 'multipart/mixed'			 * or 'image/jpeg'.  The first two will be received			 * from a streaming camera, and the third from a			 * camera which provides a single frame only.			 */			switch (ret) {				case 1:         /* not streaming */					if (SETUP)						motion_log(LOG_DEBUG, 0, "Non-streaming camera");					netcam->caps.streaming = 0;					break;				case 2:         /* streaming */					if (SETUP)						motion_log(LOG_DEBUG, 0, "Streaming camera");					netcam->caps.streaming = 1;					if ((boundary = strstr(header, "boundary="))) {						/*						 * on error recovery this						 * may already be set						 * */						if (netcam->boundary)							free(netcam->boundary);						netcam->boundary = strdup(boundary + 9);						/*						 * HTTP protocol apparently permits the boundary string						 * to be quoted (the Lumenera does this, which caused						 * trouble) so we need to get rid of any surrounding						 * quotes						 */						check_quote(netcam->boundary);						netcam->boundary_length = strlen(netcam->boundary);						if (SETUP) {							motion_log(LOG_DEBUG, 0, "Boundary string [%s]",							           netcam->boundary);						}					}					break;				default:{       /* error */						motion_log(LOG_ERR, 0, "Unrecognized content type");						free(header);						return -1;					}			}		} else if ((ret = (int) netcam_check_content_length(header)) >= 0) {			if (SETUP)				motion_log(LOG_DEBUG, 0, "Content-length present");			netcam->caps.content_length = 1;     /* set flag */			netcam->receiving->content_length = ret;		}		free(header);	}	free(header);	return retval;}/** * netcam_disconnect * *      Disconnect from the network camera. * * Parameters: * *      netcam  pointer to netcam context * * Returns:     Nothing * */static void netcam_disconnect(netcam_context_ptr netcam){	if (netcam->sock > 0) {		if (close(netcam->sock) < 0)			motion_log(LOG_ERR, 1, "netcam_disconnect");		netcam->sock = -1;	}}/** * netcam_connect * *      Attempt to open the network camera as a stream device. * * Parameters: * *      netcam    pointer to netcam_context structure *      err_flag  flag to suppress error printout (1 => suppress) *                Note that errors which indicate something other than *                a network connection problem are not suppressed. * * Returns:     0 for success, -1 for error * */static int netcam_connect(netcam_context_ptr netcam, int err_flag){	struct sockaddr_in server;      /* for connect */	struct addrinfo *res;           /* for getaddrinfo */	int ret;	int saveflags;	int back_err;	socklen_t len;	fd_set fd_w;	struct timeval selecttime;	/* Assure any previous connection has been closed */	netcam_disconnect(netcam);	/* create a new socket */	if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {		motion_log(LOG_ERR, 1, "Attempting to create socket");		return -1;	}	/* lookup the hostname given in the netcam URL */	if ((ret = getaddrinfo(netcam->connect_host, NULL, NULL, &res)) != 0) {		if (!err_flag)			motion_log(LOG_ERR, 0, "getaddrinfo() failed (%s): %s",			           netcam->connect_host, gai_strerror(ret));		netcam_disconnect(netcam);		return -1;	}	/*	 * Fill the hostname details into the 'server' structure and	 * attempt to connect to the remote server	 */	memset(&server, 0, sizeof(server));	memcpy(&server, res->ai_addr, sizeof(server));	freeaddrinfo(res);	server.sin_family = AF_INET;	server.sin_port = htons(netcam->connect_port);	/*	 * We set the socket non-blocking and then use a 'select'	 * system call to control the timeout.	 */	if ((saveflags = fcntl(netcam->sock, F_GETFL, 0)) < 0) {		motion_log(LOG_ERR, 1, "fcntl(1) on socket");		netcam_disconnect(netcam);		return -1;	}	/* Set the socket non-blocking */	if (fcntl(netcam->sock, F_SETFL, saveflags | O_NONBLOCK) < 0) {		motion_log(LOG_ERR, 1, "fcntl(2) on socket");		netcam_disconnect(netcam);		return -1;	}	/* Now the connect call will return immediately */	ret = connect(netcam->sock, (struct sockaddr *) &server,	              sizeof(server));	back_err = errno;           /* save the errno from connect */	/* If the connect failed with anything except EINPROGRESS, error */	if ((ret < 0) && (back_err != EINPROGRESS)) {		if (!err_flag)			motion_log(LOG_ERR, 1, "connect() failed (%d)", back_err);		netcam_disconnect(netcam);		return -1;	}	/* Now we do a 'select' with timeout to wait for the connect */	FD_ZERO(&fd_w);	FD_SET(netcam->sock, &fd_w);	selecttime.tv_sec = CONNECT_TIMEOUT;	selecttime.tv_usec = 0;	ret = select(FD_SETSIZE, NULL, &fd_w, NULL, &selecttime);	if (ret == 0) {            /* 0 means timeout */		if (!err_flag)			motion_log(LOG_ERR, 0, "timeout on connect()");		netcam_disconnect(netcam);		return -1;	}	/*	 * A +ve value returned from the select (actually, it must be a	 * '1' showing 1 fd's changed) shows the select has completed.	 * Now we must check the return code from the select.	 */	len = sizeof(ret);	if (getsockopt(netcam->sock, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {		motion_log(LOG_ERR, 0, "getsockopt after connect");		netcam_disconnect(netcam);		return -1;	}	/* If the return code is anything except 0, error on connect */	if (ret) {		if (!err_flag)			motion_log(LOG_ERR, 1, "connect returned error");		netcam_disconnect(netcam);		return -1;	}	/* The socket info is stored in the rbuf structure of our context */	rbuf_initialize(netcam);	return 0;            /* success */}/** * netcam_check_buffsize * * This routine checks whether there is enough room in a buffer to copy * some additional data.  If there is not enough room, it will re-allocate * the buffer and adjust it's size. * * Parameters: *      buff            Pointer to a netcam_image_buffer structure *      numbytes        The number of bytes to be copied * * Returns:             Nothing */static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes){	if ((buff->size - buff->used) >= numbytes)		return;	if (debug_level > CAMERA_INFO)		motion_log(-1, 0, "expanding buffer from %d to %d bytes",		           (int) buff->size, (int) buff->size + NETCAM_BUFFSIZE);	buff->ptr = myrealloc(buff->ptr, buff->size + NETCAM_BUFFSIZE,	                      "netcam_check_buf_size");	buff->size += NETCAM_BUFFSIZE;}/** * netcam_read_html_jpeg * * This routine reads a jpeg image from the netcam.  When it is called, * the stream is already positioned just after the image header. * * This routine is called under the four variations of two different * conditions: * 	1) Streaming or non-streaming camera * 	2) Header does or does not include Content-Length * Additionally, if it is a streaming camera, there must always be a * boundary-string. * * The routine will (attempt to) read the JPEG image.  If a Content-Length * is present, it will be used (this will result in more efficient code, and * also code which should be better at detecting and recovering from possible * error conditions). * * If a boundary-string is present (and, if the camera is streaming, this * *must* be the case), the routine will assure that it is recognized and * acted upon. * * Our algorithm for this will be as follows: * 	1) If a Content-Length is present, set the variable "remaining" * 	   to be equal to that value, else set it to a "very large" * 	   number. * 	2) While there is more data available from the camera: * 	   a) If there is a "boundary string" specified (from the initial * 	      header): * 	      i)   If the amount of data in the input buffer is less than * 	           the length of the boundary string, get more data into * 	           the input buffer (error if failure). * 	      ii)  If the boundary string is found, check how many * 	           characters remain in the input buffer before the start * 	           of the boundary string.  If that is less than the * 	           variable "remaining", reset "remaining" to be equal * 	           to that number. * 	   b) Try to copy up to "remaining" characters from the input * 	      buffer into our destination buffer. * 	   c) If there are no more characters available from the camera, * 	      exit this loop, else subtract the number of characters * 	      actually copied from the variable "remaining". * 	3) If Content-Length was present, and "remaining" is not equal * 	   to zero, generate a warning message for logging. * * * Parameters: *      netcam          Pointer to netcam context * * * Returns:             0 for success, -1 for error * */static int netcam_read_html_jpeg(netcam_context_ptr netcam){	netcam_buff_ptr buffer;	size_t remaining;       /* # characters to read */	size_t maxflush;        /* # chars before boundary */	size_t rem, rlen, ix;   /* working vars */	int retval;	char *ptr, *bptr, *rptr;	netcam_buff *xchg;	struct timeval curtime;	/*	 * Initialisation - set our local pointers to the context	 * information	 */	buffer = netcam->receiving;	/* Assure the target buffer is empty */	buffer->used = 0;	/* Prepare for read loop */	if (buffer->content_length != 0)		remaining = buffer->content_length;	else		remaining = 999999;	/* Now read in the data */	while (remaining) {		/* Assure data in input buffer */		if (netcam->response->buffer_left <= 0) {			retval = rbuf_read_bufferful(netcam);			if (retval <= 0)				break;			netcam->response->buffer_left = retval;			netcam->response->buffer_pos = netcam->response->buffer;		}		/* If a boundary string is present, take it into account */		bptr = netcam->boundary;		if (bptr) {			rptr = netcam->response->buffer_pos;			rlen = netcam->response->buffer_left;			/* Loop through buffer looking for start of boundary */			while (1) {				/*				 * Logic gets a little complicated here.  The				 * problem is that we are reading in input				 * data in packets, and there is a (small)				 * chance that the boundary string could be				 * split across successive packets.				 * First a quick check if the string *might*				 * be in the current buffer.				 */				if (rlen > remaining)					rlen = remaining;				if (remaining < netcam->boundary_length)					break;				if ((ptr = memchr(rptr, *bptr, rlen)) == NULL)					/* boundary not here (normal path) */					break;				/*				 * At least the first char was found in the				 * buffer - check for the rest				 */				rem = rlen - (ptr - rptr);				for (ix = 1; (ix < rem) && (ix < netcam->boundary_length); ix++) {					if (ptr[ix] != bptr[ix])						break;				}				if ((ix != netcam->boundary_length) && (ix != rem)) {					/*					 * Not pointing at a boundary string -					 * step along input					 */					ix = ptr - rptr + 1;					rptr += ix;					rlen -= ix;					if (rlen <= 0)						/* boundary not in buffer - go copy out						 */						break;					/*					 * not yet decided - continue					 * through input					 */					continue;				}				/*				 * If we finish the 'for' with				 * ix == boundary_length, that means we found				 * the string, and should copy any data which				 * precedes it into the target buffer, then				 * exit the main loop.				 */				if (ix == netcam->boundary_length) {					if ((ptr - netcam->response->buffer) < (int) remaining)						remaining = ptr - netcam->response->buffer;					/* go copy everything up to boundary */					break;				}				/*				 * If not, and ix == rem, that means we reached				 * the end of the input buffer in the middle of				 * our check, which is the (somewhat messy)				 * problem mentioned above.				 *				 * Assure there is data before potential				 * boundary string				 */				if (ptr != netcam->response->buffer) {					/*					 * We have a boundary string crossing					 * packets :-(. We will copy all the					 * data up to the beginning of the					 * potential boundary, then re-position					 * the (partial) string to the					 * beginning and get some more input					 * data.  First we flush the input					 * buffer up to the beginning of the					 * (potential) boundary string					 */					ix = ptr - netcam->response->buffer_pos;					netcam_check_buffsize(buffer, ix);					retval = rbuf_flush(netcam, buffer->ptr + buffer->used, ix);					buffer->used += retval;					remaining -= retval;					/*					 * Now move the boundary fragment to					 * the head of the input buffer.					 * This is really a "hack" - ideally,					 * we should have a function within the					 * module netcam_wget.c to do this job!					 */					if (debug_level > CAMERA_INFO) {						motion_log(-1, 0,						           "Potential split boundary - "						           "%d chars flushed, %d "						           "re-positioned", ix,						           (int) netcam->response->buffer_left);					}					memmove(netcam->response->buffer, ptr,					         netcam->response->buffer_left);				}       /* end of boundary split over buffer */				retval = netcam_recv(netcam, netcam->response->buffer +				                     netcam->response->buffer_left,				                     sizeof(netcam->response->buffer) -				                     netcam->response->buffer_left);				if (retval <= 0) { /* this is a fatal error */					motion_log(LOG_ERR, 1, "recv() fail after boundary string");					return -1;				}				/* Reset the input buffer pointers */				netcam->response->buffer_left = retval + netcam->response->buffer_left;				netcam->response->buffer_pos = netcam->response->buffer;

⌨️ 快捷键说明

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