V4L2驱动的移植与应用(一)

摘要:
如果要基于某个硬件来实现V4L2的接口,那这些函数就需要调用硬件的驱动去实现。

V4L2(video for linux) 可以支持多种设备,它可以有以下5种接口:

1、视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.下面也是着重讲解这种应用;

2、视频输出接口(video output interface):可以驱动计算机的外围视频图像设备——像可以输出电视信号格式的设备;

3、直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU;

4、视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号;

5、收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流;

V4L2驱动的主要功能是使程序有发现设备的能力和操作设备.它主要是用过一系列的回调函数来实现这些功能.像设置高频头的频率,帧频,视频压缩格式和图像像参数等等.

一、V4L2的移植

V4L2提供了三种不同的API来传输外围设备和用户空间的数据。下面就vivi(drivers/media/video/vivi.c)来讲解一个V4L2驱动的编写。注意它是一个虚拟的设备驱动,没有与实际的硬件打交道。
1、分析几个重要数据结构:
vivi.c包含头文件v4l2-device.h和v4l2-ioctl.h,其中v4l2-device.h中包含了v4l2-subdev.h,v4l2-subdev.h中又包含了v4l2-common.h,v4l2-common.h中包含了v4l2-dev.h。

在v4l2-dev.h中定义了结构体video_device和v4l2_file_operations;

在v4l2-ioctl.h中定义了结构体v4l2_ioctl_ops;

在v4l2-device.h中定义了结构体v4l2_device;

1) vivi_fops

static const struct v4l2_file_operations vivi_fops = {

.owner = THIS_MODULE,

.open = vivi_open,

.release = vivi_close,

.read = vivi_read,

.poll = vivi_poll,

.ioctl = video_ioctl2, /* V4L2 ioctl handler */

.mmap = vivi_mmap,

};

2) vivi_ioctl_ops

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_queryctrl = vidioc_queryctrl,

.vidioc_g_ctrl = vidioc_g_ctrl,

.vidioc_s_ctrl = vidioc_s_ctrl,

.vidioc_streamon = vidioc_streamon,

.vidioc_streamoff = vidioc_streamoff,

#ifdef CONFIG_VIDEO_V4L1_COMPAT

.vidiocgmbuf = vidiocgmbuf,

#endif

};

3) vivi_template

static struct video_device vivi_template = {

.name = "vivi",

.fops = &vivi_fops,

.ioctl_ops = &vivi_ioctl_ops,

.minor = -1,

.release = video_device_release,

.tvnorms = V4L2_STD_525_60,

.current_norm = V4L2_STD_NTSC_M,

};

其中函数vivi_xxx和vidioc_xxx都是在vivi.c中实现的。如果要基于某个硬件来实现V4L2的接口,那这些函数就需要调用硬件的驱动去实现。

4) vivi_dev
structvivi_dev {
structlist_head vivi_devlist; //内核双向链表,在内核数据结构里有描述
structsemaphore lock; //信号量,防止竞态访问
intusers; //用户数量计数
/*various device info */
unsignedint resources;
structvideo_devicevideo_dev; //这个成员是这个结构的核心,用面向对象的话来说就是基类
structvivi_dmaqueue vidq; //DMA队列
/*Several counters */
inth,m,s,us,jiffies; //定时器定义
char timestr[13]; //其它一些资源变量.
};
像这样变义的结构在Linux C 中很普遍,这也是利用C来实现面向对象编程的强大方法。建立这个结构对象之后,所有的操作都是基于这个结构,或者这个结构派生出的来的其它结构。
5) vivi_fh
structvivi_fh {
structvivi_dev*dev;
/*video capture */
structvivi_fmt*fmt;
unsignedint width,height;
structvideobuf_queuevb_vidq;
enumv4l2_buf_type type;
};
这个结构即是vivi_dev结构的更深层次封装,基于那个结构加入了更多的描述信息,如视频制式、视频画面大小、视频缓冲队列等等。在open的时候,会把这个结构赋给file结构中的private_data域。在释放设备时注销.其它的像ioctl,mmap,read,write等等都会用到这个结构,其实整个模块的编写的cdev差不多。只是视频设备的基类是video_device,而字符设备的基类是cdev而已。
2、数据传输方式:
在设备与应用程序之间有三种数据传输方式:
1)read与write这种方式,它像其它设备驱动一样,但是这种方式很慢,对于数据视频流不能满足其要求;

2)直接的内存访问,可以通过其映射方式来传输(IO数据流,交换指向缓冲区指针的方法);这是视频设备通常用的方法,采用mmap()的方法,即有内核空间里开辟内存,再在程序里把这部分的内存映射到程序空间。如果有设备内存,即直接映射到设备的内核,这种性能更高。
3)异步IO口访问,但是这种方法在V4L2模块中还没有实现。(重要:需要确认)
vivi中的mmap是利用第二种方法来实现的,这也是视频设备常用的方法:
staticint
vivi_mmap(structfile *file, structvm_area_struct * vma)
{
structvivi_fh *fh = file->private_data;
intret;
dprintk (1,"mmap called, vma=0x%08lx/n",(unsignedlong)vma);
ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d/n",
(unsignedlong)vma->vm_start,
(unsignedlong)vma->vm_end-(unsignedlong)vma->vm_start,
ret);
returnret;
}
videobuf_mmap_mapper(&fh->vb_vidq, vma); 这个核心函数把设备的I/O内存或者设备内存映射到系统为它开辟的虚拟内存。
3、操控设备的实现: ioctl
staticintvivi_ioctl(structinode *inode, structfile *file, unsignedintcmd, unsignedlongarg)
{
returnvideo_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
}
vivi_do_ioctl 这个函数里调用一些命令来设备V4L2模块中的一些结构参数来改变或者获取设备的参数

免责声明:文章转载自《V4L2驱动的移植与应用(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于微服务(四)安装MySQL出现”无法启动此程序,因为计算机中丢失VCRUNTIME140_1.dll。尝试重新安装该程序以解决此问题。“下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

v4l2视频采集摄像头

v4l2 --是Linux内核中关于视频设备的内核驱动框架,为上层访问底层的视频设备提供了统一的接口。/dev/vidioX 1.打开设备文件 fd=open("/dev/video3",O_RDWR); /dev/video3:视频设备文件名 O_RDWR:可读可写 fd: open成功反返回文件描述符 jpeg yuv2.查询设备支持哪种格式 str...

全球最大的3D数据集公开了!标记好的10800张全景图

Middlebury数据集 http://vision.middlebury.edu/stereo/data/ KITTI数据集简介与使用https://blog.csdn.net/solomon1558/article/details/70173223 http://www.dataguru.cn/article-12197-1.html 摘要: 一路走...

h5 web vlc 播放rtsp流

1.rtsp串流转换为h5可播放的ogg格式 cmd进入vlc目录执行以下命令 红色部分换成你的rtsp地址 vlc -I dummy -vvv "rtsp://192.168.226.1/stream12" --sout="#transcode{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,sample...

将文件映射到内存

mmap的好处: 和read、write系统调用相比不会产生无关的副本; 如果不出错就不会有系统调用、操作环境切换等开销; 不再需要lseek调用。 mmap的坏处: 内存映射总是PAGESIZE的整数倍,会浪费一定的内存; 如果要映射的内容非常大的时候可能找不到连续的线性地址空间; 创建并维护内核相关数据结构,这部分可能抵消双重副本节省下的开销...

HDFS缓存机制

前言 缓存,英文单词译为Cache,缓存可以帮助我们干很多事,当然最直接的体会就是可以减少不必要的数据请求和操作.同样在HDFS中,也存在着一套完整的缓存机制,但可能使用了解此机制的人并不多,因为这个配置项平时大家比较少用而且HDFS中默认是关闭此功能的.至于是哪个配置项呢,在后面的描述中将会给出详细的分析. HDFS缓存疑问点 为什么在这里会抛出这样...

FFmpeg封装格式处理

本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10506636.html FFmpeg封装格式处理相关内容分为如下几篇文章:[1]. FFmpeg封装格式处理-简介[2]. FFmpeg封装格式处理-解复用例程[3]. FFmpeg封装格式处理-复用例程[4]. FFmpeg封装格式处理-转封装...