📄 drv0-v4l2.c
字号:
#if 1 if (ng_debug) { fprintf(stderr,"v4l2: tuner cap:%s%s%s\n", (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n", (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n", (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "", (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); }#endif } return value;}static void v4l2_write_attr(struct ng_attribute *attr, int value){ struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; if (NULL != ctl) { c.id = ctl->id; c.value = value; xioctl(h->fd,VIDIOC_S_CTRL,&c,0); } else if (attr->id == ATTR_ID_NORM) { xioctl(h->fd,VIDIOC_S_STD,&h->std[value].id,0); } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_S_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); tuner.audmode = value; xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0); }}/* ---------------------------------------------------------------------- */static intv4l2_open(void *handle){ struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: open\n"); BUG_ON(h->fd != -1,"device is open"); h->fd = ng_chardev_open(h->device, O_RDWR, 81, 1); if (-1 == h->fd) return -1; if (-1 == xioctl(h->fd,VIDIOC_QUERYCAP,&h->cap,EINVAL)) { close(h->fd); return -1; } return 0;}static intv4l2_close(void *handle){ struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: close\n"); BUG_ON(h->fd == -1,"device not open"); close(h->fd); h->fd = -1; return 0;}static void*v4l2_init(char *device){ struct v4l2_handle *h; int i; if (device && 0 != strncmp(device,"/dev/",5)) return NULL; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fd = -1; h->device = strdup(device ? device : ng_dev.video); if (0 != v4l2_open(h)) goto err; if (ng_debug) fprintf(stderr, "v4l2: init\nv4l2: device info:\n" " %s %d.%d.%d / %s @ %s\n", h->cap.driver, (h->cap.version >> 16) & 0xff, (h->cap.version >> 8) & 0xff, h->cap.version & 0xff, h->cap.card,h->cap.bus_info); get_device_capabilities(h); /* attributes */ v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h)); v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h)); if (h->cap.capabilities & V4L2_CAP_TUNER) v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo); for (i = 0; i < MAX_CTRL*2; i++) { if (h->ctl[i].id == UNSET) continue; v4l2_add_attr(h, &h->ctl[i], 0, NULL); } /* capture buffers */ for (i = 0; i < WANTED_BUFFERS; i++) { ng_init_video_buf(h->buf_me+i); h->buf_me[i].release = ng_wakeup_video_buf; } /* init flags */#if 0 if (h->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY && !h->ov_error) h->flags |= CAN_OVERLAY;#endif if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) h->flags |= CAN_CAPTURE; if (h->cap.capabilities & V4L2_CAP_TUNER) h->flags |= CAN_TUNE; /* check for MPEG capabilities */ v4l2_probe_mpeg(h); v4l2_close(h); return h; err: if (h->fd != -1) close(h->fd); if (h) free(h); return NULL;}static intv4l2_fini(void *handle){ struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: fini\n"); BUG_ON(h->fd != -1,"device is open"); free(h->device); free(h); return 0;}static char*v4l2_devname(void *handle){ struct v4l2_handle *h = handle; return h->cap.card;}static char*v4l2_busname(void *handle){ struct v4l2_handle *h = handle; return h->cap.bus_info;}static struct ng_devinfo* v4l2_probe(int verbose){ struct ng_devinfo *info = NULL; struct v4l2_capability cap; int i,n,fd; n = 0; for (i = 0; NULL != ng_dev.video_scan[i]; i++) { fd = ng_chardev_open(ng_dev.video_scan[i], O_RDONLY | O_NONBLOCK, 81, verbose); if (-1 == fd) continue; if (-1 == xioctl(fd,VIDIOC_QUERYCAP,&cap,EINVAL)) { if (verbose) perror("ioctl VIDIOC_QUERYCAP"); close(fd); continue; } info = realloc(info,sizeof(*info) * (n+2)); memset(info+n,0,sizeof(*info)*2); strcpy(info[n].device, ng_dev.video_scan[i]); snprintf(info[n].name, sizeof(info[n].name), "%s", cap.card); snprintf(info[n].bus, sizeof(info[n].bus), "%s", cap.bus_info); close(fd); n++; } return info;}static int v4l2_flags(void *handle){ struct v4l2_handle *h = handle; return h->flags;}static struct ng_attribute* v4l2_attrs(void *handle){ struct v4l2_handle *h = handle; return h->attr;}/* ---------------------------------------------------------------------- */static unsigned longv4l2_getfreq(void *handle){ struct v4l2_handle *h = handle; struct v4l2_frequency f; BUG_ON(h->fd == -1,"device not open"); memset(&f,0,sizeof(f)); xioctl(h->fd, VIDIOC_G_FREQUENCY, &f, 0); return f.frequency;}static voidv4l2_setfreq(void *handle, unsigned long freq){ struct v4l2_handle *h = handle; struct v4l2_frequency f; if (ng_debug) fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16); BUG_ON(h->fd == -1,"device not open"); memset(&f,0,sizeof(f)); f.type = V4L2_TUNER_ANALOG_TV; f.frequency = freq; xioctl(h->fd, VIDIOC_S_FREQUENCY, &f, 0);}static intv4l2_tuned(void *handle){ struct v4l2_handle *h = handle; struct v4l2_tuner tuner; BUG_ON(h->fd == -1,"device not open"); usleep(10000); memset(&tuner,0,sizeof(tuner)); if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0)) return 0; return tuner.signal ? 1 : 0;}/* ---------------------------------------------------------------------- *//* overlay */#if 0static intv4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base){ struct v4l2_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0)) return -1; /* double-check settings */ if (NULL != base && h->ov_fb.base != base) { fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n"); fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base); h->ov_error = 1; return -1; } if (h->ov_fb.fmt.width != fmt->width || h->ov_fb.fmt.height != fmt->height) { fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n"); fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n", fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height); h->ov_error = 1; return -1; } if (fmt->bytesperline > 0 && fmt->bytesperline != h->ov_fb.fmt.bytesperline) { fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n"); fprintf(stderr,"v4l2: me=%d v4l=%d\n", fmt->bytesperline,h->ov_fb.fmt.bytesperline); h->ov_error = 1; return -1; }#if 0 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) { fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n"); fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n", xawtv_pixelformat[fmt->fmtid] & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff, ng_vfmt_to_desc[fmt->fmtid], h->ov_fb.fmt.pixelformat & 0xff, (h->ov_fb.fmt.pixelformat >> 8) & 0xff, (h->ov_fb.fmt.pixelformat >> 16) & 0xff, (h->ov_fb.fmt.pixelformat >> 24) & 0xff); h->ov_error = 1; return -1; }#endif return 0;}static intv4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect){ struct v4l2_handle *h = handle; struct v4l2_format win; int rc,i; BUG_ON(h->fd == -1,"device not open"); if (h->ov_error) return -1; if (NULL == fmt) { if (ng_debug) fprintf(stderr,"v4l2: overlay off\n"); if (h->ov_enabled) { h->ov_enabled = 0; h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); } return 0; } if (ng_debug) fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n", fmt->width,fmt->height,x,y,count); memset(&win,0,sizeof(win)); win.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; win.fmt.win.w.left = x; win.fmt.win.w.top = y; win.fmt.win.w.width = fmt->width; win.fmt.win.w.height = fmt->height; /* check against max. size */ xioctl(h->fd,VIDIOC_TRY_FMT,&win,0); if (win.fmt.win.w.width != (int)fmt->width) win.fmt.win.w.left = x + (fmt->width - win.fmt.win.w.width)/2; if (win.fmt.win.w.height != (int)fmt->height) win.fmt.win.w.top = y + (fmt->height - win.fmt.win.w.height)/2; if (aspect) ng_ratio_fixup(&win.fmt.win.w.width,&win.fmt.win.w.height, &win.fmt.win.w.left,&win.fmt.win.w.top); /* fixups */ ng_check_clipping(win.fmt.win.w.width, win.fmt.win.w.height, x - win.fmt.win.w.left, y - win.fmt.win.w.top, oc, &count); h->ov_win = win; if (h->ov_fb.capability & V4L2_FBUF_CAP_LIST_CLIPPING) { h->ov_win.fmt.win.clips = h->ov_clips; h->ov_win.fmt.win.clipcount = count; for (i = 0; i < count; i++) { h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1]; h->ov_clips[i].c.left = oc[i].x1; h->ov_clips[i].c.top = oc[i].y1; h->ov_clips[i].c.width = oc[i].x2-oc[i].x1; h->ov_clips[i].c.height = oc[i].y2-oc[i].y1; } }#if 0 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) { h->ov_win.chromakey = 0; /* FIXME */ }#endif rc = xioctl(h->fd, VIDIOC_S_FMT, &h->ov_win, 0); h->ov_enabled = (0 == rc) ? 1 : 0; h->ov_on = (0 == rc) ? 1 : 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); return 0;}#endif/* ---------------------------------------------------------------------- *//* capture helpers */static intv4l2_queue_buffer(struct v4l2_handle *h){ int frame = h->queue % h->reqbufs.count; int rc; if (0 != h->buf_me[frame].refcount) { if (0 != h->queue - h->waiton) return -1; fprintf(stderr,"v4l2: waiting for a free buffer\n"); ng_waiton_video_buf(h->buf_me+frame); } rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0); if (0 == rc) h->queue++; return rc;}static voidv4l2_queue_all(struct v4l2_handle *h)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -