嵌⼊式linux应⽤摄像头编程拍照简单⽰例基于V4L2接⼝
linux上⾯摄像头有专⽤的接⼝V4L和V4L2,这⾥分享⼀个V4L2接⼝采集图⽚的⽰例,这⾥硬件野⽕的imx开发板,摄像头为uvc摄像头,pcl上ubuntu也运⾏通过
1、先要确定/dev/video*设备⽂件是否存在,不存在就需要修改内核启⽤摄像头⽀持
Device Drivers --->
<*> Multimedia support --->
[*] Video capture adapters --->
[*]V4L USB devices --->
<*> USB Video Class (UVC)
[*] UVC input events device support
2、打开设备⽂件
video_dev =open("\dev\video0",O_RDWR));
3、获取摄像头信息
ioctl(video_dev,VIDIOCGCAP,&video_cap)
4、获取摄像头通道
ioctl(video_dev,VIDIOCGCHAN,&video_chan)
5、获取捕捉属性
ioctl(video_dev,VIDIOCGPICT,&video_pic)
6、设置捕捉属性
ioctl(video_dev,VIDIOCSPICT,&video_pic)
7、映射地址
ioctl(video_dev,VIDIOCGMBUF,&mbuf)
mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_dev,0);
8、获取摄像头图像
ioctl(video_dev,VIDIOCMCAPTURE,&mmap)
9、保存
c程序
camera.c
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
#include<errno.h>
#include<linux/videodev2.h>
#include<sys/mman.h>
#include<sys/time.h>
int fd;
struct v4l2_buffer buf;
struct buffer
{
{mmap格式怎么打开
void* start;
unsigned int length;
long long int timestamp;
}*buffers;
volatile int IMAGEWIDTH,IMAGEHEIGHT,FRAME_NUM;
//申请缓存并映⽤户空间地址
static int v4l2_mem_ops()
{
unsigned int n_buffers;
struct v4l2_requestbuffers req;
//申请帧缓冲
<=V4L2_MEMORY_MMAP;
if(ioctl(fd,VIDIOC_REQBUFS,&req)==-1)
{
printf("request for buffers error\n");
return-1;
}
// 申请⽤户空间的地址列
buffers =unt*sizeof(*buffers));
if(!buffers)
{
printf ("out of memory!\n");
return-1;
}
// 进⾏内存映射
for(n_buffers =0; n_buffers < FRAME_NUM; n_buffers++)
{
< = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
//查询
if(ioctl (fd, VIDIOC_QUERYBUF,&buf)==-1)
{
printf("query buffer error\n");
return-1;
}
//映射
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =mmap(NULL,buf.length,PROT_READ|PROT_WRITE, MAP_SHARED, fd, ffset);
if(buffers[n_buffers].start == MAP_FAILED)
{
printf("buffer map error\n");
return-1;
}
}
return0;
}
int camera_init(char*camera_dev,int img_w,int img_h,int frame_n)
{
struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt;
struct v4l2_streamparm stream_para;
IMAGEWIDTH = img_h;
IMAGEWIDTH = img_h;
IMAGEWIDTH = img_w;
FRAME_NUM = frame_n;
//打开摄像头设备
fd =open(camera_dev, O_RDWR);
if(fd ==-1)
{
printf("[%s]:[%d] open camera file error\r\n", __FUNCTION__,__LINE__);
return-1;
}
//查询设备属性
if(ioctl(fd, VIDIOC_QUERYCAP,&cap)==-1)
{
printf("Error opening device %s: unable to query device.\n",FILE_VIDEO);
return-1;
}
else
{
printf("driver:\t\t%s\n",cap.driver);
printf("card:\t\t%s\n",cap.card);
printf("bus_info:\t%s\n",cap.bus_info);
printf("version:\t%d\n",cap.version);
printf("capabilities:\t%x\n",cap.capabilities);
if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)== V4L2_CAP_VIDEO_CAPTURE) {
printf("Device %s: supports capture.\n",FILE_VIDEO);
}
if((cap.capabilities & V4L2_CAP_STREAMING)== V4L2_CAP_STREAMING)
{
printf("Device %s: supports streaming.\n",FILE_VIDEO);
}
}
//显⽰所有⽀持帧格式
fmtdesc.index=0;
printf("Support format:\n");
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
{
printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
fmtdesc.index++;
}
//检查是否⽀持某帧格式
struct v4l2_format fmt_test;
pe=V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt_test.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB32;
if(ioctl(fd,VIDIOC_TRY_FMT,&fmt_test)==-1)
{
printf("not support format RGB32!\n");
}
else
{
printf("support format RGB32\n");
}
//查看及设置当前格式
printf("\n");
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;//jpg格式
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//yuv格式
fmt.fmt.pix.height = img_h;
fmt.fmt.pix.width = img_w;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
printf("pe:\t\t%d\n",pe);
printf("pe:\t\t%d\n",pe);
printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat &0xFF,(fmt.fmt.pix.pixelformat >>8)&0xFF,(fmt.fmt.pix.pixelformat >>16)&0xFF,(fmt.f mt.pix.pixelformat >>24)&0xFF);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
if(ioctl(fd, VIDIOC_S_FMT,&fmt)==-1)
{
printf("Unable to set format\n");
return-1;
}
printf("\n");
if(ioctl(fd, VIDIOC_G_FMT,&fmt)==-1)
{
printf("Unable to get format\n");
return-1;
}
{
printf("pe:\t\t%d\n",pe);
printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat &0xFF,(fmt.fmt.pix.pixelformat >>8)&0xFF,(fmt.fmt.pix.pixelformat >>16)&0xFF,(fm t.fmt.pix.pixelformat >>24)&0xFF);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
}
//设置及查看帧速率,这⾥只能是30帧,就是1秒采集30张图
memset(&stream_para,0,sizeof(struct v4l2_streamparm));
pe = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stream_para.parm.capture.timeperframe.denominator =30;
stream_para.parm.capture.timeperframe.numerator =1;
if(ioctl(fd, VIDIOC_S_PARM,&stream_para)==-1)
{
printf("Unable to set frame rate\n");
return-1;
}
if(ioctl(fd, VIDIOC_G_PARM,&stream_para)==-1)
{
printf("Unable to get frame rate\n");
return-1;
}
{
printf("numerator:%d\ndenominator:%d\n",stream_para.parm.capture.timeperframe.numerator,stream_para.parm.capture.timeperframe.denominator );
}
int ret =v4l2_mem_ops();
if(ret ==-1)return ret;
return0;
}
int camera_get_pic(char*picname,int picnum)
{
unsigned int n_buffers;
enum v4l2_buf_type type;
char file_name[100];
char index_str[10];
long long int extra_time =0;
long long int cur_time =0;
long long int last_time =0;
//⼊队和开启采集
for(n_buffers =0; n_buffers < FRAME_NUM; n_buffers++)
{
buf.index = n_buffers;
ioctl(fd, VIDIOC_QBUF,&buf);
ioctl(fd, VIDIOC_QBUF,&buf);
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON,&type);
//出队,处理,写⼊yuv⽂件,⼊队,循环进⾏
int loop = picnum/FRAME_NUM;
if(loop ==0) loop =1;
while(loop >0)
{
for(n_buffers =0; n_buffers < FRAME_NUM; n_buffers++)
{
if(picnum ==(n_buffers+FRAME_NUM*loop))
return0;
//出队
buf.index = n_buffers;
ioctl(fd, VIDIOC_DQBUF,&buf);
//查看采集数据的时间戳之差,单位为微妙
buffers[n_buffers].timestamp = buf.timestamp.tv_sec*1000000+buf.timestamp.tv_usec; cur_time = buffers[n_buffers].timestamp;
extra_time = cur_time - last_time;
last_time = cur_time;
printf("time_deta:%lld\n\n",extra_time);
printf("buf_len:%d\n",buffers[n_buffers].length);
//处理数据只是简单写⼊⽂件,名字以loop的次数和帧缓冲数⽬有关
printf("grab image data OK\n");
memset(file_name,0,sizeof(file_name));
memset(index_str,0,sizeof(index_str));
sprintf(index_str,"%d",loop*4+n_buffers);
strcpy(file_name, picname);
strcat(file_name, index_str);
strcat(file_name,".jpg");
//strcat(file_name,".yuv");
FILE *fp2 =fopen(file_name,"wb");
if(!fp2)
{
printf("open %s error\n",file_name);
return(-1);
}
fwrite(buffers[n_buffers].start, IMAGEHEIGHT*IMAGEWIDTH*2,1,fp2);
fclose(fp2);
printf("save %s OK\n",file_name);
//⼊队循环
ioctl(fd, VIDIOC_QBUF,&buf);
}
loop--;
}
}
int close_camera()
{
unsigned int n_buffers;
enum v4l2_buf_type type;
//关闭流
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON,&type);
//关闭内存映射
for(n_buffers=0;n_buffers<FRAME_NUM;n_buffers++)
{
munmap(buffers[n_buffers].start,buffers[n_buffers].length);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论