📄 w3cam.c
字号:
/* * w3cam.c * * Copyright (C) 1998 - 2001 Rasca, Berlin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <errno.h>#ifdef USE_SYSLOG#include <syslog.h>#endif#if defined __GLIBC__ && __GLIBC__ >= 2#include <libgen.h> /* basename */#endif#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <fcntl.h>#include <unistd.h>#include <linux/types.h>#include <linux/videodev.h>#ifdef HAVE_LIBZ#include <zlib.h>#endif#ifdef HAVE_LIBPNG#include <png.h>#endif#ifdef HAVE_LIBJPEG#include <jpeglib.h>#endif#ifdef HAVE_LIBTTF#include <freetype.h>#endif#include "w3cam.h"#include "cgi.h"#include "v4l.h"/* * some default values, change these to fit your needs * most of these could be changed at runtime with config file */#define FMT_DEFAULT FMT_JPEG /* FMT_PPM, FMT_JPEG, FMT_PNG */#define QUALITY_DEFAULT 65 /* JPEG default quality */#define WIDTH_DEFAULT 240 /* default width and height of the image */#define HEIGHT_DEFAULT 180#define MODE_DEFAULT MODE_PLAIN /* MODE_GUI or MODE_PLAIN */#define USEC_DEFAULT 20000 /* wait microseconds before capturing */#define REFRESH_DEFAULT OFF /* don't use refreshing */#define MIN_REFRESH 0.0 /* min refresh time, compile time option */#define FREQLIST_DEFAULT "878;9076;9844;9460" /* default frequenzies */#define MAX_TRY_OPEN 20 /* may be the device is locked, so try max*//* end of default values * ********************* *//* */voidusage (char *pname, int width, int height, int color, int quality, int usec){ cgi_response (http_bad_request, "text/html"); printf ( "<title>w3cam - help</title><pre>W3Cam, Version %s\n\n" "Usage: %s<?parameters>\n" "CGI parameters (GET or POST):\n" " help show this page\n" " size=#x# geometry of picture " "[default = %dx%d]\n" " color={0|1} color or grey mode " "[default = %d]\n" " input={tv|composite|composite2|s-video} define input source\n" " quality={1-100} jpeg quality " "[default = %d]\n" " format={ppm|png|jpeg} output format\n" " freq=# define frequenzy for TV\n" " usleep=# sleep # micro secs before cap. " "[default = %d]\n" " mode=[gui|html] build a page with panel or plain html\n" " refresh=#.# time in sec to refresh gui\n" " norm={pal|ntsc|secam} tv norm\n" " bgr={1|0} swap RGB to BGR (default: no)\n", VERSION, basename(pname), width, height, color, quality, usec); printf ( "\nCompiled in features:\n");#ifdef HAVE_LIBPNG printf (" PNG file format\n");#endif#ifdef HAVE_LIBJPEG printf (" JPEG file format\n");#endif#ifdef HAVE_LIBTTF printf ( " TTF/TimeStamp\n");#endif#ifdef USE_SYSLOG printf ( " SYSLOG support\n");#endif exit (0);}/* */voidlog (char *info){#ifdef USE_SYSLOG syslog (LOG_USER, "%s\n", info);#else fprintf (stderr, "%s\n", info);#endif}/* */voidlog2 (char *s1, char *s2){#ifdef USE_SYSLOG syslog (LOG_USER, "%s %s\n", s1, s2);#else fprintf (stderr, "%s %s\n", s1, s2);#endif}/* * parse comma seperated frequency list */char **parse_list (char *freqs){ char **flist = NULL; char *p = freqs, *end = NULL; int num = 0, i, len; if (!freqs) return (NULL); while ((p = strchr(p, ';')) != NULL) { p++; num++; } num++; flist = malloc ((num + 1) * sizeof (char *)); flist[num] = NULL; p = freqs; for (i = 0; i < num; i++) { if (i == (num-1)) { /* last element */ len = strlen (p); } else { end = strchr(p, ';'); len = end - p; } flist[i] = malloc (len+1); strncpy (flist[i], p, len); p = end+1; } return (flist);}/* * read rgb image from v4l device * return: new allocated buffer */unsigned char *get_image (int dev, int width, int height, int input, int usec, unsigned long freq, int palette){ struct video_mbuf vid_buf; struct video_mmap vid_mmap; char *map; unsigned char *buff; int size, len, bpp; register int i; if (input == IN_TV) { if (freq > 0) { if (ioctl (dev, VIDIOCSFREQ, &freq) == -1) log2 ("ioctl (VIDIOCSREQ):", strerror(errno)); } } /* it seems some cards need a little bit time to come in sync with the new settings */ if (usec) usleep (usec); if (palette != VIDEO_PALETTE_GREY) { /* RGB or YUV */ size = width * height * 3; bpp = 3; } else { size = width * height * 1; bpp = 1; } vid_mmap.format = palette; if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { /* do a normal read() */ struct video_window vid_win; if (ioctl (dev, VIDIOCGWIN, &vid_win) != -1) { vid_win.width = width; vid_win.height = height; if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) { log2 ("ioctl(VIDIOCSWIN):", strerror(errno)); return (NULL); } } map = malloc (size); if (!map) return (NULL); len = read (dev, map, size); if (len <= 0) { free (map); return NULL; } if (palette == VIDEO_PALETTE_YUV420P) { char *convmap; convmap = malloc ( width * height * bpp ); v4l_yuv420p2rgb (convmap, map, width, height, bpp * 8); memcpy (map, convmap, (size_t) width * height * bpp); free (convmap); } else if (palette == VIDEO_PALETTE_YUV422P) { char *convmap; convmap = malloc ( width * height * bpp ); v4l_yuv422p2rgb (convmap, map, width, height, bpp * 8); memcpy (map, convmap, (size_t) width * height * bpp); free (convmap); } return (map); } map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0); if ((unsigned char *)-1 == (unsigned char *)map) { log2 ("mmap():", strerror(errno)); return (NULL); } vid_mmap.frame = 0; vid_mmap.width = width; vid_mmap.height =height; if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { log2 ("ioctl(VIDIOCMCAPTURE):", strerror(errno)); munmap (map, vid_buf.size); return (NULL); } if (ioctl (dev, VIDIOCSYNC, &vid_mmap.frame) == -1) { log2 ("ioctl(VIDIOCSYNC):", strerror(errno)); munmap (map, vid_buf.size); return (NULL); } buff = (unsigned char *) malloc (size); if (buff) { if (palette == VIDEO_PALETTE_YUV420P) { v4l_yuv420p2rgb (buff, map, width, height, 24); } else if (palette == VIDEO_PALETTE_YUV422P) { v4l_yuv422p2rgb (buff, map, width, height, 24); } else { for (i = 0; i < size; i++) buff[i] = map[i]; } } else { perror ("malloc()"); } munmap (map, vid_buf.size); return (buff);}/* */voidput_image_jpeg (char *image, int width, int height, int quality, int color){#ifdef HAVE_LIBJPEG register int x, y, line_width; JSAMPROW row_ptr[1]; struct jpeg_compress_struct cjpeg; struct jpeg_error_mgr jerr; char *line = NULL; if (color) { line_width = width * 3; line = malloc (line_width); if (!line) return; } else { line_width = width; } cjpeg.err = jpeg_std_error(&jerr); jpeg_create_compress (&cjpeg); cjpeg.image_width = width; cjpeg.image_height= height; if (color) { cjpeg.input_components = 3; cjpeg.in_color_space = JCS_RGB; } else { cjpeg.input_components = 1; cjpeg.in_color_space = JCS_GRAYSCALE; } jpeg_set_defaults (&cjpeg); jpeg_simple_progression (&cjpeg); jpeg_set_quality (&cjpeg, quality, TRUE); cjpeg.dct_method = JDCT_FASTEST; jpeg_stdio_dest (&cjpeg, stdout); jpeg_start_compress (&cjpeg, TRUE); if (color) { row_ptr[0] = line; for ( y = 0; y < height; y++) { for (x = 0; x < line_width; x += 3) { line[x] = image[x+2]; line[x+1] = image[x+1]; line[x+2] = image[x]; } image += line_width; jpeg_write_scanlines (&cjpeg, row_ptr, 1); } free (line); } else { for ( y = 0; y < height; y++) { row_ptr[0] = image; jpeg_write_scanlines (&cjpeg, row_ptr, 1); image += line_width; } } jpeg_finish_compress (&cjpeg); jpeg_destroy_compress (&cjpeg);#endif}/* * write png image to stdout */voidput_image_png (char *image, int width, int height, int color){#ifdef HAVE_LIBPNG register int y; register char *p; png_infop info_ptr; png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return; info_ptr = png_create_info_struct (png_ptr); if (!info_ptr) return; png_init_io (png_ptr, stdout); if (color) { png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_bgr (png_ptr); } else { png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } png_write_info (png_ptr, info_ptr); p = image; if (color) { width *= 3; for (y = 0; y < height; y++) { png_write_row (png_ptr, p); p += width; } } else { for (y = 0; y < height; y++) { png_write_row (png_ptr, p); p += width; } } png_write_end (png_ptr, info_ptr); png_destroy_write_struct (&png_ptr, &info_ptr);#endif}/* * write ppm image to stdout */voidput_image_ppm (char *image, int width, int height){ int x, y, ls=0; unsigned char *p = (unsigned char *)image; printf ("P3\n%d %d\n%d\n", width, height, 255); for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { printf ("%03d %03d %03d ", p[2], p[1], p[0]); p += 3; if (ls++ > 4) { printf ("\n"); ls = 0; } } }}/* */const char *palette2string (int palette) { if (palette == VIDEO_PALETTE_RGB24) return "rgb24"; if (palette == VIDEO_PALETTE_YUV420P) return "yuv420p"; if (palette == VIDEO_PALETTE_YUV422P) return "yuv422p"; if (palette == VIDEO_PALETTE_GREY) return "grey"; return "color";}/* * create a plain html page */voidmake_html (int width, int height, int color, int input, int fmt, int quality, float refresh, int us, int norm, int freq, char **freqs, int pal, int swapRGB){ cgi_response (http_ok, "text/html"); /* cgi_refresh (refresh, NULL); */ cgi_html_start ("W3Cam"); printf ("<DIV class=image><IMG width=%d height=%d src=\"%s?" "size=%dx%d&color=%s&id=%d&refresh=%1.2f&usleep=%d&freq=%d" "&mode=plain", width, height, cgi_script_name(), width, height, palette2string(pal),(int)time(NULL), refresh, us, freq); if (input != INPUT_DEFAULT) printf ("&input=%s", input == IN_TV? "tv" : input == IN_COMP1 ? "composite" : input == IN_COMP2? "composite2" : "s-video"); if (norm != OFF) printf ("&norm=%s", norm == NORM_PAL ? "pal": norm == NORM_NTSC ? "ntsc" : "secam"); if (fmt != FMT_DEFAULT) printf ("&format=%s", fmt == FMT_PNG? "png": fmt == FMT_JPEG? "jpeg": "ppm"); if (quality) printf ("&quality=%d", quality); if (swapRGB) printf ("&bgr=1"); printf ("\"></DIV>\n");}/* * create a html page with panel */voidmake_gui (int width, int height, int color, int input, int fmt, int quality, float refresh, int us, int norm, int freq, char **freqs, int pal, int swapRGB){ make_html (width, height, color, input, fmt, quality, refresh, us, norm, freq, freqs, pal, swapRGB); printf ("<P><DIV class=panel><FORM>\n"); printf ("<INPUT type=hidden name=width value=%d>", width); printf ("<INPUT type=hidden name=height value=%d>\n", height); printf ("<INPUT type=hidden name=mode value=gui>"); printf ("<INPUT type=hidden name=quality value=%d>\n", quality); printf ("<INPUT type=hidden name=usleep value=%d>\n", us); printf ("Input:<SELECT name=input>\n"); printf ("<option%s value='-1'>Default</option>", input == INPUT_DEFAULT? " selected":""); printf ("<option%s>TV</option>", input == IN_TV? " selected":""); printf ("<option%s>Composite</option>", input == IN_COMP1 ? " selected":""); printf ("<option%s>Composite2</option>", input == IN_COMP2? " selected":""); printf ("<option%s>S-Video</option></SELECT>\n", input == IN_SVIDEO? " selected":""); if ((norm != OFF) && (input == IN_TV)) { printf ("Norm:<SELECT name=norm>\n"); printf ("<option%s>PAL</option>", norm == NORM_PAL ? " selected":""); printf ("<option%s>NTSC</option>", norm == NORM_NTSC? " selected":"");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -