应用层:
case IO_METHOD_MMAP:
for (i=0; i<n_buffers; ++i) { //for循环,buffer[0] buffer[1]分别加入视频缓存队列 ,传递结构体struct v4l2_buffer内容到内核
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);
}