📄 drv1-v4l.c
字号:
/* * interface to the v4l driver * * (c) 1997-2004 Gerd Knorr <kraxel@bytesex.org> * */#include "config.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <math.h>#include <errno.h>#include <fcntl.h>#include <string.h>#include <signal.h>#include <pthread.h>#include <sys/types.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/mman.h>#include "videodev.h"#include "grab-ng.h"#include "struct-dump.h"#include "struct-v4l.h"#define SYNC_TIMEOUT 5/* ---------------------------------------------------------------------- *//* open+close */static void* v4l_init(char *device);static int v4l_open(void *handle);static int v4l_close(void *handle);static int v4l_fini(void *handle);static char* v4l_devname(void *handle);static struct ng_devinfo* v4l_probe(int verbose);/* attributes */static int v4l_flags(void *handle);static struct ng_attribute* v4l_attrs(void *handle);static int v4l_read_attr(struct ng_attribute*);static void v4l_write_attr(struct ng_attribute*, int val);#if 0/* overlay */static int v4l_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);static int v4l_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect);#endif/* capture video */static int v4l_setformat(void *handle, struct ng_video_fmt *fmt);static int v4l_startvideo(void *handle, int fps, unsigned int buffers);static void v4l_stopvideo(void *handle);static struct ng_video_buf* v4l_nextframe(void *handle);static struct ng_video_buf* v4l_getimage(void *handle);/* tuner */static unsigned long v4l_getfreq(void *handle);static void v4l_setfreq(void *handle, unsigned long freq);static int v4l_tuned(void *handle);/* ---------------------------------------------------------------------- */static const char *device_cap[] = { "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", "frameram", "scales", "monochrome", NULL};static const char *device_pal[] = { "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422", "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p", "yuv420p", "yuv410p"};#define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN")static struct STRTAB stereo[] = { { 0, "auto" }, { VIDEO_SOUND_MONO, "mono" }, { VIDEO_SOUND_STEREO, "stereo" }, { VIDEO_SOUND_LANG1, "lang1" }, { VIDEO_SOUND_LANG2, "lang2" }, { -1, NULL },};static struct STRTAB norms_v4l[] = { { VIDEO_MODE_PAL, "PAL" }, { VIDEO_MODE_NTSC, "NTSC" }, { VIDEO_MODE_SECAM, "SECAM" }, { VIDEO_MODE_AUTO, "AUTO" }, { -1, NULL }};static struct STRTAB norms_bttv[] = { { VIDEO_MODE_PAL, "PAL" }, { VIDEO_MODE_NTSC, "NTSC" }, { VIDEO_MODE_SECAM, "SECAM" }, { 3, "PAL-NC" }, { 4, "PAL-M" }, { 5, "PAL-N" }, { 6, "NTSC-JP" }, { -1, NULL }};static unsigned short format2palette[VIDEO_FMT_COUNT] = { [ VIDEO_RGB08 ] = VIDEO_PALETTE_HI240, [ VIDEO_GRAY ] = VIDEO_PALETTE_GREY, [ VIDEO_RGB15_LE ] = VIDEO_PALETTE_RGB555, [ VIDEO_RGB16_LE ] = VIDEO_PALETTE_RGB565, [ VIDEO_BGR24 ] = VIDEO_PALETTE_RGB24, [ VIDEO_BGR32 ] = VIDEO_PALETTE_RGB32, [ VIDEO_YUYV ] = VIDEO_PALETTE_YUV422, [ VIDEO_UYVY ] = VIDEO_PALETTE_UYVY, [ VIDEO_YUV422P ] = VIDEO_PALETTE_YUV422P, [ VIDEO_YUV420P ] = VIDEO_PALETTE_YUV420P,};#if 0/* pass 0/1 by reference */static int one = 1, zero = 0;#endif/* ---------------------------------------------------------------------- */struct v4l_handle { int fd; char *device; /* general informations */ struct video_capability capability; struct video_channel *channels; struct video_tuner tuner; struct video_audio audio; struct video_picture pict; /* attributes */ int nattr; struct ng_attribute *attr; int input; int audio_mode; /* overlay */ struct video_buffer fbuf; struct video_window win; int ov_error; unsigned int ov_fmtid; int ov_enabled; int ov_on; /* capture */ int use_read; int rw; struct ng_video_fmt fmt; long long start; int fps; /* capture via read() */ struct ng_video_fmt rd_fmt; struct video_window rd_win; unsigned int rd_fmtid; /* capture to mmap()'ed buffers */ struct video_mbuf mbuf; unsigned char *mmap; unsigned int nbuf; unsigned int queue; unsigned int waiton; int probe[VIDEO_FMT_COUNT]; struct video_mmap *buf_v4l; struct ng_video_buf *buf_me;};struct ng_vid_driver v4l_driver = { .name = "v4l", .priority = 2, .init = v4l_init, .open = v4l_open, .close = v4l_close, .fini = v4l_fini, .devname = v4l_devname, .probe = v4l_probe, .capabilities = v4l_flags, .list_attrs = v4l_attrs,#if 0 .setupfb = v4l_setupfb, .overlay = v4l_overlay,#endif .setformat = v4l_setformat, .startvideo = v4l_startvideo, .stopvideo = v4l_stopvideo, .nextframe = v4l_nextframe, .getimage = v4l_getimage, .getfreq = v4l_getfreq, .setfreq = v4l_setfreq, .is_tuned = v4l_tuned,};/* ---------------------------------------------------------------------- */static int alarms;static voidsigalarm(int signal){ alarms++; fprintf(stderr,"v4l: timeout (got SIGALRM), hardware/driver problems?\n");}static voidsiginit(void){ struct sigaction act,old; memset(&act,0,sizeof(act)); act.sa_handler = sigalarm; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&old);}/* ---------------------------------------------------------------------- */#define PREFIX "ioctl: "static intxioctl(int fd, int cmd, void *arg){ int rc; rc = ioctl(fd,cmd,arg); if (0 == rc && ng_debug < 2) return 0; print_ioctl(stderr,ioctls_v4l1,PREFIX,cmd,arg); fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc;}/* ---------------------------------------------------------------------- */static voidv4l_add_attr(struct v4l_handle *h, int id, int type, int defval, struct STRTAB *choices){ h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute)); memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); h->attr[h->nattr].id = id; h->attr[h->nattr].priority = 2; h->attr[h->nattr].type = type; h->attr[h->nattr].defval = defval; h->attr[h->nattr].choices = choices; if (ATTR_TYPE_INTEGER == type) { h->attr[h->nattr].min = 0; h->attr[h->nattr].max = 65535; } if (id < ATTR_ID_COUNT) h->attr[h->nattr].name = ng_attr_to_desc[id]; h->attr[h->nattr].read = v4l_read_attr; h->attr[h->nattr].write = v4l_write_attr; h->attr[h->nattr].handle = h; h->nattr++;}static voidv4l_buffer_map(struct v4l_handle *h){ int i, flags; if (0 == xioctl(h->fd,VIDIOCGMBUF,&h->mbuf)) { if (ng_debug) fprintf(stderr," mbuf: size=%d frames=%d\n", h->mbuf.size,h->mbuf.frames); flags = PROT_READ; if (h->rw) flags |= PROT_WRITE; h->mmap = mmap(0,h->mbuf.size, flags, MAP_SHARED,h->fd,0); if (MAP_FAILED == h->mmap) perror("mmap"); } else { h->mmap = MAP_FAILED; } if (MAP_FAILED != h->mmap) { if (ng_debug) fprintf(stderr," v4l: using mapped buffers for capture\n"); h->use_read = 0; h->nbuf = h->mbuf.frames; h->buf_v4l = malloc(h->nbuf * sizeof(struct video_mmap)); memset(h->buf_v4l,0,h->nbuf * sizeof(struct video_mmap)); h->buf_me = malloc(h->nbuf * sizeof(struct ng_video_buf)); for (i = 0; i < h->nbuf; i++) { ng_init_video_buf(h->buf_me+i); h->buf_me[i].release = ng_wakeup_video_buf; } } else { if (ng_debug) fprintf(stderr," v4l: using read() for capture\n"); h->use_read = 1; }}static voidv4l_buffer_unmap(struct v4l_handle *h){ if (MAP_FAILED != h->mmap) { munmap(h->mmap,h->mbuf.size); free(h->buf_v4l); free(h->buf_me); h->buf_v4l = NULL; h->buf_me = NULL; h->nbuf = 0; h->mmap = MAP_FAILED; } else { h->use_read = 0; }}/* ---------------------------------------------------------------------- */static intv4l_open(void *handle){ struct v4l_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l: open\n"); BUG_ON(h->fd != -1,"device is open"); h->rw = 1; h->fd = ng_chardev_open(h->device, O_RDWR, 81, 1); if (-1 == h->fd) { h->rw = 0; h->fd = ng_chardev_open(h->device, O_RDONLY, 81, 1); if (-1 == h->fd) return -1; } if (-1 == ioctl(h->fd,VIDIOCGCAP,&h->capability)) { close(h->fd); return -1; } v4l_buffer_map(h); return 0;}static intv4l_close(void *handle){ struct v4l_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l: close\n"); BUG_ON(h->fd == -1,"device not open"); v4l_buffer_unmap(h); close(h->fd); h->fd = -1; return 0;}static void*v4l_init(char *device){ struct v4l_handle *h; struct STRTAB *inputs; struct STRTAB *norms; unsigned int i; int rc; if (device && 0 != strncmp(device,"/dev/",5)) return NULL; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->device = strdup(device ? device : ng_dev.video); h->fd = -1; h->mmap = MAP_FAILED; /* open device */ if (0 != v4l_open(h)) goto err; if (ng_debug) fprintf(stderr, "v4l: init: %s (%s)\n",device,h->capability.name); siginit(); if (ng_debug) { fprintf(stderr," capabilities: "); for (i = 0; device_cap[i] != NULL; i++) if (h->capability.type & (1 << i)) fprintf(stderr," %s",device_cap[i]); fprintf(stderr,"\n"); fprintf(stderr," size : %dx%d => %dx%d\n", h->capability.minwidth,h->capability.minheight, h->capability.maxwidth,h->capability.maxheight); } /* input sources */ if (ng_debug) fprintf(stderr," channels: %d\n",h->capability.channels); h->channels = malloc(sizeof(struct video_channel)*h->capability.channels); memset(h->channels,0,sizeof(struct video_channel)*h->capability.channels); inputs = malloc(sizeof(struct STRTAB)*(h->capability.channels+1)); memset(inputs,0,sizeof(struct STRTAB)*(h->capability.channels+1)); for (i = 0; i < h->capability.channels; i++) { h->channels[i].channel = i; xioctl(h->fd,VIDIOCGCHAN,&(h->channels[i])); inputs[i].nr = i; inputs[i].str = h->channels[i].name; if (ng_debug) fprintf(stderr," %s: %d %s%s %s%s\n", h->channels[i].name, h->channels[i].tuners, (h->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", (h->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", (h->channels[i].type & VIDEO_TYPE_TV) ? "tv " : "", (h->channels[i].type & VIDEO_TYPE_CAMERA) ? "camera " : ""); } inputs[i].nr = -1; inputs[i].str = NULL; v4l_add_attr(h,ATTR_ID_INPUT,ATTR_TYPE_CHOICE,0,inputs); /* audios */ if (ng_debug) fprintf(stderr," audios : %d\n",h->capability.audios); if (h->capability.audios) { h->audio.audio = 0; xioctl(h->fd,VIDIOCGAUDIO,&h->audio); if (ng_debug) { fprintf(stderr," %d (%s): ",i,h->audio.name); if (h->audio.flags & VIDEO_AUDIO_MUTABLE) fprintf(stderr,"muted=%s ", (h->audio.flags&VIDEO_AUDIO_MUTE) ? "yes":"no"); if (h->audio.flags & VIDEO_AUDIO_VOLUME) fprintf(stderr,"volume=%d ",h->audio.volume);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -