头文件如下
#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;
}