📄 drv0-v4l2.c
字号:
{ 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_v4l2[i].length)) 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; BUG_ON(h->fd == -1,"device not open"); 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; BUG_ON(h->fd == -1,"device not open"); 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; BUG_ON(h->fd == -1,"device not open"); 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,frame = 0; BUG_ON(h->fd == -1,"device not open"); 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 { buf = ng_malloc_video_buf(NULL, &h->fmt_me); rc = read(h->fd,buf->data,buf->size); if (rc != buf->size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%ld\n",rc,buf->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 frame,rc; BUG_ON(h->fd == -1,"device not open"); buf = ng_malloc_video_buf(NULL, &h->fmt_me); if (h->cap.capabilities & V4L2_CAP_READWRITE) { rc = read(h->fd,buf->data,buf->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,buf->size); h->ov_on = 1; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); } if (rc != buf->size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%ld\n",rc,buf->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,buf->size); v4l2_stop_streaming(h); } return buf;}/* ---------------------------------------------------------------------- */#define MPEG_TYPE_V4L2 1#define MPEG_TYPE_IVTV 2/* from ivtv.h */#define IVTV_IOC_G_CODEC 0xFFEE7703#define IVTV_IOC_S_CODEC 0xFFEE7704#define IVTV_STREAM_PS 0#define IVTV_STREAM_TS 1/* more follow .... */struct ivtv_ioctl_codec { uint32_t aspect; uint32_t audio_bitmap; uint32_t bframes; uint32_t bitrate_mode; uint32_t bitrate; uint32_t bitrate_peak; uint32_t dnr_mode; uint32_t dnr_spatial; uint32_t dnr_temporal; uint32_t dnr_type; uint32_t framerate; uint32_t framespergop; uint32_t gop_closure; uint32_t pulldown; uint32_t stream_type;};static void v4l2_probe_mpeg(struct v4l2_handle *h){ struct ivtv_ioctl_codec codec; int i; /* check for v4l2 device */ for (i = 0; i < h->nfmts; i++) { if (h->fmt[i].pixelformat == V4L2_PIX_FMT_MPEG) { /* saa7134 sets this and deliveres a transport stream */ /* FIXME: v4l2 API needs some refinements for this... */ h->flags |= CAN_MPEG_TS; h->mpeg = MPEG_TYPE_V4L2; } } if (h->mpeg) goto done; /* check for ivtv driver */ if (0 == ioctl(h->fd, IVTV_IOC_G_CODEC, &codec)) { h->flags |= CAN_MPEG_PS; h->flags |= CAN_MPEG_TS; h->mpeg = MPEG_TYPE_IVTV; } if (h->mpeg) goto done;done: if (!ng_debug) return; switch (h->mpeg) { case MPEG_TYPE_V4L2: fprintf(stderr, "v4l2: detected MPEG-capable v4l2 device.\n"); break; case MPEG_TYPE_IVTV: fprintf(stderr, "v4l2: detected ivtv driver\n"); break; default: return; } if (h->flags & CAN_MPEG_TS) fprintf(stderr, "v4l2: supports mpeg transport streams\n"); if (h->flags & CAN_MPEG_TS) fprintf(stderr, "v4l2: supports mpeg programs streams\n");}static char *v4l2_setup_mpeg(void *handle, int flags){ struct v4l2_handle *h = handle; switch (h->mpeg) { case MPEG_TYPE_V4L2: return h->device; case MPEG_TYPE_IVTV: { struct ivtv_ioctl_codec codec; if (0 != ioctl(h->fd, IVTV_IOC_G_CODEC, &codec)) return NULL; if (flags & MPEG_FLAGS_PS) codec.stream_type = IVTV_STREAM_PS; if (flags & MPEG_FLAGS_TS) codec.stream_type = IVTV_STREAM_TS; if (0 != ioctl(h->fd, IVTV_IOC_S_CODEC, &codec)) return NULL; return h->device; } default: return NULL; }}/* ---------------------------------------------------------------------- */static void __init plugin_init(void){ ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -