theme: awesome-green
1.应用层关闭视频流
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0)
{
printf("ERR(%s):VIDIOC_STREAMOFF failed\n", __func__);
return -1;
}
2.驱动层关闭视频流
调用平台关闭视频流驱动接口vidioc_streamoff
- vidioc_streamoff
- vb2_ioctl_streamoff
vb2_streamoff
int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
/*return vdev->queue->owner && vdev->queue->owner != file->private_data;*/
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
return vb2_streamoff(vdev->queue, i);
}
int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
/*return q->fileio*/
if (vb2_fileio_is_active(q)) {
dprintk(1, "file io in progress\n");
return -EBUSY;
}
return vb2_internal_streamoff(q, type);
}
- vidioc_streamoff
- vb2_ioctl_streamoff
- vb2_streamoff
vb2_internal_streamoff
static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
/*如果传下来的type与vb2_queue的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 = !V4L2_TYPE_IS_OUTPUT(q->type);
dprintk(3, "successful\n");
return 0;
}
**
* __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.
*/
/*
* 如果q->start_streaming_called = 1(在streaming_on中置为1)
* 调用平台平台stop_streaming,
*/
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().
*/
/* owned_by_drv_count变量
* __enqueue_in_driver 函数里面进行inc加操作
* vb2_buffer_done 函数里面会进行 dec减操作
* 理想情况下,这个值为0
* 当不为0的话,说明还有buffer在被驱动操作,没有存入数据
* 也就是没有执行vb2_buffer_done
*/
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));
}
//将各种状态置为0
q->streaming = 0;
q->start_streaming_called = 0;
q->queued_count = 0;
q->error = 0;
/*
* Remove all buffers from videobuf's list...
* 将所有的buffer从队列上移除
*/
INIT_LIST_HEAD(&q->queued_list);
/*
* ...and done list; userspace will not receive any buffers it
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
atomic_set(&q->owned_by_drv_count, 0);
/*唤醒等待q->done_wq的进程*/
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_internal_dqbuf() there is a critical
* call to __fill_v4l2_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];
/*
* 取出所有vb2_buffer,并且
* 如果vb->state != VB2_BUF_STATE_DEQUEUED
* 那么将vb->state = VB2_BUF_STATE_PREPARED
* 调用buf_finish,这里没有实现不分析
*/
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
vb->state = VB2_BUF_STATE_PREPARED;
call_void_vb_qop(vb, buf_finish, vb);
}
/*将vb->state置为VB2_BUF_STATE_DEQUEUED*/
__vb2_dqbuf(vb);
}
}
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 */
//如果vb->state == VB2_BUF_STATE_DEQUEUED,返回,不成立
if (vb->state == VB2_BUF_STATE_DEQUEUED)
return;
//将vb->state置为VB2_BUF_STATE_DEQUEUED
vb->state = VB2_BUF_STATE_DEQUEUED;
/* unmap DMABUF buffer */
//如果q->memory类型为DMA,调用平台的unmap_dmabuf函数
if (q->memory == V4L2_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;
}
}
- vidioc_streamoff
- vb2_ioctl_streamoff
- vb2_streamoff
- vb2_internal_streamoff
- stop_streaming
xvip_dma_stop_streaming
static void xvip_dma_stop_streaming(struct vb2_queue *vq)
{
struct xvip_dma *dma = vb2_get_drv_priv(vq);
struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity);
struct xvip_dma_buffer *buf, *nbuf;
/* Stop the pipeline. */
/*调用所有器件的stop_stream函数,如CSI,Sensor*/
xvip_pipeline_set_stream(pipe, false);
/* Stop and reset the DMA engine. 停止DMA传输*/
dmaengine_terminate_all(dma->dma);
/* Cleanup the pipeline and mark it as being stopped. */
xvip_pipeline_cleanup(pipe);
media_entity_pipeline_stop(&dma->video.entity);
/* Give back all queued buffers to videobuf2. */
spin_lock_irq(&dma->queued_lock);
/*取出所有的vb2_buffer buf
*并且唤醒等待进程
*删除buffer的vb2_queue
*/
list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
list_del(&buf->queue);
}
spin_unlock_irq(&dma->queued_lock);
}
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags;
unsigned int plane;
//当vb->state不等于VB2_BUF_STATE_ACTIVE打印堆栈状态,并返回错误
if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE))
return;
/*如果state != VB2_BUF_STATE_DONE &&
* state != VB2_BUF_STATE_ERROR &&
* state != VB2_BUF_STATE_QUEUED
* 打印堆栈状态,并且将state置为VB2_BUF_STATE_ERROR
*/
if (WARN_ON(state != VB2_BUF_STATE_DONE &&
state != VB2_BUF_STATE_ERROR &&
state != VB2_BUF_STATE_QUEUED))
state = VB2_BUF_STATE_ERROR;
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Although this is not a callback, it still does have to balance
* with the buf_queue op. So update this counter manually.
*/
vb->cnt_buf_done++;
#endif
dprintk(4, "done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, state);
/* sync buffers
* 同步buffer
*/
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, finish, vb->planes[plane].mem_priv);
/* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
vb->state = state;
/*
*如果state != VB2_BUF_STATE_QUEUED
*把vb->done_entry挂载到q->done_list链表上
*/
if (state != VB2_BUF_STATE_QUEUED)
list_add_tail(&vb->done_entry, &q->done_list);
//减少q->owned_by_drv_count
atomic_dec(&q->owned_by_drv_count);
spin_unlock_irqrestore(&q->done_lock, flags);
/*如果state == VB2_BUF_STATE_QUEUED,返回*/
if (state == VB2_BUF_STATE_QUEUED)
return;
/*唤醒等待队列进程*/
/* Inform any processes that may be waiting for buffers */
wake_up(&q->done_wq);
}