VIDIOC_STREAMOFF停止取流
- 创建了微信群欢迎一起学习:
- 1. 概述
- 2.应用层
- 3. 驱动层
- 3.1 vb2_streamoff 函数
- 3.2 vb2_core_streamoff函数
- 3.2 __vb2_queue_cancel函数
- 3.2 __vb2_dqbuf函数
1. 概述
- 关闭视频流,munmap解除参数start所指向的内存起始地存起始地址。
2.应用层
// 停止视频的采集
enum v4l2_buf_type unBuffType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == this->ioCtrl(m_nFd, VIDIOC_STREAMOFF, &unBuffType))
{
LOGERROR("CV4l2CaptureIr::stopCapture is error... VIDIOC_STREAMOFF m_unIoMethod=[V4L2_IO_METHOD_MMAP]");
return ReturnCode_Error;
}
3. 驱动层
3.1 vb2_streamoff 函数
int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
/*
* 之前的分析都没有涉及到fileio
* vivi这部分文章,后续可能会去专门分析
*/
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
return -EBUSY;
}
return vb2_core_streamoff(q, type);
}
3.2 vb2_core_streamoff函数
int vb2_core_streamoff(struct vb2_queue *q, unsigned int type)
{
if (type != q->type) {
dprintk(1, "invalid stream type\n");
return -EINVAL;
}
/*
* Cancel will pause streaming and remove all buffers from the driver
* and videobuf, effectively returning control over them to userspace.
*
* Note that we do this even if q->streaming == 0: if you prepare or
* queue buffers, and then call streamoff without ever having called
* streamon, you would still expect those buffers to be returned to
* their normal dequeued state.
*/
__vb2_queue_cancel(q);
q->waiting_for_buffers = !q->is_output;
q->last_buffer_dequeued = false;
dprintk(3, "successful\n");
return 0;
}
EXPORT_SYMBOL_GPL(vb2_core_streamoff);
3.2 __vb2_queue_cancel函数
/**
* __vb2_queue_cancel() - cancel and stop (pause) streaming
*
* Removes all queued buffers from driver's queue and all buffers queued by
* userspace from videobuf's queue. Returns to state after reqbufs.
*/
static void __vb2_queue_cancel(struct vb2_queue *q)
{
unsigned int i;
/*
* Tell driver to stop all transactions and release all queued
* buffers.
*/
if (q->start_streaming_called)
call_void_qop(q, stop_streaming, q);
/*
* If you see this warning, then the driver isn't cleaning up properly
* in stop_streaming(). See the stop_streaming() documentation in
* videobuf2-core.h for more information how buffers should be returned
* to vb2 in stop_streaming().
*/
if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
for (i = 0; i < q->num_buffers; ++i)
if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE)
vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
/* Must be zero now */
WARN_ON(atomic_read(&q->owned_by_drv_count));
}
// 重置各种数据成员
q->streaming = 0;
q->start_streaming_called = 0;
q->queued_count = 0;
q->error = 0;
// 清空queued_list
/*
* Remove all buffers from videobuf's list...
*/
INIT_LIST_HEAD(&q->queued_list);
// 清空done_list
/*
* ...and done list; userspace will not receive any buffers it
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
//设置owned_by_drv_count为0
atomic_set(&q->owned_by_drv_count, 0);
// 唤醒等待线程
/*
* 可能如下?
* 1.其他应用在使用poll
* 2.其他应用在dqbuf
*/
wake_up_all(&q->done_wq);
/*
* Reinitialize all buffers for next use.
* Make sure to call buf_finish for any queued buffers. Normally
* that's done in dqbuf, but that's not going to happen when we
* cancel the whole queue. Note: this code belongs here, not in
* __vb2_dqbuf() since in vb2_core_dqbuf() there is a critical
* call to __fill_user_buffer() after buf_finish(). That order can't
* be changed, so we can't move the buf_finish() to __vb2_dqbuf().
*/
for (i = 0; i < q->num_buffers; ++i) {
struct vb2_buffer *vb = q->bufs[i];
if (vb->state == VB2_BUF_STATE_PREPARED ||
vb->state == VB2_BUF_STATE_QUEUED) {
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, finish,
vb->planes[plane].mem_priv);
}
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
vb->state = VB2_BUF_STATE_PREPARED;
call_void_vb_qop(vb, buf_finish, vb);
}
__vb2_dqbuf(vb);
}
}
3.2 __vb2_dqbuf函数
/**
* __vb2_dqbuf() - bring back the buffer to the DEQUEUED state
*/
static void __vb2_dqbuf(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned int i;
// 检查状态是否为出队列了
/* nothing to do if the buffer is already dequeued */
if (vb->state == VB2_BUF_STATE_DEQUEUED)
return;
//设置出队列状态VB2_BUF_STATE_DEQUEUED
vb->state = VB2_BUF_STATE_DEQUEUED;
//unmap 释放内存
/* unmap DMABUF buffer */
if (q->memory == VB2_MEMORY_DMABUF)
for (i = 0; i < vb->num_planes; ++i) {
if (!vb->planes[i].dbuf_mapped)
continue;
call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
vb->planes[i].dbuf_mapped = 0;
}
}
- 注意:
在执行完off之后其实几个相关队列中的buffer都被清理了,所以再次执行on的时候需要重新reqbuffer、qbuf等操作。