int video_fd = v4l2_open(“/dev/video0”, O_RDWR | O_NONBLOCK, 0);
开启视频设备文件;
v4l2_capability cap;
int ret = vc_ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
获取设备能力,功能,是否有视频输入,采集输入输出方式(直接读写,流形式(内存映射(不需要new),用户内存指针等));
int vc_ioctl(int fd, unsigned long int request, void *arg){
int ret = 0;
do { ret = v4l2_ioctl( fd, request, arg ); }
while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));
return ret;
}各种io控制,具体数据结构可以自己f2进去慢慢看。
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
{
//not a video capture device
}
if(cap.capabilities & V4L2_CAP_READWRITE)
{
//is read and write!
}
if(cap.capabilities & V4L2_CAP_STREAMING)
{
//it can use mmap!
}
设置帧格式:
v4l2_format fmt , afmt;
afmt.pixelformat = V4L2_PIX_FMT_YUV420;
memset(&fmt, 0x00, sizeof(fmt));
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix = afmt;
vc_ioctl(video_fd, VIDIOC_S_FMT, &fmt);
获取视频帧格式,定义an image format:
v4l2_format fmt;memset(&fmt, 0x00, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//类型都是这个宏 。。
vc_ioctl(video_fd, VIDIOC_G_FMT, &fmt);
获取帧率:
v4l2_streamparm param;
memset(¶m, 0x00, sizeof(param));
param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vc_ioctl(video_fd, VIDIOC_G_PARM, ¶m);//获取。。
if (param.parm.capture.timeperframe.numerator != 0)
int fps = param.parm.capture.timeperframe.denominator / param.parm.capture.timeperframe.numerator; //我也不知道为什么这么算???
设置帧率:
v4l2_streamparm param;
memset(¶m, 0x00, sizeof(param));
param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
param.parm.capture.timeperframe.denominator = fps; //分母param.parm.capture.timeperframe.numerator = 1; //分子
vc_ioctl(video_fd, VIDIOC_S_PARM, ¶m);//设置。。
这里采用内存映射获取输入流:1.设置为内存映射; 2.指定大小的内存映射缓冲区(不小于3,不大于5)
v4l2_requestbuffers req;req.count = 4;//缓冲区大小
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;//内存映射
int ret = vc_ioctl(video_fd, VIDIOC_REQBUFS, &req);
class Ca_Buf
{
public:
unsigned long video_len;
char * video_buf;
Ca_Buf()
: video_len(0)
, video_buf(0)
{}
};
std::vector< Ca_Buf > buffers;
buffers.resize(4);
for (unsigned int i = 0; i < 4; i ++)
{
v4l2_buffer buf;
memset(&buf, 0x00, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ret = vc_ioctl(video_fd, VIDIOC_QUERYBUF, &buf);
buffers[i].video_len = buf.length;
buffers[i].video_buf = (char*)v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, video_fd, buf.m.offset);//内存映射 。。
if (buffers[i].video_buf == MAP_FAILED)
{
printf("capture mmap buf failure!\n");
return -1;
}
ret = vc_ioctl(video_fd, VIDIOC_QBUF, &buf);
}
开始采集码流:
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = vc_ioctl(video_fd, VIDIOC_STREAMON, &type);
获取缓冲区中视频帧流,取出最先入队的帧缓冲区指针:
v4l2_buffer dq_buf;
memset(&dq_buf,0,sizeof(dq_buf));
dq_buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
dq_buf.memory=V4L2_MEMORY_MMAP;
dq_buf.index=0;
int ret = vc_ioctl(video_fd, VIDIOC_DQBUF, &dq_buf);
这出队后是码流处理,渲染或是存储,反正就是拷贝后(随你怎么用)才能将指针入队。将缓冲区指针再次入队,等待收取新的帧流:
int ret = vc_ioctl(video_fd, VIDIOC_QBUF, &dq_buf);
停止采集数据:
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int ret = vc_ioctl(video_fd, VIDIOC_STREAMOFF, &type);
释放内存映射:
for(size_t i = 0; i < buffers.size(); i++)
{
ret = v4l2_munmap(buffers[i].video_buf, buffers[i].video_len);
if (ret == -1)
{ printf("capture munmap buf failure!\n"); return -1; }
}
关闭设备文件:v4l2_close(video_fd);
检查当前视频设备支持的标准
在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测
v4l2_std_id std;ret = vc_ioctl(video_fd, VIDIOC_QUERYSTD, &std);