Linux v4l2架构学习总链接
step 7 : 读取数据
2,出队列
struct v4l2_buffer buffer;
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd, VIDIOC_DQBUF, &buffer) < 0)
{
printf("ERR(%s):VIDIOC_DQBUF failed, dropped frame\n", __func__);
return -1;
}
调用驱动代码 vidioc_dqbuf
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct vivi_dev *dev = video_drvdata(file);
return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
vidioc_dqbuf
-> vb2_dqbuf
-> vb2_core_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;
}
int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
bool nonblocking)
{
struct vb2_buffer *vb = NULL;
int ret;
/*
* 看下面具体分析
* ret = 0的时候,得到有效的buf的地址 vb
*/
ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
if (ret < 0)
return ret;
switch (vb->state) {
/*
* 正常来说,STATE_DONE
*/
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;
}
/*
* vb可以访问到缓冲区,驱动可以最后对缓冲区的数据进行修改
* 不修改的话,后面将释放放给用户空间
*/
call_void_vb_qop(vb, buf_finish, vb);
if (pindex)
*pindex = vb->index;
/* Fill buffer information for the userspace */
/*
* __vb2_get_done_vb中分析过
* 如果这个last_buffer_dequeued置位了,会不会忽略最后一帧
* last_buffer_dequeued的条件是
* 1.V4L2_BUF_FLAG_DONE,vb2_buffer_done中会置位
* 2.V4L2_BUF_FLAG_DONE,驱动中可以置位
* 以上2个条件成立才会将last_buffer_dequeued置1
* 关键是last_buffer_dequeued在哪里置1呢?
* 就是下面这个fill_user_buffer
* 说明出来完标记了V4L2_BUF_FLAG_DONE和V4L2_BUF_FLAG_LAST的
* 这最后一帧后,才将last_buffer_dequeued置1,所以最后一帧不会丢
*/
if (pb)
call_void_bufop(q, fill_user_buffer, vb, pb);
/* Remove from videobuf queue */
/*
* 出队列,并将计数减1
*/
list_del(&vb->queued_entry);
q->queued_count--;
trace_vb2_dqbuf(q, vb);
/* go back to dequeued state */
/*
* 对于MMAP
* 主要就是 vb->state = VB2_BUF_STATE_DEQUEUED;
* 更改状态
*/
__vb2_dqbuf(vb);
dprintk(2, "dqbuf of buffer %d, with state %d\n",
vb->index, vb->state);
return 0;
}
vidioc_dqbuf
-> vb2_dqbuf
-> vb2_core_dqbuf
-> __vb2_get_done_vb
static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
{
/*
* All operations on vb_done_list are performed under done_lock
* spinlock protection. However, buffers may be removed from
* it and returned to userspace only while holding both driver's
* lock and the done_lock spinlock. Thus we can be sure that as
* long as we hold the driver's lock, the list will remain not
* empty if list_empty() check succeeds.
*/
for (;;) {
int ret;
/*
* waiting_in_dqbuf这个值什么时候置1?
* 见这个函数下面的代码.....
*/
if (q->waiting_in_dqbuf) {
dprintk(1, "another dup()ped fd is waiting for a buffer\n");
return -EBUSY;
}
/*
* 调用过STREAM_ON 这里streaming值为1
* 如何为0,说明执行力stream_off操作,就不会有数据继续产生
* 所以这里也不用继续执行了
*/
if (!q->streaming) {
dprintk(1, "streaming off, will not wait for buffers\n");
return -EINVAL;
}
if (q->error) {
dprintk(1, "Queue in error state, will not wait for buffers\n");
return -EIO;
}
/*
* 如果这个last_buffer_dequeued置位了
* 那么说明后面没有有效的帧数据了,所以直接返回就行
* 问题来了,这里会不会忽略最后一帧?
* 答案是不会,原因后面分析
*/
if (q->last_buffer_dequeued) {
dprintk(3, "last buffer dequeued already, will not wait for buffers\n");
return -EPIPE;
}
/*
* done_list上有buffer则跳出这个循环,继续往下走
* 对于使用了select的方式,这里应该就返回了
*/
if (!list_empty(&q->done_list)) {
/*
* Found a buffer that we were waiting for.
*/
break;
}
/*
* 如果应用传递的是不堵塞
* 那么这里直接返回
*/
if (nonblocking) {
dprintk(3, "nonblocking and no buffers to dequeue, will not wait\n");
return -EAGAIN;
}
/*
* 走到这里说明应用打算使用阻塞方式
* 将waiting_in_dqbuf置1
*/
q->waiting_in_dqbuf = 1;
/*
* We are streaming and blocking, wait for another buffer to
* become ready or for streamoff. Driver's lock is released to
* allow streamoff or qbuf to be called while waiting.
*/
/*
* wait_prepare 对应vivi驱动的vivi_unlock
* 主要就是代码 mutex_unlock(&dev->mutex);
* 释放自旋锁
* 没有这个必要要使用锁???
*/
call_void_qop(q, wait_prepare, q);
/*
* All locks have been released, it is safe to sleep now.
*/
dprintk(3, "will sleep waiting for buffers\n");
/*
* wait_event_interruptible(wq, condition)
* 对于condition来说
* condition = 0 休眠
* condition = 1 唤醒
* 前提是wake_up_interruptible唤醒后,进一步才是condition
* 对于返回值
* 1.condition = 1时调用这个函数将直接返回0
* 2.正常wakeup且condition=1 返回0
* 3.其他信号唤醒,返回负值
*/
ret = wait_event_interruptible(q->done_wq,
!list_empty(&q->done_list) || !q->streaming ||
q->error);
/*
* We need to reevaluate both conditions again after reacquiring
* the locks or return an error if one occurred.
*/
/*
* wait_finish 对应vivi驱动的vivi_lock
* 主要就是代码 mutex_lock(&dev->mutex);
* 获取自旋锁
*
* 如果这样的话,就算stream_off,自旋锁还是没有释放 ???
*/
call_void_qop(q, wait_finish, q);
q->waiting_in_dqbuf = 0;
if (ret) {
dprintk(1, "sleep was interrupted\n");
return ret;
}
}
return 0;
}
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 = 0 获取到了有效的buffer
*/
ret = __vb2_wait_for_done_vb(q, nonblocking);
if (ret)
return ret;
/*
* 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);
/*
* 得到一个有效的buffer,*vb是地址
*/
*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.
*/
/*
* verify_planes_array 这里对应的是多平台
*/
if (pb)
ret = call_bufop(q, verify_planes_array, *vb, pb);
if (!ret)
/*
* 将buffer从done_list上移除
*/
list_del(&(*vb)->done_entry);
spin_unlock_irqrestore(&q->done_lock, flags);
return ret;
}
应用程序放在后面写