UVC摄像头视频流原理解析

1.UVC摄像i头从插入到加载驱动,看我前面的文章分析过程

2.UVC摄像头驱动加载时在kernel\drivers\media\usb\uvc\uvc_driver.c uvc_probe->函数中完成的
整个流程如下

  uvc_register_chains->
          uvc_register_terms->
                uvc_register_video->
                        vdev->v4l2_dev = &dev->vdev;
                        vdev->fops = &uvc_fops;
                        vdev->ioctl_ops = &uvc_ioctl_ops;
                        video_register_device->
                                  __video_register_device->   H:\RK3399\kernel\drivers\media\v4l2-core\v4l2-dev.c
                                              case VFL_TYPE_GRABBER:
                                                               name_base = "video";

//这个字符串就是我们在/dev/下面看到的vido0,video1等设备,按摄像头
3.应用层app打开camera,最后必然调用open("/dev/video0") 打开设备
uvc_v4l2_open-> kernel\drivers\media\usb\uvc\uvc_v4l2.c
4.摄像头打开的同时就开始操作摄像头,进行抓取视频流的初始化工作
从uvc_start_streaming-> drivers/media/usb/uvc/uvc_queue.c 开始
uvc_init_video_isoc->urb->complete = uvc_video_complete;
重要的就是注册了一个uvc_video_complete一个urb完成函数,这个就是我们视频数据解析的开始
完成的时候注册了一个视频解析函数uvc_video_decode_isoc

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) {
                uvc_video_validate_buffer(stream, buf);
                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) {  //确认数据结束标志
            uvc_video_validate_buffer(stream, buf);              //判断数据是否有效
            buf = uvc_queue_next_buffer(&stream->queue, buf);   //找到下一个空buf并把当前buf数据送到用户空间
        }
    }
}

struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
        struct uvc_buffer *buf)
{
    struct uvc_buffer *nextbuf;
    unsigned long flags;

    if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
        buf->error = 0;
        buf->state = UVC_BUF_STATE_QUEUED;
        buf->bytesused = 0;
        vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
        return buf;
    }

    spin_lock_irqsave(&queue->irqlock, flags);
    list_del(&buf->queue);
    if (!list_empty(&queue->irqqueue))
        nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,   //查找下一个空buf来存储下一帧数据
                       queue);
    else
        nextbuf = NULL;
    spin_unlock_irqrestore(&queue->irqlock, flags);

    buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
    vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
    vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);     //数据完成,把当前帧返回用户空间,唤醒等待数据的进程

    return nextbuf;
}

从urb数据不断的完成,不断的中断通知系统,系统调用 uvc_video_complete进而调用 uvc_video_decode_isoc来解析视频数据
在 uvc_video_complete被回调的时候 usb_submit_urb会再次被提交,从而保证整个数据采集中断不断的进行,这些数据一帧一帧的被解析出来,我们再把每帧数据送到用户空间,用户通过app把这些画帧按一定的速度显示出来,从而就形成了我们看到的视频。

你可能感兴趣的:(linux,操作系统,android,驱动程序,uvc)