?? mvc.c
字號:
/* * vidcat.c * * Copyright (C) 1998 Rasca, Berlin * EMail: thron@gmx.de * Modified: merlin@turbolinux.com.cn Jun.16, Jul.7, 2000 * * 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 <getopt.h>#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>#include <time.h>#include <jpeglib.h>#include "mvc.h"/* * read rgb image from v4l device * return: mmap'ed buffer and size */char *get_image (int dev, int width, int height, int input, int norm, int fmt, int *size){ struct video_capability vid_caps; struct video_mbuf vid_buf; struct video_mmap vid_mmap; struct video_channel vid_chnl; char *map; int len; if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { perror ("ioctl (VIDIOCGCAP)"); return (NULL); } vid_chnl.channel = -1; if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { perror ("ioctl (VIDIOCGCHAN)"); } else { printf("get channel failed\n"); vid_chnl.channel = input; vid_chnl.norm = norm; if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { perror ("ioctl (VIDIOCSCHAN)"); return (NULL); } else printf("get channel failed. but set channel success\n\n"); } if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { map = malloc (width * height * 3); len = read (dev, map, width * height * 3); if (len <= 0) { free (map); return (NULL); } *size = 0; return (map); } //void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset); //int munmap(void *start, size_t length); //mmap returns a pointer to the mapped area ,or MAP_FAILED (-1) is returned map = mmap (0, vid_buf.size, PROT_READ | PROT_WRITE, MAP_SHARED, dev, 0); if ((unsigned char *) -1 == (unsigned char *) map) //???? what's the meaning? { perror ("mmap()"); return (NULL); } vid_mmap.format = fmt; vid_mmap.frame = 0; vid_mmap.width = width; vid_mmap.height = height; if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { perror ("VIDIOCMCAPTURE"); munmap (map, vid_buf.size); return (NULL); } if (ioctl (dev, VIDIOCSYNC, &vid_mmap) == -1) { perror ("VIDIOCSYNC"); munmap (map, vid_buf.size); return (NULL); } *size = vid_buf.size; return (map);}/* * Write image buffer to timestamp named jpeg file. */voidput_image_jpeg (char *filename, char *image, int width, int height, int quality){ int y, x, line_width; JSAMPROW row_ptr[1]; struct jpeg_compress_struct cjpeg; struct jpeg_error_mgr jerr; char *line; FILE *fd; if ((fd = fopen (filename, "w+")) == NULL) { fprintf (stderr, "Error: Can't Create File %s\n", filename); exit (-2); } line = malloc (width * 3); if (!line) return; cjpeg.err = jpeg_std_error (&jerr); jpeg_create_compress (&cjpeg); cjpeg.image_width = width; cjpeg.image_height = height; cjpeg.input_components = 3; cjpeg.in_color_space = JCS_RGB; jpeg_set_defaults (&cjpeg); jpeg_set_quality (&cjpeg, quality, TRUE); cjpeg.dct_method = JDCT_FASTEST; jpeg_stdio_dest (&cjpeg, fd); jpeg_start_compress (&cjpeg, TRUE); row_ptr[0] = line; line_width = width * 3; 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]; } jpeg_write_scanlines (&cjpeg, row_ptr, 1); image += line_width; } jpeg_finish_compress (&cjpeg); jpeg_destroy_compress (&cjpeg); free (line); fclose (fd);}/* * main() */intmain (int argc, char *argv[]){ int width = DEF_WIDTH, height = DEF_HEIGHT, size, dev = -1, c, n = 0; char *image, *oldimg, *device = VIDEO_DEV; char lasttime[32], timename[32], filename[64]; time_t now; struct tm *tm; int max_try = 5; /* we try 5 seconds/times to open the device */ int quality = QUAL_DEFAULT; /* default jpeg quality setting */ int input = IN_DEFAULT; int norm = NORM_DEFAULT; int palette = VIDEO_PALETTE_RGB24; int blk_x = 16; int blk_y = 8; int color_lim = 50; int blk_lim = blk_x * blk_y / 64 + 1; oldimg = malloc (width * height * 3); while ((c = getopt (argc, argv, "s:q:a:b:c:n:i:d")) != EOF) { switch (c) { case 'd': device = optarg; break; case 's': sscanf (optarg, "%dx%d", &width, &height); break; case 'a': sscanf (optarg, "%dx%d", &blk_x, &blk_y); blk_lim = blk_x * blk_y / 64 + 1; break; case 'b': sscanf (optarg, "%d", &blk_lim); break; case 'c': sscanf (optarg, "%d", &color_lim); break; case 'n': if (strcasecmp ("ntsc", optarg) == 0) { norm = NORM_NTSC; } else if (strcasecmp ("pal", optarg) == 0) { norm = NORM_PAL; } else if (strcasecmp ("secam", optarg) == 0) { norm = NORM_SECAM; } break; case 'q': sscanf (optarg, "%d", &quality); break; case 'i': if (strcasecmp ("tv", optarg) == 0) { input = IN_TV; } else if (strcasecmp ("comp1", optarg) == 0) { input = IN_COMPOSITE; } else if (strcasecmp ("comp2", optarg) == 0) { input = IN_COMPOSITE2; } else if (strcasecmp ("s-video", optarg) == 0) { input = IN_SVIDEO; } break; default: fprintf (stderr, "%s, Version %s\n" "Usage: %s <options>\n" " -s XxY define size of the output image (default: %dx%d)\n" " -a HxV define sense areas in Horizantal and Vertical (default: %dx%d)\n" " -i {tv|comp1|comp2|s-video} which input channel to use\n" " -n {pal|ntsc|secam} which norm to use, default: PAL\n" " -q <quality> only for jpeg: quality setting (1-100, default: %d)\n" " -d <device> video device (default: " VIDEO_DEV ")\n" " -b <diff_block_limit> blocks different limit, default: %d\n" " -c <diff_color_limit> color different limit, default: %d\n", argv[0], VERSION, argv[0], DEF_WIDTH, DEF_HEIGHT, blk_x, blk_y, QUAL_DEFAULT, blk_lim, color_lim); exit (1); break; } }#ifdef DEBUG fprintf (stderr, "-------------------- Debug Info ---------------------\n"); fprintf (stderr, " ImageSize: %dx%d\n", width, height); fprintf (stderr, " ImageQuality: %d\n", quality); fprintf (stderr, " VideoDEV: %s\n", device); fprintf (stderr, " VideoInput(TV=0, COMP1=1, COMP2=2, SVIDEO=3): %d\n", input); fprintf (stderr, " VideoNORM(PAL=0, NTSC=1, SECAM=2, AUTO=3): %d\n", norm); fprintf (stderr, " SenseBlockSize: %dx%d\n", blk_x, blk_y); fprintf (stderr, " ColorLimit: %d\n", color_lim); fprintf (stderr, " BlockLimit: %d\n", blk_lim); fprintf (stderr, "-----------------------------------------------------\n");#endifloop: /* open the video4linux device */ max_try = 5; while ((dev = open (device, O_RDWR)) == -1 && --max_try) sleep (1); if (dev == -1) { fprintf (stderr, "Can't open device %s\n", VIDEO_DEV); exit (-1); } else { printf("device opening success!"); } image = get_image (dev, width, height, input, norm, palette, &size); if (image) { if (cmp_img(image, oldimg, width, height, blk_x, blk_y, color_lim, blk_lim) == 1) { time (&now); tm = localtime (&now); strftime (timename, 31, "%Y%m%d-%H%M%S", tm); if (strcmp (timename, lasttime) == 0) n++; else n = 0; strcpy (lasttime, timename); sprintf (filename, "mvc%s-%d.jpg", timename, n);#ifdef DEBUG printf ("Writing: %s \a\n", filename);#endif put_image_jpeg (filename, image, width, height, quality); } memcpy (oldimg, image, width * height * 3); if (size) munmap (image, size); else if (image) free (image); } else { fprintf (stderr, "Error: Can't get image\n"); } close (dev); usleep (500000); goto loop;}/* * Compare image img1 and img2 by split blocks, * if changed, return 1. */intcmp_img (char *img1, char *img2, int width, int height, int split_x, int split_y, int c_lim, int b_lim){ int i, count; RGB a1[8192], a2[8192]; int color_diff[8192]; proc_img (a1, img1, width, height, split_x, split_y); proc_img (a2, img2, width, height, split_x, split_y); count = 0; for (i = 0; i < split_x * split_y; i++) { color_diff[i] = abs (a1[i].red - a2[i].red) + abs (a1[i].green - a2[i].green) + abs (a1[i].blue - a2[i].blue); if (color_diff[i] > c_lim) { count++; } if (count >= b_lim) { return 1; } } return 0;}/* * Split image buffer *img (width=w, height=h) into sx * sy blocks. * For every splited block, calculate its average RGB color, then * store this RGB color into array r. */intproc_img (RGB * r, char *img, int w, int h, int sx, int sy){ unsigned char *p; int x, y, m, n; int blk_wid = w / sx, blk_hgt = h / sy; int x0, y0, x1, y1; unsigned long s = blk_wid * blk_hgt; unsigned long R, G, B; for (n = 1; n <= sy; n++) { for (m = 1; m <= sx; m++) { x0 = (m - 1) * blk_wid; y0 = (n - 1) * blk_hgt; x1 = blk_wid * m - 1; y1 = blk_hgt * n - 1; R = G = B = 0; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) { p = img + (y * w + x) * 3; R += *(p + 2); G += *(p + 1); B += *p; } } r->red = R / s; r->green = G / s; r->blue = B / s; r++; } } return s;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -