Linux v4l2编程API

蔚落 2022-02-13 05:17 295阅读 0赞
  1. 在进行V4L2开发中,常用的命令标志符如下(some are optional):
  2. VIDIOC_REQBUFS:分配内存
  3. VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
  4. VIDIOC_QUERYCAP:查询驱动功能
  5. VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
  6. VIDIOC_S_FMT:设置当前驱动的频捕获格式
  7. VIDIOC_G_FMT:读取当前驱动的频捕获格式
  8. VIDIOC_TRY_FMT:验证当前驱动的显示格式
  9. VIDIOC_CROPCAP:查询驱动的修剪能力
  10. VIDIOC_S_CROP:设置视频信号的边框
  11. VIDIOC_G_CROP:读取视频信号的边框
  12. VIDIOC_QBUF:把数据从缓存中读取出来
  13. VIDIOC_DQBUF:把数据放回缓存队列
  14. VIDIOC_STREAMON:开始视频显示函数
  15. VIDIOC_STREAMOFF:结束视频显示函数
  16. VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PALNTSC
  17. 1 查询设备能力
  18. struct v4l2_capability cap;
  19. rel = ioctl(fdUsbCam, VIDIOC_QUERYCAP,&cap);
  20. if(rel != 0)
  21. {
  22. perror("ioctl VIDIOC_QUERYCAP");
  23. return -1;
  24. }
  25. 2:查询当前捕获格式:
  26. memset(&fmt, 0, sizeof(structv4l2_format));
  27. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  28. if (ioctl(fdUsbCam, VIDIOC_G_FMT, &fmt)< 0)
  29. {
  30. printf("get format failed\n");
  31. return -1;
  32. }
  33. 3:设置当前捕获格式
  34. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  35. fmt.fmt.pix.width = 640;
  36. fmt.fmt.pix.height = 480;
  37. fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;
  38. fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
  39. rel = ioctl(fdUsbCam, VIDIOC_S_FMT, &fmt);
  40. if (rel < 0)
  41. {
  42. printf("\nSet format failed\n");
  43. return -1;
  44. }
  45. 4:读取Stream 设置。(主要是帧率)
  46. struct v4l2_streamparm *setfps;
  47. setfps=(struct v4l2_streamparm *) calloc(1, sizeof(structv4l2_streamparm));
  48. memset(setfps, 0, sizeof(struct v4l2_streamparm));
  49. setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  50. rel = ioctl(fdUsbCam,VIDIOC_G_PARM, setfps);
  51. if(rel == 0)
  52. {
  53. printf("\n Frame rate: %u/%u\n",
  54. setfps->parm.capture.timeperframe.denominator,
  55. setfps->parm.capture.timeperframe.numerator );
  56. }
  57. else
  58. {
  59. perror("Unable to read out current framerate");
  60. return -1;
  61. }
  62. 5:设置Stream参数。(主要是采集帧数)
  63. struct v4l2_streamparm *setfps;
  64. setfps=(struct v4l2_streamparm *) calloc(1, sizeof(structv4l2_streamparm));
  65. memset(setfps, 0, sizeof(struct v4l2_streamparm));
  66. setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  67. setfps->parm.capture.timeperframe.numerator=1;
  68. setfps->parm.capture.timeperframe.denominator=60;
  69. rel = ioctl(fdUsbCam,VIDIOC_S_PARM, setfps);
  70. if(rel != 0)
  71. {
  72. printf("\nUnable to Set FPS");
  73. return -1;
  74. }
  75. 6 分配内存
  76. 接下来可以为视频捕获分配内存:
  77. struct v4l2_requestbuffers req;
  78. req.count = BUFFER_COUNT;//缓存数量,也就是说在缓存队列里保持多少张照片(3)
  79. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
  80. req.memory = V4L2_MEMORY_MMAP;//V4L2_MEMORY_MMAP或V4L2_MEMORY_USERPTR
  81. if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
  82. return -1;
  83. }
  84. 7 获取并记录缓存的物理空间
  85. 使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:
  86. typedef struct VideoBuffer {
  87. void *start;
  88. size_t length;
  89. } VideoBuffer;
  90. 使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:
  91. typedef struct VideoBuffer {
  92. void *start;
  93. size_t length;
  94. } VideoBuffer;
  95. v4l2_buffer 结构如下:
  96. struct v4l2_buffer {
  97. __u32 index;
  98. enum v4l2_buf_type type;
  99. __u32 bytesused;
  100. __u32 flags;
  101. enum v4l2_field field;
  102. struct timeval timestamp;
  103. struct v4l2_timecode timecode;
  104. __u32 sequence;
  105. /* memory location */
  106. enum v4l2_memory memory;
  107. union {
  108. __u32 offset;
  109. unsigned long userptr;
  110. } m;
  111. __u32 length;
  112. __u32 input;
  113. __u32 reserved;
  114. };
  115. VideoBuffer* buffers = calloc( req.count, sizeof(*buffers) );
  116. struct v4l2_buffer buf;
  117. for (numBufs = 0; numBufs < req.count; numBufs++)
  118. {
  119. memset( &buf, 0, sizeof(buf) );
  120. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  121. buf.memory = V4L2_MEMORY_MMAP;
  122. buf.index = numBufs;
  123. // 读取缓存
  124. if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
  125. return -1;
  126. }
  127. buffers[numBufs].length = buf.length;
  128. // 转换成相对地址
  129. buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
  130. MAP_SHARED,fd, buf.m.offset);
  131. //NULL起始地址,有huf.length这么长,fd是映射到的文件,offset被映射对象内容的起点。
  132. MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新
  133. if (buffers[numBufs].start == MAP_FAILED) {
  134. return -1;
  135. }
  136. // 放入缓存队列
  137. if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
  138. return -1;
  139. }
  140. }
  141. 8 处理采集数据
  142. V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUFVIDIOC_QBUF
  143. struct v4l2_buffer buf;
  144. memset(&buf,0,sizeof(buf));
  145. buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
  146. buf.memory=V4L2_MEMORY_MMAP;
  147. buf.index=0;//读取缓存
  148. if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) == -1)
  149. {
  150. return -1;
  151. }
  152. //…………视频处理算法//重新放入缓存队列(重点图像处理)
  153. if (ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {
  154. return -1;
  155. }

发表评论

表情:
评论列表 (有 0 条评论,295人围观)

还没有评论,来说两句吧...

相关阅读

    相关 inux V4L2 Camera 编程

    V4L2(Video For Linux Two) 是Linux内核提供给应用程序访问音、视频驱动的统一接口。这里描述的是如何从遵循V4L2规范的Camera设备读取Video