V4L2中命令在内核中来龙去脉
来源:互联网 发布:淘宝html模板 编辑:程序博客网 时间:2024/06/06 07:38
1. VIDIOC_REQBUFS: 请求Kernel分配Video Buffer
其申请流程如下图所示:
1.1 Kernel态相关数据结构
- struct uvc_fh {
- struct uvc_video_chain *chain;
- struct uvc_streaming *stream; //Stream--->
- enum uvc_handle_state state;
- };
- struct uvc_streaming {
- struct list_head list;
- struct uvc_device *dev;
- struct video_device *vdev;
- struct uvc_video_chain *chain;
- atomic_t active;
- struct usb_interface *intf;
- int intfnum;
- __u16 maxpsize;
- struct uvc_streaming_header header;
- enum v4l2_buf_type type;
- unsigned int nformats;
- struct uvc_format *format;
- struct uvc_streaming_control ctrl;
- struct uvc_format *cur_format;
- struct uvc_frame *cur_frame;
- /* Protect access to ctrl, cur_format, cur_frame and hardware video
- * probe control.
- */
- struct mutex mutex;
- unsigned int frozen : 1;
- struct uvc_video_queue queue; // UVC Video Queue--->
- void (*decode) (struct urb *urb, struct uvc_streaming *video,
- struct uvc_buffer *buf);
- /* Context data used by the bulk completion handler. */
- struct {
- __u8 header[256];
- unsigned int header_size;
- int skip_payload;
- __u32 payload_size;
- __u32 max_payload_size;
- } bulk;
- struct urb *urb[UVC_URBS];
- char *urb_buffer[UVC_URBS];
- dma_addr_t urb_dma[UVC_URBS];
- unsigned int urb_size;
- __u32 sequence;
- __u8 last_fid;
- struct tasklet_struct *tasklet[UVC_URBS]; /* ddl@rock-chips.com */
- };
- struct uvc_video_queue {
- enum v4l2_buf_type type;
- void *mem; // 已经分配的连续虚拟内存的首地址
- unsigned int flags;
- unsigned int count; // 已分配的buffer个数
- unsigned int buf_size; // 每个buffer的大小
- unsigned int buf_used;
- struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; // UVC buffer--->
- struct mutex mutex; /* protects buffers and mainqueue */
- spinlock_t irqlock; /* protects irqqueue */
- wait_queue_head_t wait; /* wait if mainqueue is empty */
- struct list_head mainqueue;
- struct list_head irqqueue;
- };
- struct uvc_buffer {
- unsigned long vma_use_count;
- struct list_head stream;
- /* Touched by interrupt handler. */
- struct v4l2_buffer buf; // v4l2_buffer --->
- struct list_head queue;
- wait_queue_head_t wait; // 初始化等待队列
- enum uvc_buffer_state state;
- unsigned int error;
- };
- struct v4l2_buffer {
- __u32 index; //buffer索引
- enum v4l2_buf_type type; //如V4L2_BUF_TYPE_VIDEO_CAPTURE
- __u32 bytesused;
- __u32 flags;
- enum v4l2_field field; // V4L2_FIELD_NONE
- struct timeval timestamp;
- struct v4l2_timecode timecode;
- __u32 sequence;
- /* memory location */
- enum v4l2_memory memory; // V4L2_MEMORY_MMAP
- union {
- __u32 offset; //在已经分配的大块内存中的偏移量,
- //其首地址保存在uvc_video_queue->mem中
- unsigned long userptr;
- struct v4l2_plane *planes;
- } m;
- __u32 length; //申请的内存大小
- __u32 input;
- __u32 reserved;
- };
struct uvc_fh {struct uvc_video_chain *chain;struct uvc_streaming *stream; //Stream--->enum uvc_handle_state state;};struct uvc_streaming {struct list_head list;struct uvc_device *dev;struct video_device *vdev;struct uvc_video_chain *chain;atomic_t active;struct usb_interface *intf;int intfnum;__u16 maxpsize;struct uvc_streaming_header header;enum v4l2_buf_type type;unsigned int nformats;struct uvc_format *format;struct uvc_streaming_control ctrl;struct uvc_format *cur_format;struct uvc_frame *cur_frame;/* Protect access to ctrl, cur_format, cur_frame and hardware video * probe control. */struct mutex mutex;unsigned int frozen : 1;struct uvc_video_queue queue; // UVC Video Queue--->void (*decode) (struct urb *urb, struct uvc_streaming *video,struct uvc_buffer *buf);/* Context data used by the bulk completion handler. */struct {__u8 header[256];unsigned int header_size;int skip_payload;__u32 payload_size;__u32 max_payload_size;} bulk;struct urb *urb[UVC_URBS];char *urb_buffer[UVC_URBS];dma_addr_t urb_dma[UVC_URBS];unsigned int urb_size;__u32 sequence;__u8 last_fid; struct tasklet_struct *tasklet[UVC_URBS]; /* ddl@rock-chips.com */};struct uvc_video_queue {enum v4l2_buf_type type;void *mem; // 已经分配的连续虚拟内存的首地址unsigned int flags;unsigned int count; // 已分配的buffer个数unsigned int buf_size; // 每个buffer的大小unsigned int buf_used;struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; // UVC buffer--->struct mutex mutex;/* protects buffers and mainqueue */spinlock_t irqlock;/* protects irqqueue */ wait_queue_head_t wait; /* wait if mainqueue is empty */struct list_head mainqueue;struct list_head irqqueue; };struct uvc_buffer {unsigned long vma_use_count;struct list_head stream;/* Touched by interrupt handler. */struct v4l2_buffer buf; // v4l2_buffer --->struct list_head queue;wait_queue_head_t wait; // 初始化等待队列enum uvc_buffer_state state;unsigned int error;};struct v4l2_buffer {__u32index; //buffer索引enum v4l2_buf_type type; //如V4L2_BUF_TYPE_VIDEO_CAPTURE__u32bytesused;__u32flags;enum v4l2_fieldfield; // V4L2_FIELD_NONEstruct timevaltimestamp; struct v4l2_timecodetimecode;__u32sequence;/* memory location */enum v4l2_memory memory; // V4L2_MEMORY_MMAPunion {__u32 offset; //在已经分配的大块内存中的偏移量, //其首地址保存在uvc_video_queue->mem中unsigned long userptr;struct v4l2_plane *planes;} m;__u32length; //申请的内存大小__u32input;__u32reserved;};
1.2 uvc_alloc_buffers实现代码
- /*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
- int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
- unsigned int buflength)
- {
- unsigned int bufsize = PAGE_ALIGN(buflength);
- unsigned int i;
- void *mem = NULL;
- int ret;
- if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
- nbuffers = UVC_MAX_VIDEO_BUFFERS;
- mutex_lock(&queue->mutex);
- if ((ret = __uvc_free_buffers(queue)) < 0)
- goto done;
- /* Bail out if no buffers should be allocated. */
- if (nbuffers == 0)
- goto done;
- /* Decrement the number of buffers until allocation succeeds. */
- for (; nbuffers > 0; --nbuffers) {
- mem = vmalloc_32(nbuffers * bufsize);
- if (mem != NULL)
- break;
- }
- if (mem == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- for (i = 0; i < nbuffers; ++i) {
- memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
- queue->buffer[i].buf.index = i;
- queue->buffer[i].buf.m.offset = i * bufsize;
- queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = queue->type;
- queue->buffer[i].buf.field = V4L2_FIELD_NONE;
- queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
- queue->buffer[i].buf.flags = 0;
- init_waitqueue_head(&queue->buffer[i].wait);
- }
- queue->mem = mem;
- queue->count = nbuffers;
- queue->buf_size = bufsize;
- ret = nbuffers;
- done:
- mutex_unlock(&queue->mutex);
- return ret;
- }
/* * Allocate the video buffers. * * Pages are reserved to make sure they will not be swapped, as they will be * filled in the URB completion handler. * * Buffers will be individually mapped, so they must all be page aligned. */int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,unsigned int buflength){unsigned int bufsize = PAGE_ALIGN(buflength);unsigned int i;void *mem = NULL;int ret;if (nbuffers > UVC_MAX_VIDEO_BUFFERS)nbuffers = UVC_MAX_VIDEO_BUFFERS;mutex_lock(&queue->mutex);if ((ret = __uvc_free_buffers(queue)) < 0)goto done;/* Bail out if no buffers should be allocated. */if (nbuffers == 0)goto done;/* Decrement the number of buffers until allocation succeeds. */for (; nbuffers > 0; --nbuffers) {mem = vmalloc_32(nbuffers * bufsize);if (mem != NULL)break;}if (mem == NULL) {ret = -ENOMEM;goto done;}for (i = 0; i < nbuffers; ++i) {memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);queue->buffer[i].buf.index = i;queue->buffer[i].buf.m.offset = i * bufsize;queue->buffer[i].buf.length = buflength;queue->buffer[i].buf.type = queue->type;queue->buffer[i].buf.field = V4L2_FIELD_NONE;queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;queue->buffer[i].buf.flags = 0;init_waitqueue_head(&queue->buffer[i].wait);}queue->mem = mem;queue->count = nbuffers;queue->buf_size = bufsize;ret = nbuffers;done:mutex_unlock(&queue->mutex);return ret;}
2. VIDIOC_QUERYBUF: 把Kernel分配的内存映射到用户空间
3. VIDIOC_QBUF: 把uvc_buffer放入队列中
- /*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
- */
- int uvc_queue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf)
- {
- struct uvc_buffer *buf;
- unsigned long flags;
- int ret = 0;
- uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
- mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
- ret = -EINVAL;
- goto done;
- }
- buf = &queue->buffer[v4l2_buf->index];
- if (buf->state != UVC_BUF_STATE_IDLE) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
- "(%u).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- v4l2_buf->bytesused > buf->buf.length) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
- ret = -EINVAL;
- goto done;
- }
- spin_lock_irqsave(&queue->irqlock, flags);
- if (queue->flags & UVC_QUEUE_DISCONNECTED) {
- spin_unlock_irqrestore(&queue->irqlock, flags);
- ret = -ENODEV;
- goto done;
- }
- buf->state = UVC_BUF_STATE_QUEUED;
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- buf->buf.bytesused = 0;
- else
- buf->buf.bytesused = v4l2_buf->bytesused;
- list_add_tail(&buf->stream, &queue->mainqueue);
- list_add_tail(&buf->queue, &queue->irqqueue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
- done:
- mutex_unlock(&queue->mutex);
- return ret;
- }
/* * Queue a video buffer. Attempting to queue a buffer that has already been * queued will return -EINVAL. */int uvc_queue_buffer(struct uvc_video_queue *queue,struct v4l2_buffer *v4l2_buf){struct uvc_buffer *buf;unsigned long flags;int ret = 0;uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);if (v4l2_buf->type != queue->type || v4l2_buf->memory != V4L2_MEMORY_MMAP) {uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) ""and/or memory (%u).\n", v4l2_buf->type,v4l2_buf->memory);return -EINVAL;}mutex_lock(&queue->mutex);if (v4l2_buf->index >= queue->count) {uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");ret = -EINVAL;goto done;}buf = &queue->buffer[v4l2_buf->index];if (buf->state != UVC_BUF_STATE_IDLE) {uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state ""(%u).\n", buf->state);ret = -EINVAL;goto done;}if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && v4l2_buf->bytesused > buf->buf.length) {uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");ret = -EINVAL;goto done;}spin_lock_irqsave(&queue->irqlock, flags);if (queue->flags & UVC_QUEUE_DISCONNECTED) {spin_unlock_irqrestore(&queue->irqlock, flags);ret = -ENODEV;goto done;}buf->state = UVC_BUF_STATE_QUEUED;if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)buf->buf.bytesused = 0;elsebuf->buf.bytesused = v4l2_buf->bytesused;list_add_tail(&buf->stream, &queue->mainqueue);list_add_tail(&buf->queue, &queue->irqqueue);spin_unlock_irqrestore(&queue->irqlock, flags);done:mutex_unlock(&queue->mutex);return ret;}
4. VIDIOC_STREAMON: 做好准备工作并提交URB请求
- /*
- * Initialize bulk URBs and allocate transfer buffers. The packet size is
- * given by the endpoint.
- */
- static int uvc_init_video_bulk(struct uvc_streaming *stream,
- struct usb_host_endpoint *ep, gfp_t gfp_flags)
- {
- struct urb *urb;
- unsigned int npackets, pipe, i;
- u16 psize;
- u32 size;
- // 获取每个包的大小
- psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
- // 一次可传输的最大负荷传输大小
- size = stream->ctrl.dwMaxPayloadTransferSize;
- stream->bulk.max_payload_size = size;
- /*
- 分配置urb传输buffer,返回包个数(size/psize),它指每个urb
- 包含多少个包; 为每个stream->urb_buffer分配DMA buffer,如下:
- for (i = 0; i < UVC_URBS; ++i) {
- stream->urb_size = psize * npackets; // urb_buffer的大小
- //分配DMA内存,并把地址保存在urb_buffer[i]和urb_dma[i]中,
- //同一块内存,不同的表示方法
- //1) stream->urb_buffer[i] = offset + page->vaddr;
- //2) stream->urb_dma[i] = offset + page->dma;
- stream->urb_buffer[i] = usb_alloc_coherent(
- stream->dev->udev, stream->urb_size,
- gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
- if (!stream->urb_buffer[i]) {
- uvc_free_urb_buffers(stream);
- break;
- }
- }
- */
- npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
- if (npackets == 0)
- return -ENOMEM;
- size = npackets * psize;
- if (usb_endpoint_dir_in(&ep->desc))
- pipe = usb_rcvbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
- else
- pipe = usb_sndbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
- if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- size = 0;
- for (i = 0; i < UVC_URBS; ++i) {
- // 创建一个 urb
- urb = usb_alloc_urb(0, gfp_flags);
- if (urb == NULL) {
- uvc_uninit_video(stream, 1);
- return -ENOMEM;
- }
- /* 填充urb参数
- struct urb {
- void *transfer_buffer; // (in) associated data buffer
- dma_addr_t transfer_dma;// (in) dma addr for transfer_buffer
- usb_complete_t complete;// (in) completion routine
- struct usb_iso_packet_descriptor iso_frame_desc[0];
- // (in) ISO ONLY
- }
- */
- usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
- stream->urb_buffer[i], //传输buffer
- size, //传输buffer的大小
- uvc_video_complete, //URB请求完成之后的callback
- stream);
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = stream->urb_dma[i]; //给urb->transfer_dma赋值
- // 把此urb保存到stream->urb[i]中
- stream->urb[i] = urb;
- }
- return 0;
- }
/* * Initialize bulk URBs and allocate transfer buffers. The packet size is * given by the endpoint. */static int uvc_init_video_bulk(struct uvc_streaming *stream,struct usb_host_endpoint *ep, gfp_t gfp_flags){struct urb *urb;unsigned int npackets, pipe, i;u16 psize;u32 size; // 获取每个包的大小psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;// 一次可传输的最大负荷传输大小size = stream->ctrl.dwMaxPayloadTransferSize;stream->bulk.max_payload_size = size; /* 分配置urb传输buffer,返回包个数(size/psize),它指每个urb 包含多少个包; 为每个stream->urb_buffer分配DMA buffer,如下: for (i = 0; i < UVC_URBS; ++i) { stream->urb_size = psize * npackets; // urb_buffer的大小 //分配DMA内存,并把地址保存在urb_buffer[i]和urb_dma[i]中, //同一块内存,不同的表示方法 //1) stream->urb_buffer[i] = offset + page->vaddr; //2) stream->urb_dma[i] = offset + page->dma; stream->urb_buffer[i] = usb_alloc_coherent( stream->dev->udev, stream->urb_size, gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); if (!stream->urb_buffer[i]) { uvc_free_urb_buffers(stream); break; } } */npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);if (npackets == 0)return -ENOMEM;size = npackets * psize;if (usb_endpoint_dir_in(&ep->desc))pipe = usb_rcvbulkpipe(stream->dev->udev, ep->desc.bEndpointAddress);elsepipe = usb_sndbulkpipe(stream->dev->udev, ep->desc.bEndpointAddress);if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)size = 0;for (i = 0; i < UVC_URBS; ++i) { // 创建一个 urburb = usb_alloc_urb(0, gfp_flags);if (urb == NULL) {uvc_uninit_video(stream, 1);return -ENOMEM;} /* 填充urb参数struct urb {void *transfer_buffer;// (in) associated data bufferdma_addr_t transfer_dma;// (in) dma addr for transfer_bufferusb_complete_t complete;// (in) completion routinestruct usb_iso_packet_descriptor iso_frame_desc[0]; // (in) ISO ONLY}*/usb_fill_bulk_urb(urb, stream->dev->udev, pipe, stream->urb_buffer[i], //传输buffer size, //传输buffer的大小 uvc_video_complete, //URB请求完成之后的callback stream);urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;urb->transfer_dma = stream->urb_dma[i]; //给urb->transfer_dma赋值// 把此urb保存到stream->urb[i]中stream->urb[i] = urb;}return 0;}
5. urb数据解析 (uvc_video_complete)
当URB请求(usb_submit_urb)完成之后,它将调用其回调函数(uvc_video_complete),下面分析此回调函数到底做了些什么。即如何把transfer_buffer或transfer_dma中数据转换为应用程序需要的v4l2_buffer中的数据。
5.1 uvc_video_complete
- static void uvc_video_complete(struct urb *urb)
- {
- struct uvc_streaming *stream = urb->context;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *buf = NULL;
- unsigned long flags;
- int ret;
- switch (urb->status) {
- case 0:
- break;
- default:
- uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
- "completion handler.\n", urb->status);
- case -ENOENT: /* usb_kill_urb() called. */
- if (stream->frozen)
- return;
- case -ECONNRESET: /* usb_unlink_urb() called. */
- case -ESHUTDOWN: /* The endpoint is being disabled. */
- uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
- return;
- }
- spin_lock_irqsave(&queue->irqlock, flags);
- if (!list_empty(&queue->irqqueue))
- buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);//从queue->irqqueue中取出一个空的uvc_buffer
- spin_unlock_irqrestore(&queue->irqlock, flags);
- //把urb中的数据转换为uvc_buffer中的数据,并设置对应的状态
- stream->decode(urb, stream, buf);
- if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
- ret);
- }
- }
static void uvc_video_complete(struct urb *urb){ struct uvc_streaming *stream = urb->context;struct uvc_video_queue *queue = &stream->queue;struct uvc_buffer *buf = NULL;unsigned long flags;int ret;switch (urb->status) {case 0:break;default:uvc_printk(KERN_WARNING, "Non-zero status (%d) in video ""completion handler.\n", urb->status);case -ENOENT:/* usb_kill_urb() called. */if (stream->frozen)return;case -ECONNRESET:/* usb_unlink_urb() called. */case -ESHUTDOWN:/* The endpoint is being disabled. */uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);return;} spin_lock_irqsave(&queue->irqlock, flags);if (!list_empty(&queue->irqqueue))buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, queue);//从queue->irqqueue中取出一个空的uvc_bufferspin_unlock_irqrestore(&queue->irqlock, flags); //把urb中的数据转换为uvc_buffer中的数据,并设置对应的状态stream->decode(urb, stream, buf);if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",ret);}}
5.2 stream->decode是什么?
现在关键是stream->decode到底做了些什么?它也是一个回调函数,首先要搞明白它是一个什么函数,其注册过程如下图所示:
5.3 uvc_video_decode_bulk
5.4 uvc_video_decode_isoc
- static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
- {
- u8 *mem;
- int ret, i;
- for (i = 0; i < urb->number_of_packets; ++i) {
- if (urb->iso_frame_desc[i].status < 0) {
- uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
- "lost (%d).\n", urb->iso_frame_desc[i].status);
- /* Mark the buffer as faulty. */
- if (buf != NULL)
- buf->error = 1;
- continue;
- }
- /* Decode the payload header. */
- mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- do {
- ret = uvc_video_decode_start(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
- if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
- if (ret < 0)
- continue;
- /* Decode the payload data. */
- uvc_video_decode_data(stream, buf, mem + ret,
- urb->iso_frame_desc[i].actual_length - ret);
- /* Process the header again. */
- uvc_video_decode_end(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
- if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->buf.length != buf->buf.bytesused &&
- !(stream->cur_format->flags &
- UVC_FMT_FLAG_COMPRESSED))
- buf->error = 1;
- buf = uvc_queue_next_buffer(&stream->queue, buf);
- }
- }
- }
static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,struct uvc_buffer *buf){u8 *mem;int ret, i;for (i = 0; i < urb->number_of_packets; ++i) {if (urb->iso_frame_desc[i].status < 0) {uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame ""lost (%d).\n", urb->iso_frame_desc[i].status); /* Mark the buffer as faulty. */if (buf != NULL)buf->error = 1;continue;}/* Decode the payload header. */mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;do {ret = uvc_video_decode_start(stream, buf, mem,urb->iso_frame_desc[i].actual_length);if (ret == -EAGAIN)buf = uvc_queue_next_buffer(&stream->queue, buf);} while (ret == -EAGAIN);if (ret < 0)continue;/* Decode the payload data. */uvc_video_decode_data(stream, buf, mem + ret,urb->iso_frame_desc[i].actual_length - ret);/* Process the header again. */uvc_video_decode_end(stream, buf, mem,urb->iso_frame_desc[i].actual_length);if (buf->state == UVC_BUF_STATE_READY) {if (buf->buf.length != buf->buf.bytesused && !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))buf->error = 1;buf = uvc_queue_next_buffer(&stream->queue, buf);}}}
6. VIDIOC_DQBUF: 获取视频数据
7. CameraHAL工作流程
- V4L2中命令在内核中来龙去脉
- android 中“am profile” 命令的来龙去脉
- 弄清WinXP中“错误报告”的来龙去脉
- MFC中函数DoDataExchange 的来龙去脉
- C++中 inline函数的来龙去脉
- Unity工程中 .Meta 文件的来龙去脉
- 浏览器中User-Agent的来龙去脉
- 在内核中寻找内核符号表
- 在内核中添加函数
- 在内核中引入代码
- 在内核中实现realloc
- V4L2中filed的理解
- V4l2中soc_camera框架图
- Ubuntu V4l2中摄像头输出Mjpeg数据在Qt中显示
- Linux 视频设备驱动V4L2最常用的控制命令使用说明--实际中应用的整理
- 关于V4L2中操作比较重要的几个命令以及一般操作流程总结
- ASP.NET中如何实现FORM认证登录?来龙去脉
- 看Java中==、equals、hashCode的来龙去脉
- C/C++中extern关键字详解
- char* 与LPTSTR (或LPCTSTR)及CString 之间的转换
- HTMLEncode
- POJ_2255
- 黑马程序员 IO流
- V4L2中命令在内核中来龙去脉
- bashrc and bash_profile 等!!!!
- DirectByteBuffer
- 第一道题目:一个美国人在菜市场上做生意。第一次,8美元买了一只鸡,9美元卖掉了;第二次,10美元买了同样的一只鸡,11美元又卖掉了。
- linux实现抓包 (使用原始套接字数据连路层协议)
- 查询和修改 Oracle 参数
- C语言的谜题
- 4.1 Instantiating a Table View
- 如何在eclipse中查看API源码