从vivi学习V4L2架构(八):buffer入队-QBUF

一、应用层buffer入队

只需设置type,memory, buffer的index就可以了。

for (i = 0; i < req.count; ++i)
{
    memset(&buf, 0, sizeof(buf));

    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = i;

    if (ioctl (fd, VIDIOC_QBUF, &buf) < 0)
        printf ("VIDIOC_QBUF failed\n");

    printf("buf[%d].flags = 0x%08x\n", i, buf.flags);
}

二、驱动层实现

上层调用下来,和之前一样进入__video_do_ioctl函数

static long __video_do_ioctl(struct file *file,
		unsigned int cmd, void *arg)
{
	struct video_device *vfd = video_devdata(file);
	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
	void *fh = file->private_data;
	struct v4l2_fh *vfh = NULL;
	struct v4l2_format f_copy;
	int use_fh_prio = 0;
	long ret = -EINVAL;
... ...
    case VIDIOC_QBUF:
	{
		struct v4l2_buffer *p = arg;

		if (!ops->vidioc_qbuf)
			break;
        //判断一下type类型是否支持
		ret = check_fmt(ops, p->type);
		if (ret)
			break;
        
        //直接调用vidioc_qbuf
		ret = ops->vidioc_qbuf(file, fh, p);
		if (!ret)
			dbgbuf(cmd, vfd, p);
		break;
	}
... ...
}

下面看看vivi驱动里面vidioc_qbuf

static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct vivi_dev *dev = video_drvdata(file);
    //直接调用vb2_qbuf
	return vb2_qbuf(&dev->vb_vidq, p);
}


int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
{
	struct vb2_buffer *vb;
	int ret = 0;

    //下面是一些条件判断,这里直接掉过
	if (q->fileio) {
		dprintk(1, "qbuf: file io in progress\n");
		return -EBUSY;
	}

	if (b->type != q->type) {
		dprintk(1, "qbuf: invalid buffer type\n");
		return -EINVAL;
	}

	if (b->index >= q->num_buffers) {
		dprintk(1, "qbuf: buffer index out of range\n");
		return -EINVAL;
	}
    
    //根据index获取到vb2_buffer
	vb = q->bufs[b->index];
	if (NULL == vb) {
		/* Should never happen */
		dprintk(1, "qbuf: buffer is NULL\n");
		return -EINVAL;
	}

	if (b->memory != q->memory) {
		dprintk(1, "qbuf: invalid memory type\n");
		return -EINVAL;
	}

	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
		dprintk(1, "qbuf: buffer already in use\n");
		return -EINVAL;
	}
   
    //这里是V4L2_MEMORY_MMAP类型,所走下面分支
    //__qbuf_mmap主要是将b->field, b->timestap, b->input, b->flags赋值给
    //vb->v4l2_buf
	if (q->memory == V4L2_MEMORY_MMAP)
		ret = __qbuf_mmap(vb, b);
	else if (q->memory == V4L2_MEMORY_USERPTR)
		ret = __qbuf_userptr(vb, b);
	else {
		WARN(1, "Invalid queue type\n");
		return -EINVAL;
	}

	if (ret)
		return ret;

    //buf_prepare主要设置vb2_buffer->v4l2_planes[0].bytesused
    //vivi_buffer.fmt=vivi_dev.fmt
    //准备vivi输出数据precalculate_bars, precalculate_line
	ret = call_qop(q, buf_prepare, vb);
	if (ret) {
		dprintk(1, "qbuf: buffer preparation failed\n");
		return ret;
	}

	/*
	 * Add to the queued buffers list, a buffer will stay on it until
	 * dequeued in dqbuf.
	 */
    //将vb2_buffer->quued_entry加入到vb2_queue->queued_list
    //并将vb2_buffer state改成VB2_BUF_STATE_QUEUED
	list_add_tail(&vb->queued_entry, &q->queued_list);
	vb->state = VB2_BUF_STATE_QUEUED;

	/*
	 * If already streaming, give the buffer to driver for processing.
	 * If not, the buffer will be given to driver on next streamon.
	 */
	if (q->streaming)
		__enqueue_in_driver(vb);

	dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
	return 0;
}
EXPORT_SYMBOL_GPL(vb2_qbuf);

_qbuf_mmap

static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b)
{
	return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
}

static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
				struct v4l2_plane *v4l2_planes)
{
	unsigned int plane;
	int ret;
    
    //不满足条件直接进else
	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
		/*
		 * Verify that the userspace gave us a valid array for
		 * plane information.
		 */
		ret = __verify_planes_array(vb, b);
		if (ret)
			return ret;

		/* Fill in driver-provided information for OUTPUT types */
		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
			/*
			 * Will have to go up to b->length when API starts
			 * accepting variable number of planes.
			 */
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].bytesused =
					b->m.planes[plane].bytesused;
				v4l2_planes[plane].data_offset =
					b->m.planes[plane].data_offset;
			}
		}

		if (b->memory == V4L2_MEMORY_USERPTR) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].m.userptr =
					b->m.planes[plane].m.userptr;
				v4l2_planes[plane].length =
					b->m.planes[plane].length;
			}
		}
	} else {
		/*
		 * Single-planar buffers do not use planes array,
		 * so fill in relevant v4l2_buffer struct fields instead.
		 * In videobuf we use our internal V4l2_planes struct for
		 * single-planar buffers as well, for simplicity.
		 */
        //不是OUTPUT类型跳过
		if (V4L2_TYPE_IS_OUTPUT(b->type))
			v4l2_planes[0].bytesused = b->bytesused;

		if (b->memory == V4L2_MEMORY_USERPTR) {
			v4l2_planes[0].m.userptr = b->m.userptr;
			v4l2_planes[0].length = b->length;
		}
	}
    
    //将vb2_buffer的v4l2_buf赋值
	vb->v4l2_buf.field = b->field;
	vb->v4l2_buf.timestamp = b->timestamp;
	vb->v4l2_buf.input = b->input;
	vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;

	return 0;
}

再看一下buffer_prepare

static int buffer_prepare(struct vb2_buffer *vb)
{
	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
	unsigned long size;

	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);

	BUG_ON(NULL == dev->fmt);

	/*
	 * Theses properties only change when queue is idle, see s_fmt.
	 * The below checks should not be performed here, on each
	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
	 * should thus be moved to buffer_init and s_fmt.
	 */
	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
	    dev->height < 32 || dev->height > MAX_HEIGHT)
		return -EINVAL;

    //计算一帧数据的大小
	size = dev->width * dev->height * 2;
	if (vb2_plane_size(vb, 0) < size) {
		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
				__func__, vb2_plane_size(vb, 0), size);
		return -EINVAL;
	}

    //将vb->v4l2_planes[0].bytesused = size;
	vb2_set_plane_payload(&buf->vb, 0, size);

    //将vivi_dev->fmt赋值给vivi_buffer->fmt
	buf->fmt = dev->fmt;

    //提前准备视频数据
	precalculate_bars(dev);
	precalculate_line(dev);

	return 0;
}

你可能感兴趣的:(v4l2,学习,网络,c++)