999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

Linux系統(tǒng)下USB攝像頭驅(qū)動(dòng)多緩沖與圖像采集研究

2008-12-31 00:00:00張文涯
電腦知識(shí)與技術(shù) 2008年33期

摘要:通過對(duì)基于中星微ZC0301芯片的USB攝像頭符合Video for Linux和Video for Linux Version Two標(biāo)準(zhǔn)的兩個(gè)驅(qū)動(dòng)程序的分析研究,給出了符合這兩種標(biāo)準(zhǔn)的USB攝像頭驅(qū)動(dòng)程序在圖像數(shù)據(jù)多幀緩沖和圖像采集設(shè)計(jì)中的不同點(diǎn),并實(shí)現(xiàn)了相應(yīng)的圖像采集程序。

關(guān)鍵詞:Linux;攝像頭;驅(qū)動(dòng)程序;Video for Linux;Video for Linux Two;多緩沖

中圖分類號(hào):TP316文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)33-1485-04

The Investigation of Multi-Buffer in USB Camera Driving Program and Image Capture in Linux System

ZHANG Wen-ya

(School of Information Science Technology, Southwest Jiaotong University, Chengdu 610031, China)

Abstract: This paper analyzes two USB camera drivingprograms of Vimicro company's ZC0301 chip.One is in conformity with the Video for Linux principle and the other is in conformity with the Video for Linux Two principle.The difference between the two programs about multi-buffer and image capture is given,and the image capture program is implemented.

Key words: Linux; camera; device driver; Video for Linux; Video for Linux Two; multi-buffer

1 引言

USB攝像頭目前已得到廣泛應(yīng)用。因其靈活、方便的特性,易于集成到嵌入式系統(tǒng)中。比如視頻聊天、網(wǎng)絡(luò)監(jiān)控和可視電話等。在我們開發(fā)的無線網(wǎng)絡(luò)攝像機(jī)系統(tǒng)中,USB攝像頭直接連接到嵌入式開發(fā)版,先用攝像頭進(jìn)行圖像采集,再通過嵌入式模塊進(jìn)行進(jìn)一步的處理。攝像頭驅(qū)動(dòng)程序一般在設(shè)計(jì)中采用符合V4L(Video for Linux)標(biāo)準(zhǔn)的驅(qū)動(dòng)程序配合相應(yīng)的應(yīng)用程序,用的比較多的是開源的spca5xx驅(qū)動(dòng)程序,但隨著Video for Linux Version Two標(biāo)準(zhǔn)的出現(xiàn),在一些驅(qū)動(dòng)中也采用符合V4L2(Video for Linux Version Two)標(biāo)準(zhǔn)的驅(qū)動(dòng)程序配合相應(yīng)的應(yīng)用程序。作者在開發(fā)過程中使用的是基于中星微ZC0301芯片的攝像頭。通過在設(shè)計(jì)過程中對(duì)這款攝像頭分別基于這兩種標(biāo)準(zhǔn)的驅(qū)動(dòng)程序的研究,給出了這兩種驅(qū)動(dòng)程序在多緩沖和圖像采集方面處理的不同點(diǎn),并分別給出相應(yīng)的圖像采集程序框架,以期加深讀者對(duì)驅(qū)動(dòng)程序的理解,根據(jù)實(shí)際開發(fā)需要更好的進(jìn)行應(yīng)用程序方面的設(shè)計(jì)。符合V4L的驅(qū)動(dòng)程序參考開源的gspcav1驅(qū)動(dòng)程序,符合V4L2的驅(qū)動(dòng)程序參考linux2.6內(nèi)核內(nèi)的zc0301驅(qū)動(dòng)程序。

2 使用多緩沖提高效果

在Linux系統(tǒng)中,文件操作通常是由read、write等系統(tǒng)調(diào)用來完成。通過在驅(qū)動(dòng)中用copy_to_user,copy_from_user等函數(shù)在內(nèi)核態(tài)、用戶態(tài)內(nèi)存空間中互相拷貝數(shù)據(jù)。但我們主要處理的是大批量的圖像數(shù)據(jù),采用上面的方法,頻繁的進(jìn)行讀寫,會(huì)增加時(shí)間開銷。因此一般采用內(nèi)存映射的方法來解決。mmap 方法是 file_operation 結(jié)構(gòu)的一部分, 當(dāng)發(fā)出 mmap系統(tǒng)調(diào)用時(shí)被引用。首先申請(qǐng)足夠大的內(nèi)核態(tài)內(nèi)存,將其作為圖像數(shù)據(jù)緩沖空間,URB帶回的圖像數(shù)據(jù)在這里暫存;然后使用函數(shù)將其逐頁映射到用戶空間中。用戶態(tài)的圖像處理程序使用mmap() 函數(shù),直接讀寫內(nèi)核態(tài)圖像緩沖內(nèi)存,這樣可以大大減少額外開銷,提高效率。

2.1 符合V4L標(biāo)準(zhǔn)的驅(qū)動(dòng)中的多幀緩沖

在gspcav1驅(qū)動(dòng)程序中,采用雙幀緩沖,即在核態(tài)內(nèi)存申請(qǐng)兩幀圖像緩沖內(nèi)存。

gspcav1的設(shè)備數(shù)據(jù)結(jié)構(gòu)

struct usb_spca50x {

struct video_device *vdev;

struct usb_device *dev;

char *fbuf;

struct spca50x_frame frame[SPCA50X_NUMFRAMES];

struct spca50x_sbuf sbuf[SPCA50X_NUMSBUF];

……}

其中struct spca50x_frame {

unsigned char *data;/* 幀緩沖區(qū) */

unsigned char *tmpbuffer;

……};

用來保存捕獲的每一幀圖像數(shù)據(jù)及狀態(tài)等等多個(gè)重要信息。SPCA50X_NUMFRAMES宏定義為2,在驅(qū)動(dòng)中明確定義采用雙緩沖來進(jìn)行圖像捕捉。用戶不可以在應(yīng)用程序中進(jìn)行修改。在驅(qū)動(dòng)中通過spca50x_alloc()函數(shù)分配兩幀的核態(tài)內(nèi)存。部分代碼如下:

static int spca50x_alloc(struct usb_spca50x *spca50x)

{……

spca50x->fbuf = rvmalloc(SPCA50X_NUMFRAMES * MAX_DATA_SIZE);

……

for (i = 0; i < SPCA50X_NUMFRAMES; i++) {

……

spca50x->frame[i].grabstate = FRAME_UNUSED;

spca50x->frame[i].data = spca50x->fbuf + i * MAX_DATA_SIZE;

spca50x->frame[i].highwater=spca50x->frame[i].data;

}……}

spca50x->fbuf一次被分配兩幀空間,再將它對(duì)應(yīng)的地址按幀分別賦給spca50x->frame[i].data。使用spca50x_move_data()函數(shù)將urb中的數(shù)據(jù)傳到設(shè)備幀緩沖。驅(qū)動(dòng)提供mmap文件操作方式。部分代碼如下:

static int spca5xx_mmap(struct file *file, struct vm_area_struct *vma)

{……

pos = (unsigned long) spca50x->fbuf;

while (size > 0) {

page = kvirt_to_pa(pos);

if(remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {up(spca50x->lock);

return -EAGAIN;}

start += PAGE_SIZE;

pos += PAGE_SIZE;

if (size > PAGE_SIZE)

size -= PAGE_SIZE;

elsesize = 0;

……}

大量工作由內(nèi)核完成,為實(shí)現(xiàn) mmap, 驅(qū)動(dòng)只要建立合適的頁表給用來存取設(shè)備的虛擬地址范圍。如果需要, 用新的操作集合替換vma->vm_ops。在這里建立頁表的方法是調(diào)用 remap_pfn_range 一次完成全部。

2.2 符合V4L2標(biāo)準(zhǔn)的驅(qū)動(dòng)中的多幀緩沖

在zc0301驅(qū)動(dòng)中使用多幀緩沖提高效果。申請(qǐng)的緩沖幀數(shù)可以由用戶定義,但不能超過該驅(qū)動(dòng)定義的最大值32,不能小于2。 zc0301的設(shè)備數(shù)據(jù)結(jié)構(gòu)

struct zc0301_device {

struct video_device* v4ldev;

struct usb_device* usbdev;

struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];

struct list_head inqueue, outqueue;

……}

struct zc0301_frame_t定義如下:

struct zc0301_frame_t {

void* bufmem;

struct v4l2_buffer buf;

enum zc0301_frame_state state;

struct list_head frame;

unsigned long vma_use_count;};

該結(jié)構(gòu)體用來保存在驅(qū)動(dòng)中每幀圖像數(shù)據(jù)的存儲(chǔ)地址及該幀的狀態(tài)等多個(gè)重要信息。用戶可根據(jù)需要在應(yīng)用程序中用ioctl VIDIOC_REQBUFS 來初始化要映射的內(nèi)存空間。在驅(qū)動(dòng)中 zc0301_request_buffers函數(shù)來申請(qǐng)幀緩沖空間,部分代碼如下:

static u32 zc0301_request_buffers(

struct zc0301_device* cam, u32count,enum

zc0301_io_method io)

{……

cam->nbuffers = count;

while (cam->nbuffers > 0) {

if ((buff = vmalloc_32_user(cam->nbuffers *PAGE_ALIGN(imagesize))))

break;

cam->nbuffers--;}

for (i = 0; i < cam->nbuffers; i++) {

cam->frame[i].bufmem = buff + i*

PAGE_ALIGN(imagesize);

cam->frame[i].buf.index = i;

cam->frame[i].buf.m.offset = i*

PAGE_ALIGN(imagesize);

……

cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;

}

return cam->nbuffers;}

使用vmalloc分配count個(gè)幀空間,再通過循環(huán)將每幀的起始地址和偏移地址存入cam->frame[i]中。可通過zc0301_release_buffers()函數(shù)釋放空間。該驅(qū)動(dòng)提供的mmap文件操作方式部分代碼如下:

static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)

{……

void *pos;

pos = cam->frame[i].bufmem;

while (size > 0) { /* size is page- aligned */

if(vm_insert_page(vma,start,vmalloc_to_page

(pos))) {

mutex_unlock(cam->fileop_mutex);

return -EAGAIN;}

start += PAGE_SIZE;

pos += PAGE_SIZE;

size -= PAGE_SIZE;

}……}

為實(shí)現(xiàn)該mmap文件操作,驅(qū)動(dòng)在建立頁表給用來存取設(shè)備的虛擬地址范圍時(shí)使用vm_insert_page()函數(shù),將分配好的每一頁依次插入的用戶虛擬空間中。

3 圖像采集

3.1 符合V4L標(biāo)準(zhǔn)的圖像采集

gspcav1驅(qū)動(dòng)中用ioctl命令VIDIOCMCAPTURE進(jìn)行圖像采集。執(zhí)行該命令后該幀狀態(tài)為spca50x->

frame[vm->frame].grabstate=FRAME_READY。該命令中判斷用戶所給圖像參數(shù)是否滿足要求,設(shè)置采集圖像數(shù)據(jù),寫寄存器參數(shù),設(shè)置該幀狀態(tài)為FRAME_READY,開始采集圖像數(shù)據(jù)。但并不表示已經(jīng)完成整個(gè)圖像數(shù)據(jù)的捕捉,需要通過VIDIOCSYNC進(jìn)行同步。這個(gè)命令表示該幀圖像已經(jīng)完成。驅(qū)動(dòng)將在此等待幀狀態(tài)由FRAME_GRABBING變?yōu)镕RAME_DONE,在等待隊(duì)列中阻塞等待圖像采集完成wait_event_interruptible(spca50x->frame[

frame].wq,(spca50x->frame[frame].grabstate==FRAME_DONE)),當(dāng)該幀狀態(tài)為FRAME_DONE時(shí)釋放當(dāng)前幀,將其狀態(tài)改為FRAME_UNUSED,當(dāng)另一幀被填滿時(shí)可以再次使用這一幀。

3.2 符合V4L2標(biāo)準(zhǔn)的圖像采集

zc0301驅(qū)動(dòng)中用兩個(gè)FIFO的緩沖區(qū)隊(duì)列來完成圖像的獲取和輸出。struct list_head inqueue, outqueue;當(dāng)前幀狀態(tài)cam->frame[i].state == F_UNUSED加入到inqueue中,用來捕捉圖像數(shù)據(jù),而一旦該幀數(shù)據(jù)捕捉完畢就從inqueue隊(duì)列中移出,加入到outqueue隊(duì)列中,ioctl命令 VIDIOC_QBUF用于將空閑的幀加入到輸入隊(duì)列inqueue中,接收下一幀圖像, VIDIOC_DQBUF則從輸出隊(duì)列中獲得已捕捉到的一幀圖像。zc0301_vidioc_qbuf()函數(shù)用來實(shí)現(xiàn)將一幀加入inqueue隊(duì)列,部分代碼如下:

static int zc0301_vidioc_qbuf(

struct zc0301_device* cam, void __user * arg)

{……

if (copy_from_user(b, arg, sizeof(b)))

return -EFAULT;

……

cam->frame[b.index].state = F_QUEUED;

spin_lock_irqsave(cam->queue_lock, lock_flags);

list_add_tail(cam->frame[b.index].frame, cam->inqueue);

spin_unlock_irqrestore(cam->queue_lock, lock_flags);

……}

驅(qū)動(dòng)中用zc0301_vidioc_dqbuf()函數(shù),從outqueue隊(duì)列中得到一幀圖像,部分代碼如下:

static int zc0301_vidioc_dqbuf(

struct zc0301_device* cam, struct file* filp,

void __user * arg)

{ ……

if (copy_from_user(b, arg, sizeof(b)))

return -EFAULT;

……

timeout=wait_event_interruptible_timeout( cam->wait_frame,(!list_empty(cam->outqueue)) ||

(cam->state DEV_DISCONNECTED) ||(cam->state

DEV_MISCONFIGURED),cam->module_param.frame_timeout*1000* msecs_to_jiffies(1) );

spin_lock_irqsave(cam->queue_lock, lock_flags);

f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);

list_del(cam->outqueue.next);

spin_unlock_irqrestore(cam->queue_lock, lock_flags);

f->state = F_UNUSED;

memcpy(b, f->buf, sizeof(b));

……

if (copy_to_user(arg, b, sizeof(b)))

return -EFAULT;

……}

V4l2中通過select判斷圖像是否已經(jīng)捕捉完畢,與VIDIOC_DQBUF配合使用。通過select()函數(shù)判斷該驅(qū)動(dòng)是否有數(shù)據(jù)可以讀出。當(dāng)設(shè)備已捕獲到數(shù)據(jù)時(shí)通過VIDIOC_DQBUF輸出。

4 USB攝像頭圖像采集

在嵌入式Linux系統(tǒng)中,USB攝像頭被注冊(cè)為一個(gè)標(biāo)準(zhǔn)的視頻設(shè)備/dev/video,在這里我們采用mmap方式獲取視頻圖像,給出現(xiàn)有的Video for Linux兩個(gè)版本下通過API接口獲取視頻圖像數(shù)據(jù)的主要步驟。

4.1 基于V4L API接口主要操作步驟

1) 打開視頻設(shè)備

Linux系統(tǒng)中,攝像頭的設(shè)備文件為/dev/video0,調(diào)用系統(tǒng)函數(shù)open打開該設(shè)備。

fd=open (dev_name, O_RDWR);

2) 通過ioctl函數(shù)VIDIOCGCAP控制命令讀取設(shè)備

struct video_capability包括攝像頭的屬性,攝像頭所能獲取的最大圖像大小,用像素作單位。通過ioctl發(fā)出VIDIOCGPICT控制命令,struct video_picture主要定義了圖像的屬性,諸如亮度,對(duì)比度,等等。

3) 設(shè)置視頻捕獲的圖像格式

struct video_picture campic;

ampic.palette =VIDEO_PALETTE_RGB24;

campic.brightness = 44464;

campic.hue = 36000;

campic.colour = 0;

campic.contrast = 43312;

campic.whiteness = 13312;

campic.depth = 24;

ret = ioctl( cam_fd, VIDIOCSPICT,cam_pic ); //*設(shè)置攝像頭緩沖中voideo_picture信息*/

4) 視頻數(shù)據(jù)幀捕獲。

使用ioctl命令VIDIOCGMBUF獲得幀緩沖空間,使用mmap()內(nèi)存映射到用戶空間,然后調(diào)用VIDIOCMCAPTURE開始采集圖像數(shù)據(jù),VIDIOCSYNC同步等待一幀完成。獲取圖像數(shù)據(jù)后就可以進(jìn)行圖片輸出或其它編解碼處理。

4.2 基于V412 API接口主要操作步驟

1) 打開視頻設(shè)備

操作與V4L基本相同,調(diào)用open()打開該設(shè)備。

fd=open (dev_name, O_RDWR);

2) 獲取該視頻設(shè)備所支持的V4L2特性

所有的V4L2設(shè)備驅(qū)動(dòng)都需要支持VIDIOC_QUERYCAP ioctl的系統(tǒng)調(diào)用。通過該調(diào)用,確定該驅(qū)動(dòng)程序是否與V4L2規(guī)范相兼容,同時(shí)獲取該設(shè)備所支持的V4L2特性。

ret=ioctl(fd, VIDIOC_QUERYCAP, cap);

在攝像頭應(yīng)用程序的開發(fā)過程中需要判定該設(shè)備是否支持視頻捕獲

if(!(cap.capabilitiesV4L2_CAP_VIDEO_CAPTURE))

{fprintf (stderr, \"%s is no video capture device\\", dev_name);

exit (EXIT_FAILURE);}

如果采用mmap方式還要判斷該設(shè)備是否支持流采集

if (!(cap.capabilities V4L2_CAP_STREAMING)) {

fprintf (stderr, \"%s does not support streaming i/o\\",dev_name);

exit (EXIT_FAILURE);}

3) 設(shè)置視頻捕獲的圖像格式

memset(fmt, 0, sizeof(struct v412 format));

fint.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

fint.fint.pix.width=640;

fint.fint.pix.height=480;

fint.fint.pix.pixelformat= V4L2_PIX_FMT_JPEG;

ret=ioctl(fd, VIDIOC_S_FMT, fmt );

4) 建立到用戶區(qū)的內(nèi)存映射

通過ioctl VIDIOC_REQBUF 申請(qǐng)內(nèi)核緩沖區(qū),根據(jù)需要分配若干個(gè)幀,再通過ioctl VIDIOC_QUERYBUF 得到一幀數(shù)據(jù),通過 mmap映射到用戶空間中。

mmap (NULL /* start anywhere */,

buf.length,PROT_READ | PROT_WRITE

/* required */, MAP_SHARED /* recommended */,

fd, buf.m.offset);

5) 視頻數(shù)據(jù)幀采集

將緩沖幀加入inqueue輸入隊(duì)列,準(zhǔn)備緩沖圖像數(shù)據(jù)空間,通過VIDIOC_STREAMON開始捕獲圖像數(shù)據(jù)。用select()確定一幀數(shù)據(jù)是否捕捉完成,由VIDIOC_ DQBUF得到輸出的幀圖像數(shù)據(jù)。

5結(jié)束語

具體分析了V4L與V4L2兩個(gè)不同標(biāo)準(zhǔn)下USB攝像頭驅(qū)動(dòng)中多幀緩沖的實(shí)現(xiàn)以及兩種標(biāo)準(zhǔn)下采集圖像數(shù)據(jù)的不同方式,并分別給出了相應(yīng)的圖像采集主要步驟。在這兩種驅(qū)動(dòng)下實(shí)現(xiàn)了圖像采集應(yīng)用程序的開發(fā)。

參考文獻(xiàn):

[1] Jonathan Corbet. Linux設(shè)備驅(qū)動(dòng)程序 [M]. 3版. 北京:中國電力出版社,2006.

[2] 劉春成.基于嵌入式Linux的USB攝像頭驅(qū)動(dòng)開發(fā)[J].計(jì)算機(jī)工程與設(shè)計(jì),2007,28(8):1885-1888.

[3] 王滔,季曉勇.在嵌入式Linux平臺(tái)上使用USB攝像頭[J].微計(jì)算機(jī)應(yīng)用,2006,27(1):52-54.

[4] Video for Linux Two API Specification Revision 0.24[S], 2008

[5] 毛德操,胡希明.Linux內(nèi)核源代碼情景分析(上、下)[M].杭州:浙江大學(xué)出版社,2001.

主站蜘蛛池模板: 91精品日韩人妻无码久久| 亚洲福利视频网址| 欧美国产在线一区| 日本黄色不卡视频| 国产乱人视频免费观看| 成人无码区免费视频网站蜜臀| 思思热精品在线8| 2021国产乱人伦在线播放 | 国产青青操| 97成人在线视频| 亚洲系列中文字幕一区二区| 亚洲高清资源| 国产一区二区精品福利| 成人毛片免费在线观看| 啪啪国产视频| 久久久波多野结衣av一区二区| 久久综合丝袜日本网| 久久久久国产一级毛片高清板| 91成人在线免费视频| 亚洲水蜜桃久久综合网站| 在线视频一区二区三区不卡| a色毛片免费视频| 99r在线精品视频在线播放| 久久青草免费91线频观看不卡| 久久伊伊香蕉综合精品| 国产精品污视频| 亚洲成a人片7777| 国产成人高清精品免费| Aⅴ无码专区在线观看| 国产69囗曝护士吞精在线视频| 青青青视频91在线 | 亚洲高清中文字幕在线看不卡| 无码专区国产精品第一页| 久久99热66这里只有精品一| 色久综合在线| 欧洲精品视频在线观看| 丝袜亚洲综合| 国产成人麻豆精品| 成年看免费观看视频拍拍| 国产午夜人做人免费视频中文| 91无码视频在线观看| 大香伊人久久| 九九这里只有精品视频| 亚洲欧美一区二区三区麻豆| 国产乱视频网站| 人妻中文久热无码丝袜| 精品一區二區久久久久久久網站| 国产日本欧美亚洲精品视| 中文字幕人成人乱码亚洲电影| 毛片最新网址| 国产99在线| 国产麻豆永久视频| a级毛片网| 精品国产免费观看| 亚洲—日韩aV在线| 欧美一级高清免费a| 91麻豆精品国产高清在线| 日韩在线播放中文字幕| 在线视频亚洲色图| 亚洲 欧美 偷自乱 图片| 亚洲人成网站观看在线观看| 欧美性色综合网| 国产在线观看99| 无码'专区第一页| 国产视频欧美| 在线观看欧美精品二区| 欧美日韩动态图| 国产sm重味一区二区三区| 成人精品视频一区二区在线| 久久夜色精品| 热久久综合这里只有精品电影| 午夜成人在线视频| 色婷婷视频在线| 国产二级毛片| 亚洲日韩在线满18点击进入| 一本大道无码高清| 男女男精品视频| 国产在线无码一区二区三区| 亚洲人成亚洲精品| 中文字幕亚洲电影| 免费A级毛片无码免费视频| 欧美激情视频一区|