📄 drv0-v4l2.c
字号:
/* * interface to the v4l2 driver * * (c) 1998-2002 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 <inttypes.h>#include <sys/types.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/mman.h>#include <pthread.h>#include <asm/types.h> /* XXX glibc */#include "videodev2.h"#include "grab-ng.h"#include "struct-dump.h"#include "struct-v4l2.h"/* ---------------------------------------------------------------------- *//* open+close */static void* v4l2_init(char *device);static int v4l2_open(void *handle);static int v4l2_close(void *handle);static int v4l2_fini(void *handle);static struct ng_devinfo* v4l2_probe(int verbose);/* attributes */static char* v4l2_devname(void *handle);static char* v4l2_busname(void *handle);static int v4l2_flags(void *handle);static struct ng_attribute* v4l2_attrs(void *handle);static int v4l2_read_attr(struct ng_attribute*);static void v4l2_write_attr(struct ng_attribute*, int val);#if 0/* overlay */static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);static int v4l2_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 v4l2_setformat(void *handle, struct ng_video_fmt *fmt);static int v4l2_startvideo(void *handle, int fps, unsigned int buffers);static void v4l2_stopvideo(void *handle);static struct ng_video_buf* v4l2_nextframe(void *handle);static struct ng_video_buf* v4l2_getimage(void *handle);/* mpeg */static char *v4l2_setup_mpeg(void *handle, int flags);/* tuner */static unsigned long v4l2_getfreq(void *handle);static void v4l2_setfreq(void *handle, unsigned long freq);static int v4l2_tuned(void *handle);/* ---------------------------------------------------------------------- */#define WANTED_BUFFERS 32#define MAX_INPUT 16#define MAX_NORM 16#define MAX_FORMAT 32#define MAX_CTRL 32struct v4l2_handle { int fd; char *device; /* device descriptions */ int ninputs,nstds,nfmts; struct v4l2_capability cap; struct v4l2_streamparm streamparm; struct v4l2_input inp[MAX_INPUT]; struct v4l2_standard std[MAX_NORM]; struct v4l2_fmtdesc fmt[MAX_FORMAT]; struct v4l2_queryctrl ctl[MAX_CTRL*2]; int flags; int mpeg; /* attributes */ int nattr; struct ng_attribute *attr; /* capture */ int fps,first; long long start; struct v4l2_format fmt_v4l2; struct ng_video_fmt fmt_me; struct v4l2_requestbuffers reqbufs; struct v4l2_buffer buf_v4l2[WANTED_BUFFERS]; struct ng_video_buf buf_me[WANTED_BUFFERS]; unsigned int queue,waiton; /* overlay */ struct v4l2_framebuffer ov_fb; struct v4l2_format ov_win; struct v4l2_clip ov_clips[256];#if 0 enum v4l2_field ov_fields;#endif int ov_error; int ov_enabled; int ov_on;};static void v4l2_probe_mpeg(struct v4l2_handle *h);/* ---------------------------------------------------------------------- */struct ng_vid_driver v4l2_driver = { .name = "v4l2", .priority = 1, .init = v4l2_init, .open = v4l2_open, .close = v4l2_close, .fini = v4l2_fini, .devname = v4l2_devname, .busname = v4l2_busname, .probe = v4l2_probe, .capabilities = v4l2_flags, .list_attrs = v4l2_attrs,#if 0 .setupfb = v4l2_setupfb, .overlay = v4l2_overlay,#endif .setformat = v4l2_setformat, .startvideo = v4l2_startvideo, .stopvideo = v4l2_stopvideo, .nextframe = v4l2_nextframe, .getimage = v4l2_getimage, .getfreq = v4l2_getfreq, .setfreq = v4l2_setfreq, .is_tuned = v4l2_tuned, .setup_mpeg = v4l2_setup_mpeg,};static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = { [ VIDEO_RGB08 ] = V4L2_PIX_FMT_HI240, [ VIDEO_GRAY ] = V4L2_PIX_FMT_GREY, [ VIDEO_RGB15_LE ] = V4L2_PIX_FMT_RGB555, [ VIDEO_RGB16_LE ] = V4L2_PIX_FMT_RGB565, [ VIDEO_RGB15_BE ] = V4L2_PIX_FMT_RGB555X, [ VIDEO_RGB16_BE ] = V4L2_PIX_FMT_RGB565X, [ VIDEO_BGR24 ] = V4L2_PIX_FMT_BGR24, [ VIDEO_BGR32 ] = V4L2_PIX_FMT_BGR32, [ VIDEO_RGB24 ] = V4L2_PIX_FMT_RGB24, [ VIDEO_YUYV ] = V4L2_PIX_FMT_YUYV, [ VIDEO_UYVY ] = V4L2_PIX_FMT_UYVY, [ VIDEO_YUV422P ] = V4L2_PIX_FMT_YUV422P, [ VIDEO_YUV420P ] = V4L2_PIX_FMT_YUV420,};static struct STRTAB stereo[] = { { V4L2_TUNER_MODE_MONO, "mono" }, { V4L2_TUNER_MODE_STEREO, "stereo" }, { V4L2_TUNER_MODE_LANG1, "lang1" }, { V4L2_TUNER_MODE_LANG2, "lang2" }, { -1, NULL },};/* ---------------------------------------------------------------------- *//* debug output */#define PREFIX "ioctl: "static intxioctl(int fd, int cmd, void *arg, int mayfail){ int rc; rc = ioctl(fd,cmd,arg); if (0 == rc && ng_debug < 2) return rc; if (mayfail && errno == mayfail && ng_debug < 2) return rc; print_ioctl(stderr,ioctls_v4l2,PREFIX,cmd,arg); fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc;}static voidprint_bufinfo(struct v4l2_buffer *buf){ static char *type[] = { [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", }; fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n", buf->index, buf->type < sizeof(type)/sizeof(char*) ? type[buf->type] : "unknown", buf->m.offset,buf->length,buf->bytesused);}/* ---------------------------------------------------------------------- *//* helpers */static voidget_device_capabilities(struct v4l2_handle *h){ int i; for (h->ninputs = 0; h->ninputs < MAX_INPUT; h->ninputs++) { h->inp[h->ninputs].index = h->ninputs; if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], EINVAL)) break; } for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) { h->std[h->nstds].index = h->nstds; if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL)) break; } for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) { h->fmt[h->nfmts].index = h->nfmts; h->fmt[h->nfmts].type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(h->fd, VIDIOC_ENUM_FMT, &h->fmt[h->nfmts], EINVAL)) break; } h->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm); /* controls */ for (i = 0; i < MAX_CTRL; i++) { h->ctl[i].id = V4L2_CID_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) || (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i].id = -1; } for (i = 0; i < MAX_CTRL; i++) { h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) || (h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i+MAX_CTRL].id = -1; }}static struct STRTAB *build_norms(struct v4l2_handle *h){ struct STRTAB *norms; int i; norms = malloc(sizeof(struct STRTAB) * (h->nstds+1)); for (i = 0; i < h->nstds; i++) { norms[i].nr = i; norms[i].str = h->std[i].name; } norms[i].nr = -1; norms[i].str = NULL; return norms;}static struct STRTAB *build_inputs(struct v4l2_handle *h){ struct STRTAB *inputs; int i; inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1)); for (i = 0; i < h->ninputs; i++) { inputs[i].nr = i; inputs[i].str = h->inp[i].name; } inputs[i].nr = -1; inputs[i].str = NULL; return inputs;}/* ---------------------------------------------------------------------- */static struct V4L2_ATTR { unsigned int id; unsigned int v4l2;} v4l2_attr[] = { { ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME }, { ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE }, { ATTR_ID_COLOR, V4L2_CID_SATURATION }, { ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS }, { ATTR_ID_HUE, V4L2_CID_HUE }, { ATTR_ID_CONTRAST, V4L2_CID_CONTRAST },};#define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR))static struct STRTAB*v4l2_menu(int fd, const struct v4l2_queryctrl *ctl){ struct STRTAB *menu; struct v4l2_querymenu item; int i; menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2)); for (i = ctl->minimum; i <= ctl->maximum; i++) { item.id = ctl->id; item.index = i; if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) { free(menu); return NULL; } menu[i-ctl->minimum].nr = i; menu[i-ctl->minimum].str = strdup(item.name); } menu[i-ctl->minimum].nr = -1; menu[i-ctl->minimum].str = NULL; return menu;}static voidv4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl, int id, struct STRTAB *choices){ static int private_ids = ATTR_ID_COUNT; unsigned int i; h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute)); memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); if (ctl) { for (i = 0; i < NUM_ATTR; i++) if (v4l2_attr[i].v4l2 == ctl->id) break; if (i != NUM_ATTR) { h->attr[h->nattr].id = v4l2_attr[i].id; } else { h->attr[h->nattr].id = private_ids++; } h->attr[h->nattr].name = ctl->name; h->attr[h->nattr].priority = 2; h->attr[h->nattr].priv = ctl; h->attr[h->nattr].defval = ctl->default_value; switch (ctl->type) { case V4L2_CTRL_TYPE_INTEGER: h->attr[h->nattr].type = ATTR_TYPE_INTEGER; h->attr[h->nattr].defval = ctl->default_value; h->attr[h->nattr].min = ctl->minimum; h->attr[h->nattr].max = ctl->maximum; break; case V4L2_CTRL_TYPE_BOOLEAN: h->attr[h->nattr].type = ATTR_TYPE_BOOL; break; case V4L2_CTRL_TYPE_MENU: h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl); break; default: memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); return; } } else { /* for norms + inputs */ h->attr[h->nattr].id = id; if (-1 == h->attr[h->nattr].id) h->attr[h->nattr].id = private_ids++; h->attr[h->nattr].defval = 0; h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = choices; } if (h->attr[h->nattr].id < ATTR_ID_COUNT) h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id]; h->attr[h->nattr].read = v4l2_read_attr; h->attr[h->nattr].write = v4l2_write_attr; h->attr[h->nattr].handle = h; h->nattr++;}static int v4l2_read_attr(struct ng_attribute *attr){ struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; v4l2_std_id std; int value = 0; int i; if (NULL != ctl) { c.id = ctl->id; xioctl(h->fd,VIDIOC_G_CTRL,&c,0); value = c.value; } else if (attr->id == ATTR_ID_NORM) { value = -1; xioctl(h->fd,VIDIOC_G_STD,&std,0); for (i = 0; i < h->nstds; i++) if (std & h->std[i].id) value = i; } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_G_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); value = tuner.audmode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -