Linux系统之V4L2视频驱动-VIDIOC_QUERYBUF查询缓存信息

发布时间:2023-04-27 09:27:24
VIDIOC_QUERYBUF查询缓存信息代码详细说明
  • 1. 概述
  • 2 应用层
  • 2.1 struct v4l2_buffer结构
  • 3. 驱动层
  • 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};

上一篇 磁盘分区在Windows和Linux下的表现形式对比
下一篇 Servlet添加自定义的过滤器没有效果?

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题