linux uvc深刻理解( 四)

上文把uvc驅動的初始化部分分析的差很少了,從如今起咱們開始着手uvc的操做流程,先給出我本身寫的一個調用v4l2接口的應用,方便以後的分析web

int main()
{
int ret;
int camera_fd;
//打開uvc設備,獲取設備句柄
camera_fd = open("/dev/video2",O_RDWR);
//獲取設備支持格式
struct v4l2_fmtdesc fmt;
memset(&fmt,0x0,sizeof(fmt));
fmt.index = 0;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

while ((ret = ioctl(camera_fd, VIDIOC_ENUM_FMT, &fmt)) == 0) {
fmt.index++;
printf("{ pixelformat = ''%c%c%c%c'', description = ''%s'' }\n",\
fmt.pixelformat & 0xFF, (fmt.pixelformat >> 8) & 0xFF, \
(fmt.pixelformat >> 16) & 0xFF, (fmt.pixelformat >> 24) & 0xFF, \
fmt.description);
}
//查詢設備能力,capabilities是用掩碼錶示
struct v4l2_capability cap;
ret = ioctl(camera_fd, VIDIOC_QUERYCAP, &cap);
if(ret < 0)
{
printf("get vidieo capability error,error code: %d \n", errno);
return -1;
}
printf("{ Capability: driver:'%s', card:'%s',buf_info:'%s',version:%d,capabilities:0x%x}\n",\
cap.driver,cap.card,cap.bus_info,cap.version,cap.capabilities);
//設置獲取視頻格式
struct v4l2_format tv4l2_format;
CLEAR(tv4l2_format);
tv4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tv4l2_format.fmt.pix.width = MAX_WIDTH;
tv4l2_format.fmt.pix.height = MAX_HEIGHT;
tv4l2_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
tv4l2_format.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(camera_fd, VIDIOC_S_FMT, &tv4l2_format);
if(ret < 0)
{
perror("VIDIOC_S_FMT");
}
printf("{ Format width: %d, height:%d}\n",tv4l2_format.fmt.pix.width,tv4l2_format.fmt.pix.height);

//設置視頻流信息,關於視頻fps
struct v4l2_streamparm *setfps;
setfps = (struct v4l2_streamparm *)calloc(1,sizeof(struct v4l2_streamparm));
memset(setfps,0,sizeof(struct v4l2_streamparm));
setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps->parm.capture.timeperframe.numerator = 1;
setfps->parm.capture.timeperframe.denominator = 30;
if(ioctl(camera_fd, VIDIOC_S_PARM,setfps) < 0)
{
perror("VIDIOC_S_PARM");
}
//申請一個擁有1個緩衝幀的緩衝區
struct v4l2_requestbuffers v4l2_reqbuf;
memset(&v4l2_reqbuf,0,sizeof(struct v4l2_requestbuffers));
v4l2_reqbuf.count = 1;
v4l2_reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_reqbuf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(camera_fd, VIDIOC_REQBUFS, &v4l2_reqbuf);
if(ret < 0)
perror("VIDIOC_REQBUFS");
printf("{ Reqbuffer count: %d}\n",v4l2_reqbuf.count);
//獲取緩衝幀的地址,長度:
struct v4l2_buffer map_buffer;
map_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
map_buffer.index = 0;
map_buffer.memory = V4L2_MEMORY_MMAP;
ret = ioctl(camera_fd,VIDIOC_QUERYBUF,&map_buffer);
if(ret < 0)
perror("VIDIOC_QUERYBUF");
printf("{ Querybuffer length:%d, m.offset: %d}\n",map_buffer.length,map_buffer.m.offset);

//以mmap共享內存的方式將緩衝幀與應用層共享
void *map_address = mmap(NULL, \
map_buffer.length, \
PROT_READ | PROT_WRITE ,\
MAP_SHARED, \
camera_fd, map_buffer.m.offset);
if(map_address == MAP_FAILED){
printf("mmap failed!\n");
exit(1);
}

//將緩衝幀放入緩衝隊列
struct v4l2_buffer camera_buf;
camera_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
camera_buf.memory = V4L2_MEMORY_MMAP;
camera_buf.index = 0;
if(-1 == ioctl(camera_fd, VIDIOC_QBUF, &camera_buf))
{
perror("VIDIOC_QBUF");
exit(EXIT_FAILURE);
}
//啓動視頻流
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(camera_fd,VIDIOC_STREAMON,&type))
{
perror("VIDIOC_STREAMON");
exit(EXIT_FAILURE);
}

fd_set fds;
struct timeval tv;
int camera_index;
char *filename = malloc(20*sizeof(char));
for(camera_index = 0;camera_index < MAX_FPS;camera_index++)
{
FD_ZERO(&fds);
FD_SET(camera_fd, &fds);
tv.tv_sec = 2;
tv.tv_usec = 0;
//經過select方式監聽數據,超時2s
ret = select(camera_fd+1,&fds,NULL,NULL,&tv);
if(ret == -1)
{
perror("select");
exit(EXIT_FAILURE);
}
if(ret == 0)
{
fprintf(stderr,"select time out\n");
exit(EXIT_FAILURE);
}
//將數據從緩衝隊列取出
struct v4l2_buffer get_buffer;
get_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
get_buffer.memory = V4L2_MEMORY_MMAP;
if(-1 == ioctl(camera_fd,VIDIOC_DQBUF,&get_buffer))
{
perror("VIDIOC_DQBUF");
exit(EXIT_FAILURE);
}

printf("{ Get Buffer OK index:%d length: %d time: %ld:%ld}\n",get_buffer.index,get_buffer.length,get_buffer.timestamp.tv_sec,get_buffer.timestamp.tv_usec);

// 此處將獲取的yuv422數據進行轉化成RGB方便顯示以及libjpeg壓縮,不關乎v4l2操做流程因此略去
//繼續將緩衝幀放入緩衝對列去獲取數據
if(-1 == ioctl(camera_fd,VIDIOC_QBUF,&get_buffer))
{
perror("VIDIOC_QBUF");
exit(EXIT_FAILURE);
}
}

if(-1 == munmap(map_address,map_buffer.length))
{
perror("munmap");
exit(EXIT_FAILURE);
}
printf("munmap,then exit\n");

return 0;

}

在我本機上執行的結果以下:bash

ggj@ggj:v4l2_camera$ ./camera
{ pixelformat = ''YUYV'', description = ''YUV 4:2:2 (YUYV)'' }
{ Capability: driver:'uvcvideo', card:'Acer Crystal Eye webcam',buf_info:'usb-0000:00:1a.7-1',version:198664,capabilities:0x84000001}
{ Format width: 640, height:480}
{ Reqbuffer count: 1}
{ Querybuffer length:614400, m.offset: 0}
{ Get Buffer OK index:0 length: 614400 time: 664:888343}
munmap,then exit
相關文章
相關標籤/搜索