【genius_platform软件平台开发】第六十三讲:Linux系统之V4L2视频驱动-select查询

刚建的微信群欢迎加入一起学习、讨论:

请添加图片描述

1. 概述

  • 这一步主要是通过select函数在应用层查询是否有可读状态,如果有的话则执行后面的读取数据流操作。具体select做个简单分析得了,属于网络协议栈范畴。

2.应用层

for (;;)
    {
        fd_set readFds;
        struct timeval tv;

        FD_ZERO(&readFds);
        FD_SET(m_nFd, &readFds);

        /* Timeout. */
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        nRet = ::select(m_nFd + 1, &readFds, NULL, NULL, &tv);
        if (SOCKET_ERROR == nRet) // 出错
        {
            if (EINTR == errno)
            {
                continue;
            }
            LOGERROR("CV4l2CaptureIr::queryDesc is error... select nRet=[-1]");
            return ReturnCode_Error;
        }
        else if (0 == nRet) //超时
        {
            LOGERROR("CV4l2CaptureIr::queryDesc is warning... select timeout nRet=[0]");
            return ReturnCode_Success;
        }
        else
        {
            //LOGMSG("CV4l2CaptureIr::queryDesc select is suc... m_nFd=[%d] nRet=[%d]", m_nFd, nRet);
            // 有数据了
            return ReturnCode_Success;
        }
    }

3. 驱动层

SYSCALL_DEFINE5(select – kernel/fs/select.c
kern_select
core_sys_select
do_select
vfs_poll
file->f_op->poll

xxxx_poll

3.1 vb2_poll函数

unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
	struct video_device *vfd = video_devdata(file);
	unsigned long req_events = poll_requested_events(wait);
	unsigned int res = 0;

	// 挂入休眠队列,是否休眠还要看返回值,大概没有数据就休眠,有数据就不休眠
	if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
		struct v4l2_fh *fh = file->private_data;

		if (v4l2_event_pending(fh))
			res = POLLPRI;
		else if (req_events & POLLPRI)
			poll_wait(file, &fh->wait, wait);
	}

	return res | vb2_core_poll(q, file, wait);
}
EXPORT_SYMBOL_GPL(vb2_poll);

3.2 vb2_core_poll 函数


unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
	...

	/*
	 * There is nothing to wait for if the queue isn't streaming, or if the
	 * error flag is set.
	 */
	if (!vb2_is_streaming(q) || q->error)
		return POLLERR;

	// 如果done list为空,则挂起等待

	if (list_empty(&q->done_list)) {
		/*
		 * If the last buffer was dequeued from a capture queue,
		 * return immediately. DQBUF will return -EPIPE.
		 */
		if (q->last_buffer_dequeued)
			return POLLIN | POLLRDNORM;

		poll_wait(file, &q->done_wq, wait);
	}
	/* 从前文分析可以知道stream_on后就会开始产生数据
     * 并且把填充好数据的buffer插入到done_list链表尾部
     * 唤醒等到的线程 wake_up(&q->done_wq);
     * 不为空,则从done list队列中获取到entry
     * /
	/*
	 * Take first buffer available for dequeuing.
	 */
	spin_lock_irqsave(&q->done_lock, flags);
	if (!list_empty(&q->done_list))
		vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
	spin_unlock_irqrestore(&q->done_lock, flags);

	if (vb && (vb->state == VB2_BUF_STATE_DONE
			|| vb->state == VB2_BUF_STATE_ERROR)) {
		return (q->is_output) ?
				POLLOUT | POLLWRNORM :
				POLLIN | POLLRDNORM;
	}
	return 0;
}
EXPORT_SYMBOL_GPL(vb2_core_poll);
  • 唤醒之后,我们就可以去从视频输出队列中取出buffer,然后根据映射关系,在应用空间取出视频数据了
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

隨意的風

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

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

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

打赏作者

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

抵扣说明:

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

余额充值