• 视频传输


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

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

    驱动:字符设备驱动

    怎么写驱动程序:构造file_operations

                                 告诉内核

                                 入口函数

                                 出口函数

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

                             硬件相关层:

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

    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;    // 分配video_device结构体,设置并通过video_register_device注册  video_device结构体有两个重要的成员 ->fops和->ioctl_ops

                                                                           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,  -->video_usercopy(file, cmd, arg, __video_do_ioctl) -->__video_do_ioctl --> 根据应用层ioctl传入的参数调用video_device->ioctl_ops中对应的函数

    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中

              

                                             

  • 相关阅读:
    kafka 副本复制的几个参数
    kafka 吞吐量为什么这么大?
    netty 的线程模型
    pulsar 实现的一种 RateLimiter
    rocketMQ 长轮询
    对比 kafka 和 rocketmq 的 IO
    配置 kafka 同步刷盘
    使用Shell脚本删除/清空日志文件
    反爬虫之JS反编译:PyExecJS
    LInux查看网速带宽及各进程占用情况:nethogs
  • 原文地址:https://www.cnblogs.com/zhu-g5may/p/9970364.html
Copyright © 2020-2023  润新知