📄 drv-v4l.c
字号:
/* * interface to the v4l driver * * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> * 2005-3-23 modified by threewater<threewater@up-tech.com> * */#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 <linux/videodev.h>#include "grab-ng.h"#include "struct-dump.h"#include "struct-v4l.h"#define SYNC_TIMEOUT 5/* ---------------------------------------------------------------------- *//* open+close */static void* v4l_open(char *device);static int v4l_close(void *handle);/* attributes */static char* v4l_devname(void *handle);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);/* 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);/* 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,};/* pass 0/1 by reference */static int one = 1, zero = 0;/* ---------------------------------------------------------------------- */struct v4l_handle { int fd; /* 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; 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", open: v4l_open, close: v4l_close, get_devname: v4l_devname, capabilities: v4l_flags, list_attrs: v4l_attrs, setupfb: v4l_setupfb, overlay: v4l_overlay, 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].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 void*v4l_open(char *device){ struct v4l_handle *h; struct STRTAB *inputs; struct STRTAB *norms; unsigned int i; int rc; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); /* open device */ if (-1 == (h->fd = open(device,O_RDWR))) { fprintf(stderr,"v4l: open %s: %s\n",device,strerror(errno)); goto err; } if (-1 == ioctl(h->fd,VIDIOCGCAP,&h->capability)) goto err; if (ng_debug) fprintf(stderr, "v4l: open: %s (%s)\n",device,h->capability.name); fcntl(h->fd,F_SETFD,FD_CLOEXEC); 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); if (h->audio.flags & VIDEO_AUDIO_BASS) fprintf(stderr,"bass=%d ",h->audio.bass); if (h->audio.flags & VIDEO_AUDIO_TREBLE) fprintf(stderr,"treble=%d ",h->audio.treble); fprintf(stderr,"\n"); } v4l_add_attr(h,ATTR_ID_MUTE,ATTR_TYPE_BOOL,0,NULL); v4l_add_attr(h,ATTR_ID_AUDIO_MODE,ATTR_TYPE_CHOICE,0,stereo); if (h->audio.flags & VIDEO_AUDIO_VOLUME) v4l_add_attr(h,ATTR_ID_VOLUME,ATTR_TYPE_INTEGER,0,NULL); } /* tv norms / tuner */ norms = malloc(sizeof(norms_v4l)); memcpy(norms,norms_v4l,sizeof(norms_v4l)); if (h->capability.type & VID_TYPE_TUNER) { /* have tuner */ xioctl(h->fd,VIDIOCGTUNER,&h->tuner); if (ng_debug) fprintf(stderr," tuner : %s %lu-%lu", h->tuner.name,h->tuner.rangelow,h->tuner.rangehigh); for (i = 0; norms[i].str != NULL; i++) { if (h->tuner.flags & (1<<i)) { if (ng_debug) fprintf(stderr," %s",norms[i].str); } else norms[i].nr = -1; } if (ng_debug) fprintf(stderr,"\n"); } else { /* no tuner */ struct video_channel vchan; memcpy(&vchan, &h->channels[0], sizeof(struct video_channel)); for (i = 0; norms[i].str != NULL; i++) { vchan.norm = i; if (-1 == xioctl(h->fd,VIDIOCSCHAN,&vchan)) norms[i].nr = -1; else if (ng_debug) fprintf(stderr," %s",norms[i].str); } /* restore settings after probe */ memcpy(&vchan, &h->channels[0], sizeof(struct video_channel)); xioctl(h->fd,VIDIOCSCHAN,&vchan); if (ng_debug) fprintf(stderr,"\n"); } #if 1#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) /* dirty hack time / v4l design flaw -- works with bttv only * this adds support for a few less common PAL versions */ if (-1 != (rc = ioctl(h->fd,BTTV_VERSION,&i))) { norms = norms_bttv; if (ng_debug || rc < 0x000700) fprintf(stderr,"v4l: bttv version %d.%d.%d\n", (rc >> 16) & 0xff, (rc >> 8) & 0xff, rc & 0xff); if (rc < 0x000700) fprintf(stderr, "v4l: prehistoric bttv version found, please try to\n" " upgrade the driver before mailing bug reports\n"); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -