来源:http://blog.csdn.net/myarrow/article/details/8475728
1. VIDIOC_REQBUFS: 请求Kernel分配Video Buffer
其申请流程如下图所示:
1.1 Kernel态相关数据结构
1.2 uvc_alloc_buffers实现代码
-
-
-
-
-
-
-
-
-
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;
-
-
-
if (nbuffers == 0)
-
goto done;
-
-
-
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放入队列中
-
-
-
-
-
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;
-
}
4. VIDIOC_STREAMON: 做好准备工作并提交URB请求
-
-
-
-
-
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;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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 = usb_alloc_urb(0, gfp_flags);
-
if (urb == NULL) {
-
uvc_uninit_video(stream, 1);
-
return -ENOMEM;
-
}
-
-
-
-
-
-
-
-
-
-
-
usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
-
stream->urb_buffer[i],
-
size,
-
uvc_video_complete,
-
stream);
-
-
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-
urb->transfer_dma = stream->urb_dma[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:
-
if (stream->frozen)
-
return;
-
-
case -ECONNRESET:
-
case -ESHUTDOWN:
-
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);
-
spin_unlock_irqrestore(&queue->irqlock, flags);
-
-
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);
-
-
if (buf != NULL)
-
buf->error = 1;
-
continue;
-
}
-
-
-
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;
-
-
-
uvc_video_decode_data(stream, buf, mem + ret,
-
urb->iso_frame_desc[i].actual_length - ret);
-
-
-
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工作流程
阅读(2985) | 评论(0) | 转发(0) |