Linux&UVC驱动
+ -

LINUX&UVC驱动将缓冲区加入队列VIDIOC_QBUF

2024-04-02 108 0

将缓冲区放入队列,这样就可以使用该队列读取数据了

  1. // 将缓冲区放入队列
  2. for (unsigned int i = 0; i < reqbuf.count; i++) {
  3. memset(&buf, 0, sizeof(buf));
  4. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  5. buf.memory = V4L2_MEMORY_MMAP;
  6. buf.index = i;
  7. if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
  8. perror("Failed to queue buffer");
  9. close(fd);
  10. return EXIT_FAILURE;
  11. }
  12. }

VIDIOC_QBUF对应的内核回调是vidioc_qbuf

  1. const struct v4l2_ioctl_ops uvc_ioctl_ops = {
  2. .vidioc_qbuf = uvc_ioctl_qbuf,
  3. }
  4. static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
  5. {
  6. struct uvc_fh *handle = fh;
  7. struct uvc_streaming *stream = handle->stream;
  8. if (!uvc_has_privileges(handle))
  9. return -EBUSY;
  10. return uvc_queue_buffer(&stream->queue, stream->vdev.v4l2_dev->mdev, buf);
  11. }

vb2_qbuf

  1. int uvc_queue_buffer(struct uvc_video_queue *queue,
  2. struct media_device *mdev, struct v4l2_buffer *buf)
  3. {
  4. int ret;
  5. mutex_lock(&queue->mutex);
  6. ret = vb2_qbuf(&queue->queue, mdev, buf);
  7. mutex_unlock(&queue->mutex);
  8. return ret;
  9. }

vb2_qbuf:

  1. int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev,
  2. struct v4l2_buffer *b)
  3. {
  4. struct media_request *req = NULL;
  5. int ret;
  6. if (vb2_fileio_is_active(q)) {
  7. dprintk(1, "file io in progress\n");
  8. return -EBUSY;
  9. }
  10. ret = vb2_queue_or_prepare_buf(q, mdev, b, false, &req);
  11. if (ret)
  12. return ret;
  13. ret = vb2_core_qbuf(q, b->index, b, req);
  14. if (req)
  15. media_request_put(req);
  16. return ret;
  17. }
  18. EXPORT_SYMBOL_GPL(vb2_qbuf);

vb2_queue_or_prepare_buf

  1. // 一些前期的准备检查
  2. static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
  3. const char *opname)
  4. {
  5. // 主要做了一些检查
  6. if (b->type != q->type) {
  7. dprintk(1, "%s: invalid buffer type\n", opname);
  8. return -EINVAL;
  9. }
  10. // 索引检查
  11. if (b->index >= q->num_buffers) {
  12. dprintk(1, "%s: buffer index out of range\n", opname);
  13. return -EINVAL;
  14. }
  15. // 是否为空检查
  16. if (q->bufs[b->index] == NULL) {
  17. /* Should never happen */
  18. dprintk(1, "%s: buffer is NULL\n", opname);
  19. return -EINVAL;
  20. }
  21. // memory类型检查
  22. if (b->memory != q->memory) {
  23. dprintk(1, "%s: invalid memory type\n", opname);
  24. return -EINVAL;
  25. }
  26. return __verify_planes_array(q->bufs[b->index], b);
  27. }

verify_planes_array函数

  1. /**
  2. * __verify_planes_array() - verify that the planes array passed in struct
  3. * v4l2_buffer from userspace can be safely used
  4. */
  5. static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
  6. {
  7. if (!V4L2_TYPE_IS_MULTIPLANAR(b->type))
  8. return 0;
  9. /* Is memory for copying plane information present? */
  10. if (b->m.planes == NULL)
  11. {
  12. dprintk(1, "multi-planar buffer passed but planes array not provided\n");
  13. return -EINVAL;
  14. }
  15. if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES)
  16. {
  17. dprintk(1, "incorrect planes array length, expected %d, got %d\n",
  18. vb->num_planes, b->length);
  19. return -EINVAL;
  20. }
  21. return 0;
  22. }

vb2_core_qbuf函数

  1. // 核心处理函数
  2. int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
  3. {
  4. struct vb2_buffer *vb;
  5. int ret;
  6. if (q->error) {
  7. dprintk(1, "fatal error occurred on queue\n");
  8. return -EIO;
  9. }
  10. // 根据索引取出vb
  11. vb = q->bufs[index];
  12. switch (vb->state)
  13. {
  14. /*
  15. 前面的所有分析中只有reqbufs的时候
  16. * 状态设置成了VB2_BUF_STATE_DEQUEUED
  17. * 表示在用户空间控制
  18. * 所以要分析__buf_prepare这个函数
  19. * */
  20. case VB2_BUF_STATE_DEQUEUED:
  21. ret = __buf_prepare(vb, pb);
  22. if (ret)
  23. return ret;
  24. break;
  25. case VB2_BUF_STATE_PREPARED:
  26. break;
  27. case VB2_BUF_STATE_PREPARING:
  28. dprintk(1, "buffer still being prepared\n");
  29. return -EINVAL;
  30. default:
  31. dprintk(1, "invalid buffer state %d\n", vb->state);
  32. return -EINVAL;
  33. }
  34. // 添加到队列缓冲区buffer list中,数据帧将一直保留在该list队列中,直到在dqbuf中退出队列
  35. // 将这个 buffer 挂入 q->queued_list
  36. /*
  37. * Add to the queued buffers list, a buffer will stay on it until
  38. * dequeued in dqbuf.
  39. */
  40. list_add_tail(&vb->queued_entry, &q->queued_list);
  41. q->queued_count++;
  42. q->waiting_for_buffers = false;
  43. vb->state = VB2_BUF_STATE_QUEUED;
  44. if (pb)
  45. call_void_bufop(q, copy_timestamp, vb, pb);
  46. trace_vb2_qbuf(q, vb);
  47. /*
  48. * If already streaming, give the buffer to driver for processing.
  49. * If not, the buffer will be given to driver on next streamon.
  50. */
  51. if (q->start_streaming_called)
  52. __enqueue_in_driver(vb);
  53. /* Fill buffer information for the userspace */
  54. if (pb)
  55. call_void_bufop(q, fill_user_buffer, vb, pb);
  56. // 如果之前是在start_streaming_called 或者streaming状态,则只有当buffer足够了才会执行start streaming
  57. /*
  58. * If streamon has been called, and we haven't yet called
  59. * start_streaming() since not enough buffers were queued, and
  60. * we now have reached the minimum number of queued buffers,
  61. * then we can finally call start_streaming().
  62. */
  63. if (q->streaming && !q->start_streaming_called &&
  64. q->queued_count >= q->min_buffers_needed) {
  65. ret = vb2_start_streaming(q);
  66. if (ret)
  67. return ret;
  68. }
  69. dprintk(2, "qbuf of buffer %d succeeded\n", vb->index);
  70. return 0;
  71. }
  72. EXPORT_SYMBOL_GPL(vb2_core_qbuf);

buf_prepare函数

  1. static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
  2. {
  3. struct vb2_queue *q = vb->vb2_queue;
  4. unsigned int plane;
  5. int ret;
  6. if (q->error) {
  7. dprintk(1, "fatal error occurred on queue\n");
  8. return -EIO;
  9. }
  10. // 设置state=VB2_BUF_STATE_PREPARING
  11. vb->state = VB2_BUF_STATE_PREPARING;
  12. switch (q->memory) {
  13. /*
  14. * 驱动会执行MMAP
  15. */
  16. case VB2_MEMORY_MMAP:
  17. ret = __prepare_mmap(vb, pb);
  18. break;
  19. case VB2_MEMORY_USERPTR:
  20. ret = __prepare_userptr(vb, pb);
  21. break;
  22. case VB2_MEMORY_DMABUF:
  23. ret = __prepare_dmabuf(vb, pb);
  24. break;
  25. default:
  26. WARN(1, "Invalid queue type\n");
  27. ret = -EINVAL;
  28. }
  29. ...

prepare_mmap函数

  1. static int __prepare_mmap(struct vb2_buffer *vb, const void *pb)
  2. {
  3. int ret = 0;
  4. /*
  5. * pb是用户空间传入的,所以存在
  6. */
  7. if (pb)
  8. /*
  9. * 变换之后 vb->vb2_queue->buf_ops->fill_vb2_buffer
  10. * call_bufop 对应__fill_vb2_buffer
  11. */
  12. ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
  13. vb, pb, vb->planes);
  14. /*
  15. * vb->vb2_queue->ops->buf_prepare
  16. * 就是buf_prepare
  17. */
  18. return ret ? ret : call_vb_qop(vb, buf_prepare, vb);
  19. }

fill_vb2_buffer函数

  1. /**
  2. * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a
  3. * v4l2_buffer by the userspace. It also verifies that struct
  4. * v4l2_buffer has a valid number of planes.
  5. */
  6. static int __fill_vb2_buffer(struct vb2_buffer *vb,
  7. const void *pb, struct vb2_plane *planes)
  8. {
  9. struct vb2_queue *q = vb->vb2_queue;
  10. const struct v4l2_buffer *b = pb;
  11. struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
  12. unsigned int plane;
  13. int ret;
  14. // 对于capature length=0
  15. ret = __verify_length(vb, b);
  16. if (ret < 0) {
  17. dprintk(1, "plane parameters verification failed: %d\n", ret);
  18. return ret;
  19. }
  20. if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
  21. /*
  22. * If the format's field is ALTERNATE, then the buffer's field
  23. * should be either TOP or BOTTOM, not ALTERNATE since that
  24. * makes no sense. The driver has to know whether the
  25. * buffer represents a top or a bottom field in order to
  26. * program any DMA correctly. Using ALTERNATE is wrong, since
  27. * that just says that it is either a top or a bottom field,
  28. * but not which of the two it is.
  29. */
  30. dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
  31. return -EINVAL;
  32. }
  33. vb->timestamp = 0;
  34. vbuf->sequence = 0;
  35. // 多平面适配格式
  36. if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
  37. if (b->memory == VB2_MEMORY_USERPTR) {
  38. for (plane = 0; plane < vb->num_planes; ++plane) {
  39. planes[plane].m.userptr =
  40. b->m.planes[plane].m.userptr;
  41. planes[plane].length =
  42. b->m.planes[plane].length;
  43. }
  44. }
  45. if (b->memory == VB2_MEMORY_DMABUF) {
  46. for (plane = 0; plane < vb->num_planes; ++plane) {
  47. planes[plane].m.fd =
  48. b->m.planes[plane].m.fd;
  49. planes[plane].length =
  50. b->m.planes[plane].length;
  51. }
  52. }
  53. /* Fill in driver-provided information for OUTPUT types */
  54. if (V4L2_TYPE_IS_OUTPUT(b->type)) {
  55. /*
  56. * Will have to go up to b->length when API starts
  57. * accepting variable number of planes.
  58. *
  59. * If bytesused == 0 for the output buffer, then fall
  60. * back to the full buffer size. In that case
  61. * userspace clearly never bothered to set it and
  62. * it's a safe assumption that they really meant to
  63. * use the full plane sizes.
  64. *
  65. * Some drivers, e.g. old codec drivers, use bytesused == 0
  66. * as a way to indicate that streaming is finished.
  67. * In that case, the driver should use the
  68. * allow_zero_bytesused flag to keep old userspace
  69. * applications working.
  70. */
  71. for (plane = 0; plane < vb->num_planes; ++plane) {
  72. struct vb2_plane *pdst = &planes[plane];
  73. struct v4l2_plane *psrc = &b->m.planes[plane];
  74. if (psrc->bytesused == 0)
  75. vb2_warn_zero_bytesused(vb);
  76. if (vb->vb2_queue->allow_zero_bytesused)
  77. pdst->bytesused = psrc->bytesused;
  78. else
  79. pdst->bytesused = psrc->bytesused ?
  80. psrc->bytesused : pdst->length;
  81. pdst->data_offset = psrc->data_offset;
  82. }
  83. }
  84. } else {
  85. // 单平面视频格式
  86. /*
  87. * Single-planar buffers do not use planes array,
  88. * so fill in relevant v4l2_buffer struct fields instead.
  89. * In videobuf we use our internal V4l2_planes struct for
  90. * single-planar buffers as well, for simplicity.
  91. *
  92. * If bytesused == 0 for the output buffer, then fall back
  93. * to the full buffer size as that's a sensible default.
  94. *
  95. * Some drivers, e.g. old codec drivers, use bytesused == 0 as
  96. * a way to indicate that streaming is finished. In that case,
  97. * the driver should use the allow_zero_bytesused flag to keep
  98. * old userspace applications working.
  99. */
  100. // 用户空间指针,直接赋值
  101. if (b->memory == VB2_MEMORY_USERPTR) {
  102. planes[0].m.userptr = b->m.userptr;
  103. planes[0].length = b->length;
  104. }
  105. // dma方式
  106. if (b->memory == VB2_MEMORY_DMABUF) {
  107. planes[0].m.fd = b->m.fd;
  108. planes[0].length = b->length;
  109. }
  110. /*
  111. *enum v4l2_buf_type {
  112. V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
  113. V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
  114. V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
  115. V4L2_BUF_TYPE_VBI_CAPTURE = 4,
  116. V4L2_BUF_TYPE_VBI_OUTPUT = 5,
  117. V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
  118. V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
  119. V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
  120. V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
  121. V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10,
  122. V4L2_BUF_TYPE_SDR_CAPTURE = 11,
  123. V4L2_BUF_TYPE_SDR_OUTPUT = 12,
  124. V4L2_BUF_TYPE_META_CAPTURE = 13,
  125. V4L2_BUF_TYPE_PRIVATE = 0x80,
  126. };
  127. #define V4L2_TYPE_IS_MULTIPLANAR(type) \
  128. ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \
  129. || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
  130. #define V4L2_TYPE_IS_OUTPUT(type) \
  131. ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \
  132. || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \
  133. || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \
  134. || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \
  135. || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \
  136. || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT \
  137. || (type) == V4L2_BUF_TYPE_SDR_OUTPUT)
  138. */
  139. if (V4L2_TYPE_IS_OUTPUT(b->type))
  140. {
  141. if (b->bytesused == 0)
  142. vb2_warn_zero_bytesused(vb);
  143. if (vb->vb2_queue->allow_zero_bytesused)
  144. planes[0].bytesused = b->bytesused;
  145. else
  146. planes[0].bytesused = b->bytesused ?
  147. b->bytesused : planes[0].length;
  148. } else
  149. {
  150. // 所以V4L2_BUF_TYPE_VIDEO_CAPTURE会走到这里
  151. planes[0].bytesused = 0;
  152. }
  153. }
  154. // 下面都不用的
  155. /* Zero flags that the vb2 core handles */
  156. vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
  157. if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
  158. /*
  159. * Non-COPY timestamps and non-OUTPUT queues will get
  160. * their timestamp and timestamp source flags from the
  161. * queue.
  162. */
  163. vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
  164. }
  165. if (V4L2_TYPE_IS_OUTPUT(b->type)) {
  166. /*
  167. * For output buffers mask out the timecode flag:
  168. * this will be handled later in vb2_qbuf().
  169. * The 'field' is valid metadata for this output buffer
  170. * and so that needs to be copied here.
  171. */
  172. vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
  173. vbuf->field = b->field;
  174. } else {
  175. /* Zero any output buffer flags as this is a capture buffer */
  176. vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS;
  177. }
  178. return 0;
  179. }

buffer_prepare函数

  1. static int buffer_prepare(struct vb2_buffer *vb)
  2. {
  3. struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
  4. struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
  5. unsigned long size;
  6. BUG_ON(NULL == dev->fmt);
  7. // 检查wh等数值
  8. /*
  9. * Theses properties only change when queue is idle, see s_fmt.
  10. * The below checks should not be performed here, on each
  11. * buffer_prepare (i.e. on each qbuf). Most of the code in this function
  12. * should thus be moved to buffer_init and s_fmt.
  13. */
  14. if (dev->width < 48 || dev->width > MAX_WIDTH ||
  15. dev->height < 32 || dev->height > MAX_HEIGHT)
  16. return -EINVAL;
  17. size = dev->width * dev->height * 2;
  18. /*
  19. *vb->planes[i].length == size
  20. * 这是之前reqbufs时候设置的
  21. */
  22. if (vb2_plane_size(vb, 0) < size) {
  23. dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
  24. __func__, vb2_plane_size(vb, 0), size);
  25. return -EINVAL;
  26. }
  27. /*
  28. * vb2_set_plane_payload-> vb->planes[0].bytesused = size;
  29. * 终于找到bytesused设置的地方了
  30. * 这里只设置planes[0],而不考虑planes[1],是单平面的视频格式
  31. */
  32. vb2_set_plane_payload(&buf->vb, 0, size);
  33. buf->fmt = dev->fmt;
  34. precalculate_bars(dev);
  35. precalculate_line(dev);
  36. return 0;
  37. }

vb2_set_plane_payload函数

  1. /**
  2. * vb2_set_plane_payload() - set bytesused for the plane plane_no
  3. * @vb: buffer for which plane payload should be set
  4. * @plane_no: plane number for which payload should be set
  5. * @size: payload in bytes
  6. */
  7. static inline void vb2_set_plane_payload(struct vb2_buffer *vb,
  8. unsigned int plane_no, unsigned long size)
  9. {
  10. if (plane_no < vb->num_planes)
  11. vb->planes[plane_no].bytesused = size;
  12. }

0 篇笔记 写笔记

LINUX&UVC驱动将缓冲区加入队列VIDIOC_QBUF
将缓冲区放入队列,这样就可以使用该队列读取数据了 // 将缓冲区放入队列 for (unsigned int i = 0; i < reqbuf.count; i++) { memset(&buf, 0, sizeof(buf)); bu......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!