📄 webcam_server.c
字号:
/*********************************************************************
* webcam_server *
* *
* (c) 2007 Jason totti guojunjie@jinyaco.com.cn *
* *
* 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 <sys/mman.h>
#include <fcntl.h>
#include "webcam_server.h"
#include "filters.h"
#include "jdatabuf.h"
/*-----------------------------------------------------------
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 176
#define DEF_HEIGHT 144
//#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 VIDEO_PALETTE_RGB24
#define MAX_BAD_GRABS 10 /* max bad image captures before exit */
#define CAPTURE_PAUSE 75000 /* pause for 75ms between captures */
char *str_replace(const char *str, const char *find, const char *replace)
{
char *ptr,*ret =NULL;
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)
{
printf("creat socket error\n");
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)
{
printf("setsockopt is set error\n");
return -1;
}
if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)
{
printf("bind is error\n");
return -1;
}
if(listen(sockfd, 8) < 0)
{
printf("listen is error\n");
return -1;
}
return sockfd;
}
/*---------------------------------------------------------------------
Get the video device struct information
struct video_window vid_win
struct video_picture vid_pic
struct video_capability vid_caps
struct video_mbuf vid_mbuf
---------------------------------------------------------------------*/
void get_cam_info(struct caminfo *cam)
{
if(ioctl(cam->dev, VIDIOCGCAP, &cam->vid_caps) != 0)
{
printf("error ioctl (VIDIOCGCAP)");
return;
}
if(ioctl(cam->dev, VIDIOCGWIN, &cam->vid_win) != 0)
{
printf("error ioctl (VIDIOCGCAP)");
return;
}
if(ioctl(cam->dev, VIDIOCGPICT, &cam->vid_pic) != 0)
{
printf("error ioctl (VIDIOCGCAP)");
return;
}
if(ioctl(cam->dev, VIDIOCGMBUF, &cam->vid_mbuf) == 0)
{
if(!cam->mmap)
cam->mmap = mmap(0, cam->vid_mbuf.size, PROT_READ, MAP_SHARED, cam->dev, 0);
if(cam->mmap == NULL)
printf("error cam mmap");
}
}
/*---------------------------------------------------------------------
Set the video device struct information
struct video_window vid_win
struct video_picture vid_pic
---------------------------------------------------------------------*/
int set_cam_info(struct caminfo *cam)
{
if (ioctl (cam->dev, VIDIOCSPICT, &cam->vid_pic) == -1) {
printf ("error ioctl (VIDIOCSPICT)");
return -1;
}
if (ioctl (cam->dev, VIDIOCSWIN, &cam->vid_win) == -1) {
printf ("error ioctl (VIDIOCSWIN)");
return -1;
}
return 0;
}
/*---------------------------------------------------------------------
Get the image from video device
---------------------------------------------------------------------*/
struct image *get_cam_image(struct caminfo *cam)
{
static struct image *img = NULL;
int res;
img = (struct image*)malloc(sizeof(struct image));
img->width = cam->o.width;
img->height = cam->o.height;
img->bufsize = img->width * img->height * 3;
img->buf = NULL;
/* Set the mmap information */
cam->vid_v4lmmap.format = cam->o.palette;
cam->vid_v4lmmap.frame = 0;
cam->vid_v4lmmap.width = cam->o.width;
cam->vid_v4lmmap.height = cam->o.height;
/* read an image from camera */
res = ioctl(cam->dev, VIDIOCMCAPTURE, &cam->vid_v4lmmap);
if(res != 0)
return NULL;
res = ioctl(cam->dev, VIDIOCSYNC, &cam->vid_v4lmmap);
if(res != 0)
return NULL;
img->buf = cam->mmap;
return img;
}
/* --------------------------------------------------------------
Open the camera device
----------------------------------------------------------------*/
int open_cam(struct caminfo *cam, char *devfile)
{
if(!devfile)
return -1;
/* initialize and open camera */
cam->dev = open(devfile, O_RDONLY);
if(cam->dev < 0)
{
printf("The dev is open error\n");
return -1;
}
return cam->dev;
}
/* --------------------------------------------------------------
Close the camera device
----------------------------------------------------------------*/
int close_cam(struct caminfo *cam)
{
return close(cam->dev);
}
/*----------------------------------------------------------------------
Malloc the new image memeory
----------------------------------------------------------------------*/
struct image *image_new(int width, int height)
{
struct image *img = (struct image*)malloc(sizeof(struct image));
if(img)
{
img->width = width;
img->height = height;
img->bufsize = width*height*3;
img->buf = (char *)malloc(img->bufsize);
if(!img->bufsize)
{
free(img);
img = NULL;
}
}
return img;
}
/*----------------------------------------------------------------------
free the image memeory
----------------------------------------------------------------------*/
void image_delete(struct image *img)
{
free(img->buf);
}
/*----------------------------------------------------------------------
format the palette
----------------------------------------------------------------------*/
static void unpalette_bgr24(struct image *dst, unsigned char *src)
{
unsigned char *dstbuf, *dstend;
dstbuf = dst->buf;
dstend = dstbuf + dst->bufsize;
while (dstbuf < dstend)
{
dstbuf[0] = src[2];
dstbuf[1] = src[1];
dstbuf[2] = src[0];
dstbuf += 3;
src += 3;
}
}
/*-----------------------------------------------------------------------
Get the data to the Imagedata struct
-----------------------------------------------------------------------*/
struct imagedata *peek(struct caminfo *cam)
{
struct imagedata *ptr;
//获取jpeg图像数据
ptr = (struct imagedata*)malloc(sizeof(struct imagedata));
ptr = cam->data;
return ptr;
}
/*-----------------------------------------------------------
grab_thread
- runs only when clients are connected or when test mode
enabled
- captures an image, converts it to jpeg, pushes it on
queue, loops
-----------------------------------------------------------*/
int grab_thread(struct caminfo *cam)
{
char *jpeg_data = NULL;
int jpeg_len = 0;
struct imagedata *new;
struct image *img = NULL, *tmp = NULL;
while(1)
{
/*if(!cam->o.test_fps)
{
// wait for a connection
sem_wait(&cam->sem_con);
sem_post(&cam->sem_con);
}*/
/* fetch an image */
img = get_cam_image(cam);
if(img == NULL)
{
printf("Bad image grab\n");
usleep(100000);
continue;
}
/* convert to rgb24 */
tmp = image_new(img->width, img->height);
unpalette_bgr24(tmp, img->buf);
img = tmp;
/* swap rgb? */
if(cam->o.swap_rgb)
swap_rgb24(img);
/* adjust gamma? */
if(cam->o.gamma)
adjust_gamma(img, cam->o.gamma);
/* flip horiz/vert */
if(cam->o.flip_horiz)
fliph(img);
if(cam->o.flip_vert)
flipv(img);
/* rotate image? */
if(cam->o.rotate > 0)
rotate_image(img, cam->o.rotate);
/* add the caption? */
/*if(cam->o.caption && strlen(cam->o.caption) > 0)
{
char *text,*tmp;
char viewers[16], frames[16], version[16];
int x,y;
snprintf(viewers, 15, "%d", cam->s.num_users);
snprintf(frames, 15, "%d", cam->s.id_newest_img);
snprintf(version, 15, "%s", get_version());
tmp = str_replace(cam->o.caption, "%%v", viewers);
text = str_replace(tmp, "%%f", frames);
free(tmp);
tmp = str_replace(text, "%%V", version);
free(text);
text = tmp;
x = 50;
y = 20;
add_text(img, text, cam->o.text_fg, cam->o.text_bg, cam->o.trans, cam->o.text_xpos, cam->o.text_ypos);
free(text);
}*/
/* allocate some storage for the new image */
new = (struct imagedata *)malloc(sizeof(struct imagedata));
if(!new)
{
printf("imagedata malloc is error\n");
free(new);
continue;
}
/* compress the image in jpeg format */
jpeg_len = image2jpeg(img, &jpeg_data, cam->o.jpeg_quality);
image_delete(tmp);
free(tmp);
/* set fields */
new->len = jpeg_len;
new->jpeg_data = jpeg_data;
cam->data = new ;
//printf("The image length is =====%d\n", jpeg_len);
//free(new);
//image_delete(img);
//free(img);
}
printf("grab thread exiting...\n");
munmap(cam->mmap, cam->vid_mbuf.size);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -