Chinaunix首页 | 论坛 | 博客
  • 博客访问: 712137
  • 博文数量: 165
  • 博客积分: 8218
  • 博客等级: 中将
  • 技术积分: 1749
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-07 19:48
文章分类

全部博文(165)

文章存档

2014年(4)

2011年(3)

2010年(6)

2009年(43)

2008年(109)

分类: LINUX

2008-10-05 21:01:24




关于SPCAVIEW获取JPEG图片实现方法的分析
USB Camera驱动的配套软件Spcaview能够通过调用接口函数,实现自动定时获取一帧图片,并保存在指定目录中,其图片保存格式为标准JPEG.
具体执行操作命令:(shell命令行形式)
#./spcaview –p x
注: P 为保存图片参数,x 为几秒钟自动保存一张
在Spcaview的实现原代码中,关于图片获取功能实现在main函数的spcagrab函数中,其功能主要负责一边显示图象,一边抓取图片,作为函数 调用,由程式员实现。为了实现同步操作,Spcaview采用了创建线程的形式,通过pthread_create创建子线程,负责读取一帧图片,解码, 并保存为JPEG格式。
其具体函数形式为:
int spcaGrab (……..) {
    ………….
/* laugth the picture thread */
mypict.data = malloc(frame_size);   //分配内存空间,以保存一帧的数据
mypict.sizeIn = frame_size;
mypict.width = image_width;
mypict.height = image_height;
mypict.formatIn = format;
pthread_mutex_init(&mypict.mutex, NULL);
pthread_cond_init(&mypict.cond, NULL);
wstatus = pthread_create (&waitandshoot_id, NULL, (void *) waitandshoot, &mypict);
                              //waitandshoot为线程注册函数,当线程被执行的时候,即执行waitandshoot中的代码。
   …………
                 }
由上面的关键代码pthread_create可知,&mypict传递了关键数据结构给子线程,且mypict结构中的data而子线程依据mypict.data中数据信息,处理图像数据,并解码保存图片。
当线程被建立以后,mypict.data所指向的内存空间还为空,能够推断,后面一定会有给他加载数据的操作,其具体的操作为:
memcpy (mypict.data,tmp,frame_size);
tmp为一字符指针,指向主程式所取得的数据信息:
unsigned char *tmp;(定义在main函数开始)
主程式中获得一帧数据的方法和实现:
进程要通过驱动读取Camera数据,能够通过两种方式,第一种是通过内存映射,使用mmap系统调用,将缓冲区直接影射到进程自己的用户空间,对frame buffer进行直接操作,获取帧数据。第二种是通过read系统调用,只读取其中一帧大小的数据,并直接对其操作,而不进行内存映射。
在Spcaview的代码实现中,这两种方法都有实现,由if语句进行选择,程式按照参数grabMethod的值进行不同操作,才用不同方法读取帧数据。
其具体的代码如下:
Mmap方法的实现代码:     
                 //mmap实现内存映射,将buffer从内核空间映射到进程空间
pFramebuffer =(unsigned char *) mmap (0, videombuf.size,
                            PROT_READ | PROT_WRITE,
                            MAP_SHARED, fd, 0);
if (grabMethod) {
        memcpy (tmp,
                pFramebuffer +
                videombuf.offsets[vmmap.frame],
                frame_size);
                       //将具体的一帧数据拷贝到tmp,传递给子线程,videombuf.offsets[vammp.frame]为frame.buffer中具体一帧的偏移地址。

    vmmap.frame = (vmmap.frame + 1) % videombuf.frames;
                         //通过求余运算,循环取帧。
        
            } else {
Read方法的实现代码:
                /* read method */
                len = read (fd, tmp, frame_size);
                                      //直接读取一帧数据,最为简洁
            }
以上两种方法,都能简洁的获取一帧的数据,并获得很好的效果,是抓图功能的低层实现,均调用的的是Linux用户C库的函数,而没有使用其他三方库的支持。再往下,即是内核通过file_operation结构调用驱动程式实现的向上接口。
阅读(1037) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~