码迷,mamicode.com
首页 > 其他好文 > 详细

嵌入式专题: UVC摄像头摄像

时间:2014-07-12 21:12:02      阅读:666      评论:0      收藏:0      [点我收藏+]

标签:des   blog   文件   数据   os   width   

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

嵌入式专题: UVC摄像头摄像

标签:des   blog   文件   数据   os   width   

原文地址:http://blog.csdn.net/iamshaofa/article/details/37693077

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!