頭文件如下
#ifndef __V4L2_LIB_H__
#define __V4L2_LIB_H__
class CapCocos
{
public:
CapCocos();
~CapCocos();
int OpenVideo(const char *video);
unsigned char* GetVideoData();
int CloseVideo();
private:
int fdVideo;
struct buffers
{
void* start;
unsigned int length;
}*buffers;
unsigned char *pData;
};
#endif
代碼如下
#include<stdio.h>
#include <stdlib.h>#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <string.h>
//#include <errno.h>
#include <sys/mman.h>
#include <v4l2Cocos.h>
CapCocos::CapCocos()
{
fdVideo=0;
pData=0;
}
CapCocos::~CapCocos()
{
CloseVideo();
}
int CapCocos::CloseVideo()
{
if(fdVideo!=0)
{
close(fdVideo);
fdVideo=0;
delete pData;
pData=0;
}
}
int CapCocos::OpenVideo(const char *video)
{
//打開設備
//int fd = open("/dev/video0", O_RDWR);
int fd=open(video, O_RDWR);
if (fd < 0) return 1;
//查詢cap的功能,必須支持 V4L2_CAP_VIDEO_CAPTURE
struct v4l2_capability cap;
if(ioctl(fd, VIDIOC_QUERYCAP, &cap)<0)
{
close(fd);
return 2;
}
//printf("%s \n%s\n%s\n %08x %08x\n", cap.driver, cap.card, cap.bus_info, cap.version, cap.capabilities);
//printf("V4L2_CAP_VIDEO_CAPTURE = %08x %d \n", V4L2_CAP_VIDEO_CAPTURE, V4L2_CAP_VIDEO_CAPTURE&cap.capabilities);
if (!(V4L2_CAP_VIDEO_CAPTURE&cap.capabilities))
{
//errmsg("capture not support");
close(fd);
return 3;
}
//
//枚舉支持的格式 分辨率 ...
#if 0
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Support format:\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
{
printf("%d.%s type=%08x flags=%08x pixelformat=%08x\n", fmtdesc.index + 1, fmtdesc.description, fmtdesc.type, fmtdesc.flags, fmtdesc.pixelformat);
fmtdesc.index++;
}
#endif
/*
VIDIOC_REQBUFS 命令通過結構 v4l2_requestbuffers 請求驅動申請一片連續的內存用於緩存視頻信息
count 指定根據圖像佔用空間大小申請的緩存區個數,type 爲視頻捕獲模式,memory 爲內存區的使用方式。
*/
struct v4l2_requestbuffers req;
req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if( ioctl(fd, VIDIOC_REQBUFS, &req)<0)
{
close(fd);
return 4;
}
buffers = (struct buffers*)calloc(req.count, sizeof(*buffers));
if (!buffers)
{
close(fd);
return 5;
}
struct v4l2_buffer buf;
for (unsigned int n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
{
close(fd);
return 100+n_buffers;
}
//將攝像頭的緩衝 映射到內存中, 並且 將地址 長度 記錄到 buffers 中
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
{
close(fd);
return 200+n_buffers;
}
}
unsigned int i;
for (i = 0; i < 4; ++i)
{
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if(ioctl(fd, VIDIOC_QBUF, &buf)<0)
{
close(fd);
return 6;
}
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_STREAMON, &type)<0)
{
close(fd);
return 7;
}
fdVideo=fd;
pData=new unsigned char[640*480*2];
return 0;
}
unsigned char* CapCocos::GetVideoData()
{
if(fdVideo)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if(ioctl(fdVideo, VIDIOC_DQBUF, &buf)<0) return 0;
memcpy(pData,buffers[buf.index].start,buffers[buf.index].length);
//告訴驅動數據處理已經完成
if(ioctl(fdVideo, VIDIOC_QBUF, &buf)<0) return 0;
return pData;
}
return 0;
}