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

📄 webcam_server.c

📁 一个基于linux下的摄像头应用程序
💻 C
字号:
/********************************************************************* * webcam_server                                                     * *                                                                   * * (c) 2002 Donn Morrison donn@donn.dyndns.org                       * *                                                                   * * code used from Gerd Knorr's xawtv (libng)                         * * - and -                                                           * * Cory Lueninghoener's gqcam                                        * *                                                                   * *    waits for connections from a viewer and sends                  * *    jpeg encoded captures as a live video feed                     * *                                                                   * *********************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <pthread.h>#include <linux/videodev.h>#include <semaphore.h>#include <sys/ioctl.h>#include "webcam_server.h"#include "grabber.h"#include "watchdog.h"#include "client.h"#include "version.h"#include "camera.h"#include "unpalette.h"#define DEBUG 0/*-----------------------------------------------------------  default options  -----------------------------------------------------------*/#define DEF_PORT		8888#define DEF_QUALITY		60#define DEF_CAMDEVFILE		"/dev/video0"#define DEF_LOGFILE		"/var/log/webcam_server.log"#define DEF_CAPTION		"%Y-%m-%d %H:%M:%S" /* strftime */#define DEF_WIDTH		320#define DEF_HEIGHT		240#define DEF_RETRYINIT		0#define DEF_DAEMON		0#define DEF_SWAPRGB		0#define DEF_TESTFPS		0#define DEF_FLIP_HORIZ		0#define DEF_FLIP_VERT		0#define DEF_GAMMA		0//#define DEF_TEXT_FG		{0,0,0}//#define DEF_TEXT_BG		{255,255,255}#define DEF_ROTATE		0#define DEF_FORCE_READ		0#define DEF_ALLOW_HTTP		1#define DEF_ALLOW_STREAM	1#define DEF_MAX_STREAM_BYTES	0#define DEF_MAX_STREAM_SECONDS	0#define DEF_MAX_STREAM_FRAMES	0/* ** currently not implemented#define DEF_ALLOW_ADMIN		0#define DEF_ADMIN_PW		"\0"*//*-----------------------------------------------------------  create_and_listen  - creates a server socket and listens  - its a seperate function to clean up main  -----------------------------------------------------------*/int create_and_listen(int port){	int sockfd, yes=1;	struct sockaddr_in addr;		if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)	{		perror("socket");		return -1;	}		memset(&addr, 0, sizeof(addr));		addr.sin_family = AF_INET;	addr.sin_port = htons(port);	addr.sin_addr.s_addr = htonl(INADDR_ANY);		if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)	{		perror("setsockopt");		return -1;	}		if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)	{		perror("bind");		return -1;	}		if(listen(sockfd, 5) < 0)	{		perror("listen");		return -1;	}		return sockfd;}/*-----------------------------------------------------------  log  - opens a logfile for appending on first call  - subsequent calls write to the open logfile and/or stdout  -----------------------------------------------------------*/void log(struct caminfo *cam, char *text){	static int tried = 0;	static int dups = 0;	time_t      t;	struct tm  *tm;	char date[128];	static char *last_msg = NULL;	if(!tried)	{		/* open log file */		cam->log = fopen(cam->o.logfile, "a");		if(cam->log == NULL)		{			fprintf(stderr, "could not open logfile '%s' for writing\n", cam->o.logfile);		}		tried = 1;	}		time(&t);	tm = localtime(&t);	strftime(date,127,"%Y-%m-%d %H:%M:%S",tm);		if(last_msg)	{		if(strcmp(last_msg, text) == 0)		{			dups++;			return;		}		else		{			free(last_msg);			last_msg = NULL;		}	}	/* write the message to stdout and/or logfile */	pthread_mutex_lock(&cam->lock_log);	if(cam->o.verbose)	{		if(dups > 0)		{			fprintf(stdout, "%s [%s] log: the last message repeated %d times\n", date, cam->o.devfile, dups);		}				fprintf(stdout, "%s [%s] %s", date, cam->o.devfile, text);		fflush(stdout);	}			if(cam->log)	{		if(dups > 0)		{			fprintf(cam->log, "%s [%s] log: the last message repeated %d times\n", date, cam->o.devfile, dups);		}		fprintf(cam->log, "%s [%s] %s", date, cam->o.devfile, text);		fflush(cam->log);	}	pthread_mutex_unlock(&cam->lock_log);		if(!last_msg)	{		last_msg = (char *)malloc(strlen(text)+1);		strcpy(last_msg, text);		dups = 0;	}}/*-----------------------------------------------------------  usage, parse_args  - highly complex, undocumented functions used for encrypting    and secretly displaying or parsing various portions of text  -----------------------------------------------------------*/void usage(){printf("webcam_server %s, copyright 2001,2002 donn morrison\n\n", get_version());printf("usage: webcam_server [options]\n\n\     option             description [default value]\n\n\     -a                 - test mode (fps) [no]\n\     -c \"caption\"       - caption text [%%Y-%%m-%%d %%H:%%M:%%S]\n\     -d video_device    - v4l compliant device [/dev/video]\n\     -Ds                - disable stream support [no]\n\     -Dh                - disable http support [no]\n\     -fh		- flip image horizontally\n\     -fv		- flip image vertically\n\     -g geometry        - change default geometry (WIDTHxHEIGHT) [320x240]\n\     -G gamma		- gamma correction (-100-100) [0]\n\     -h                 - this help screen\n\     -l logfile         - log to file [/var/log/webcam_server.log]\n\     -mb                - maximum bytes per connection [0 (disabled)]\n\     -ms                - maximum seconds per connection [0 (disabled)]\n\     -mf                - maximum frames per connection [0 (disabled)]\n\     -n                 - force use of read() system call, rather than mmap\n\     -p tcp_port        - tcp listen port [8888]\n\     -q jpeg_quality    - jpeg compression quality (0-100) [60]\n\     -r                 - if camera init fails, retry forever [no]\n\     -R value           - rotate image value*90 degrees (0-3) [0]\n\     -s                 - daemon mode [no]\n\     -tf colour         - text forground colour (0-255) [255]\n\     -v                 - verbose [no]\n\     -x                 - swap RGB -> BGR [no]\n\\n");/* ** currently not implemented     -tb colour         - text background colour (0-255) [0]\n\     -Ea                - enable admin support [no]\n\     -e password        - set admin password [null]\n\*/}int parse_args(struct caminfo *cam, int argc, char *argv[]){	int res = 0, i;	for(i=1; i<argc; i++)	{		if(argv[i][0] == '-')		{			switch(argv[i][1])			{			case 'h':				usage();				return -1;			case 'p':				if(i+1 < argc)					cam->o.port = atoi(argv[++i]);				else					res = -1;				break;			case 'd':				if(i+1 < argc)					cam->o.devfile = argv[++i];				else					res = -1;				break;			case 'c':				if(i+1 < argc)					cam->o.caption = argv[++i];				else					res = -1;				break;			case 'v':				cam->o.verbose = 1;				break;			case 'r':				cam->o.retry_init = 1;				break;			case 's':				cam->o.daemon = 1;				break;			case 'q':				if(i+1 < argc)					cam->o.jpeg_quality = atoi(argv[++i]);				else					res = -1;				break;			case 'x':				cam->o.swap_rgb = 1;				break;			case 'f':				switch(argv[i][2])				{					case 'h':						cam->o.flip_horiz = 1;						break;					case 'v':						cam->o.flip_vert = 1;						break;				}				break;			case 't':				switch(argv[i][2])				{					case 'f':						if(i+1 < argc)						{							sscanf(argv[++i], "%d,%d,%d", &cam->o.text_fg.r,							                              &cam->o.text_fg.g,										      &cam->o.text_fg.b);						}						else							res = -1;						break;					case 'b':						if(i+1 < argc)						{							sscanf(argv[++i], "%d,%d,%d", &cam->o.text_bg.r,							                              &cam->o.text_bg.g,										      &cam->o.text_bg.b);						}						else							res = -1;						break;					default:						res = -1;				}				break;			case 'D':				switch(argv[i][2])				{					case 'h':						cam->o.allow_http = 0;						break;					case 's':						cam->o.allow_stream = 0;						break;					default:						res = -1;				}				break;/* ** currently not implemented			case 'E':				switch(argv[i][2])				{					case 'a':						cam->o.allow_admin = 1;						break;					default:						res = -1;				}				break;			case 'e':				if(i+1 < argc)					cam->o.admin_pw = argv[++i];				else					res = -1;				break;*/			case 'm':				if(i+1 < argc)				switch(argv[i][2])				{					case 'b':						cam->o.max_stream_bytes = atoi(argv[++i]);						break;					case 's':						cam->o.max_stream_seconds = atoi(argv[++i]);						break;					case 'f':						cam->o.max_stream_frames = atoi(argv[++i]);						break;					default:						res = -1;				}				else					res = -1;				break;			case 'a':				cam->o.test_fps = 1;				break;			case 'n':				cam->o.use_read = 1;				break;			case 'l':				if(i+1 < argc)					cam->o.logfile = argv[++i];				else					res = -1;				break;			case 'R':				if(i+1 < argc)					cam->o.rotate = atoi(argv[++i]);				else					res = -1;				break;			case 'g':				if(i+1 < argc)				{					int w,h;					char *arg = argv[++i];					char *ptr;					ptr = (char *)strchr(arg, 'x');					if(!ptr)					{						res = -1;						break;					}					*ptr = 0; // eek! changing the cmd line params					ptr++;					w = atoi(arg);					h = atoi(ptr);					if(w < 1 || h < 1)					{						fprintf(stderr, "invalid width, height: %d,%d. using defaults: %d,%d\n",						       w,h,DEF_WIDTH,DEF_HEIGHT);						cam->o.width = DEF_WIDTH;						cam->o.height = DEF_HEIGHT;					}					cam->o.width = w;					cam->o.height = h;				}				else					res = -1;				break;			case 'G':				if(i+1 < argc)				{					cam->o.gamma = atoi(argv[++i]);				}				else					res = -1;				break;			default:				res = -1;				break;			};		}		else		{			res = -1;		}		if(res == -1)		{			fprintf(stderr, "invalid option or missing parameter: %s\n", argv[i]);			return res;		}	}		return res;}int main(int argc, char *argv[]){	int sockfd=0, clientfd;	struct sockaddr_in remote_addr;	socklen_t addr_len;	pthread_t pt;	struct caminfo *cam;	struct connection *con;	int res;		cam = (struct caminfo *)malloc(sizeof(struct caminfo));	if(!cam)	{		fprintf(stderr, "malloc error\n");		exit(1);	}	cam->mmap = NULL;	/* ignore broken pipes n stuff */	signal(SIGPIPE, SIG_IGN);	signal(SIGALRM, SIG_IGN);	/* init mutexes */	pthread_mutex_init(&cam->lock_queue, NULL);	pthread_mutex_init(&cam->lock_info, NULL);	pthread_mutex_init(&cam->lock_id, NULL);	pthread_mutex_init(&cam->lock_log, NULL);	sem_init(&cam->sem_con, 0, 0);	/* defaults */	cam->o.caption = DEF_CAPTION;	cam->o.devfile = DEF_CAMDEVFILE;	cam->o.port = DEF_PORT;	cam->o.jpeg_quality = DEF_QUALITY;	cam->o.retry_init = DEF_RETRYINIT;	cam->o.daemon = DEF_DAEMON;	cam->o.swap_rgb = DEF_SWAPRGB;	cam->o.test_fps = DEF_TESTFPS;	cam->o.width = DEF_WIDTH;	cam->o.height = DEF_HEIGHT;	cam->o.logfile = DEF_LOGFILE;	cam->o.flip_horiz = DEF_FLIP_HORIZ;	cam->o.flip_vert = DEF_FLIP_VERT;	cam->o.gamma = DEF_GAMMA;//	cam->o.text_fg = DEF_TEXT_FG;//	cam->o.text_bg = DEF_TEXT_BG;	memset(&cam->o.text_fg, 0, 3);	memset(&cam->o.text_fg, 255, 3);	cam->o.rotate = DEF_ROTATE;	cam->o.use_read = DEF_FORCE_READ;	cam->o.allow_http = DEF_ALLOW_HTTP;	cam->o.allow_stream = DEF_ALLOW_STREAM;	cam->o.max_stream_bytes = DEF_MAX_STREAM_BYTES;	cam->o.max_stream_seconds = DEF_MAX_STREAM_SECONDS;	cam->o.max_stream_frames = DEF_MAX_STREAM_FRAMES;/* ** currently not implemented	cam->o.admin_pw = DEF_ADMIN_PW;	cam->o.allow_admin = DEF_ALLOW_ADMIN;*/	printf("main pid = %d\n", getpid());	/* overwrite defaults with command line args */	if(parse_args(cam, argc, argv) < 0)		exit(1);	/* don't do this stuff if we're in test mode */	if(!cam->o.test_fps)	{		/* create listening socket */		sockfd = create_and_listen(cam->o.port);		if(sockfd < 1)			exit(1);		/* go into daemon mode if told to */			if(cam->o.daemon)			if(daemon(0,0) < 0)			{				fprintf(stderr, "daemon failed.\n");				exit(1);			}	}		/* open camera device...retry infinitely if told to */	res = open_cam(cam, cam->o.devfile);		while(res < 0 && cam->o.retry_init)	{		usleep(5000000);		fprintf(stderr, "camera init failed, retrying...\n");		res = open_cam(cam, cam->o.devfile);	}	if(res < 0)	{		fprintf(stderr, "unable to initialise camera\n");		exit(1);	}	/* get camera defaults */	get_cam_info(cam);	cam->vid_win.width = cam->o.width;	cam->vid_win.height = cam->o.height;	if(set_cam_info(cam) < 0)	{		fprintf(stderr, "error setting video device parameters, using defaults\n");		get_cam_info(cam);		if(set_cam_info(cam) < 0)		{			fprintf(stderr, "not a valid video device? quitting.\n");			exit(1);		}	}	cam->o.width = cam->vid_win.width;	cam->o.height = cam->vid_win.height;		{		/* check for a valid colour palette */		int palfound = 0;		int brightness = -1, hue = -1, colour = -1, contrast = -1, whiteness = -1;		for(cam->pal = palettes; cam->pal->val >= 0; cam->pal++)		{			cam->vid_pic.palette = cam->pal->val;			cam->vid_pic.depth = cam->pal->depth;			if(brightness >= 0) cam->vid_pic.brightness = brightness;			if(hue >= 0) cam->vid_pic.hue = hue;			if(colour >= 0) cam->vid_pic.colour = colour;			if(contrast >= 0) cam->vid_pic.contrast = contrast;			if(whiteness >= 0) cam->vid_pic.whiteness = whiteness;			ioctl(cam->dev, VIDIOCSPICT, &cam->vid_pic);			ioctl(cam->dev, VIDIOCGPICT, &cam->vid_pic);			if(cam->vid_pic.palette == cam->pal->val)			{				palfound = 1;				break;			}		}		if(!palfound)		{			printf("No supported colour palette found.\n");			return 1;		}	}	cam->grab_thread_alive = 1;	pthread_create(&cam->pt_grab, NULL, (void*)grab_thread, (void *)cam);	/* start the watchdog thread */	pthread_create(&pt, NULL, (void*)watchdog_thread, (void *)cam);	pthread_detach(pt);	if(cam->o.test_fps)	{		pthread_join(cam->pt_grab, NULL);		exit(0);	}	else	{		pthread_detach(cam->pt_grab);	}	log(cam, "webcam_server started\n");	addr_len = sizeof(remote_addr);	while((clientfd = accept(sockfd, (struct sockaddr *)&remote_addr, &addr_len)) > 0)	{		/* con is free'd at end of handle_connection */		con = (struct connection*)malloc(sizeof(struct connection));		con->cam = cam;		/* get connection info */		con->socketfd = clientfd;		memcpy(&con->remote_addr, &remote_addr, addr_len);		/* handle the connection */		pthread_create(&pt, NULL, (void*)handle_connection, (void*)con);		pthread_detach(pt);	}		close(sockfd);	return 0;}

⌨️ 快捷键说明

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