📄 streamer.c
字号:
/* Nemesis * Copyright (C) 1999 John Ferlito <johnf@inodes.org> * Copyright (C) 1997 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * 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 <unistd.h>#include <math.h>#include <errno.h>#include <fcntl.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/mman.h>#include <sys/shm.h>#include <sys/ipc.h>#include <sys/wait.h>#include <gtk/gtk.h>#include <Imlib.h>#include <setjmp.h>#include <asm/types.h> /* XXX glibc */#include <linux/videodev.h>#include "streamer.h"#include "colorspace.h"#include "writefile.h"#include <X11/Xlib.h>#define DEVNAME "/dev/video"#define JPEG_MUL 3#define JPEG_DIV 1jmp_buf env;int sigs;ImlibData *id;ImlibImage *im;Window x_window;/* ---------------------------------------------------------------------- */static struct video_capability capability;static struct video_channel channel;static struct video_window window;static unsigned char *map = NULL;static struct video_mmap gb1, gb2;static struct video_mbuf gb_buffers = {2 * 0x151000, 0, {0, 0x151000}};static unsigned char *buffers;static int bufsize;static int bfirst = 0;static int blast = 0;static int bufcount = 6;static int wtalk, rtalk;static int wsync, rsync, synctime = 500;static struct timeval start;static int tvnorm = VIDEO_MODE_PAL;static int input = -1;static char *device = DEVNAME;static char *filename = NULL;static int single = 1, absframes = 1, x11 = 0;static int fd = -1, width = 320, height = 240, quiet = 0, fps = 30;static int signaled = 0;/* ---------------------------------------------------------------------- */void usage(char *prog){ char *h; if (NULL != (h = strrchr(prog, '/'))) prog = h + 1; fprintf(stderr, "%s grabs image(s) from a bt848 card\n" "\n" "usage: %s [ options ]\n" "\n" "options:\n" " -q quiet operation\n" " -c device specify device [%s]\n" " -s size specify size [%dx%d]\n" " -b buffers specify # of buffers [%d]\n" " -t times number of frames [%d]\n" " -r fps frame rate [%d]\n" " -o file output file name [%s]\n" " -i input set input source (int) [no change]\n" "\n" "If the filename has some digits, %s will write multiple files,\n" "otherwise one huge file. Writing to one file works with raw\n" "data only." "\n" "funny chars:\n" " + grabbed picture queued to fifo\n" " o grabbed picture not queued (fifo full)\n" " - picture written to disk and dequeued from fifo\n" " s sync\n" " xx/yy (at end of line) xx frames queued, yy frames grabbed\n" "\n" "examples:\n" " %s -o image.jpg write single image\n" " %s | display -size 320x240 write image to stdout\n" " %s -s 320x240 -t 5 -o frame000.jpg write 5 image files\n" "\n" "--\n" "(c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>\n" "(c) 1999 Glengarry Castle specific hacks John Ferlito <johnf@zip.com.au>\n", prog, prog, device, width, height, bufcount, absframes, fps, filename ? filename : "stdout", prog, prog, prog, prog);}/* ---------------------------------------------------------------------- */void writer(){ char buffer; int fd = -1; signal(SIGINT, SIG_IGN); if (single) { if (filename) { if (-1 == (fd = open(filename, O_RDWR | O_CREAT, 0666))) { fprintf(stderr, "writer: open %s: %s\n", filename, strerror(errno)); exit(1); } } } for (;;) { /* wait for frame */ switch (read(rtalk, &buffer, 1)) { case -1: perror("writer: read socket"); exit(1); case 0: if (!quiet) fprintf(stderr, "writer: done\n"); exit(0); return; } /* write out */ write_jpeg(filename, buffers + buffer * bufsize, width, height); patch_up(filename); /* Display on screen */ if(x11) { im = Imlib_create_image_from_data(id, buffers + buffer * bufsize, NULL, width, height); Imlib_apply_image(id, im, x_window); Imlib_destroy_image(id, im); XFlush(dpy); } /* free buffer */ if (1 != write(wtalk, &buffer, 1)) { perror("writer: write socket"); exit(1); } if (!quiet) fprintf(stderr, "-"); } }/* ---------------------------------------------------------------------- */void syncer(){ char dummy; signal(SIGINT, SIG_IGN); for (;;) { switch (read(rsync, &dummy, 1)) { case -1: perror("syncer: read socket"); exit(1); case 0: if (!quiet) fprintf(stderr, "syncer: done\n"); exit(0); default: if (!quiet) fprintf(stderr, "s"); sync(); } }}/* ---------------------------------------------------------------------- */int putbuffer(char *src){ static int lastsec, lastsync, secframes, secqueued, absqueued, timediff; char buffer; unsigned char *dest; struct timeval tv; /* Work out the time */ gettimeofday(&tv, NULL); timediff = (tv.tv_sec - start.tv_sec) * 1000; timediff += (tv.tv_usec - start.tv_usec) / 1000; if (absqueued * 1000 / fps > timediff) return absqueued; /* Do we need to sync */ if (timediff > lastsync + synctime) { /* sync */ lastsync = timediff - timediff % synctime; if (1 != write(wsync, &bfirst, 1)) { perror("grabber: write socket"); exit(1); } } if (timediff > lastsec + 1000) { /* statistics */ if (!quiet && secframes) fprintf(stderr, " %2d/%2d\n", secqueued, secframes); lastsec = timediff - timediff % 1000; secqueued = 0; secframes = 0; } /* check for free buffers */ switch (read(rtalk, &buffer, 1)) { case -1: if (errno != EAGAIN) { perror("grabber: read socket"); exit(1); } break; case 0: /* nothing */ break; default: blast++; if (blast == bufcount) blast = 0; break; } secframes++; if ((bfirst + 1) % bufcount == blast) { /* no buffer free */ if (!quiet) fprintf(stderr, "o"); return absqueued; } /* copy / convert */ dest = buffers + bufsize * bfirst; rgb24_to_bgr24(dest, src, width, height); /* queue buffer */ if (1 != write(wtalk, &bfirst, 1)) { perror("grabber: write socket"); exit(1); } secqueued++; absqueued++; bfirst++; if (bfirst == bufcount) bfirst = 0; if (!quiet) fprintf(stderr, "+"); return absqueued;}/* ---------------------------------------------------------------------- */void ctrlc(int signal){ static char text[] = "^C - one moment please\n"; write(2, text, strlen(text)); signaled = 1;}int main(int argc, char **argv){ int shm_id, c, s, count = 0, i, n, p1[2], p2[2], queued = 0; static struct video_picture pict; int one=1; for (;;) { if (-1 == (c = getopt(argc, argv, "qs:c:o:i:t:b:r:xh"))) break; switch (c) { case 'q': quiet = 1; break; case 's': if (2 != sscanf(optarg, "%dx%d", &width, &height)) width = height = 0; break; case 'c': device = optarg; break; case 'o': filename = optarg; for (i = 0, n = strlen(filename); i < n; i++) { if (isdigit(filename[i])) single = 0; } break; case 'i': input = atoi(optarg); break; case 't': absframes = atoi(optarg); break; case 'b': bufcount = atoi(optarg); break; case 'r': fps = atoi(optarg); break; case 'x': x11 = 1; break; case 'h': default: usage(argv[0]); exit(1); } } if(filename == NULL) { usage(argv[0]); exit(1); } /* Gtk Window */ if(x11) { x_window = create_window(width, height); } /* Open Device */ if (-1 == fd && -1 == (fd = open(device, O_RDWR))) { fprintf(stderr, "open %s: %s\n", device, strerror(errno)); exit(1); } /* Get Settings */ if (-1 == ioctl(fd, VIDIOCGCAP, &capability)) { perror("ioctl VIDIOCGCAP"); exit(1); } if (-1 == ioctl(fd, VIDIOCGCHAN, &channel)) perror("ioctl VIDIOCGCHAN"); if (-1 == ioctl(fd, VIDIOCGWIN, &window)) perror("ioctl VIDIOCGWIN"); /* Set Channel Info */ if (tvnorm != -1 || input != -1) { if (tvnorm != -1) channel.norm = tvnorm; if (input != -1) channel.channel = input; if (-1 == ioctl(fd, VIDIOCSCHAN, &channel)) perror("ioctl VIDIOCSCHAN"); } /* mmap() buffer */ if (-1 == ioctl(fd, VIDIOCGMBUF, &gb_buffers)) { perror("ioctl VIDIOCGMBUF"); } map = mmap(0, gb_buffers.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((unsigned char *) -1 == map) { perror("mmap"); } else { if (!quiet) fprintf(stderr, "v4l: mmap()'ed buffer size = 0x%x\n", gb_buffers.size); } /* buffer initialisation */ if (absframes < bufcount) bufcount = absframes + 1; bufsize = width * height * JPEG_MUL / JPEG_DIV; if (-1 == (shm_id = shmget(IPC_PRIVATE, bufsize * bufcount, IPC_CREAT | 0700))) { perror("shmget"); exit(1); } buffers = shmat(shm_id, 0, 0); if ((void *) -1 == buffers) { perror("shmat"); exit(1); } shmctl(shm_id, IPC_RMID, 0); /* start up writer */ if (-1 == pipe(p1) || -1 == pipe(p2)) { perror("pipe"); exit(1); } switch (fork()) { case -1: perror("fork"); exit(1); case 0: close(p1[0]); close(p2[1]); wtalk = p1[1]; rtalk = p2[0]; fcntl(rtalk, F_SETFL, 0); nice(5); writer(); exit(0); default: close(p2[0]); close(p1[1]); wtalk = p2[1]; rtalk = p1[0]; fcntl(rtalk, F_SETFL, O_NONBLOCK); break; } /* start up syncer */ if (-1 == pipe(p1)) { perror("pipe"); exit(1); } switch (fork()) { case -1: perror("fork"); exit(1); case 0: close(p1[1]); rsync = p1[0]; fcntl(rsync, F_SETFL, 0); nice(10); syncer(); exit(0); default: close(p1[0]); wsync = p1[1]; break; } /* catch ^C */ signal(SIGINT, ctrlc); /* prepare for grabbing */ if (-1 == ioctl(fd,VIDIOCGPICT,&pict)) perror("ioctl VIDIOCGPICT"); /* No need ti change brightness anymore */ /* pict.contrast = 56678; * pict.brightness = 35867; */ pict.palette = VIDEO_PALETTE_RGB24; if (-1 == ioctl(fd,VIDIOCSPICT,&pict)) perror("ioctl VIDIOCSPICT"); gb1.format = VIDEO_PALETTE_RGB24; gb1.frame = 0; gb1.width = width; gb1.height = height; gb2.format = VIDEO_PALETTE_RGB24; gb2.frame = 1; gb2.width = width; gb2.height = height; if (-1 == ioctl(fd, VIDIOCMCAPTURE, &gb1)) { if (errno == EAGAIN) fprintf(stderr, "grabber chip can't sync (no station tuned in?)\n"); else perror("ioctl VIDIOCMCAPTURE"); exit(1); } count++; /* main loop */ gettimeofday(&start, NULL); for (; queued < absframes && !signaled; count++) { if (-1 == ioctl(fd, VIDIOCMCAPTURE, (count % 2) ? &gb2 : &gb1)) { if (errno == EAGAIN) fprintf(stderr, "grabber chip can't sync (no station tuned in?)\n"); else perror("ioctl VIDIOCMCAPTURE"); exit(1); } if (-1 == ioctl(fd, VIDIOCSYNC, (count % 2) ? &gb1.frame : &gb2.frame)) { perror("ioctl VIDIOCSYNC"); exit(1); } queued = putbuffer(map + gb_buffers.offsets[(count % 2) ? 0 : 1]); } if (-1 == ioctl(fd, VIDIOCSYNC, (count % 2) ? &gb1.frame : &gb2.frame)) { perror("ioctl VIDIOCSYNC"); exit(1); } /* done */ if (!quiet) fprintf(stderr, "\n"); close(fd); close(wtalk); close(wsync); wait(&s); wait(&s); return 0;}void clicked(void){ siglongjmp(env, -1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -