光电学院电子信息工程专业“嵌入式信息系统课程设计”任务书第一章基础知识一、编程原理如何对各种音视频设备进行操作是在Linux上进行音频编程的关键,通过内核提供的一组系统调用,应用程序能够访问驱动程序提供的各种音视频设备接口,这是在Linux 下进行音视频编程最简单也是最直接的方法。
在Linux下,设备驱动程序可以看成Linux 内核与外部设备之间的接口。
设备驱动程序向应用程序屏蔽了硬件实现了的细节,使得应用程序可以像操作普通文件一样来操作外部设备,可以使用和操作文件中相同的、标准的系统调用接口函数来完成对硬件设备的打开、关闭、读写和I/O控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。
本系统平台使用的嵌入式Linux系统在内核主要功能上与Linux操作系统没本质区别,所以驱动程序要实现的任务也一样,只要编译时使用的编译器、部分头文件和库文件等要涉及到具体处理器体系结构,这些都可以在Makefile文件中具体指定。
Video4Linux(简V4L)是Linux中关于视频设备的内核驱动,它为针对视频设备的应用程序编程提供一系列接口函数,这些视频设备包括现今市场上流行的TV卡、视频捕捉卡和USB摄像头等。
对于电视卡、摄像头,其驱动程序中需要提供基本的I/O操作接口函数open、read、write、close的实现。
对中断的处理实现,内存映射功能以及对I/O通道的控制接口函数ioctl的实现等,并把它们定义在struct file_operations中。
这样当应用程序对设备文件进行诸如open、close、read、write等系统调用操作时,Linux内核将通过file_operations结构访问驱动程序提供的函数。
例如,当应用程序对设备文件执行读操作时,内核将调用file_operations结构中的read函数。
在系统平台上对摄像头驱动编译进内核后,摄像头就可正常工作了,接着就可以进行了本课题的主要内下一步对视频流的采集编程。
摄像头被驱动后,只需要再编写一个对视频流采集的应用程序就可以了。
根据嵌入式系统开发特征,先在宿主机上编写应用程序,再使用交叉编译器进行编译链接,生成在目标平台的可执行文件。
宿主机与目标板通信采用打印终端的方式进行交叉调试,成功后移植到目标平台。
本设计编写采集程序是在安装Linux操作系统的宿主机PC机上进行的。
Linux 的帧缓冲设备Framebuffer 是在Linux 内核架构版本2.2 以后推出的标准显示设备驱动接口。
采用mmap 系统调用,可以将framebuffer 的显示缓存映射为可连续访问的一段内存储针,进行绘图工作。
而且多个进程可以映射到同一个显示缓冲区。
由于映射操作都是由内核来完成,所以我们基本上不用对Framebuffer 做改动。
Framebuffer 驱动程序的实现分为两个方面:一方面是对LCD 及其相关部分的初始化,包括画在缓冲区的创建和对DMA 通道的设置,我们做的工作主要体现在这方面;另外一方面是对画面缓冲区的读写及控制,具体到代码为read、write、ioctl 等系统调用接口。
至于将画面缓冲区的内容输出到LCD 显示屏上,则由硬件自动完成。
对于软件来说是透明的。
当对于DMA 通道和画面缓冲区设置完成后,DMA 开始正常工作,并将缓冲区中的内容不断发送到LCD 上。
这个过程是基于DMA对于LCD 的不断刷新的。
基于该特性,framebuffer 驱动程序必须将画面缓冲区的存储空间(物理空间)重新映射到一个不加高缓存和写缓存的虚拟地址区间中,这样能才保证应用程序通过mmap将该缓存映射到用户空间后,对于该画面缓存的写操作能够实时的体现在LCD 上。
帧缓冲设备对应的设备文件为/dev/fb0-31,linux 可以支持最多可达32 个帧缓冲设备,/dev/fb0 为当前默认的帧缓冲设备。
帧缓冲设备为标准字符设备,主设备好号为29,次设备号则从0 到31,分别对应/dev/fb0-fb31.对驱动程序的基本概念和基本框架的详细介绍见选题2嵌入式Linux设备驱动程序设计文档。
二、编程接口1、Video4Linux2 编程接口(1)程序中定义的数据结构Østruct video_capability vc;Østruct video_window vw;Østruct video_mbuf vm;Østruct video_channel vch;这些数据结构都是由Video4Linux支持的,它们的用途如下:²video_capability :设备的基本信息(设备名称、支持的最大最小分辨率、信号源信息等)²video_window :关于capture area的信息²video_mbuf :利用mmap进行映射的帧的信息²video_channel: 关于各个信号源的属性(2)系统调用函数程序中用到的主要系统调用函数有:Øopen("/dev/voideo0",int flags)Øclose(fd)Ømmap(void *start,size_t length,int prot,int flags,int fd,off_t offset)Ømunmap(void *start,size_tlength)Øioctl(int fd,int cmd,…)前面提到Linux系统中把设备看成设备文件,在用户空间可以通过标准的I/O系统调用函数操作设备文件,从而达到与设备通信交互的目的。
当然,在设备驱动中要提供对这些函数的相应支持。
打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。
这一步是可选的。
在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理,其中fd代表设备文件描述符,cmd代表用户程序对设备的控制命令,省略号一般是一个表示类型长度的参数,也可没有。
extern int ioctl (int __fd, unsigned long int __request, …) __THROW;__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;__request:具体的命令标志符。
在进行V4L2开发中,一般会用到以下的命令标志符:VIDIOC_REQBUFS:分配内存VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址VIDIOC_QUERYCAP:查询驱动功能VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式VIDIOC_S_FMT:设置当前驱动的频捕获格式VIDIOC_G_FMT:读取当前驱动的频捕获格式VIDIOC_TRY_FMT:验证当前驱动的显示格式VIDIOC_CROPCAP:查询驱动的修剪能力VIDIOC_S_CROP:设置视频信号的边框VIDIOC_G_CROP:读取视频信号的边框VIDIOC_QBUF:把数据从缓存中读取出来VIDIOC_DQBUF:把数据放回缓存队列VIDIOC_STREAMON:开始视频显示函数VIDIOC_STREAMOFF:结束视频显示函数VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。
这些IO调用,有些是必须的,有些是可选择的。
2、采集程序一般操作流程(1) 打开设备文件int fd=open(”/dev/video0″,O_RDWR);摄像头在系统中对应的设备文件一般为/dev/video0(本开发平台上为/dev/video1),采用系统调用函数display_fd = open((const char *)display_dev_name, mode);其中display_dev_name="/dev/video1",display_fd是设备打开后返回的文件描述符(打开错误返回-1),以后的系统调用函数就可使用它来对设备文件进行操作了。
(2) 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。
调动参数VIDIOC_QUERYCAP, 数据结构是struct v4l2_capability 。
调用函数如下:ioctl(display_fd, VIDIOC_QUERYCAP, &capability)(3)选择视频输入,一个视频设备可以有多个视频输入。
VIDIOC_S_INPUT,struct v4l2_input(可以不需要)(4) 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format实例程序如下:(5) 向驱动申请帧缓冲,一般不超过5个。
struct v4l2_requestbuffers实例程序如下:(6) 申请物理内存 ,并将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。
将申请到的帧缓冲全部入队列,以便存放采集到的数据。
VIDIOC_QBUF, struct v4l2_buffer(7)开始视频的采集。
VIDIOC_STREAMON(8)出队列以取得已采集数据的帧缓冲,取得原始采集数据。
VIDIOC_DQBUF, 将缓冲重新入队列尾,这样可以循环采集。
VIDIOC_QBUF(9)停止视频的采集。
VIDIOC_STREAMOFF关闭视频设备。
close(fd);(10)2、LCD(Framebuffer设备)编程接口LCD 的设备文件操作结构如下:在用户空间,对/dev/fb 下设备的操作主要有以下几个步骤:(1)用open 操作打开/dev/fb 设备文件。
open (fb_dev_name, O_RDWR)(2)用ioctl 操作取得当前显示屏的参数,如分辨率,显示颜色数,屏幕大小等,并可计算出显示屏缓冲区的大小。
ioctl(fb, FBIOGET_VSCREENINFO, &fb_vinfo等。
(3)映射MAP 操作,将文件的内容映射到用户空间。
fbdev.fb_mem = mmap (NULL, fbdev.fb_size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0)(4)读取用户映射空间的屏幕缓冲区,进行进行颜色空间的转换,显示。
三、编译运行应用程序程序源代码位于/home/user/Project/driver/video目录下,也可以到ftp://59.64.74.111/10embedded下去下载,详细分别程序结构,理解程序实现原理,采集显示程序用到的图像数据格式是RGB565,掌握图像格式转换方法。