📄 webcam_server.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 0void print_rgb(char * hdr, struct RGB x) { printf("rgb:%s = %d,%d,%d\n", hdr,x.r&0xFF,x.g&0xFF,x.b&0xFF); }/*----------------------------------------------------------- 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_TRANS {128,0,128}#define DEF_TEXT_XPOS 0 #define DEF_TEXT_YPOS 0#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"*/#define DEF_PALETTE -1char *str_replace(const char *str, const char *find, const char *replace){ char *ptr,*ret; int found=0; ptr = (char*)str; while((ptr=strstr(ptr, find))) { char *start,*end; int slen,elen,rlen,flen; rlen = strlen(replace); flen = strlen(find); slen = ptr - str; elen = strlen(ptr)-flen; start = (char*)malloc(slen+1); strncpy(start, str, slen); start[slen]=0; end = (char*)malloc(elen+1); strncpy(end, ptr+flen, elen); end[elen]=0; ret = (char*)malloc(slen+elen+rlen+1); sprintf(ret, "%s%s%s", start, replace, end); free(start); free(end); ptr = ret; found=1; } if(!found) { ret = (char*)malloc(strlen(str)+1); strcpy(ret, str); } return ret;}/*----------------------------------------------------------- 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-2004 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], \"\" for none\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 CCW (0-3) [0]\n\ -s - daemon mode [no]\n\ -tf R,G,B - text forground colour [255,255,255]\n\ -tb R,G,B - text background colour [0,0,0]\n\ -tt R,G,B - transparency colour [128,0,128]\n\ (set -tf or -tb to this to make transparent)\n\ -T x,y - xy-position of text [0,0]\n\ -v - verbose [no]\n\ -x - swap RGB -> BGR [no]\n\\n");/* ** currently not implemented -Ea - enable admin support [no]\n\ -e password - set admin password [null]\n\ -P - force palette n (videodev.h) [off]\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': case '-': 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 'P': if(i+1 < argc) cam->o.palette = 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': { if(i+1 < argc) { int x,y; sscanf(argv[++i], "%d,%d", &x,&y); cam->o.text_xpos = x; cam->o.text_ypos = y; printf("text xy = %d,%d\n", x,y); } else res = -1; } break; case 't': switch(argv[i][2]) { case 'f': if(i+1 < argc) { int r,g,b; sscanf(argv[++i], "%d,%d,%d", &r, &g, &b); cam->o.text_fg.r = r; cam->o.text_fg.g = g;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -