清空v4l2 usbcamera缓存

本文探讨USBCamera缓存队列在倒车影像应用中的问题,揭示重复调用startPreview和stopPreview导致的残留影像问题。通过自定义缓存队列清空流程,确保每次启动时获取最新影像,避免显示旧画面。

        做过usbcamera的同学们应该都知道,usbcamera有一个缓存队列,当应用上面调用startPreview的时候,就会层层的调到usbcamera 的ioctl(mFd, VIDIOC_DQBUF, &tmp_buf);用于从队列里出去一个缓存,并将这个缓存返回给用户去处理。当处理完后,要接着调用ioctl (mFd, VIDIOC_QBUF, &tmp_buf);来将刚刚出队的这个缓存重新放回队列。否则会导致队列里的缓存不够而读不出任何东西来,表现为黑屏。

        usbcamera提供了一系列的ioctl来操作视频流的处理,但没有提供清空缓存队列这个功能。如果刚好某个应用,只open了usbcamera一次,然后就重复调用startPreview和stopPreview,这个时候就会出现一个问题。

       即当用户在stopPreview的时候,最后一次读取的这个缓存队列(假设有8个缓存buf)里的buf的id为1,也就是只读了这个队列的第1个,还有剩下的7个缓存里面的数据没有被读出来。而这个时候上层用户调用了stopPreview,停止调用缓存数据。那么就会出,下次调用startPreview的时候,会先将这剩下的7个buf读出来的情况。因为我们的队列是先进先出的,你上次stop的时候出了一个,剩下的7个自然又自动往前排了,坐等下次取出来。

       以倒车为例,上次司机倒车完后,下次如果再启动倒车,再调用startPreview的时候,首先会显示上次倒车时最后的影像,然后才会接着显示新的影像。

        要解决这个BUG,首先想到的是要将这个队列给清空。蛋疼的是,usbcamera没有清空的ioctl操作。不过我们可以自己想办法来模拟清空的操作。比如我们在启动倒车前,先循环将这个缓存里的Buf出队,然后再入队。这么一来,入队的buf,录的自然就是新的影像了。上代码:

        //倒车前,先清掉缓存里残留的上次倒车最后画面
        if(status == UVC_PARK)
        {
		   int numBufs = 0;
		   int result = 0;
	 	   struct v4l2_buffer tmp_buf ;   
#if V4L2DEVICE_FPS_LIMIT > 0
			   struct timeval prevTime;
			   gettimeofday(&prevTime, NULL);
#endif		   
	 	   for (numBufs = 0; numBufs < V4L2DEVICE_BUF_COUNT; numBufs++)
	 	   {
	 		   memset( &tmp_buf, 0, sizeof(tmp_buf) );
	 		   tmp_buf.type =  V4L2_BUF_TYPE_VIDEO_CAPTURE ;   
			   tmp_buf.memory = V4L2_MEMORY_MMAP ;	 
			   tmp_buf.index = 0;

			   
			   result = ioctl(mFd, VIDIOC_DQBUF, &tmp_buf);
			   if ( result != 0)
			   {
					ALOGD("v4l2UvcStatusUpdate VIDIOC_DQBUF error (id=%u): %s (%d)", numBufs, strerror(errno), errno);
				//   return;
			   }
			   else
			   {
			       ALOGD("v4l2UvcStatusUpdate VIDIOC_DQBUF done numBufs is %d, index is %d ", numBufs, tmp_buf.index);   
			   }
			   
			   
			   result = ioctl (mFd, VIDIOC_QBUF, &tmp_buf);
			   if ( result < 0)
			   {
				   ALOGD("v4l2UvcStatusUpdate Could not VIDIOC_QBUF %d: %s (%d)", numBufs, strerror(errno), errno);
			   }
			   else
			   {
			       ALOGD("v4l2UvcStatusUpdate VIDIOC_QBUF done numBufs is %d ", numBufs);
			   }
#if V4L2DEVICE_FPS_LIMIT > 0
               double  step = 1000*1000/V4L2DEVICE_FPS_LIMIT;//微秒
			   struct timeval nowTime;
			   gettimeofday(&nowTime, NULL);
			   double  interval = (nowTime.tv_usec - prevTime.tv_usec);
			   ALOGD("v4l2UvcStatusUpdate startTime is [%ld] , nowTime is [%ld] \n", prevTime.tv_usec, nowTime.tv_usec);
			   ALOGD("v4l2UvcStatusUpdate FPS is [%d] , interval time is [%lf] , step is %lf\n", V4L2DEVICE_FPS_LIMIT, interval, step);   
			   //如果是放在缓存里,两次取缓存的时间间隔会非常的短,都在1000微秒以内。而如果是正常读取队列的话,会在30*1000到50*1000之间。
			   //所以下面用一个正常时的间隔的一半值来做阈值就足够了。
			   if(interval >= step/2)
			   {
			       ALOGD("v4l2UvcStatusUpdate this frame is not buff ");
			       break;
			   }
			   prevTime = nowTime;
#endif
	 	   	}

        }

 

### v4l2 DMA 实现与故障排除 视频捕获设备通常依赖于 Video4Linux2 (V4L2) API 来实现数据流处理功能。DMA(Direct Memory Access)技术用于减少 CPU 的负载并提高传输效率,在 V4L2 中扮演着重要角色。 #### 1. **V4L2 和 DMA 基础** V4L2 是 Linux 下的一个框架,支持多种多媒体硬件接口,包括摄像头、电视卡和其他视频输入/输出设备[^1]。DMA 技术允许外设直接访问内存而无需 CPU 干预,从而显著提升性能和降低功耗。在嵌入式系统中,这种组合特别常见。 对于基于 ARM 或其他架构的 SoC 芯片组来说,V4L2 驱动程序可能通过以下方式利用 DMA: - 使用 `dmaengine` 子系统来管理缓冲区分配和数据移动操作。 - 利用专用寄存器配置硬件 FIFO 或者触发特定事件中断以同步数据流动状态。 #### 2. **典型实现流程** 以下是简化版的 V4L2 DMA 实现逻辑: ```c #include <linux/videodev2.h> #include <media/v4l2-device.h> static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned long sizes[], struct device *alloc_devs[]) { /* 设置队列参数 */ if (*num_planes) return sizes[0]; // 返回第一个平面大小作为示例 *num_planes = 1; sizes[0] = FRAME_SIZE; // 定义帧尺寸 return 0; } static void buffer_prepare(struct vb2_buffer *vb) { struct sg_table sgt; /* 准备 SG 表格供 DMA 引擎使用 */ if (!sg_alloc_table(&sgt, 1, &vb->planes[0].mem_priv, GFP_KERNEL)) { dma_map_sg(vb->vb2_queue->dev, sgt.sgl, sgt.nents, DMA_FROM_DEVICE); } } ``` 以上代码片段展示了如何设置缓冲区以及准备散列表结构以便后续由 DMA 控制器完成实际的数据搬运工作[^2]。 #### 3. **常见问题排查方法** 当遇到有关 V4L2 和 DMA 方面的技术难题时,可以尝试以下几个方向来进行诊断分析: - **检查驱动初始化过程中的错误日志** 如果发现某些资源未能成功申请,则可能是由于权限不足或者硬件不兼容引起的问题。可以通过 dmesg 查看是否有任何异常提示信息存在[^3]。 - **验证缓冲机制是否正常运作** 确认所有的缓冲描述符都已正确建立,并且能够按照预期顺序被填充或清空。如果某个阶段出现了阻塞现象,则需进一步定位具体原因所在位置。 - **评估带宽需求匹配情况** 对目标平台上的总线宽度及时钟频率做出合理估算之后再决定采用何种模式执行图像采集任务。过高估计可能会导致溢出风险;反之则会浪费潜在能力。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值