【genius_platform软件平台开发】第六十四讲:Linux系统之V4L2视频驱动-VIDIOC_DQBUF出队列

创建了微信群欢迎一起学习:

请添加图片描述

1. 概述

  • 从v4l2驱动层中读取视频帧缓存数据。

2.应用层

struct v4l2_buffer info;
    memset(&info, 0, sizeof(info));
// 取出FIFO缓存中已经采样的帧缓存
            memset(&info, 0, sizeof(info));
            info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            info.memory = V4L2_MEMORY_MMAP;
            info.index = 0;  // 此值由下面的ioctl返回
            // 应用程序从视频采集输出队列中取出已经采集好数据的帧缓冲区
            if (-1 == this->ioCtrl(m_nFd, VIDIOC_DQBUF, &info))
            {
                switch (errno)
                {
                    case EAGAIN:
                    {
                        //LOGWARNING("CV4l2CaptureIr::getData V4L2_IO_METHOD_MMAP is warning... EAGAIN errno=[%d] reason=[%s]", errno, strerror(errno));
                        return ReturnCode_WouldBlock;
                    }
                    case EIO:
                    {
                        LOGWARNING("CV4l2CaptureIr::getData V4L2_IO_METHOD_MMAP is warning... EIO errno=[%d] reason=[%s]", errno, strerror(errno));
                        return ReturnCode_IoCodeError;
                    }
                    /* fall through */
                    default:
                    {
                        LOGWARNING("CV4l2CaptureIr::getData V4L2_IO_METHOD_MMAP is error... VIDIOC_DQBUF errno=[%d] reason=[%s]", errno, strerror(errno));
                        return ReturnCode_Error;
                    }
                }
            }

            CHECKI(nIdx < m_nBuffersCount);

            // 设置标识位
            bQBuffFlag = true;

            // 获取数据指针
            pBuffer = (unsigned char*)m_pBuffers[info.index].pBuffer;

            // 设置size bytesused=0不知道为啥???
            nSize = info.bytesused;

3. 驱动层

3.1 vb2_dqbuf函数

int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
{
	int ret;

	if (vb2_fileio_is_active(q)) {
		dprintk(1, "file io in progress\n");
		return -EBUSY;
	}

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

	ret = vb2_core_dqbuf(q, NULL, b, nonblocking);

	/*
	 *  After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
	 *  cleared.
	 */
	b->flags &= ~V4L2_BUF_FLAG_DONE;

	return ret;
}
EXPORT_SYMBOL_GPL(vb2_dqbuf);

3.2 vb2_core_dqbuf 函数


int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
		   bool nonblocking)
{
	struct vb2_buffer *vb = NULL;
	int ret;

	// 非阻塞等待获取vb
	ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
	if (ret < 0)
		return ret;
	
	// 如果状态等DONE.继续
	switch (vb->state) 
	{
	case VB2_BUF_STATE_DONE:
		dprintk(3, "returning done buffer\n");
		break;
	case VB2_BUF_STATE_ERROR:
		dprintk(3, "returning done buffer with errors\n");
		break;
	default:
		dprintk(1, "invalid buffer state\n");
		return -EINVAL;
	}

	// 通知特定设备的buf_finish,具体里面干啥的未深入查看???
	call_void_vb_qop(vb, buf_finish, vb);

	if (pindex)
		*pindex = vb->index;

	// 填充buffer数据到用户空间,应用程序可以通过这个buffer的mmap地址进行读取数据了
	/* Fill buffer information for the userspace */
	if (pb)
		call_void_bufop(q, fill_user_buffer, vb, pb);

	// 注意“这里涉及到以下成员的含义和元素的转换
	/*
	struct list_head		queued_list;
	unsigned int			queued_count;

	atomic_t			owned_by_drv_count;
	struct list_head		done_list;
	*/
	// 从done_list队列中移除
	/* Remove from videobuf queue */
	list_del(&vb->queued_entry);
	
	// 减少队列数量, 为啥不是owned_by_drv_count???
	q->queued_count--;

	trace_vb2_dqbuf(q, vb);

	/* go back to dequeued state */
	__vb2_dqbuf(vb);

	dprintk(2, "dqbuf of buffer %d, with state %d\n",
			vb->index, vb->state);

	return 0;

}
EXPORT_SYMBOL_GPL(vb2_core_dqbuf);

3.3 __vb2_get_done_vb函数


/**
 * __vb2_get_done_vb() - get a buffer ready for dequeuing
 *
 * Will sleep if required for nonblocking == false.
 */
static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, void *pb, int nonblocking)
{
	unsigned long flags;
	int ret = 0;

	// 等待至少一帧在完成列表上可用
	/*
	 * Wait for at least one buffer to become available on the done_list.
	 */
	ret = __vb2_wait_for_done_vb(q, nonblocking);
	if (ret)
		return ret;

	// 从done_list队列中获取到该done_entry节点
	/*
	 * Driver's lock has been held since we last verified that done_list
	 * is not empty, so no need for another list_empty(done_list) check.
	 */
	spin_lock_irqsave(&q->done_lock, flags);
	*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
	/*
	 * Only remove the buffer from done_list if all planes can be
	 * handled. Some cases such as V4L2 file I/O and DVB have pb
	 * == NULL; skip the check then as there's nothing to verify.
	 */
	if (pb)
		ret = call_bufop(q, verify_planes_array, *vb, pb);
		
	if (!ret)
		// 出错从done_list队列中移除
		list_del(&(*vb)->done_entry);
		
	spin_unlock_irqrestore(&q->done_lock, flags);

	return ret;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值