linux应用项目(二)摄像头(1)V4L2框架分析
来源:互联网 发布:jenkins php 自动部署 编辑:程序博客网 时间:2024/06/01 08:46
1、回顾字符设备驱动程序基本框架
1.1、简单的字符设备驱动程序
(1)file_operations
(2)register_chrdev(major,name,file_operations)
(3)module_init
(4)module_exit
(5)MODULE_LICENSE("GPL");
新:
(1)分配cdev结构体
(2)设置cdev结构体
(2)cdev_add
1.2、复杂的字符设备驱动程序(分层)
内核中:fbmen.c(核心层,内核提供)
(1)file_operations
(2)register_chrdev(major,name,file_operations)
(3)module_init
(4)module_exit
(5)MODULE_LICENSE("GPL");
硬件相关:
(1)分配一个fb_info结构体
(2)设置fb_info结构体
(3)注册fb_info
(4)硬件相关操作
注册就是把结构体fb_info告诉fbmen.c,应用程序open、read、write的时候,首先调用fbmen的open、read、write。这个ope、nread、write里面调用到注册的fb_info里面提供的函数,或者根据这个结构体里面来操作硬件。分层的时候我只需要关注于硬件相关层的内容。
对于分层的字符设备驱动程序怎么写:
内核提供了上层的程序,我们只需要
(1) 分配某个结构体
(2) 设置这个结构体
(3) 注册这个结构体
(4) 硬件相关操作
结构体具体驱动具体分析,对于lcd是fb_info
2、V4L2框架分析: video for linux version 2
猜测:
也分为至少两层
核心层一样,系统写好的,有一个file_operation结构体,和提供给下层的注册方法。
搜索:grep"Found UVC" * -nR
drivers/media/video/uvc/uvc_driver.c:
media/video/uvc/uvc_driver.c:1848: uvc_printk(KERN_INFO, "Found UVC%u.%02x device %s (%04x:%04x)\n"
2.1、uvc_driver.c代码分析
(1)对于USB类驱动程序,会构造一个usb_driver结构体
static int __init uvc_init(void){int ret;uvc_debugfs_init();ret = usb_register(&uvc_driver.driver);if (ret < 0) {uvc_debugfs_cleanup();return ret;}printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");return 0;}
struct uvc_driver uvc_driver = {.driver = {.name= "uvcvideo",.probe= uvc_probe,.disconnect= uvc_disconnect,.suspend= uvc_suspend,.resume= uvc_resume,.reset_resume= uvc_reset_resume,.id_table= uvc_ids,.supports_autosuspend = 1,},};
结构体里有一个uvc_probe函数,当发现uvc_ids支持的设备时候时会调用uvc_probe函数,在uvc_probe里面一定有分配注册某个结构体。
看看Probe函数
uvc_probe{v4l2_device_registeruvc_register_chains{uvc_register_terms{uvc_register_video{struct video_device *vdev;vdev = video_device_alloc();vdev->fops = &uvc_fops;//核心层提供的函数V4l2-dev.c (linux-3.4.2\drivers\media\video):ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); }{vdev->cdev = cdev_alloc();vdev->cdev->ops = &v4l2_fops;cdev_add}}}}
应用程序openread 最终调用驱动的open read(v4l2里面file_operation)file_operation里面的函数会调用到videv——device里面的方法和属性
2.2、分析Vivi.c虚拟视频驱动-硬件驱动部分 (linux-3.4.2\drivers\media\video)
1.分配video_device
2.设置
3.注册:video_register_device(注册的思路就是将结构体存入数组,引用程序open的时候从数组中以次设备号为索引取出,并调用里面的open函数)
(1)分析Vivi.c代码
vivi_init{vivi_create_instance{ // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数v4l2_device_register video_device_alloc//分配*vfd = vivi_template;//设置{static struct video_device vivi_template = {.name= "vivi",.fops = &vivi_fops,.ioctl_ops = &vivi_ioctl_ops,.release= video_device_release,.tvnorms = V4L2_STD_525_60,.current_norm = V4L2_STD_NTSC_M,};}video_register_device//注册{__video_register_device{switch (type) {case VFL_TYPE_GRABBER:name_base = "video";break;case VFL_TYPE_VBI:name_base = "vbi";break;case VFL_TYPE_RADIO:name_base = "radio";break;case VFL_TYPE_SUBDEV:name_base = "v4l-subdev";vdev->cdev = cdev_alloc();vdev->cdev->ops = &v4l2_fops;cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);video_device[vdev->minor] = vdev;}}}}
注册的结果是更新数组,将 video_device 放入数组中video_device[vdev->minor] = vdev; 以此设备号为下标存起来。
(2)分析vivi.c的open,read,write,ioctl过程
1. open
app: open("/dev/video0",....)
---------------------------------------------------
drv: v4l2_fops.v4l2_open
vdev = video_devdata(filp); // 根据次设备号从数组video_device中得到video_device
ret = vdev->fops->open(filp);
vivi_ioctl_ops.open
v4l2_fh_open
struct video_device *video_devdata(struct file *file)
{
return video_device[iminor(file->f_path.dentry->d_inode)];
}
2. read
app: read ....
---------------------------------------------------
drv: v4l2_fops.v4l2_read
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->read(filp, buf, sz, off);
3. ioctl
app: ioctl
----------------------------------------------------
drv: v4l2_fops.unlocked_ioctl
v4l2_ioctl
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl);
__video_do_ioctl
struct video_device *vfd = video_devdata(file);
根据APP传入的cmd来获得、设置"某些属性"
(3)怎么写V4L2驱动
2.3、xawtv源码分析(应用程序如和调用驱动,实现视频播放)
(1)xawtv的几大函数:
1. v4l2_open
2. v4l2_read_attr/v4l2_write_attr
3. v4l2_start_streaming
4. v4l2_nextframe/v4l2_waiton
(2)根据虚拟驱动vivi的使用过程彻底分析摄像头驱动
// 1~7都是在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 // 把缓冲区放入队列
}
(3)摄像头驱动程序必需的11个ioctl:(vivi.c提供iocrl函数,会被应用程序所调用)
// 表示它是一个摄像头设备
.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,
未完待续。。。。。。。
- linux应用项目(二)摄像头(1)V4L2框架分析
- linux应用项目(二)摄像头(2)从零写一个V4L2虚拟摄像头驱动之详细分析
- 摄像头驱动笔记1---V4L2框架分析
- V4L2(二)虚拟摄像头驱动vivi深入分析
- 韦东山项目视频之摄像头驱动1 V4L2框架分析
- 摄像头驱动(二)————V4L2 虚拟摄像头驱动vivi深入分析
- UVC网络摄像头(二) V4L2
- 【原创】IP摄像头技术纵览(二)---linux 视频开发接口V4L2概述
- linux之V4L2摄像头应用流程
- linux学习之 V4L2的摄像头应用
- linux之V4L2摄像头应用流程
- linux之V4L2摄像头应用流程
- linux之V4L2摄像头应用流程
- linux之V4L2摄像头应用流程
- [完结]Linux内核中的V4L2核心框架分析(V4L2 framework,video for linux 2,linux视频子系统)
- Linux内核中的V4L2核心框架分析(V4L2 framework,video for linux 2,linux视频子系统)
- Linux内核中的V4L2核心框架分析(V4L2 framework,video for linux 2,linux视频子系统) .
- V4L2摄像头应用流程
- 一、PCI配置空间简介
- svn 过滤指定提交者
- 内联函数
- latex 参考文献 natbib, biblatex 引用网页,超链接
- Android LayoutInflater的inflate方法中attachToRoot的作用
- linux应用项目(二)摄像头(1)V4L2框架分析
- MQTT入门篇
- c#上传图片到服务器
- vsftpd
- k-means中的邻近度函数
- 8种基本数据类型
- android 高级之旅 (七) CoordinatorLayout 的基本用法
- c++顺序容器原理
- 二维数组