V4L2框架-视频流的停止(VIDIOC_STREAMOFF)


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);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值