前言
學習Linux快1個月了,Linux教學視頻看完了,然後在虛擬機上裝了個CentOS6.3把該做的實驗大多也做了。突然就想玩玩剛買來的藍魔USB攝像頭(型號M2200),我給自己定了個計劃,先寫個攝像頭驅動再寫個應用層上面與圖像有關的隨便什麼程序。
正文
1,先是驅動,我在想USB攝像頭的話USB總線協議部分Linux應該已經有了,我只要基於這個USB總線協議上增加一層攝像頭的通信協議就可以了。於是我就想把我的攝像頭拆了看看裡面用的是什麼芯片,結果沒有捨得拆,於是我干脆先到淘寶網物品信息部分看看有沒有我的M2200所用芯片信息,結果查出了芯片供應商是中星微但具體芯片型號沒有,我捨不得拆,怎麼辦。我突然想起來我的攝像頭是免驅的,既然windows都自帶它的驅動,就說明芯片那邊使用的協議一定也是符合某個標准的。上於是在網上搗鼓了一下,我靠,有好多論文和論壇都在講關於USB攝像頭驅動,居然有這麼多人在玩攝像頭,看來我落伍了。看著看著我漸漸的明白了,原來有個V4L(video for Linux)協議,果不其然。既然Linux都已經自帶了攝像頭驅動,那我就不寫了。但是我要看看我的CentOS6.3有沒有集成攝像頭驅動,我把攝像頭插上,windows給我自動安裝程序,安裝完了,好像又安裝了一個vmware usb device什麼東東。不管它(後來才知道windows關機後再啟動虛擬機就不會安裝vmware usb device了,要設置下:虛擬機->可移動設備->usb設備上鉤一下),然後再lsmod | grep video下就能看到uvcvideo、videodev之類的模塊如圖1,用ll /dev命令也就能看到video0這個設備文件了如圖2。
圖1
圖2
2,應用層,上網搜一搜,天啦,也有好多程序,很給力,看來我有了很好的學習材料,先給出一些傳送門http://www.linuxidc.com/Linux/2012-12/77159.htm(這位叫d_south的朋友總結了網上的USB攝像頭程序然後給出了自己的想法和源程序,我就是借鑒的這個,稍微改一下能通過gcc編譯),還有人把網上的程序搜集到一塊了,比如http://www.linuxidc.com/Linux/2012-12/77160.htm,好多好多,我不一一例舉了。我把d_south的程序一個字母一個字母的用gedit編譯器敲進去,形成了如下的程序。
v4l.h頭文件
#ifndef _V4L_H_
#define _V4L_H_
#include <stdio.h>
#include <stdlib.h> //stdio.h and stdlib.h are needed by perror function
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> //O_RDWR
#include <unistd.h>
#include <sys/mman.h> //unistd.h and sys/mman.h are needed by mmap function
#include <stdbool.h>//false and true
#include <sys/ioctl.h>
#include <linux/videodev.h>//v4l API
typedef struct _v4l_struct
{
int fd;
struct video_capability capability;
struct video_picture picture;
struct video_mmap mmap;
struct video_mbuf mbuf;
unsigned char *map;
int frame_current;
int frame_using[VIDEO_MAX_FRAME];
}v4l_device;
extern int v4l_open(char*,v4l_device*);
extern int v4l_close(v4l_device*);
extern int v4l_get_capability(v4l_device*);
extern int v4l_get_picture(v4l_device*);
extern int v4l_get_mbuf(v4l_device*);
extern int v4l_set_picture(v4l_device*,int,int,int,int,int);
extern int v4l_grab_picture(v4l_device*,unsigned int);
extern int v4l_mmap_init(v4l_device*);
extern int v4l_grab_init(v4l_device*,int,int);
extern int v4l_grab_frame(v4l_device*,int);
extern int v4l_grab_sync(v4l_device*);
#define DEFAULT_DEVICE "/dev/video0"
int v4l_open(char *dev,v4l_device *vd)
{
if(!dev)
dev=DEFAULT_DEVICE;
if((vd->fd=open(dev,O_RDWR))<0)
{
perror("v4l_open fail");
return -1;
}
if(v4l_get_capability(vd))
return -1;
printf("video capture device name:%s\n",vd->capability.name);
if(v4l_get_picture(vd))
return -1;
printf("frames number is %d\n",vd->mbuf.frames);
return 0;
}
int v4l_close(v4l_device *vd)
{
munmap(vd->map,vd->mbuf.size);
close(vd->fd);
return 0;
}
int v4l_get_capability(v4l_device *vd)
{
if(ioctl(vd->fd,VIDIOCGCAP,&vd->capability)<0)
{
perror("v4l_get_capability fail");
return -1;
}
return 0;
}
int v4l_get_picture(v4l_device *vd)
{
if(ioctl(vd->fd,VIDIOCGPICT,&vd->picture)<0)
{
perror("v4l_get_picture fail");
return -1;
}
return 0;
}
int v4l_get_mbuf(v4l_device *vd)
{
if(ioctl(vd->fd,VIDIOCGMBUF,&vd->mbuf)<0)
{
perror("v4l_get_mbuf fail");
return -1;
}
return 0;
}
int v4l_set_picture(v4l_device *vd,int br,int hue,int col,int cont,int white)
{
if(br)
vd->picture.brightness=br;
if(hue)
vd->picture.hue=hue;
if(col)
vd->picture.colour=col;
if(cont)
vd->picture.contrast=cont;
if(white)
vd->picture.whiteness=white;
if(ioctl(vd->fd,VIDIOCSPICT,&vd->picture)<0)
{
perror("v4l_set_picture fail");
return -1;
}
return 0;
}
int v4l_grab_picture(v4l_device *vd,unsigned int size)
{
if(read(vd->fd,vd->map,size)==0)
return -1;
return 0;
}
int v4l_mmap_init(v4l_device *vd)
{
if(v4l_get_mbuf(vd)<0)
return -1;
if((vd->map=(unsigned char*)mmap(0,vd->mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,vd->fd,0))<0)
{
perror("v4l_mmap_init fail");
return -1;
}
return 0;
}
int v4l_grab_init(v4l_device *vd,int width,int height)
{
vd->mmap.width=width;
vd->mmap.height=height;
vd->mmap.format=vd->picture.palette;
vd->frame_current=0;
vd->frame_using[0]=false;
vd->frame_using[1]=false;
return v4l_grab_frame(vd,0);
}
int v4l_grab_frame(v4l_device *vd,int frame)
{
if(vd->frame_using[frame])
{
fprintf(stderr,"v4l_grab_frame %d is already used\n",frame);
return -1;
}
vd->mmap.frame=frame;
if(ioctl(vd->fd,VIDIOCMCAPTURE,&vd->mmap)<0)
{
perror("v4l_grab_frame fail");
return -1;
}
vd->frame_using[frame]=true;
vd->frame_current=frame;
return 0;
}
int v4l_grab_sync(v4l_device *vd)
{
if(ioctl(vd->fd,VIDIOCSYNC,&vd->frame_current)<0)
{
perror("v4l_grab_sync fail");
return -1;
}
vd->frame_using[vd->frame_current]=false;
return 0;
}
#endif