zoukankan      html  css  js  c++  java
  • 摄像头驱动_摄像头驱动程序必需的11个ioctl及摄像头数据的获取过程

    摄像头驱动_摄像头驱动程序必需的11个ioctl及摄像头数据的获取过程

    根据虚拟驱动vivi的使用过程彻底分析摄像头驱动
    // 1~2都是在v4l2_open里调用
    1. open
    2. ioctl(4, VIDIOC_QUERYCAP

    // 3~7 都是在get_device_capabilities里调用
    3. for()
    ioctl(4, VIDIOC_ENUMINPUT // 列举输入源,VIDIOC_ENUMINPUT/VIDIOC_G_INPUT/VIDIOC_S_INPUT不是必需的
    4. for()
    ioctl(4, VIDIOC_ENUMSTD // 列举标准(制式), 不是必需的
    5. for()
    ioctl(4, VIDIOC_ENUM_FMT // 列举格式

    6. ioctl(4, VIDIOC_G_PARM
    7. for()
    ioctl(4, VIDIOC_QUERYCTRL // 查询属性(比如说亮度值最小值、最大值、默认值)

    // 8~10都是通过v4l2_read_attr来调用的
    8. ioctl(4, VIDIOC_G_STD // 获得当前使用的标准(制式), 不是必需的
    9. ioctl(4, VIDIOC_G_INPUT
    10. ioctl(4, VIDIOC_G_CTRL // 获得当前属性, 比如亮度是多少

    11. ioctl(4, VIDIOC_TRY_FMT // 试试能否支持某种格式
    12. ioctl(4, VIDIOC_S_FMT // 设置摄像头使用某种格式


    // 13~16在v4l2_start_streaming
    13. ioctl(4, VIDIOC_REQBUFS // 请求系统分配缓冲区
    14. for()
    ioctl(4, VIDIOC_QUERYBUF // 查询所分配的缓冲区
    mmap
    15. for ()
    ioctl(4, VIDIOC_QBUF // 把缓冲区放入队列
    16. ioctl(4, VIDIOC_STREAMON // 启动摄像头


    // 17里都是通过v4l2_write_attr来调用的
    17. for ()
    ioctl(4, VIDIOC_S_CTRL // 设置属性
    ioctl(4, VIDIOC_S_INPUT // 设置输入源
    ioctl(4, VIDIOC_S_STD // 设置标准(制式), 不是必需的

    // v4l2_nextframe > v4l2_waiton
    18. v4l2_queue_all
    v4l2_waiton
    for ()
    {
    select(5, [4], NULL, NULL, {5, 0}) = 1 (in [4], left {4, 985979})
    ioctl(4, VIDIOC_DQBUF // de-queue, 把缓冲区从队列中取出
    // 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据
    ioctl(4, VIDIOC_QBUF // 把缓冲区放入队列
    }

    xawtv的几大函数:
    1. v4l2_open
    2. v4l2_read_attr/v4l2_write_attr
    3. v4l2_start_streaming
    4. v4l2_nextframe/v4l2_waiton

    摄像头驱动程序必需的11个ioctl:
    // 表示它是一个摄像头设备
    .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_streamon = vidioc_streamon,
    .vidioc_streamoff = vidioc_streamoff,

    继续分析数据的获取过程:
    1. 请求分配缓冲区:
    ioctl(4, VIDIOC_REQBUFS // 请求系统分配缓冲区
    videobuf_reqbufs(队列, v4l2_requestbuffers) // 队列在open函数用videobuf_queue_vmalloc_init初始化
    // 注意:这个IOCTL只是分配缓冲区的头部信息,真正的缓存还没有分配呢

    2. 查询映射缓冲区:
    ioctl(4, VIDIOC_QUERYBUF // 查询所分配的缓冲区
    videobuf_querybuf // 获得缓冲区的数据格式、大小、每一行长度、高度
    mmap(参数里有"大小") // 在这里才分配缓存
    v4l2_mmap
    vivi_mmap
    videobuf_mmap_mapper
    videobuf-vmalloc.c里的__videobuf_mmap_mapper
    mem->vmalloc = vmalloc_user(pages); // 在这里才给缓冲区分配空间

    3. 把缓冲区放入队列:
    ioctl(4, VIDIOC_QBUF // 把缓冲区放入队列
    videobuf_qbuf
    q->ops->buf_prepare(q, buf, field); // 调用驱动程序提供的函数做些预处理
    list_add_tail(&buf->stream, &q->stream); // 把缓冲区放入队列的尾部
    q->ops->buf_queue(q, buf); // 调用驱动程序提供的"入队列函数"

    4. 启动摄像头
    ioctl(4, VIDIOC_STREAMON
    videobuf_streamon
    q->streaming = 1;

    5. 用select查询是否有数据
    // 驱动程序里必定有: 产生数据、唤醒进程
    v4l2_poll
    vdev->fops->poll
    vivi_poll
    videobuf_poll_stream
    // 从队列的头部获得缓冲区
    buf = list_entry(q->stream.next, struct videobuf_buffer, stream);

    // 如果没有数据则休眠
    poll_wait(file, &buf->done, wait);

    谁来产生数据、谁来唤醒它?
    内核线程vivi_thread每30MS执行一次,它调用
    vivi_thread_tick
    vivi_fillbuff(fh, buf); // 构造数据
    wake_up(&buf->vb.done); // 唤醒进程

    6. 有数据后从队列里取出缓冲区
    // 有那么多缓冲区,APP如何知道哪一个缓冲区有数据?调用VIDIOC_DQBUF
    ioctl(4, VIDIOC_DQBUF
    vidioc_dqbuf
    // 在队列里获得有数据的缓冲区
    retval = stream_next_buffer(q, &buf, nonblocking);

    // 把它从队列中删掉
    list_del(&buf->stream);

    // 把这个缓冲区的状态返回给APP
    videobuf_status(q, b, buf, q->type);

    7. 应用程序根据VIDIOC_DQBUF所得到缓冲区状态,知道是哪一个缓冲区有数据
    就去读对应的地址(该地址来自前面的mmap)

    怎么写摄像头驱动程序:
    1. 分配video_device:video_device_alloc
    2. 设置
    .fops
    .ioctl_ops (里面需要设置11项)
    如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops
    3. 注册: video_register_device

    http://blog.163.com/pangzy_me/blog/static/9704366520152211501555/

  • 相关阅读:
    虚函数和纯虚函数
    MS CRM 2011中PartyList类型字段的实例化
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(4)
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(2)
    MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第二部分)——IOrganizationService(二)
    MS CRM 2011 SDK 5.08已经发布
    MS CRM 2011 Q2的一些更新
    最近很忙
    Microsoft Dynamics CRM 2011最近的一些更新
    补一篇,Update Rollup 12 终于发布了
  • 原文地址:https://www.cnblogs.com/eustoma/p/7499528.html
Copyright © 2011-2022 走看看