• 初识V4L2(三)-------分析vivi.c 虚拟视频驱动


    1、分配video_device结构体

    2、设置

    3、注册  video_register_device

    分析vivi.c:

    vivi_init( )//入口函数

     vivi_create_instance()

      ret = v4l2_device_register(NULL, &dev->v4l2_dev);

      /*注意dev->v4l2_dev在该函数v4l2_device_register中被设置,这个结构体在后边将被用到。

      ,这个函数只是做了某些初始化的工作,并没有什么注册

      */

       vfd = video_device_alloc(); 

        1、设置 

        *vfd = vivi_template;

        vivi_template结构体中主要有成员变量:

        .fops = &vivi_fops,

        .ioctl_ops = &vivi_ioctl_ops,

        .release = video_device_release,

        2、
        vfd->v4l2_dev = &dev->v4l2_dev;

        v4l2_dev是在v4l2_device_register()中设置的

        3、设置"ctrl"(用于app的ioctl)。在应用程序中ioctl中可以做什么事情,就是在vivi.c这个地方设置的。(注意本文是分析vivi.c,对于其他的也是一样的)  

          hdl = &dev->ctrl_handler;
          v4l2_ctrl_handler_init(hdl, 11);//初始化一个ctrl_handler

          /*v4l2_ctrl_new_std 添加一个新的标准的ctrl

            v4l2_ctrl_new_custom添加一个客户自定义的ctrl*/
          dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
          dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
          dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
          dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
          dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);

       video_register_device()

        __video_register_device()//在上一篇博客中,这个函数已经简要的分析,在此不再赘述。

    vivi 的入口函数:vivi_init()
      static int __init vivi_init(void)
      {   
        for (i = 0; i < n_devs; i++) { /n_devs=1
          ret = vivi_create_instance(i);//调用该函数来创建设备
        }
      }
    vivi_create_instance(int inst)
    {
      struct video_device *vfd; //这是一个核心的结构,对应视频视频设备节点
      .........
      vfd = video_device_alloc(); //动态分配了一个video_device
      /*这里的vfd被设置成了vivi_template,在后面的代码中会以次设备号为索引把vfd放入到video_device[]中,在其它函数中根据次设备号从video_device[]数组中获取的video_deice就是vivi_template*/
      *vfd = vivi_template;
      ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
    }

    如何写v4l2驱动

    (1)分配/设置/注册 v4l2_device

      v4l2_device并不重要,里面只是提供了一些辅助的信息,比如自旋锁、引用计数等,目的是给以后的video_device使用

      利用函数v4l2_device_register得到一个结构体v4l2_device结构体

    (2)分配video_device

      利用函数video_device_alloc得到结构体video_device

    (3)设置

      得到的video_device称为vfd

      a、vfd->v4l2_dev就让该结构体的v4L2_dev指向v4L2_device_register函数得到的结构体v4l2_device

      b、

        *vfd = vivi_template;

        static struct video_device vivi_template = {
          .name = "vivi",
          .fops = &vivi_fops,
          .ioctl_ops = &vivi_ioctl_ops,
          .release = video_device_release,

        }; 

        static const struct v4l2_file_operations vivi_fops = {
          .owner = THIS_MODULE,
          .open = v4l2_fh_open,
          .release = vivi_close,
          .read = vivi_read,
          .poll = vivi_poll,
          .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
          .mmap = vivi_mmap,
        };   

        static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
          .vidioc_querycap = vidioc_querycap,
          .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
          .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
          .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
          .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
          .vidioc_reqbufs = vidioc_reqbufs,
          .vidioc_querybuf = vidioc_querybuf,
          .vidioc_qbuf = vidioc_qbuf,
          .vidioc_dqbuf = vidioc_dqbuf,
          .vidioc_s_std = vidioc_s_std,
          .vidioc_enum_input = vidioc_enum_input,
          .vidioc_g_input = vidioc_g_input,
          .vidioc_s_input = vidioc_s_input,
          .vidioc_streamon = vidioc_streamon,
          .vidioc_streamoff = vidioc_streamoff,
          .vidioc_log_status = v4l2_ctrl_log_status,
          .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
          .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
        };

      可以用下面这幅图简要说明其中的关系:

        

      c、app可以通过ioctl来设置、获得亮度等信息

        驱动程序里面谁来接收、存储、设置到硬件或提供信息给硬件

        在驱动程序里面抽象出一个结构体v4l2_ctrl,称为属性。每个v4l2_ctrl对应一项,比如说亮度、音量等信息。

        用v4l2_ctrl_handler来管理v4l2_ctrl。v4l2_ctrl_handler就像一个链表一样,里面需要填充各个属性,也可理解为设置各个属性。

         (1)v4L2_ctrl_handler_init  初始化一个ctrl_handler

         (2)v4L2_ctrl_new_std     v4L2_ctrl_new_custom

            创建v4L2_ctrl,并且放入链表v4L2_ctrl_handler中

         (3)与video_dev关联

            v4L2_dev.ctrl_handler = hdl //将上面两步创建出来的v4L2_ctrl_handler赋给v4L2_dev中的ctrl_handler

            video_dev->v4L2_dev = v4L2_dev  //video_dev是我们的核心。

          

  • 相关阅读:
    RedisCacheTool参考其中的文件读写功能
    eclipse eayExplorer 查看代码的资源管理器打开方式
    有关写代码效率的问题
    Eclipse
    解决pdm打开只显示表名不显示字段的步骤
    绝对定位元素的水平垂直居中
    Maven依赖之Scope
    无提示关闭弹出窗口
    Maven模块与模块间的依赖
    Maven+Hibernate4注解0配置示例
  • 原文地址:https://www.cnblogs.com/-glb/p/10292951.html
Copyright © 2020-2023  润新知