应用层:
case IO_METHOD_MMAP:
for (i=0; i struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; //i = 0,1 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); break; ------------------------------------------------------------------------------------------------------------------------------------------------------------ 内核: (1) drivers/media/v4l2-core/v4l2-ioctl.c IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE) static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); return ret ? ret : ops->vidioc_qbuf(file, fh, p); //strtuct file对应 应用层打开的/dev/vedio0 的文件描述符fd } (2) drivers/media/platform/soc_camera/soc_camera.c static int soc_camera_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); WARN_ON(priv != file->private_data); if (icd->streamer != file) return -EBUSY; if (ici->ops->init_videobuf) return videobuf_qbuf(&icd->vb_vidq, p); else return vb2_qbuf(&icd->vb2_vidq, p); } int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) { /* * Add to the queued buffers list, a buffer will stay on it until * dequeued in dqbuf. */ list_add_tail(&vb->queued_entry, &q->queued_list); vb->state = VB2_BUF_STATE_QUEUED; //把buffer[0] 和 buffer[1]加入链表queued_list,一直存在,直到在dqbuf的时候dequeued一个buffer if (q->streaming) __enqueue_in_driver(vb); //执行完streamon后才进入 /* Fill buffer information for the userspace */ __fill_v4l2_buffer(vb, b); }