📄 webcam.c
字号:
/* * (c) 1998-2000 Gerd Knorr * (c) 2000-2004 Tom Gilbert * */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <math.h>#include <stdarg.h>#include <errno.h>#include <fcntl.h>#include <time.h>#include <sys/time.h>#include <sys/mman.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/select.h>#include <signal.h>#include <X11/Xlib.h>#include <Imlib2.h>#include <giblib.h>#include <curl/types.h>#include <curl/curl.h>#include <curl/easy.h>#include <sys/types.h>#include <linux/videodev.h>#include <net/if.h>#include "parseconfig.h"#include "pwc-ioctl.h"#define VERSION "1.9"void camlog(char *fmt, ...);char *ftp_host = "www";char *ftp_user = "webcam";char *ftp_pass = "xxxxxx";char *ftp_dir = "public_html/images";char *ftp_file = "webcam.jpeg";char *ftp_tmp = "uploading.jpeg";int ftp_debug = 0;char *temp_file = "/tmp/webcam.jpg";pid_t childpid = 0;int ftp_passive = 1;int ftp_do = 1;int ftp_upload_every = 1; /* default to upload every shot */int ftp_keepalive = 1;int ftp_delete_first = 0;char *scp_target = NULL;char *grab_device = "/dev/video0";char *grab_text = ""; /* strftime */char *action_pre_shot = NULL;char *action_post_shot = NULL;char *action_post_upload = NULL;char *grab_infofile = NULL;char *logfile = NULL;int grab_width = 320;int grab_height = 240;float grab_delay = 3.0;int grab_quality = 75;int lag_reduce = 5;int scp_timeout = 30;int text_r = 255;int text_g = 255;int text_b = 255;int text_a = 255;char *text_font = "arial/8";int title_r = 255;int title_g = 255;int title_b = 255;int title_a = 255;int bg_r = 0;int bg_g = 0;int bg_b = 0;int bg_a = 150;int close_dev = 0;int ftp_timeout = 30;int cam_contrast = 50;int cam_brightness = 50;int cam_hue = 50;int cam_colour = 50;int cam_whiteness = 50;int cam_framerate = 10;char *title_font = "arial/8";char *ttf_dir = "/usr/X11R6/lib/X11/fonts/TrueType";char *archive_ext = "jpg";char *grab_archive = NULL;int archive_subdirs = 0; /* default to archive without */ /* subdirs */int archive_shot_every = 1; /* default to archive every shot */char *archive_thumbnails_dir = NULL;int archive_thumbnails_create = 0; /* default is not to create archive thumbnails */int archive_thumbnails_width = 120;int archive_thumbnails_height = 90;char *grab_blockfile = NULL;char *upload_blockfile = NULL;char *grab_postprocess = NULL;char *title_text = NULL;gib_style *title_style = NULL;gib_style *text_style = NULL;char *title_style_file = NULL;char *text_style_file = NULL;char *overlay_file = NULL;Imlib_Image overlay_im = NULL;int overlay_x = 0, overlay_y = 0;Imlib_Font title_fn, text_fn;char *ftp_interface = "-";char *watch_interface = NULL;char *offline_image = NULL;int interface_active = 0;int device_palette;char *pwc_wb_mode = "auto";int pwc_wb_red = 50;int pwc_wb_blue = 50;int crop = 0;int crop_x = 0;int crop_y = 0;int crop_width = 0;int crop_height = 0;int scale = 0;int scale_width = 0;int scale_height = 0;int v_width[5] = { 128, 160, 176, 320, 640 };int v_height[5] = { 96, 120, 144, 240, 480 };int v_curr = -1;int v_force = 0;int bw_percent = 100;int delay_correct = 0;int reinit_device = 0;int flip_horizontal = 0;int flip_vertical = 0;int orientation = 0;int connections = 0;CURL *curl_handle = NULL;struct video_picture cam_pic;/* these work for v4l only, not v4l2 */int grab_input = 0;int grab_norm = VIDEO_MODE_PAL;static struct video_mmap grab_buf;static int grab_fd = -1;static int grab_size = 0;static unsigned char *grab_data = NULL;Imlib_Image convert_yuv420p_to_imlib2(unsigned char *mem, int width, int height);int execvp_with_timeout(int timeout, char *file, char **argv);void alarm_handler(int sig);int save_image(Imlib_Image image, char *file);struct timeval add_timevals( struct timeval t1, struct timeval t2 ){ struct timeval tr; tr.tv_usec = t1.tv_usec + t2.tv_usec; tr.tv_sec = t1.tv_sec + t2.tv_sec + tr.tv_usec/1000000; tr.tv_usec = tr.tv_usec%1000000; return tr;}struct timeval sub_timevals( struct timeval t1, struct timeval t2 ){ struct timeval tr; tr.tv_usec = t1.tv_usec - t2.tv_usec; tr.tv_sec = t1.tv_sec - t2.tv_sec + t1.tv_usec/1000000; while( tr.tv_usec<0 ){ tr.tv_sec-=1; tr.tv_usec+=1000000; } return tr;}float float_timeval( struct timeval t ){ float f = 1e-6 * t.tv_usec; f += t.tv_sec; return f;}struct timeval timeval_float( float f ){ struct timeval tr; tr.tv_sec = (time_t) floor(f); f -= tr.tv_sec; tr.tv_usec = (suseconds_t) round(1e6*f); return tr;}voidclose_device(){ if (munmap(grab_data, grab_size) != 0) { perror("munmap()"); exit(1); } grab_data = NULL; if (close(grab_fd)) perror("close(grab_fd) "); grab_fd = -1;}inttry_palette(int fd, int pal, int depth){ cam_pic.palette = pal; cam_pic.depth = depth; if (ioctl(fd, VIDIOCSPICT, &cam_pic) < 0) return 0; if (ioctl(fd, VIDIOCGPICT, &cam_pic) < 0) return 0; if (cam_pic.palette == pal) return 1; return 0;}intfind_palette(int fd, struct video_mmap *vid){ if (try_palette(fd, VIDEO_PALETTE_RGB24, 24)) { camlog("negotiated palette RGB24\n"); return VIDEO_PALETTE_RGB24; } if (try_palette(fd, VIDEO_PALETTE_YUV420P, 16)) { camlog("negotiated palette YUV420P\n"); return VIDEO_PALETTE_YUV420P; } if (try_palette(fd, VIDEO_PALETTE_YUV420, 16)) { camlog("negotiated palette YUV420\n"); return VIDEO_PALETTE_YUV420; } fprintf(stderr, "No supported palette found, please report your device to the author\n"); exit(2); return 0;}voidgrab_init(){ struct video_capability grab_cap; struct video_channel grab_chan; struct video_mbuf vid_mbuf; int type; if ((grab_fd = open(grab_device, O_RDWR)) == -1) { fprintf(stderr, "open %s: %s\n", grab_device, strerror(errno)); exit(1); } if (ioctl(grab_fd, VIDIOCGCAP, &grab_cap) == -1) { fprintf(stderr, "%s: no v4l device\n", grab_device); exit(1); } if (ioctl(grab_fd, VIDIOCGPICT, &cam_pic) < 0) perror("getting pic info"); cam_pic.contrast = 65535 * ((float) cam_contrast / 100); cam_pic.brightness = 65535 * ((float) cam_brightness / 100); cam_pic.hue = 65535 * ((float) cam_hue / 100); cam_pic.colour = 65535 * ((float) cam_colour / 100); cam_pic.whiteness = 65535 * ((float) cam_whiteness / 100); if (ioctl(grab_fd, VIDIOCSPICT, &cam_pic) < 0) perror("setting cam pic"); device_palette = find_palette(grab_fd, &grab_buf); grab_buf.format = device_palette; grab_buf.frame = 0; grab_buf.width = grab_width; grab_buf.height = grab_height; ioctl(grab_fd, VIDIOCGMBUF, &vid_mbuf); camlog("%s detected\n", grab_cap.name); /* special philips features */ if (sscanf(grab_cap.name, "Philips %d webcam", &type) > 0) { struct video_window vwin; int shutter = -1; int gain = -1; struct pwc_whitebalance wb; /* philips cam detected, maybe enable special features */ camlog("enabling pwc-specific features\n"); ioctl(grab_fd, VIDIOCGWIN, &vwin); if (vwin.flags & PWC_FPS_MASK) { /* Set new framerate */ vwin.flags &= ~PWC_FPS_FRMASK; vwin.flags |= (cam_framerate << PWC_FPS_SHIFT); } /* Turning off snapshot mode */ vwin.flags &= ~(PWC_FPS_SNAPSHOT); if (ioctl(grab_fd, VIDIOCSWIN, &vwin) < 0) perror("trying to set extra pwc flags"); if (ioctl(grab_fd, VIDIOCPWCSAGC, &gain) < 0) perror("trying to set gain"); if (ioctl(grab_fd, VIDIOCPWCSSHUTTER, &shutter) < 0) perror("trying to set shutter"); wb.mode = PWC_WB_AUTO; wb.manual_red = 50; wb.manual_blue = 50; if (!strcasecmp(pwc_wb_mode, "auto")) { wb.mode = PWC_WB_AUTO; } else if (!strcasecmp(pwc_wb_mode, "indoor")) { wb.mode = PWC_WB_INDOOR; } else if (!strcasecmp(pwc_wb_mode, "outdoor")) { wb.mode = PWC_WB_OUTDOOR; } else if (!strcasecmp(pwc_wb_mode, "fluorescent")) { wb.mode = PWC_WB_FL; } else if (!strcasecmp(pwc_wb_mode, "manual")) { wb.mode = PWC_WB_MANUAL; wb.manual_red = 65535 * ((float) pwc_wb_red / 100); wb.manual_blue = 65535 * ((float) pwc_wb_blue / 100); } else { camlog("unknown pwc white balance mode '%s' ignored\n", pwc_wb_mode); } if (ioctl(grab_fd, VIDIOCPWCSAWB, &wb) < 0) perror("trying to set pwc white balance mode"); } /* set image source and TV norm */ grab_chan.channel = grab_input; if (ioctl(grab_fd, VIDIOCGCHAN, &grab_chan) == -1) { perror("ioctl VIDIOCGCHAN"); exit(1); } grab_chan.channel = grab_input; grab_chan.norm = grab_norm; if (ioctl(grab_fd, VIDIOCSCHAN, &grab_chan) == -1) { perror("ioctl VIDIOCSCHAN"); exit(1); } /* grab_size = grab_buf.width * grab_buf.height * 3; */ grab_size = vid_mbuf.size; grab_data = mmap(0, grab_size, PROT_READ | PROT_WRITE, MAP_SHARED, grab_fd, 0); if ((grab_data == NULL) || (MAP_FAILED == grab_data)) { fprintf(stderr, "couldn't mmap vidcam. your card doesn't support that?\n"); exit(1); }}/* This is a really simplistic approach. Speedups are welcomed. */Imlib_Imageconvert_yuv420p_to_imlib2(unsigned char *src, int width, int height){ int line, col; int y, u, v, yy, vr = 0, ug = 0, vg = 0, ub = 0; int r, g, b; unsigned char *sy, *su, *sv; Imlib_Image im; DATA32 *data, *dest; im = imlib_create_image(width, height); imlib_context_set_image(im); data = imlib_image_get_data(); dest = data; sy = src; su = sy + (width * height); sv = su + (width * height / 4); for (line = 0; line < height; line++) { for (col = 0; col < width; col++) { y = *sy++; yy = y << 8; u = *su - 128; ug = 88 * u; ub = 454 * u; v = *sv - 128; vg = 183 * v; vr = 359 * v; if ((col & 1) == 0) { su++; sv++; } r = (yy + vr) >> 8; g = (yy - ug - vg) >> 8; b = (yy + ub) >> 8; if (r < 0) r = 0; if (r > 255) r = 255; if (g < 0) g = 0; if (g > 255) g = 255; if (b < 0) b = 0; if (b > 255) b = 255; *dest = (r << 16) | (g << 8) | b | 0xff000000; dest++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -