刚建的微信群欢迎加入一起学习、讨论:
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,然后根据映射关系,在应用空间取出视频数据了