视频传输

视频传输方式一:以IIC协议,通过IO口传输视频流:

视频传输方式二:以usb接口传输视频流:

驱动:字符设备驱动

怎么写驱动程序:构造file_operations

                             告诉内核

                             入口函数

                             出口函数

v4l2驱动框架:核心层 -- > file_operations

                         硬件相关层:

1、将usb摄像头设备插到装有虚拟机的pc上,dmesg会打印出一些发现usb摄像头设备的信息,在内核中grep找到打印信息的具体位置;

扫描二维码关注公众号,回复: 6982213 查看本文章

2、查找打印信息

3、用source insight或其他阅读软件打开uvc_driver.c文件

      3.1 -->struct uvc_driver

                 --> uvc_probe:

                       v4l2_device_register

                       uvc_register_chains ---uvc_register_video--video_device  video_register_device

                                                          ---struct video_device *vdev;

                                                                       struct uvc_device *dev,

                                                                 vdev->v4l2_dev = &dev->vdev;
                                                                 vdev->fops = &uvc_fops;

                       media_device_register

4、在内核中有v4l2-framework.txt文档可以参考

5、可以分析虚拟摄像头驱动:vivi.c

vivi_init-->vivi_create_instance-->video_device_alloc-->video_register_device-->__video_register_device-->vdev->cdev = cdev_alloc();--> cdev_add()

6、在内核中已经提供了file_operations  v4l2_fops  的一些基本函数,所以我们不需要写字符设备函数。当应用层调用ioctl函数时,调用file_operations中的ioctl---.unlocked_ioctl = v4l2_ioctl,

v4l2_ioctl------

             if (video_is_registered(vdev))
                      ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);

如果video_device已经被注册了,就调用video_device里面的fops函数里面的unlocked_ioctl函数。

而unlocked_ioctl函数内核中已经写好了,我们不需要再写---video_usercopy

----cmd_input_size(cmd);

----check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);

----得到我们想要的

static unsigned long cmd_input_size(unsigned int cmd)
{
    /* Size of structure up to and including 'field' */
#define CMDINSIZE(cmd, type, field)                 \
    case VIDIOC_##cmd:                     \
        return offsetof(struct v4l2_##type, field) +     \
            sizeof(((struct v4l2_##type *)0)->field);

    switch (cmd) {
        CMDINSIZE(ENUM_FMT,        fmtdesc,    type);
        CMDINSIZE(G_FMT,        format,        type);
        CMDINSIZE(QUERYBUF,        buffer,        length);
        CMDINSIZE(G_PARM,        streamparm,    type);
        CMDINSIZE(ENUMSTD,        standard,    index);
        CMDINSIZE(ENUMINPUT,        input,        index);
        CMDINSIZE(G_CTRL,        control,    id);
        CMDINSIZE(G_TUNER,        tuner,        index);
        CMDINSIZE(QUERYCTRL,        queryctrl,    id);
        CMDINSIZE(QUERYMENU,        querymenu,    index);
        CMDINSIZE(ENUMOUTPUT,        output,        index);
        CMDINSIZE(G_MODULATOR,        modulator,    index);
        CMDINSIZE(G_FREQUENCY,        frequency,    tuner);
        CMDINSIZE(CROPCAP,        cropcap,    type);
        CMDINSIZE(G_CROP,        crop,        type);
        CMDINSIZE(ENUMAUDIO,        audio,         index);
        CMDINSIZE(ENUMAUDOUT,        audioout,     index);
        CMDINSIZE(ENCODER_CMD,        encoder_cmd,    flags);
        CMDINSIZE(TRY_ENCODER_CMD,    encoder_cmd,    flags);
        CMDINSIZE(G_SLICED_VBI_CAP,    sliced_vbi_cap,    type);
        CMDINSIZE(ENUM_FRAMESIZES,    frmsizeenum,    pixel_format);
        CMDINSIZE(ENUM_FRAMEINTERVALS,    frmivalenum,    height);
    default:
        return _IOC_SIZE(cmd);
    }
}

static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                void * __user *user_ptr, void ***kernel_ptr)
{
    int ret = 0;

    switch (cmd) {
    case VIDIOC_QUERYBUF:
    case VIDIOC_QBUF:
    case VIDIOC_DQBUF: {
        struct v4l2_buffer *buf = parg;

        if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) {
            if (buf->length > VIDEO_MAX_PLANES) {
                ret = -EINVAL;
                break;
            }
            *user_ptr = (void __user *)buf->m.planes;
            *kernel_ptr = (void *)&buf->m.planes;
            *array_size = sizeof(struct v4l2_plane) * buf->length;
            ret = 1;
        }
        break;
    }

    case VIDIOC_S_EXT_CTRLS:
    case VIDIOC_G_EXT_CTRLS:
    case VIDIOC_TRY_EXT_CTRLS: {
        struct v4l2_ext_controls *ctrls = parg;

        if (ctrls->count != 0) {
            if (ctrls->count > V4L2_CID_MAX_CTRLS) {
                ret = -EINVAL;
                break;
            }
            *user_ptr = (void __user *)ctrls->controls;
            *kernel_ptr = (void *)&ctrls->controls;
            *array_size = sizeof(struct v4l2_ext_control)
                    * ctrls->count;
            ret = 1;
        }
        break;
    }
    }

    return ret;
}

7、用strace 可以获得程序执行过程中的系统调用

strace -o xawtv.log xawtv

xawtv所涉及的系统调用就会记录在xawtv.log中

          

                                         

猜你喜欢

转载自www.cnblogs.com/zhu-g5may/p/9970364.html