所谓的CMOS摄像头,驱动往往是一坨shit,想做摄像头应用,还是上UVC摄像头吧。
这个类里展示UVC摄像头的各种参数的设置。需要注意的是,如果帧率上不去,往往是由于曝光时间太长导致。这个关系是这样的,曝光越长,图片成像质量越好,但帧率自然就下去了。
#ifndef _UVC_CAMERA_H
#define _UVC_CAMERA_H
class UvcCamera
{
public:
UvcCamera();
~UvcCamera();
int Open(const char* dev, int width, int height);
void Close();
int WaitForFrame(int ms);
int ReadFrame(void* outbuf);
private:
int EnumFormats();
int SetFrameRate(int fps);
int SetOther();
private:
int m_fd;
struct bufinfo
{
void * start;
size_t length;
};
bufinfo m_bufs[10];
int m_bufcount;
};
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include "UvcCamera.h"
#define CLEAR(x) memset (&(x), 0, sizeof (x))
UvcCamera::UvcCamera()
{
}
UvcCamera::~UvcCamera()
{
}
int UvcCamera::Open(const char* dev, int width, int height)
{
int ret , i;
//打开设备
// m_fd = open (dev, O_RDWR /* required */ | O_NONBLOCK , 0);
m_fd = open (dev, O_RDWR);
if(m_fd < 0)
{
printf("failed to open capture device !\n");
return -1;
}
// 设置帧率
EnumFormats();
//获取摄像头参数
struct v4l2_capability cap;
ret = ioctl (m_fd, VIDIOC_QUERYCAP, &cap);
if(ret < 0)
{
printf("failed to query capability (%d)",ret);
return -1;
}
//设置图像格式
struct v4l2_format v_fmt;
CLEAR (v_fmt);
v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v_fmt.fmt.pix.width = width;
v_fmt.fmt.pix.height = height;
v_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
v_fmt.fmt.pix.field = V4L2_FIELD_ANY; //V4L2_FIELD_INTERLACED;
ret = ioctl (m_fd, VIDIOC_S_FMT, &v_fmt);
if(ret < 0)
{
printf("failed to set format (%d) \n", ret);
return -1;
}
ret = ioctl (m_fd, VIDIOC_G_FMT, &v_fmt);
if(ret < 0)
{
printf("failed to set format (%d) \n", ret);
return -1;
}
printf("real size: %d x %d \n", v_fmt.fmt.pix.width, v_fmt.fmt.pix.height);
SetOther();
SetFrameRate(15);
//cout << "the frame rate:" << (parm->parm.capture.timeperframe.numerator*1000)/(parm->parm.capture.timeperfr ame.denominator) << endl;
// imgdata_size = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; //计算图片大小
// printf("bytes per line: %d \n", fmt.fmt.pix.bytesperline);
struct v4l2_requestbuffers v_req;
CLEAR (v_req);
v_req.count = 4;
v_req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v_req.memory = V4L2_MEMORY_MMAP;
ioctl (m_fd, VIDIOC_REQBUFS, &v_req); //申请缓冲,count是申请的数量
if (v_req.count < 2)
{
printf("Insufficient buffer memory\n");
return -1;
}
m_bufcount = v_req.count;
for(i=0; i<m_bufcount; i++)
{
struct v4l2_buffer v_buf; //驱动中的一帧
CLEAR (v_buf);
v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v_buf.memory = V4L2_MEMORY_MMAP;
v_buf.index = i;
if (-1 == ioctl (m_fd, VIDIOC_QUERYBUF, &v_buf)) //映射用户空间
{
printf ("VIDIOC_QUERYBUF error\n");
}
printf("vbuf.length: %d \n", v_buf.length);
void* ptr = mmap (NULL /* start anywhere */, //通过mmap建立映射关系
v_buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
m_fd, v_buf.m.offset);
if(ptr == MAP_FAILED)
{
printf("mmap failed \n");
}
else
{
m_bufs[i].length = v_buf.length;
m_bufs[i].start = ptr;
}
}
for (i = 0; i < m_bufcount; i++)
{
struct v4l2_buffer v_buf;
CLEAR (v_buf);
v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v_buf.memory = V4L2_MEMORY_MMAP;
v_buf.index = i;
if (-1 == ioctl (m_fd, VIDIOC_QBUF, &v_buf))//申请到的缓冲进入列队
{
printf ("VIDIOC_QBUF failed\n");
}
}
// 开始捕捉图像数据
enum v4l2_buf_type v_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl (m_fd, VIDIOC_STREAMON, &v_type))
{
printf ("VIDIOC_STREAMON failed\n");
return -1;
}
return 0;
}
void UvcCamera::Close()
{
int i;
for (i = 0; i < m_bufcount; ++i)
{
if (-1 == munmap (m_bufs[i].start, m_bufs[i].length))
{
printf ("munmap error");
}
}
close(m_fd);
}
int UvcCamera::SetOther()
{
printf("......... EXPOSURE ............\n");
if(1)
{
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_EXPOSURE_AUTO;
if( 0 != ioctl(m_fd, VIDIOC_G_CTRL, &ctrl))
{
printf("failed ....\n");
return -1;
}
printf("EXPOSURE mode (old) = %d \n", ctrl.value);
ctrl.value = V4L2_EXPOSURE_MANUAL ;
if( 0 != ioctl(m_fd, VIDIOC_S_CTRL, &ctrl))
{
printf("failed to set ....\n");
return -1;
}
}
if(1)
{
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
if( 0 != ioctl(m_fd, VIDIOC_G_CTRL, &ctrl))
{
return -1;
}
printf("EXPOSURE time (old) = %d \n", ctrl.value);
ctrl.value = 50;
if( 0 != ioctl(m_fd, VIDIOC_S_CTRL, &ctrl))
{
return -1;
}
if( 0 != ioctl(m_fd, VIDIOC_G_CTRL, &ctrl))
{
return -1;
}
printf("EXPOSURE time (new) = %d \n", ctrl.value);
}
if(0)
{
v4l2_control ctrl = {0};
ctrl.id = V4L2_CID_EXPOSURE;
ctrl.value = 0;
if(ioctl(m_fd, VIDIOC_G_CTRL, &ctrl) < 0)
{
printf("V4L2_CID_EXPOSURE failed. \n");
return -1;
}
printf("V4L2_CID_EXPOSURE = %d \n", ctrl.value);
}
if(0)
{
struct v4l2_ext_controls ctrls = {0};
struct v4l2_ext_control ctrl = {0};
ctrls.ctrl_class = V4L2_CTRL_CLASS_CAMERA ;
ctrls.count = 0;
ctrls.controls = &ctrl;
ctrl.id = V4L2_CID_EXPOSURE_AUTO;
ctrl.value = 0;
if(ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
{
printf("VIDIOC_G_EXT_CTRLS failed. \n");
return -1;
}
printf("V4L2_CID_EXPOSURE_AUTO = %d \n", ctrl.value);
printf("------- set ------\n");
ctrl.id = V4L2_CID_EXPOSURE_AUTO;
ctrl.value = V4L2_EXPOSURE_SHUTTER_PRIORITY ;
if(ioctl(m_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
{
printf("VIDIOC_G_EXT_CTRLS failed. \n");
return -1;
}
printf("------- after set ------\n");
if(ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
{
printf("VIDIOC_G_EXT_CTRLS failed. \n");
return -1;
}
printf("V4L2_CID_EXPOSURE_AUTO = %d \n", ctrl.value);
}
if(1)
{
struct v4l2_ext_controls ctrls = {0};
struct v4l2_ext_control ctrl = {0};
ctrls.ctrl_class = V4L2_CTRL_CLASS_CAMERA ;
ctrls.count = 0;
ctrls.controls = &ctrl;
ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
ctrl.value = 0;
if(ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
{
printf("V4L2_CID_EXPOSURE_ABSOLUTE failed. \n");
return -1;
}
printf("V4L2_CID_EXPOSURE_ABSOLUTE = %d \n", ctrl.value);
printf("------- set V4L2_CID_EXPOSURE_ABSOLUTE------\n");
ctrl.value = 1;
if(ioctl(m_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
{
printf("VIDIOC_G_EXT_CTRLS failed. \n");
return -1;
}
printf("------- after set V4L2_CID_EXPOSURE_ABSOLUTE------\n");
if(ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
{
printf("VIDIOC_G_EXT_CTRLS failed. \n");
return -1;
}
printf("V4L2_CID_EXPOSURE_ABSOLUTE = %d \n", ctrl.value);
}
return 0;
}
int UvcCamera::SetFrameRate(int fps)
{
struct v4l2_streamparm v_param;
CLEAR(v_param);
v_param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(m_fd,VIDIOC_G_PARM, &v_param) < 0)
{
//error("set param:");
printf("failed to set framerate .\n");
return -1;
}
// parm->parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
v_param.parm.capture.timeperframe.denominator = fps;//时间间隔分母
v_param.parm.capture.timeperframe.numerator = 1;//分子
if(ioctl(m_fd,VIDIOC_S_PARM, &v_param) < 0)
{
//error("set param:");
printf("failed to set framerate .\n");
return -1;
}
if(ioctl(m_fd,VIDIOC_G_PARM, &v_param) < 0)
{
//error("set param:");
printf("failed to set framerate .\n");
return -1;
}
// 检查帧率是否设置成功
printf("framerate: %d / %d \n",
v_param.parm.output.timeperframe.numerator,
v_param.parm.output.timeperframe.denominator);
return 0;
}
int UvcCamera::EnumFormats()
{
struct v4l2_fmtdesc fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.index = 0;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while ((ioctl(m_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);
}
return 0;
}
int UvcCamera::WaitForFrame(int ms)
{
fd_set fds;
FD_ZERO (&fds);//将指定的文件描述符集清空
FD_SET (m_fd, &fds);//在文件描述符集合中增加一个新的文件描述符
/* Timeout. */
struct timeval tv;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000000;
int r = select (m_fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时
if (-1 == r)
{
return -1;
}
if (0 == r)
{
fprintf (stderr, "select timeout\n");
return 0;
}
return 1;
}
int UvcCamera::ReadFrame(void* outbuf)
{
struct v4l2_buffer v_buf;
CLEAR (v_buf);
v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v_buf.memory = V4L2_MEMORY_MMAP;
ioctl (m_fd, VIDIOC_DQBUF, &v_buf); //出列采集的帧缓冲
//assert (buf.index < m_bufcount);
//printf ("buf.index dq is %d,\n",v_buf.index);
//printf("vbuf.bytes used = %d \n", v_buf.bytesused);
// 把图像帧拷出
//int len = m_bufs[v_buf.index].length;
int len = v_buf.bytesused; // 实际大小
memcpy(outbuf, m_bufs[v_buf.index].start, len);
v_buf.bytesused = 0;
ioctl (m_fd, VIDIOC_QBUF, &v_buf); //再将其入列
return len;
}
嵌入式专题: UVC摄像头摄像,布布扣,bubuko.com
原文地址:http://blog.csdn.net/iamshaofa/article/details/37693077