所谓的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