VIDIOC_QUERYBUF查询缓存信息代码详细说明
- 3.1 vb2_ioctl_querybuf函数
- 3.2 querybuf函数
- 3.3 __fill_v4l2_buffer函数
- 3.4 enum vb2_buffer_state枚举
- 3.5 enum vb2_io_modes枚举
- 3.6 struct vb2_plane结构
- 3.7 struct vb2_buffer结构(*)
- 3.8 struct ops结构体vb2_ops
- 3.9 struct vb2_buf_ops 结构体
- 3.10 struct vb2_queue 结构体
1. 概述
VIDIOC_QUERYBUF
主要功能是查询分配良好。 buffer
核心空间中的信息长度length
和偏移量offset
.已经分配了查询V4L2
视频缓冲区的相关信息,包括缓冲区的使用状态
、核心空间偏移地址
、缓冲区长度
然后根据这些信息使用应用程序mmap
将核心空间地址映射到用户空间。
2 应用层2.1 struct v4l2_buffer结构
struct v4l2_buffer{__u32 index; //buffer 序号enum v4l2_buf_type type; //buffer 类型__u32 byteused; //buffer 已使用的字节数_u32 flags; // 区分是MMAP 还是USERPTrenumm v4l2_field field;struct timeval timestamp;// 系统时间struct获取第一个字节 v4l2_timecode timecode;__u32 sequence; // 队列中的序号enum v4l2_memory memory;//IO 方式,被应用程序设置union m{__u32 offset;// 缓冲帧地址,只有MMAP unsignedd有效 long userptr;};__u32 length;// 缓冲帧长度_u32 input;__u32 reserved;};v4l2_buffer buf; buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd , VIDIOC_QUERYBUF, &buf); if(ret < 0) { LOG("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret); return ret;
3. 驱动层3.1 vb2_ioctl_querybuf函数
int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p){ struct video_device *vdev = video_devdata(file); /* No need to call vb2_queue_is_busy(), anyone can query buffers. */ return vb2_querybuf(vdev->queue, p);}EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
3.2 querybuf函数
int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; // 取出 buf vb = q->bufs[b->index]; // 将 buf 信息写回用户空间传递的信息 b return __fill_v4l2_buffer(vb, b); }
3.3 __fill_v4l2_buffer函数
/** * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb){ struct v4l2_buffer *b = pb; /* * 这似乎是第一次看到vb2_v4l2_buffer。这里分析一下来源 * 先说这个函数的两个参数。 * 来自bufss的bufb[index],申请buffer时填写 * 来自用户空间的pb地址 * vbuf = tovb2_v4l2_buffer(vb) * 说明与vb有关 * __vb2_queue_allocvb创建如下 * vb = kzalloc(q->buf_struct_size, GFP_KERNEL); * 而q->buf_struct_size值在 * vb2_queue_init * if (q->buf_struct_size == 0) * q->buf_struct_size = sizeof(struct vb2_v4l2__buffer); * 也就是说,不是0的时候,这里会赋值 * 但是vivi驱动已经赋值了它 * q->buf_struct_size = sizeof(struct vivi_buffer); * 这样就找到了,vb2_v4l2_buffer * 实际看vivi_buffer, * struct vivi_buffer { * struct vb2_buffervb; * struct list_headlist; * struct vivi_fmt *fmt; * } * 没有看到vb2_v4l2_buffer相关的东西 * 所以去看最新的vivi驱动代码,如下 * struct vivid_buffer { * struct vb2_v4l2__buffer vb; * struct list_headlist; * }; * 这里就可以看到vb2_v4l2__buffer的来源了 * 其实主要原因是vivi驱动太老,Linux内核太新不匹配造成的 * */ struct vb2_v4l2__buffer *vbuf = tovb2_v4l2__buffer(vb); struct vb2_queue *q = vb->vb2_queue; unsigned int plane;// 直接填充数据成员信息 /* Copy back data such as timestamp, flags, etc. */ b->index = vb->index; b->type = vb->type; b->memory = vb->memory; b->bytesused = 0; b->flags = vbuf->flags; b->field = vbuf->field; b->timestamp = ns_to_timeval(vb->timestamp); b->timecode = vbuf->timecode; b->sequence = vbuf->sequence; b->reserved2 = 0; b->reserved = 0;// 暂时不解释多平面视频格式,还没有仔细研究!!!! if (q->is_multiplanar) { /* * Fill in plane-related data if userspace provided an array * for it. The caller has already verified memory and size. */ b->length = vb->num_planes; for (plane = 0; plane < vb->num_planes; ++plane) { struct v4l2_plane *pdst = &b->m.planes[plane]; struct vb2_plane *psrc = &vb->planes[plane]; pdst->bytesused = psrc->bytesused; pdst->length = psrc->length; if (q->memory == VB2_MEMORY_MMAP) pdst->m.mem_offset = psrc->m.offset; else if (q->memory == VB2_MEMORY_USERPTR) pdst->m.userptr = psrc->m.userptr; else if (q->memory == VB2_MEMORY_DMABUF) pdst->m.fd = psrc->m.fd; pdst->data_offset = psrc->data_offset; memset(pdst->reserved, 0, sizeof(pdst->reserved)); } } else { /* * length: 平面的大小可能与真实数据帧的大小不一致,为了page对齐,驱动力会变大 * byteused: 帧数据的大小,这里是0,在以下分析中可以看到更新 * length有时在应用代码中代表帧数据的大小,这个值可能是不准确的 * 比如帧大小是4812Byte,那么驱动可能是为了方便,将length设置为5000 * 所以最好使用byteused*// /* * We use length and offset in v4l2_planes array even for * single-planar buffers, but userspace does not. */ b->length = vb->planes[0].length; b->bytesused = vb->planes[0].bytesused; if (q->memory == VB2_MEMORY_MMAP) b->m.offset = vb->planes[0].m.offset; else if (q->memory == VB2_MEMORY_USERPTR) b->m.userptr = vb->planes[0].m.userptr; else if (q->memory == VB2_MEMORY_DMABUF) b->m.fd = vb->planes[0].m.fd; } /* * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; if (!q->copy_timestamp) { /* * For non-COPY timestamps, drop timestamp source bits * and obtain the timestamp source from the queue. */ b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; }/* * 对于vb->state的值 * VIDIOC_使用reqbuf时REQBUFS,看上一篇 * vb->state = VB2_BUF_STATE_DEQUEUED * 表示buffer控制用户空间,直接break*// switch (vb->state) { case VB2_BUF_STATE_QUEUED: case VB2_BUF_STATE_ACTIVE: b->flags |= V4L2_BUF_FLAG_QUEUED; break; case VB2_BUF_STATE_ERROR: b->flags |= V4L2_BUF_FLAG_ERROR; /* fall through */ case VB2_BUF_STATE_DONE: b->flags |= V4L2_BUF_FLAG_DONE; break; case VB2_BUF_STATE_PREPARED: b->flags |= V4L2_BUF_FLAG_PREPARED; break; case VB2_BUF_STATE_PREPARING: case VB2_BUF_STATE_DEQUEUED: case VB2_BUF_STATE_REQUEUEING: /* nothing */ break; } if (vb2_buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; if (!q->is_output && b->flags & V4L2_BUF_FLAG_DONE && b->flags & V4L2_BUF_FLAG_LAST) q->last_buffer_dequeued = true;}
3.4 enum vb2_buffer_state枚举
/** * enum vb2_buffer_state - current video buffer state * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf * @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used * in a hardware operation * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but * not yet dequeued to userspace * @VB2_BUF_STATE_ERROR: same as above, but the operation on the buffer * has ended with an error, which will be reported * to the userspace when it is dequeued */enum vb2_buffer_state { VB2_BUF_STATE_DEQUEUED, VB2_BUF_STATE_PREPARING, VB2_BUF_STATE_PREPARED, VB2_BUF_STATE_QUEUED, VB2_BUF_STATE_REQUEUEING, VB2_BUF_STATE_ACTIVE, VB2_BUF_STATE_DONE, VB2_BUF_STATE_ERROR,};
3.5 enum vb2_io_modes枚举
/** * enum vb2_io_modes - queue access methods * @VB2_MMAP: driver supports MMAP with streaming API * @VB2_USERPTR: driver supports USERPTR with streaming API * @VB2_READ: driver supports read() style access * @VB2_WRITE: driver supports write() style access * @VB2_DMABUF: driver supports DMABUF with streaming API */enum vb2_io_modes { VB2_MMAP = (1 << 0), VB2_USERPTR = (1 << 1), VB2_READ = (1 << 2), VB2_WRITE = (1 << 3), VB2_DMABUF = (1 << 4),}
3.6 struct vb2_plane结构
/** * struct vb2_plane - plane information * @mem_priv: private data with this plane * @dbuf: dma_buf - shared buffer object * @dbuf_mapped: flag to show whether dbuf is mapped or not * @bytesused: number of bytes occupied by data in the plane (payload) * @length: size of this plane (NOT the payload) in bytes * @min_length: minimum required size of this plane (NOT the payload) in bytes. * @length is always greater or equal to @min_length. * @offset: when memory in the associated struct vb2_buffer is * VB2_MEMORY_MMAP, equals the offset from the start of * the device memory for this plane (or is a "cookie" that * should be passed to mmap() called on the video node) * @userptr: when memory is VB2_MEMORY_USERPTR, a userspace pointer * pointing to this plane * @fd: when memory is VB2_MEMORY_DMABUF, a userspace file * descriptor associated with this plane * @m: Union with memtype-specific data (@offset, @userptr or * @fd). * @data_offset: offset in the plane to the start of data; usually 0, * unless there is a header in front of the data * Should contain enough information to be able to cover all the fields 89,2 8% * unless there is a header in front of the data * Should contain enough information to be able to cover all the fields * of struct v4l2_plane at videodev2.h */struct vb2_plane { void *mem_priv; struct dma_buf *dbuf; unsigned int dbuf_mapped; unsigned int bytesused; unsigned int length; unsigned int min_length; union { unsigned int offset; unsigned long userptr; int fd; } m; unsigned int data_offset;};
3.7 struct vb2_buffer结构(*)
* struct vb2_buffer - represents a video buffer * @vb2_queue: the queue to which this driver belongs * @index: id number of the buffer * @type: buffer type * @memory: the method, in which the actual data is passed * @num_planes: number of planes in the buffer * on an internal driver queue * @planes: private per-plane information; do not change * @timestamp: frame timestamp in ns */struct vb2_buffer { struct vb2_queue *vb2_queue; unsigned int index; unsigned int type; unsigned int memory; unsigned int num_planes; struct vb2_plane planes[VB2_MAX_PLANES]; u64 timestamp; /* private: internal use only * * state: current buffer state; do not change * queued_entry: entry on the queued buffers list, which holds * all buffers queued from userspace * done_entry: entry on the list that stores all buffers ready * to be dequeued to userspace */ enum vb2_buffer_state state; struct list_head queued_entry; struct list_head done_entry;#ifdef CONFIG_VIDEO_ADV_DEBUG /* * Counters for how often these buffer-related ops are * called. Used to check for unbalanced ops. */ u32 cnt_mem_alloc; u32 cnt_mem_put; u32 cnt_mem_get_dmabuf; u32 cnt_mem_get_userptr; u32 cnt_mem_put_userptr; u32 cnt_mem_prepare; u32 cnt_mem_finish; u32 cnt_mem_attach_dmabuf; u32 cnt_mem_detach_dmabuf; u32 cnt_mem_map_dmabuf; u32 cnt_mem_unmap_dmabuf; u32 cnt_mem_vaddr; u32 cnt_mem_cookie; u32 cnt_mem_num_users; u32 cnt_mem_mmap; u32 cnt_buf_init; u32 cnt_buf_prepare; u32 cnt_buf_finish; u32 cnt_buf_cleanup; u32 cnt_buf_queue; /* This counts the number of calls to vb2_buffer_done() */ u32 cnt_buf_done;#endif};
3.8 struct ops结构体vb2_ops
/** * struct vb2_ops - driver-specific callbacks * * @queue_setup:called from VIDIOC_REQBUFS() and VIDIOC_CREATE_BUFS() *handlers before memory allocation. It can be called *twice: if the original number of requested buffers *could not be allocated, then it will be called a *second time with the actually allocated number of *buffers to verify if that is OK. *The driver should return the required number of buffers *in \*num_buffers, the required number of planes per *buffer in \*num_planes, the size of each plane should be *set in the sizes\[\] array and optional per-plane *allocator specific device in the alloc_devs\[\] array. *When called from VIDIOC_REQBUFS(), \*num_planes == 0, *the driver has to use the currently configured format to *determine the plane sizes and \*num_buffers is the total *number of buffers that are being allocated. When called *from VIDIOC_CREATE_BUFS(), \*num_planes != 0 and it *describes the requested number of planes and sizes\[\] *contains the requested plane sizes. In this case *\*num_buffers are being allocated additionally to *q->num_buffers. If either \*num_planes or the requested *sizes are invalid callback must return %-EINVAL. * @wait_prepare:release any locks taken while calling vb2 functions; *it is called before an ioctl needs to wait for a new *buffer to arrive; required to avoid a deadlock in *blocking access type. * @wait_finish:reacquire all locks released in the previous callback; *required to continue operation after sleeping while *waiting for a new buffer to arrive. * @buf_init:called once after allocating a buffer (in MMAP case) *or after acquiring a new USERPTR buffer; drivers may *perform additional buffer-related initialization; *initialization failure (return != 0) will prevent *queue setup from completing successfully; optional. * @buf_prepare:called every time the buffer is queued from userspace *and from the VIDIOC_PREPARE_BUF() ioctl; drivers may *perform any initialization required before each *hardware operation in this callback; drivers can *access/modify the buffer here as it is still synced for *the CPU; drivers that support VIDIOC_CREATE_BUFS() must *also validate the buffer size; if an error is returned, *the buffer will not be queued in driver; optional. * @buf_finish:called before every dequeue of the buffer back to *userspace; the buffer is synced for the CPU, so drivers *can access/modify the buffer contents; drivers may *perform any operations required before userspace *accesses the buffer; optional. The buffer state can be *one of the following: %DONE and %ERROR occur while *streaming is in progress, and the %PREPARED state occurs *when the queue has been canceled and all pending *buffers are being returned to their default %DEQUEUED *state. Typically you only have to do something if the *state is %VB2_BUF_STATE_DONE, since in all other cases *the buffer contents will be ignored anyway. * @buf_cleanup:called once before the buffer is freed; drivers may *perform any additional cleanup; optional. * @start_streaming:called once to enter 'streaming' state; the driver may *receive buffers with @buf_queue callback *before @start_streaming is called; the driver gets the *number of already queued buffers in count parameter; *driver can return an error if hardware fails, in that *case all buffers that have been already given by *the @buf_queue callback are to be returned by the driver *by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED. *If you need a minimum number of buffers before you can *start streaming, then set @min_buffers_needed in the *vb2_queue structure. If that is non-zero then *@start_streaming won't be called until at least that *many buffers have been queued up by userspace. * @stop_streaming:called when 'streaming' state must be disabled; driver *should stop any DMA transactions or wait until they *finish and give back all buffers it got from &buf_queue *callback by calling vb2_buffer_done() with either *%VB2_BUF_STATE_DONE or %VB2_BUF_STATE_ERROR; may use *vb2_wait_for_all_buffers() function * @buf_queue:passes buffer vb to the driver; driver may start *hardware operation on this buffer; driver should give *the buffer back by calling vb2_buffer_done() function; *it is allways called after calling VIDIOC_STREAMON() *ioctl; might be called before @start_streaming callback *if user pre-queued buffers before calling *VIDIOC_STREAMON(). */struct vb2_ops {int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]);void (*wait_prepare)(struct vb2_queue *q);void (*wait_finish)(struct vb2_queue *q);int (*buf_init)(struct vb2_buffer *vb);int (*buf_prepare)(struct vb2_buffer *vb);void (*buf_finish)(struct vb2_buffer *vb);void (*buf_cleanup)(struct vb2_buffer *vb);int (*start_streaming)(struct vb2_queue *q, unsigned int count);void (*stop_streaming)(struct vb2_queue *q);void (*buf_queue)(struct vb2_buffer *vb);};
3.9 struct vb2_buf_ops 结构体
/** * struct vb2_buf_ops - driver-specific callbacks * * @verify_planes_array: Verify that a given user space structure contains *enough planes for the buffer. This is called *for each dequeued buffer. * @fill_user_buffer:given a vb2_buffer fill in the userspace structure. *For V4L2 this is a struct v4l2_buffer. * @fill_vb2_buffer:given a userspace structure, fill in the vb2_buffer. *If the userspace structure is invalid, then this op *will return an error. * @copy_timestamp:copy the timestamp from a userspace structure to *the vb2_buffer struct. */struct vb2_buf_ops {int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb);void (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb,struct vb2_plane *planes);void (*copy_timestamp)(struct vb2_buffer *vb, const void *pb);};
3.10 struct vb2_queue 结构体
/** * struct vb2_queue - a videobuf queue * * @type:private buffer type whose content is defined by the vb2-core *caller. For example, for V4L2, it should match *the types defined on enum &v4l2_buf_type * @io_modes:supported io methods (see vb2_io_modes enum) * @dev:device to use for the default allocation context if the driver *doesn't fill in the @alloc_devs array. * @dma_attrs:DMA attributes to use for the DMA. * @bidirectional: when this flag is set the DMA direction for the buffers of *this queue will be overridden with DMA_BIDIRECTIONAL direction. *This is useful in cases where the hardware (firmware) writes to *a buffer which is mapped as read (DMA_TO_DEVICE), or reads from *buffer which is mapped for write (DMA_FROM_DEVICE) in order *to satisfy some internal hardware restrictions or adds a padding *needed by the processing algorithm. In case the DMA mapping is *not bidirectional but the hardware (firmware) trying to access *the buffer (in the opposite direction) this could lead to an *IOMMU protection faults. * @fileio_read_once:report EOF after reading the first buffer * @fileio_write_immediately:queue buffer after each write() call * @allow_zero_bytesused:allow bytesused == 0 to be passed to the driver * @quirk_poll_must_check_waiting_for_buffers: Return POLLERR at poll when QBUF * has not been called. This is a vb1 idiom that has been adopted * also by vb2. * @lock:pointer to a mutex that protects the vb2_queue struct. The *driver can set this to a mutex to let the v4l2 core serialize *the queuing ioctls. If the driver wants to handle locking *itself, then this should be set to NULL. This lock is not used *by the videobuf2 core API. * @owner:The filehandle that 'owns' the buffers, i.e. the filehandle *that called reqbufs, create_buffers or started fileio. *This field is not used by the videobuf2 core API, but it allows *drivers to easily associate an owner filehandle with the queue. * @ops:driver-specific callbacks * @mem_ops:memory allocator specific callbacks * @buf_ops:callbacks to deliver buffer information *between user-space and kernel-space * @drv_priv:driver private data * @buf_struct_size: size of the driver-specific buffer structure; *"0" indicates the driver doesn't want to use a custom buffer *structure type. for example, sizeof(struct vb2_v4l2__buffer) *will be used for v4l2. * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAG_TIMESTAMP_* and *V4L2_BUF_FLAG_TSTAMP_SRC_* * @gfp_flags:additional gfp flags used when allocating the buffers. *Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32 *to force the buffer allocation to a specific memory zone. * @min_buffers_needed: the minimum number of buffers needed before *@start_streaming can be called. Used when a DMA engine *cannot be started unless at least this number of buffers *have been queued into the driver. *//* * Private elements (won't appear at the uAPI book): * @mmap_lock:private mutex used when buffers are allocated/freed/mmapped * @memory:current memory type used * @dma_dir:DMA mapping direction. * @bufs:videobuf buffer structures * @num_buffers: number of allocated/used buffers * @queued_list: list of buffers currently queued from userspace * @queued_count: number of buffers queued and ready for streaming. * @owned_by_drv_count: number of buffers owned by the driver * @done_list:list of buffers ready to be dequeued to userspace * @done_lock:lock to protect done_list list * @done_wq:waitqueue for processes waiting for buffers ready to be dequeued * @alloc_devs:memory type/allocator-specific per-plane device * @streaming:current streaming state * @start_streaming_called: @start_streaming was called successfully and we *started streaming. * @error:a fatal error occurred on the queue * @waiting_for_buffers: used in poll() to check if vb2 is still waiting for *buffers. Only set for capture queues if qbuf has not yet been *called since poll() needs to return POLLERR in that situation. * @is_multiplanar: set if buffer type is multiplanar * @is_output:set if buffer type is output * @copy_timestamp: set if vb2-core should set timestamps * @last_buffer_dequeued: used in poll() and DQBUF to immediately return if the *last decoded buffer was already dequeued. Set for capture queues *when a buffer with the V4L2_BUF_FLAG_LAST is dequeued. * @fileio:file io emulator internal data, used only if emulator is active * @threadio:thread io internal data, used only if thread is active */struct vb2_queue {unsigned inttype;unsigned intio_modes;struct device*dev;unsigned longdma_attrs;unsignedbidirectional:1;unsignedfileio_read_once:1;unsignedfileio_write_immediately:1;unsignedallow_zero_bytesused:1;unsigned quirk_poll_must_check_waiting_for_buffers:1;struct mutex*lock;void*owner;const struct vb2_ops*ops;const struct vb2_mem_ops*mem_ops;const struct vb2_buf_ops*buf_ops;void*drv_priv;unsigned intbuf_struct_size;u32timestamp_flags;gfp_tgfp_flags;u32min_buffers_needed;/* private: internal use only */struct mutexmmap_lock;unsigned intmemory;enum dma_data_directiondma_dir;struct vb2_buffer*bufs[VB2_MAX_FRAME];unsigned intnum_buffers;struct list_headqueued_list;unsigned intqueued_count;atomic_towned_by_drv_count;struct list_headdone_list;spinlock_tdone_lock;wait_queue_head_tdone_wq;struct device*alloc_devs[VB2_MAX_PLANES];unsigned intstreaming:1;unsigned intstart_streaming_called:1;unsigned interror:1;unsigned intwaiting_for_buffers:1;unsigned intis_multiplanar:1;unsigned intis_output:1;unsigned intcopy_timestamp:1;unsigned intlast_buffer_dequeued:1;struct vb2_fileio_data*fileio;struct vb2_threadio_data*threadio;#ifdef CONFIG_VIDEO_ADV_DEBUG/* * Counters for how often these queue-related ops are * called. Used to check for unbalanced ops. */u32cnt_queue_setup;u32cnt_wait_prepare;u32cnt_wait_finish;u32cnt_start_streaming;u32cnt_stop_streaming;#endif};