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/

  • 相关阅读:
    MFC Windows 程序设计>WinMain 简单Windows程序 命令行编译
    AT3949 [AGC022D] Shopping 题解
    CF643D Bearish Fanpages 题解
    CF643C Levels and Regions 题解
    CF241E Flights 题解
    CF671C Ultimate Weirdness of an Array 题解
    CF1592F Alice and Recoloring 题解
    GYM 102452E 题解
    CF494C Helping People 题解
    P5556 圣剑护符
  • 原文地址:https://www.cnblogs.com/eustoma/p/7499528.html
Copyright © 2011-2022 走看看