drv0-v4l2.c
来自「xawtv绝版源码」· C语言 代码 · 共 1,047 行 · 第 1/2 页
C
1,047 行
int ret = 0; if (h->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY && !h->ov_error) ret |= CAN_OVERLAY; if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ret |= CAN_CAPTURE; if (h->cap.capabilities & V4L2_CAP_TUNER) ret |= CAN_TUNE; return ret;}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; 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); 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; 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 */static intv4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base){ struct v4l2_handle *h = handle; 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; 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;}/* ---------------------------------------------------------------------- *//* 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){ for (;;) { if (h->queue - h->waiton >= h->reqbufs.count) return; if (0 != v4l2_queue_buffer(h)) return; }}static intv4l2_waiton(struct v4l2_handle *h){ struct v4l2_buffer buf; struct timeval tv; fd_set rdset; /* wait for the next frame */ again: tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&rdset); FD_SET(h->fd, &rdset); switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) { case -1: if (EINTR == errno) goto again; perror("v4l2: select"); return -1; case 0: fprintf(stderr,"v4l2: oops: select timeout\n"); return -1; } /* get it */ memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0)) return -1; h->waiton++; h->buf_v4l2[buf.index] = buf;#if 0 if (1) { /* for driver debugging */ static const char *fn[] = { "any", "none", "top", "bottom", "interlaced", "tb", "bt", "alternate", }; static struct timeval last; signed long diff; diff = (buf.timestamp.tv_sec - last.tv_sec) * 1000000; diff += buf.timestamp.tv_usec - last.tv_usec; fprintf(stderr,"\tdiff %6.1f ms buf %d field %d [%s]\n", diff/1000.0, buf.index, buf.field, fn[buf.field%8]); last = buf.timestamp; }#endif return buf.index;}static intv4l2_start_streaming(struct v4l2_handle *h, int buffers){ int disable_overlay = 0; unsigned int i; /* setup buffers */ h->reqbufs.count = buffers; h->reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->reqbufs.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0)) return -1; for (i = 0; i < h->reqbufs.count; i++) { h->buf_v4l2[i].index = i; h->buf_v4l2[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->buf_v4l2[i].memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i], 0)) return -1; h->buf_me[i].fmt = h->fmt_me; h->buf_me[i].size = h->buf_me[i].fmt.bytesperline * h->buf_me[i].fmt.height; h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, h->fd, h->buf_v4l2[i].m.offset); if (MAP_FAILED == h->buf_me[i].data) { perror("mmap"); return -1; } if (ng_debug) print_bufinfo(&h->buf_v4l2[i]); } /* queue up all buffers */ v4l2_queue_all(h); try_again: /* turn off preview (if needed) */ if (disable_overlay) { h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay off (start_streaming)\n"); } /* start capture */ if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type, h->ov_on ? EBUSY : 0)) { if (h->ov_on && errno == EBUSY) { disable_overlay = 1; goto try_again; } return -1; } return 0;}static voidv4l2_stop_streaming(struct v4l2_handle *h){ unsigned int i; /* stop capture */ if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type)) perror("ioctl VIDIOC_STREAMOFF"); /* free buffers */ for (i = 0; i < h->reqbufs.count; i++) { if (0 != h->buf_me[i].refcount) ng_waiton_video_buf(&h->buf_me[i]); if (ng_debug) print_bufinfo(&h->buf_v4l2[i]); if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size)) perror("munmap"); } h->queue = 0; h->waiton = 0; /* turn on preview (if needed) */ if (h->ov_on != h->ov_enabled) { h->ov_on = h->ov_enabled; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay on (stop_streaming)\n"); }}/* ---------------------------------------------------------------------- *//* capture interface *//* set capture parameters */static intv4l2_setformat(void *handle, struct ng_video_fmt *fmt){ struct v4l2_handle *h = handle; h->fmt_v4l2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid]; h->fmt_v4l2.fmt.pix.width = fmt->width; h->fmt_v4l2.fmt.pix.height = fmt->height; h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ANY; //h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ALTERNATE; if (fmt->bytesperline != fmt->width * ng_vfmt_to_depth[fmt->fmtid]/8) h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline; else h->fmt_v4l2.fmt.pix.bytesperline = 0; if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL)) return -1; if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid]) return -1; fmt->width = h->fmt_v4l2.fmt.pix.width; fmt->height = h->fmt_v4l2.fmt.pix.height; fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline; if (0 == fmt->bytesperline) fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->fmt_me = *fmt; if (ng_debug) fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n", fmt->width,fmt->height, h->fmt_v4l2.fmt.pix.pixelformat & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff, h->fmt_v4l2.fmt.pix.sizeimage); return 0;}/* start/stop video */static intv4l2_startvideo(void *handle, int fps, unsigned int buffers){ struct v4l2_handle *h = handle; if (0 != h->fps) fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n"); h->fps = fps; h->first = 1; h->start = 0; if (h->cap.capabilities & V4L2_CAP_STREAMING) return v4l2_start_streaming(h,buffers); return 0;}static voidv4l2_stopvideo(void *handle){ struct v4l2_handle *h = handle; if (0 == h->fps) fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n"); h->fps = 0; if (h->cap.capabilities & V4L2_CAP_STREAMING) v4l2_stop_streaming(h);}/* read images */static struct ng_video_buf*v4l2_nextframe(void *handle){ struct v4l2_handle *h = handle; struct ng_video_buf *buf = NULL; int rc,size,frame = 0; if (h->cap.capabilities & V4L2_CAP_STREAMING) { v4l2_queue_all(h); frame = v4l2_waiton(h); if (-1 == frame) return NULL; h->buf_me[frame].refcount++; buf = &h->buf_me[frame]; memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_tofday_to_timestamp(&h->buf_v4l2[frame].timestamp); } else { size = h->fmt_me.bytesperline * h->fmt_me.height; buf = ng_malloc_video_buf(&h->fmt_me,size); rc = read(h->fd,buf->data,size); if (rc != size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size); } ng_release_video_buf(buf); return NULL; } memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_get_timestamp(); } if (h->first) { h->first = 0; h->start = buf->info.ts; if (ng_debug) fprintf(stderr,"v4l2: start ts=%lld\n",h->start); } buf->info.ts -= h->start; return buf;}static struct ng_video_buf*v4l2_getimage(void *handle){ struct v4l2_handle *h = handle; struct ng_video_buf *buf; int size,frame,rc; size = h->fmt_me.bytesperline * h->fmt_me.height; buf = ng_malloc_video_buf(&h->fmt_me,size); if (h->cap.capabilities & V4L2_CAP_READWRITE) { rc = read(h->fd,buf->data,size); if (-1 == rc && EBUSY == errno && h->ov_on) { h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); rc = read(h->fd,buf->data,size); h->ov_on = 1; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); } if (rc != size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size); } ng_release_video_buf(buf); return NULL; } } else { if (-1 == v4l2_start_streaming(h,1)) { v4l2_stop_streaming(h); return NULL; } frame = v4l2_waiton(h); if (-1 == frame) { v4l2_stop_streaming(h); return NULL; } memcpy(buf->data,h->buf_me[0].data,size); v4l2_stop_streaming(h); } return buf;}/* ---------------------------------------------------------------------- */extern void ng_plugin_init(void);void ng_plugin_init(void){ ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?