树莓派学习专题<11>:利用V4L2驱动获取摄像头数据--启动/制止数据流,数据捕捉,缓存开释

[复制链接]
发表于 2025-4-29 02:51:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1. 启动和制止数据流

利用下令 VIDIOC_STREAMON 启动摄像头数据流,利用下令 VIDIOC_STREAMOFF 制止摄像头数据流。
这两条下令的定义是:
  1. #define VIDIOC_STREAMON                 _IOW('V', 18, int)
  2. #define VIDIOC_STREAMOFF         _IOW('V', 19, int)
复制代码
这两条下令都必要一个 enum v4l2_buf_type 范例的参数作为入参数。参数内容固定填写 V4L2_BUF_TYPE_VIDEO_CAPTURE
代码如下:
  1. /*******************************************************************************
  2. - Function    : __StartStream
  3. - Description : 本函数启动数据接收。
  4. - Input       : VOID
  5. - Output      : NULL
  6. - Return      : VOID
  7. - Others      :
  8. *******************************************************************************/
  9. void __StartStream(void)
  10. {
  11.     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  12.    
  13.     if(-1 == ioctl(g_iFDVideo, VIDIOC_STREAMON, &type))
  14.     {
  15.         printf("Start stream failed.\n") ;
  16.         exit(-1) ;
  17.     }
  18.     return ;
  19. }
  20. /*******************************************************************************
  21. - Function    : __StopStream
  22. - Description : 本函数停止数据接收。
  23. - Input       : VOID
  24. - Output      : NULL
  25. - Return      : VOID
  26. - Others      :
  27. *******************************************************************************/
  28. void __StopStream(void)
  29. {
  30.     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  31.    
  32.     if(-1 == ioctl(g_iFDVideo, VIDIOC_STREAMOFF, &type))
  33.     {
  34.         printf("Stop stream failed.\n") ;
  35.         exit(-1) ;
  36.     }
  37.     return ;
  38. }
复制代码
2. 捕捉数据

代码如下:
  1. /*******************************************************************************
  2. - Function    : __ReadFrame
  3. - Description : 本函数读取摄像头数据并写入到文件。
  4. - Input       : VOID
  5. - Output      : NULL
  6. - Return      : VOID
  7. - Others      :
  8. *******************************************************************************/
  9. void __ReadFrame(void)
  10. {
  11.     struct v4l2_buffer stBuf;
  12.     memset(&stBuf, 0, sizeof(stBuf)) ;
  13.     stBuf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  14.     stBuf.memory = V4L2_MEMORY_MMAP;
  15.    
  16.     if(-1 == ioctl(g_iFDVideo, VIDIOC_DQBUF, &stBuf))
  17.     {
  18.         printf("De-queue buffer failed.\n") ;
  19.         exit(-1) ;
  20.     }
  21. #if 1 == WRITE_TO_FILE
  22.     if(-1 == write(g_iFDStore, g_pstBufDesc[stBuf.index].pvBufPtr, stBuf.bytesused))
  23.     {
  24.         printf("Write camera data failed.\n") ;
  25.         exit(-1) ;
  26.     }
  27. #endif
  28.    
  29.     if(-1 == ioctl(g_iFDVideo, VIDIOC_QBUF, &stBuf))
  30.     {
  31.         printf("Re-Queue buffer failed.\n") ;
  32.         exit(-1) ;
  33.     }
  34.    
  35.     return ;
  36. }
  37. /*******************************************************************************
  38. - Function    : __CaptureFrame
  39. - Description : 本函数捕获帧数据。
  40. - Input       : VOID
  41. - Output      : NULL
  42. - Return      : VOID
  43. - Others      :
  44. *******************************************************************************/
  45. void __CaptureFrame(void)
  46. {
  47.     struct timeval stTimeVal ;
  48.     fd_set         stFDRead ;
  49.     int            iRetVal ;
  50.    
  51.     stTimeVal.tv_usec = 0 ;
  52.     stTimeVal.tv_sec  = 2 ;
  53.    
  54.     FD_ZERO(&stFDRead) ;
  55.     FD_SET(g_iFDVideo, &stFDRead) ;
  56.     iRetVal = select(g_iFDVideo + 1, &stFDRead, NULL, NULL, &stTimeVal) ;
  57.    
  58.     if(-1 == iRetVal)
  59.     {
  60.         perror("select") ;
  61.         exit(-1) ;
  62.     }
  63.     else if(0 == iRetVal)
  64.     {
  65.         printf("timeout.\n") ;
  66.         exit(-1) ;
  67.     }
  68.    
  69.     __ReadFrame() ;
  70.     return ;
  71. }
复制代码
主函数中,首先调用函数 __StartStream 来启动摄像头输出数据的接收。而后调用函数 __CaptureFrame 来捕捉一帧数据。利用 select函数监视摄像头文件形貌符的读操作。一旦监视到,则调用 __ReadFrame 函数来获取数据。
对于V4L2驱动,利用 VIDIOC_DQBUF下令来从缓存队列中取出一块就绪的缓存。该下令的定义如下:
  1. #define VIDIOC_DQBUF                _IOWR('V', 17, struct v4l2_buffer)
复制代码
下令必要一个struct v4l2_buffer范例的参数。
结构体中,index 字段指示了当前是那一块缓冲。bytesused 字段指示了缓冲中有多少有效数据量。对于非编码格式,如YUV或RGB系列格式,应该是整个缓冲都用了。利用index字段可以索引到对应缓存块在用户空间中的地址,从而获取数据。
从队列中取出缓存块后,可对缓存块中数据举行处理,例如写入文件,大概编码等。操作完毕后,还必要将缓存块重新放入到队列中。该操作利用 VIDIOC_QBUF 下令执行。
  1. #define VIDIOC_QBUF                _IOWR('V', 15, struct v4l2_buffer)
复制代码
3. 开释缓存

在利用 VIDIOC_STREAMOFF 下令制止摄像头数据流后,退出程序之前,还必要开释缓存。
  1. /*******************************************************************************
  2. - Function    : __UnmapBuffer
  3. - Description : 本函数撤除缓冲区映射。
  4. - Input       : VOID
  5. - Output      : NULL
  6. - Return      : VOID
  7. - Others      :
  8. *******************************************************************************/
  9. void __UnmapBuffer(void)
  10. {
  11.     int iLoop ;
  12.    
  13.     for(iLoop = 0 ; iLoop < 4 ; iLoop++)
  14.     {
  15.         munmap(g_pstBufDesc[iLoop].pvBufPtr, g_pstBufDesc[iLoop].szBufSize) ;
  16.     }
  17.    
  18.     free(g_pstBufDesc) ;
  19.     return ;
  20. }
复制代码
这里包罗排除 mmap 映射关系,以及开释形貌符。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5

GMT+8, 2025-7-9 10:07 , Processed in 0.228530 second(s), 35 queries 手机版|qidao123.com技术社区-IT企服评测▪应用市场 ( 浙ICP备20004199 )|网站地图

快速回复 返回顶部 返回列表