基于嵌入式Linux与S3C2410平台的视频采集

发布者:gamma14最新更新时间:2012-10-18 来源: 21IC 关键字:Linux  S3C2410  视频采集 手机看文章 扫描二维码
随时随地手机看文章

随着多媒体技术、网络技术的迅猛发展和后PC机时代的到来,利用嵌入式系统实现远程视频监控、可视电话和视频会议等应用已成为可能。为了实现这些应用,实时获得视频数据是一个重要环节。针对这一点,本文在基于嵌入式Linux系统平台上,利用Video4Linux内核应用编程接口函数,实现了单帧图像和视频连续帧的采集,并保存成文件的形式供进一步视频处理和网络传输用。

1 系统平台上的硬件系统

本文使用的系统平台硬件功能框图如图1所示。该平台采用Samsung公司的处理器S3C2410。该处理器内部集成了ARM公司ARM920T处理器核的32位微控制器,资源丰富,带独立的16KB的指令Cache和16KB数据Cache、LCD控制器、RAM控制器、NAND闪存控制器、3路UART、4路DMA、4路带PWM的Timer、并行I/O口、8路10位ADC、Touch Screen接口、I2C接口、I2S接口、2个USB接口控制器、2路SPI,主频最高可达203MHz。在处理器丰富资源的基础上,还进行了相关的配置和扩展,平台配置了16MB 16位的Flash和64MB 32位的SDRAM。通过以太网控制器芯片DM9000E扩展了一个网口,另外引出了一个HOST USB接口。通过在USB接口上外接一个带USB口的摄像头,将采集到的视频图像数据放入输入缓冲区中。然后,或者保存成文件的形式,或者运行移植到平台上的图像处理程序,对缓冲的图像数据直接进行相关处理,再保存并打成UDP包。最后,通过网络接口将图像发送到Internet上。本文只讨论其中视频采集部分的具体实现。

2 系统平台中的软件系统

2.1 Linux与嵌入式系统

Linux具有内核小,效率高,源代码开放,内核直接提供网络支持等优点。但嵌入式系统的硬件资源毕竟有限,因此不能直接把Linux作为操作系统,需要针对具体的应用通过配置内核、裁减shell和嵌入式C库对系统定制,使整个系统能够存放到容量较小的Flash中。Linux的动态模块加载,使Linux的裁减极为方便 ,高度模块化的部件使添加非常容易。正因为Linux的上述优点,在本文实现的平台上,使用的操作系统是对Linux进行了定制的armlinux。它启用了MMU(内存管理单元),是针对支持MMU的处理器设计的。

a.JPG

2.2 开发环境的建立

绝大多数Linux的软件开发都以native方式进行,即本机开发、调试,本机运行的方式。这种方式通常不适于嵌入式系统的软件开发,因为对于嵌入式系统的开发,它没有足够的资源在本机(即嵌入式系统平台)运行开发工具和调试工具。通常的嵌入式系统软件开发采用交叉编译调试的方式。交叉编译调试环境建立在宿主机(即图1所示通过串口连接的宿主机PC)上,对应的开发板叫做目标板(即嵌入式ARM2410系统)。

通常宿主机和目标板上的处理器不同,宿主机通常为Intel处理器,而目标板如图1所示为SAMSUNG S3C2410,所以程序需要使用针对处理器特点的编译器才能生成在相应平台上可运行的代码。GNU编译器提供这样的功能,在编译时,可以选择开发所需的宿主机和目标机,从而建立开发环境。在进行嵌入式开发前的第一步工作就是把一台PC机作为宿主机开发机,并在其上安装指定的操作系统。对于嵌入式Linux,宿主机PC上应安装Linux系统。之后,在宿主机上建立交叉编译调试的开发环境,开发环境的具体建立这里不细谈。本文采用移植性很强的C语言在宿主机上编写视频采集程序,再利用交叉编译调试工具编译链接生成可执行代码,最后向目标平台移植。

3 视频采集的具体实现

上面提到系统平台上运行的是armlinux。在启动后,启用了MMU,系统进入保护模式,所以应用程序就不能直接读写外设的I/O区域(包括I/O端口和I/O内存),这时一般就要借助于该外设的驱动来进入内核完成这个工作。本系统中的视频采集分两步实现:一是为USB口数码摄像头在内核中写入驱动,二是要再写入上层应用程序获取视频数据。本文着重讨论后一步。

3.1 USB口数码摄像头的驱动实现

在Linux下,设备驱动程序可以看成Linux内核与外部设备之间的接口。设备驱动程序向应用程序屏蔽了硬件实现了的细节,使得应用程序可以像操作普通文件一样来操作外部设备,可以使用和操作文件中相同的、标准的系统调用接口函数来完成对硬件设备的打开、关闭、读写和I/O控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。本系统平台使用的嵌入式armLinux系统在内核主要功能上与Linux操作系统没本质区别,所以驱动程序要实现的任务也一样,只要编译时使用的编译器、部分头文件和库文件等要涉及到具体处理器体系结构,这些都可以在Makefile文件中具体指定。

    Video4Linux(简V4L)是Linux中关于视频设备的内核驱动,它为针对视频设备的应用程序编程提供一系列接口函数,这些视频设备包括现今市场上流行的TV卡、视频捕捉卡和USB摄像头等。对于USB口摄像头,其驱动程序中需要提供基本的I/O操作接口函数open、read、write、close的实现。对中断的处理实现,内存映射功能以及对I/O通道的控制接口函数ioct1的实现等,并把它们定义在struct file_operations中。这样当应用程序对设备文件进行诸如open、close、read、write等系统调用操作时,Linux内核将通过file_operations结构访问驱动程序提供的函数。例如,当应用程序对设备文件执行读操作时,内核将调用file_operations结构中的read函数。在系统平台上对USB口数码摄像头驱动,首先把USB控制器驱动模块静态编译进内核,使平台中支持USB接口,再在需要使用摄像头采集时,使用insmode动态加载其驱动模块,这样摄像头就可正常工作了,接着进行了下一步对视频流的采集编程。

3.2 Video4Linux下的摄像头采集编程

在USB摄像头被驱动后,只需要再编写一个对视频流采集的应用程序就可以了。根据嵌入式系统开发特征,先在宿主机上编写应用程序,再使用交叉编译器进行编译链接,生成在目标平台的可执行文件。宿主机与目标板通信采用打印终端的方式进行交叉调试,成功后移植到目标平台。本文编写采集程序是在安装Linux操作系统的宿主机PC机上进行的,下面是具体论述。

(1)程序中定义的数据结构

struct voide_capability grab_cap;

struct voide_picture grab_pic;

struct voide_mmap grab_buf;

struct voide_mbuf grab_vm;

这些数据结构都是由Video4Linux支持的,它们的用途如下:

*video_capability包含摄像头的基本信息,例如设备名称、支持的最大最小分辨率、信号源信息等,分别对应着结构体中成员变量name[32]、maxwidth、maxheight、minwidth、minheight、channels(信号源个数)、type等;

*voide_picture包含设备采集图像的各种属性,如brightness(亮度)、hue(色调)、contrast(对比度)、whiteness(色度)、depth(深度)等;[page]

*video_mmap用于内存映射;

*voido_mbuf利用mmap进行映射的帧信息,实际上是输入到摄像头存储器缓冲中的帧信息,包括size(帧的大小)、frames(最多支持的帧数)、offsets(每帧相对基址的偏移)。

程序中用到的主要系统调用函数有: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系统调用函数操作设备文件,从而达到与设备通信交互的目的。当然,在设备驱动中要提供对这些函数的相应支持。这里说明一下ioctl(int fd,int cmd,…)函数,它在用户程序中用来控制I/O通道,其中,fd代表设备文件描述符,cmd代表用户程序对设备的控制命令,省略号一般是一个表示类型长度的参数,也可没有。

(2)采集程序实现过程

首先打开视频设备,摄像头在系统中对应的设备文件为/dev/video0,采用系统调用函数grab_fd=open("/dev/video0",O_RDWR),grab_fd是设备打开后返回的文件描述符(打开错误返回-1),以后的系统调用函数就可使用它来对设备文件进行操作了。接着,利用ioct1(grab_fd,VIDIOCGCAP,&grab_cap)函数读取struct video_capability中有关摄像头的信息。该函数成功返回后,这些信息从内核空间拷贝到用户程序空间grab_cap各成员分量中,使用printf函数就可得到各成员分量信息,例如printf("maxheight=%d",grab_fd.maxheight)获得最大垂直分辨率的大小。不规则用ioct1(grab_fd,VIDIOCGPICT,&grab_pic)函数读取摄像头缓冲中voideo_picture信息。在用户空间程序中可以改变这些信息,具体方法为先给分量赋新值,再调用VIDIOCSPICT ioct1函数,例如:

grab_fd.depth=3;

if(ioct1(grab_fd,VIDIOCSPICT,&grab_pic)<0)

{perror("VIDIOCSPICT");return -1;};

完成以上初始化设备工作后,就可以对视频图像截取了,有两种方法:一种是read()直接读取;另外一种mmap()内存映射。Read()通过内核缓冲区来读取数据;而mmap()通过把设备文件映射到内存中,绕过了内核缓冲区,最快的磁盘访问往往还是慢于最慢的内存访问,所以mmap()方式加速了I/O访问。另外,mmap()系统调用使得进程之间通过映射同一文件实现共享内存,各进程可以像访问普通内存一样对文件进行访问,访问时只需要使用指针而不用调用文件操作函数。因为mmap()的以上优点,所以在程序实现中采用了内存映射方式,即mmap()方式。

利用mmap()方式视频裁取具体进行操作如下。

①先使用ioct1(grab_fd,VIDIOCGMBUF,&grab_vm)函数获得摄像头存储缓冲区的帧信息,之后修改voideo_mmap中的设置,例如重新设置图像帧的垂直及水平分辨率、彩色显示格式。可利用如下语句

grab_buf.height=240;

grab_buf.width=320;

grab_buf.format=VIDEO_PALETTE_RGB24;

②接着把摄像头对应的设备文件映射到内存区,具体使用grab_data=(unsigned char*)mmap(0,grab_vm.size,PROT_READ|PROT_WRITE,MAP_SHARED,grad_fd,0)操作。这样设备文件的内容就映射到内存区,该映射内容区可读可写并且不同进程间可共享。该函数成功时返回映像内存区的指针,挫败时返回值为-1。

下面对单帧采集和连续帧采集进行说明:

*单帧采集。在上面获取的摄像头存储缓冲区帧信息中,最多可支持的帧数(frames的值)一般为两帧。对于单帧采集只需设置grab_buf.frame=0,即采集其中的第一帧,使用ioctl(grab_fd,VIDIOCMCAPTURE,&grab_buf)函数,若调用成功,则激活设备真正开始一帧图像的截取,是非阻塞的。接着使用ioct1(grab_fd,VIDIOCSYNC,&frame)函数判断该帧图像是否截取完毕,成功返回表示截取完毕,之后就可把图像数据保存成文件的形式。

*连续帧采集。在单帧的基础上,利用grab_fd.frames值确定采集完毕摄像头帧缓冲区帧数据进行循环的次数。在循环语句中,也是使用VIDIOCMCCAPTURE ioct1和VIDIOCSYNC ioctl函数完成每帧截取,但要给采集到的每帧图像赋地址,利用语句buf=grab_data+grab_vm.offsets[frame],然后保存文件的形式。若要继续采集可再加一个外循环,在外循环语句只要给原来的内循环再赋frame=0即可。

4 小结

笔者最后在宿主机PC上使用交叉编译器编译链接连续帧采集程序(以双帧采集为例并保存成bmp文件文件形式)使之生成可执行代码,并完成了向目标平台的移植。为了进一步观察采集的图像效果,笔者在目标平台带网络支持的基础上,编写了一个简单的网络通信程序,把采集到并保存为bmp的图像文件通过网络传输到PC机上进行显示,把采集到并保存为bmp的图像文件通过网络传输到PC机上进行显示,通过对效果的分析,再回到采集程序中重新设置video_picture中的信息,如亮度、对比度等和voide_mmap中的分辨率,重新移植以达到最好效果为准。

在图1中的嵌入式系统平台上,应用本文所述方法完成视频采集工作,再加上相关的视频处理并接入网络,就构成了一个智能终端设备,可用于工厂、银行及小区等场合全天候的智能监控,具有广阔的市场和应用前景。

参考文献:

[1]. ARM920T datasheet http://www.dzsc.com/datasheet/ARM920T_139814.html.
[2]. DM9000E datasheet http://www.dzsc.com/datasheet/DM9000E_264482.html.
[3]. frame datasheet http://www.dzsc.com/datasheet/frame_2528858.html.

关键字:Linux  S3C2410  视频采集 引用地址:基于嵌入式Linux与S3C2410平台的视频采集

上一篇:基于ARM与μClinux的RTU设计
下一篇:用S3C2410实现三导联远程心电监护系统

推荐阅读最新更新时间:2024-03-16 13:10

基于嵌入式Linux图形用户接口的实现
  随着Internet与网络的迅速发展 并向家庭领域不断扩展,使消费电子、计算机、通信(3C)一体化趋势日趋明显,嵌入式系统再度成为研究与应用的热点。嵌入式实时Linux操作系统以价格低廉、功能强大又易于移植而正在被广泛采用,成为新兴的力量,如今随着WAP手机、PDA、机顶盒、及DVD/VCD播放机已经迅速普及,用户对这些手持式设备的GUI提出了更高的要求,希望能看到像PC机才拥有的华丽美观的GUI。GUI已经成为了人与机器沟通的桥梁,嵌入式系统对GUI的需求越来越高,而这一切均要求有一个轻型、占用资源少、高性能、高可靠、可配置及美观的GUI支持。   1 Java的图形界面工具   Java技术对于服务器,个人电脑和嵌入式系
[嵌入式]
内核(2.6.14) + 根文件系统 +Qtopia Core 4移植 for S3C2410
TARGET CPU: S3C2410X SDRAM: HY57V561620(32MB) × 2 FLASH: K9F1208(64MB) NET: CS8900 HOST Linux Realse Version: Fecora Core 6 CrossCompiler: gcc-4.1.1/arm-linux-gcc-3.4.1 一、内核移植(2.6.14) 1 修改linux2.6.14下面的makefile文件 找到ARCH和CROSS_COMPILE,修改 ARCH ?= arm CROSS_COMPILE ?= /usr/local/arm/3.4.1/bin/arm-linux- (此处为你
[单片机]
基于嵌入式LINUX的车载导航系统设计
1 引言 车载电子设备在技术水平上的不断提高已经成为现代汽车发展的重要标志之一,而车载导航设备是其中重要组成部分。它要将数据通讯系统,影音娱乐系统,定位系统,电子控制系统实时显示出来,让用户得到充分的驾驶信息,以ARM 及嵌入式操作系统为技术核心,为车辆驾驶者提供安全行驶所必需的路况、地理信息的车载导航系统目前正在全世界得到越来越广泛的应用,大大提高了用户驾驶体验与车辆运行的安全性。 但目前市场上的车载导航系统多使用 WinCE 作为操作系统,不仅软件使用价格昂贵,而且对硬件要求较高,运行速度偏慢。本文提出并设计了一种基于GPS 和GPRS,使用嵌入式32 位处理器和嵌入式Linux 的车载导航系统。该系统采用S3C2440A
[单片机]
基于嵌入式<font color='red'>LINUX</font>的车载导航系统设计
基于Linux的kfifo移植到STM32(支持os的互斥访问)
关于kfifo kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现;它提供一个无边界的字节流服务,最重要的一点是,它使用并行无锁编程技术,即当它用于只有一个入队线程和一个出队线程的场情时,两个线程可以并发操作,而不需要任何加锁行为,就可以保证kfifo的线程安全。 具体什么是环形缓冲区,请看我以前的文章 说明 关于kfifo的相关概念我不会介绍,有兴趣可以看他的相关文档,我只将其实现过程移植重写,移植到适用stm32开发板上,并且按照我个人习惯重新命名,RingBuff- 意为环形缓冲区 RingBuff_t 环形缓冲区的结构体成员变量,具体含义看注释。 buff
[单片机]
tiny6410 Linux启动信息
NAND read: device 0 offset 0x400000, size 0x500000 //0x500000是2G? .....Boot with zImage Starting kernel ... Uncompressing Linux... done, booting the kernel. Initializing cgroup subsys cpu Linux version 2.6.38-FriendlyARM (root@jensen) (gcc version 4.5.1 (ctng-1.8.1-FA) ) #13 PREEMPT Mon Jul 18 17:07:42 HKT 20
[单片机]
基于S3C2440的嵌入式Linux驱动——SPI子系统解读(三)
该系列文章将分为四个部分: 第一部分,将对SPI子系统整体进行描述,同时给出SPI的相关数据结构,最后描述SPI总线的注册。 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一) 第二部分,该文将对SPI的主控制器(master)驱动进行描述。 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二) 第三部分,即本篇文章,该文将对SPI设备驱动,也称protocol 驱动,进行讲解。 第四部分,通过SPI设备驱动留给用户层的API,我们将从上到下描述数据是如何通过SPI的protocol 驱动,由bitbang中转,最后由master驱动将数据传输出 去。 基于S3C
[单片机]
Linux2.6.32移植到MINI2440(4)移植+分析DM9000网卡驱动
开发环境: 主机:fedora 14 虚拟机:vmware workstation 10 交叉编译工具:arm-linux-gcc 4.3.2 开发板:mini2440(2m nor ,64m sdram,256m nand) 内核版本:linux2.6.32.2 上一篇帖子的uImage可以起yaffs2文件系统,但是起不了nfs,我的yaffs2使用nfs打包来的,换一个内核可以起,bootargs也没有问题,可能是这里网卡没有移植造成的,移植结束之后再看能不能起,因为nfs对后面做驱动开发优势比较大,方便调试看现象,不需要每次都烧写进去,所以还是需要能够起nfs的。DM9000内核
[单片机]
<font color='red'>Linux</font>2.6.32移植到MINI2440(4)移植+分析DM9000网卡驱动
[linux kernel] 内核下ksz9031驱动调试踩过的坑
系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 -linux4sam_6.0 板子型号:at91sama5d3x-xplained MCU型号:sama5d36 内核中调试驱动,和uboot中会有些区别,因为内核启动过程是顺序启动的,硬件上电后,外部的器件要快速做好准备工作,内核代码初始化到这个器件如果器件没有完成上电复位,很可能会驱动失败,需要硬件和软件时序同步,这是非常重要的一点。 【Datasheet】PHY KSZ9031千兆网络芯片解读 U-bo
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved