📄 vidcat_ok_1.c
字号:
/* * vidcat.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 <getopt.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/time.h> /* gettimeofday() */#include <fcntl.h>#include <unistd.h>#include <linux/types.h>#include <linux/videodev.h>#include <signal.h>#include <jpeglib.h>#include "v4l.c"int end = 0;#define DEF_WIDTH 320 /* default width */#define DEF_HEIGHT 240 /* default height */#define FMT_UNKNOWN 0#define FMT_PPM 1#define FMT_PGM 2#define FMT_PNG 3#define FMT_JPEG 4#define FMT_YUV4MPEG 5#define FMT_RAW 6#define IN_TV 0#define IN_COMPOSITE 1#define IN_COMPOSITE2 2#define IN_SVIDEO 3#define NORM_PAL 0#define NORM_NTSC 1#define NORM_SECAM 2#define QUAL_DEFAULT 80#define VIDEO_DEV "/dev/video0"#define VERSION 5#define BMP_BUF_LEN (640 * 480 * 3)#define RGB565_BUF_LEN (BMP_BUF_LEN* 2 / 3)void put_image_jpeg (FILE *out, char *image, int width, int height, int quality, int palette);int to_yuv (FILE *out, int fd, int width, int height);int lcd_display(char *image,int width, int height,int startx,int starty);char *basename (const char *s);/* globals */static int verbose = 0;/* */doublems_time (void){ static struct timeval tod; gettimeofday (&tod, NULL); return ((double)tod.tv_sec * 1000.0 + (double)tod.tv_usec / 1000.0); }#define TIMEOUT 200void alarm_timeout(int signum){ static int i = 0; if (i < TIMEOUT) { i++; alarm(1); } else { end = 1; } return;} /* * read rgb image from v4l device * return: mmap'ed buffer and size */char *get_image (int dev, int width, int height, int palette, int *size, int pics, int timeout){ struct video_mbuf vid_buf; struct video_mmap vid_mmap; char *map, *convmap; int len; int bytes = 3; char name[20]; FILE *fp; sigset_t newset; unsigned int total = 0; unsigned int i; if (pics > 0 && timeout > 0) { fprintf(stderr, "can't assign both -t and -m options\n"); return NULL; } if (palette == VIDEO_PALETTE_GREY) bytes = 1; /* bytes per pixel */ if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { /* to do a normal read() */ struct video_window vid_win; if (verbose) { fprintf (stderr, "using read()\n"); } if (ioctl (dev, VIDIOCGWIN, &vid_win) != -1) { vid_win.width = width; vid_win.height = height; if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) { perror ("ioctl(VIDIOCSWIN)"); return (NULL); } } map = malloc (width * height * bytes); len = read (dev, map, width * height * bytes); if (len <= 0) { free (map); return (NULL); } *size = 0; if (palette == VIDEO_PALETTE_YUV420P) { convmap = malloc ( width * height * bytes ); v4l_yuv420p2rgb (convmap, map, width, height, bytes * 8); memcpy (map, convmap, (size_t) width * height * bytes); free (convmap); } else if (palette == VIDEO_PALETTE_YUV422P) { convmap = malloc ( width * height * bytes ); v4l_yuv422p2rgb (convmap, map, width, height, bytes * 8); memcpy (map, convmap, (size_t) width * height * bytes); 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) { perror ("mmap()"); return (NULL); } vid_mmap.format = palette; vid_mmap.frame = 0; vid_mmap.width = width; vid_mmap.height = height; convmap = malloc ( width * height * bytes ); if (!convmap) { fprintf (stderr, "alloc convmap error"); munmap (map, vid_buf.size); return NULL; } if (!timeout) goto next; /* 创建ALARM信号处理函数 */ if (sigemptyset(&newset)) { fprintf (stderr, "init signale set error\n"); free(convmap); munmap (map, vid_buf.size); return (NULL); } if (sigaddset(&newset, SIGALRM)) { fprintf (stderr, "add SIGALRM error\n"); free(convmap); munmap (map, vid_buf.size); return (NULL); } if (!sigismember(&newset, SIGALRM)) { perror("SIGALRM is not in signale set"); free(convmap); munmap (map, vid_buf.size); return (NULL); } if (sigprocmask(SIG_UNBLOCK, &newset, NULL)) { fprintf (stderr, "set signal mask error\n"); free(convmap); munmap (map, vid_buf.size); return (NULL); } if (signal(SIGALRM, alarm_timeout)) { fprintf (stderr, "create signal handler error\n"); free(convmap); munmap (map, vid_buf.size); return (NULL); } alarm(1);next: for (i = 0; i < pics || !end; i++, vid_mmap.frame = i & 1) { if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) < 0) { perror ("VIDIOCMCAPTURE"); fprintf (stderr, "args: width=%d height=%d palette=%d\n", vid_mmap.width, vid_mmap.height, vid_mmap.format); free(convmap); munmap (map, vid_buf.size); return (NULL); } if (ioctl (dev, VIDIOCSYNC, &vid_mmap.frame) < 0) { perror ("VIDIOCSYNC"); free(convmap); munmap (map, vid_buf.size); return (NULL); } *size = vid_buf.size; /* 完成指定的实验数 */ if (timeout) continue; if (palette == VIDEO_PALETTE_YUV420P) { if (verbose) fprintf (stderr, "converting from YUV to RGB\n"); v4l_yuv420p2rgb (convmap, map, width, height, bytes * 8); } else if (palette == VIDEO_PALETTE_YUV422P) { if (verbose) fprintf (stderr, "converting from YUV to RGB\n"); v4l_yuv422p2rgb (convmap, map, width, height, bytes * 8); } sprintf(name, "/tmp/%d.jpg", 1); fp = fopen(name, "wr"); put_image_jpeg(fp, convmap, width, height, 80, palette); fclose(fp); lcd_display(convmap,width,height,128,128); } if (end) fprintf (stderr, "FPS %f for %d, count %d\n", (float)i / TIMEOUT, TIMEOUT, i); memcpy (map, convmap, (size_t) width * height * bytes); free (convmap); return (map); if (verbose) fprintf (stderr, "got picture\n");}/* */voidput_image_jpeg (FILE *out, char *image, int width, int height, int quality, int palette){//#ifdef HAVE_LIBJPEG int y, x, line_width; JSAMPROW row_ptr[1]; struct jpeg_compress_struct cjpeg; struct jpeg_error_mgr jerr; char *line; line = malloc (width * 3); if (!line) return; if (verbose) fprintf (stderr, "writing JPEG data\n"); cjpeg.err = jpeg_std_error(&jerr); jpeg_create_compress (&cjpeg); cjpeg.image_width = width; cjpeg.image_height= height; if (palette == VIDEO_PALETTE_GREY) { cjpeg.input_components = 1; cjpeg.in_color_space = JCS_GRAYSCALE; } else { 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, out); jpeg_start_compress (&cjpeg, TRUE); row_ptr[0] = line; if (palette == VIDEO_PALETTE_GREY) { line_width = width; for ( y = 0; y < height; y++) { row_ptr[0] = image; jpeg_write_scanlines (&cjpeg, row_ptr, 1); image += line_width; } } else { 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);//#endif}/* * write YUV4MPEG stream which is nice for mpeg2enc */intto_yuv (FILE *out, int fd, int width, int height){ struct video_mbuf vid_buf; struct video_mmap vid_mmap; int do_read = 0; int done = 0; char *map; int size; int num = 0; double ms_time0, ms_time1; int tpf = 40; /* 40 ms time per frame (= 25 fps) */ if (ioctl (fd, VIDIOCGMBUF, &vid_buf) == -1) { do_read = 1; } else { fprintf (stderr, "buffsize=%d frames=%d\n",vid_buf.size,vid_buf.frames); } if (!do_read) { map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0); if ((unsigned char *)-1 == (unsigned char *)map) { perror ("mmap()"); return -1; } vid_mmap.format = VIDEO_PALETTE_YUV420P; vid_mmap.frame = 0; vid_mmap.width = width; vid_mmap.height =height; size = (width * height) + (width * height / 2); fprintf (stderr, "%dx%d bufsize=%d size=%d\n", width, height, vid_buf.size, size); printf ("YUV4MPEG%d %d %d\n", width, height, 3); if (ioctl (fd, VIDIOCMCAPTURE, &vid_mmap) == -1) { perror ("ioctl VIDIOCMCAPTURE"); munmap (map, vid_buf.size); return -1; } vid_mmap.frame = 1; if (ioctl (fd, VIDIOCMCAPTURE, &vid_mmap) == -1) { perror ("ioctl VIDIOCMCAPTURE"); munmap (map, vid_buf.size); return -1; } while (!done) { ms_time0 = ms_time(); /* milli seconds */ vid_mmap.frame = vid_mmap.frame > 0 ? 0 : 1; if (ioctl (fd, VIDIOCSYNC, &vid_mmap.frame) == -1) { perror ("ioctl VIDIOCSYNC"); munmap (map, vid_buf.size); return -1; } printf ("FRAME\n"); fwrite (map + vid_buf.offsets[vid_mmap.frame], 1, size, stdout); if (ioctl (fd, VIDIOCMCAPTURE, &vid_mmap) == -1) { perror ("ioctl VIDIOCMCAPTURE"); munmap (map, vid_buf.size); return -1; } num++; ms_time1 = ms_time () - ms_time0; if (ms_time1 < (double)tpf) { usleep (tpf - (int)ms_time1); } else { fprintf (stderr, "delayed: dt=%f\n",ms_time1 - (double)tpf); } } munmap (map, vid_buf.size); } else { fprintf (stderr, "still not implemented\n"); } return 0;}/** Display RGB24 BMP map on lcd for play video*/int lcd_display(char *image,int width, int height,int startx,int starty){ int fd; unsigned short *bgr565_buf_tmp; unsigned int y, x; bgr565_buf_tmp = (unsigned short *)malloc(RGB565_BUF_LEN); for (y = 0; y <height && (y+starty) < 480; y++) { for (x = 0; x < width*3 && (startx+x/3) < 640; ) { unsigned short b, g, r; b=0;r=0;g=0; b = image[x + 0+width*y*3]; g = image[x + 1+width*y*3]; r = image[x + 2+width*y*3]; bgr565_buf_tmp[x/3+startx+640*(y+starty)] = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); x+=3; } } fd = open("/dev/fb0", O_WRONLY); write(fd, bgr565_buf_tmp, RGB565_BUF_LEN); close(fd); free(bgr565_buf_tmp); return 0;}/* * main() */intmain (int argc, char *argv[]){ int width = DEF_WIDTH, height = DEF_HEIGHT, size, dev = -1, c; char *image, *device = VIDEO_DEV, *file = NULL; int max_try = 5; /* we try 5 seconds/times to open the device */ int quality = QUAL_DEFAULT; /* default jpeg quality setting */ int input = INPUT_DEFAULT; /* this means take over current device settings*/ int norm = NORM_DEFAULT; int loop =0 ; int binary = 0; int palette = VIDEO_PALETTE_YUV420P; int num = 0; FILE *out = stdout; int timeout = 0; int pics = 0; int format = FMT_JPEG; if (file) { out = fopen (file, "wb"); if (!out) { perror (file); return 1; } }again: /* open the video4linux device */ while (max_try) { dev = open (device, O_RDWR); if (dev == -1) { if (!--max_try) { fprintf (stderr, "Can't open device %s\n", device); return (1); } sleep (1); } else break; } if (!num) { /* if we loop we have to do this only once. so * check frame number and execute only for the * frame number "0". */ if (v4l_set_input (dev, input, norm) == -1) return (1); if (v4l_check_size (dev, &width, &height) == -1)return (1); if (v4l_check_palette (dev, &palette) == -1)return (1); } image = get_image (dev, width, height, palette, &size, pics, timeout); if (!size) close (dev); if (image) { put_image_jpeg (out, image, width, height, quality, palette); if (size) { munmap (image, size); close (dev); } else if (image) { free (image); } if (loop) { num++; goto again; } } else fprintf (stderr, "Error: Can't get image\n"); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -