基于V4L2驱动的摄像头应用程序开发.docx

上传人:b****9 文档编号:5901257 上传时间:2023-01-02 格式:DOCX 页数:9 大小:21.43KB
下载 相关 举报
基于V4L2驱动的摄像头应用程序开发.docx_第1页
第1页 / 共9页
基于V4L2驱动的摄像头应用程序开发.docx_第2页
第2页 / 共9页
基于V4L2驱动的摄像头应用程序开发.docx_第3页
第3页 / 共9页
基于V4L2驱动的摄像头应用程序开发.docx_第4页
第4页 / 共9页
基于V4L2驱动的摄像头应用程序开发.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

基于V4L2驱动的摄像头应用程序开发.docx

《基于V4L2驱动的摄像头应用程序开发.docx》由会员分享,可在线阅读,更多相关《基于V4L2驱动的摄像头应用程序开发.docx(9页珍藏版)》请在冰豆网上搜索。

基于V4L2驱动的摄像头应用程序开发.docx

基于V4L2驱动的摄像头应⽤程序开发

这⼏天在学习写⼀个基于v4l2的摄像头应⽤程序,⽹上找了很多资料和程序,终于成功的采集到了图像。

关于vl42的应⽤⽹上很多资料,我根据⾃⼰的理解总结了⼀下⾃⼰的学习成果。

⼀、相关数据结构:

参见include/linux/videodev2.h1、设备能⼒结构

structv4l2_capability{

u8 driver[16];

驱动名*/ /*

u8 card[32];

设备名*/ /*

u8 bus_info[32];设备在系统中/*的位置*/

u32 version;

驱动版本/*号*/

u32 capabilities;

设备能⼒,即/*设备⽀持的操作*/

u32 reserved[4];

保留字段*//*

};

structv4l2_fmtdesc{

u32 in要dex查;询的帧格式序号/*,由应⽤程序设置 */

enumv4l2_buf_typetype;

帧类型,/由*应⽤程序设置 */

u32 flags;

是否为压缩格式*//*

u8 descr格ipt式ion名[3称2];*/ /*

u32 pixel格for式mat;

*/ /*

u32 reserved[4];

};

2、数据格式结构structv4l2_format{

enumv4l2_buf_typetype;

帧类型,由//应⽤程序设置

union{

structv4l2_pix_format pix; /*V4L2_BUF_TYPE,_V视ID频EO设_C备A使PT⽤URE*/

structv4l2_window win; /*V4L2_BUF_TYPE_VIDEO_OVERLAY*/structv4l2_vbi_format vbi; /*V4L2_BUF_TYPE_VBI_CAPTURE*/

structv4l2_sliced_vbi_format sliced;/*V4L2_BUF_TYPE_SLICED_VBI_CAPTURE*/

u8 raw_data[200]; /*user-defined*/

}fmt;

};

3、像素格式结构structv4l2_pix_format{

u32 w宽idt度h; //

u32 height⾼;度 //

u32 pixelformat;

enumv4l2_field field;

帧格式 //

u32 bytesperline; /*forpadding,zeroifunused*/

u32 sizeimage;

enumv4l2_colorspace colorspace;

u32 priv; /*privatedata,dependsonpixelformat*/

};

4、请求缓冲

structv4l2_requestbuffers{

u32 c缓ou存nt数;量 //

enumv4l2_buf_type type;

数据流类型//

enumv4l2_memory memory;

u32 reserved[2];

};

5、数据流类型enumv4l2_buf_type{

V4L2_BUF_TYPE_VIDEO_CAPTURE =1,

V4L2_BUF_TYPE_VIDEO_OUTPUT =2,

V4L2_BUF_TYPE_VIDEO_OVERLAY =3,

V4L2_BUF_TYPE_VBI_CAPTURE =4,

V4L2_BUF_TYPE_VBI_OUTPUT =5,

V4L2_BUF_TYPE_SLICED_VBI_CAPTURE =6,

V4L2_BUF_TYPE_SLICED_VBI_OUTPUT =7,

#if1

/*Experimental*/V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY=8,

#endif

V4L2_BUF_TYPE_PRIVATE =0x80,

};

enumv4l2_memory{

V4L2_MEMORY_MMAP =1,

V4L2_MEMORY_USERPTR =2,

V4L2_MEMORY_OVERLAY =3,

};

命令标字

功能

VIDIOC_REQBUFS

申请缓存区

VIDIOC_QUERYBUF

把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址

VIDIOC_QUERYCAP

查询设备属性

VIDIOC_ENUM_FMT

获取当前驱动⽀持的视频格式

VIDIOC_S_FMT

设置当视频采集图像格式

VIDIOC_G_FMT

读取当视频采集图格式

VIDIOC_TRY_FMT

验证当前驱动的显⽰格式

VIDIOC_CROPCAP

查询设备的修剪能⼒

VIDIOC_S_CROP

设置视频信号的边框

VIDIOC_G_CROP

读取视频信号的边框

VIDIOC_QBUF

把数据从缓存区中读取出来

VIDIOC_DQBUF

把缓存区内存放回缓存队列

VIDIOC_STREAMON

开启视频采集

VIDIOC_STREAMOFF

结束视频采集

VIDIOC_QUERYSTD

检查当前视频采集设备⽀持的标准

⼆、ioctl命令字

三、成功运⾏的程序:

show.c

#include#include#include#include

#include

#include

#include#include#include#include#include#include#include#include#include

#include#include

#defineCLEAR(x)memset(&(x),0,sizeof(x))

//定义⼀个缓存结构体structbuffer

{

void*start; //空指针size_tlength; //长度⼤⼩

};

#defineCAPTURE_FILE"test.yuyv"

staticchar*dev_name=NULL; //设备名staticintfd=-1; //⽂件序列

staticstructbuffer*buffers=NULL; //缓存对象

staticunsignedintn_buffers=0; //缓存数

staticvoiderrno_exit(constchar*s) //错误输出

{

fprintf(stderr,"%serror%d,%s\n",s,errno,strerror(errno));exit(EXIT_FAILURE);

}

/*

staticvoidprocess_image(constvoid*p,size_tlength) //处理获取图像

{

//fputc('!

',stdout);

//fflush(stdout);

FILE*fp=fopen(CAPTURE_FILE,"a");

if(fp<0)

{

printf("openframedatafilefailed\n");exit(EXIT_FAILURE);

}

fwrite(p,length,1,fp);perror("fwriteerror");

fclose(fp);

fclose(fp);

printf("Captureoneframesavedin%s\n",CAPTURE_FILE);

}

*/

staticvoidread_frame(FILE*fp) //读取数据帧,⽤的都是mmap

{

structv4l2_bufferbuf;unsignedinti;

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;

if(-1==ioctl(fd,VIDIOC_DQBUF,&buf)) //读取errno_exit("VIDIOC_DQBUF");

fwrite(buffers[buf.index].start,buf.length,1,fp);

if(-1==ioctl(fd,VIDIOC_QBUF,&buf)) //放回缓存errno_exit("VIDIOC_QBUF");

}

staticvoidmainloop(void)

{

unsignedintcount;count=100;

FILE*fp=fopen(CAPTURE_FILE,"w");

if(fp<0)

{

printf("openframedatafilefailed\n");exit(EXIT_FAILURE);

}

while(count-->0)

{

read_frame(fp);

}

fclose(fp);

printf("Captureoneframesavedin%s\n",CAPTURE_FILE);

}

staticvoidstop_capturing(void)//停⽌捕获帧

{

enumv4l2_buf_typetype;

type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(-1==ioctl(fd,VIDIOC_STREAMOFF,&type))//关闭视频流errno_exit("VIDIOC_STREAMOFF");

printf("\nStreamOffsuccess!

\n");

}

staticvoidstart_capturing(void) //开始捕获帧

{

unsignedinti;

enumv4l2_buf_typetype;

enumv4l2_buf_typetype;

for(i=0;i

{

structv4l2_bufferbuf;

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;buf.index=i;

if(-1==ioctl(fd,VIDIOC_QBUF,&buf)) //放⼊缓存errno_exit("VIDIOC_QBUF");

}

type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(-1==ioctl(fd,VIDIOC_STREAMON,&type)) //打开视频流errno_exit("VIDIOC_STREAMON");

elseprintf("StreamOnsuccess!

\n");

}

staticvoiduninit_device(void) //释放存储空间

{

unsignedinti;

for(i=0;i

{

if(-1==munmap(buffers[i].start,buffers[i].length))errno_exit("munmap");

}

free(buffers);

}

staticvoidinit_mmap(void) //初始化读取⽅式

{

structv4l2_requestbuffersreq;

CLEAR(req);

req.count=2;

req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory=V4L2_MEMORY_MMAP;

if(-1==ioctl(fd,VIDIOC_REQBUFS,&req)) //分配内存

{

if(EINVAL==errno)

{

fprintf(stderr,"%sdoesnotsupportmemorymapping\n",dev_name);exit(EXIT_FAILURE);

}

else

errno_exit("VIDIOC_REQBUFS");

}

buffers=calloc(req.count,sizeof(*buffers)); //分配缓存if(!

buffers)

{

fprintf(stderr,"Outofmemory\n");exit(EXIT_FAILURE);

}

for(n_buffers=0;n_buffers

{

structv4l2_bufferbuf;

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;buf.index=n_buffers;

if(-1==ioctl(fd,VIDIOC_QUERYBUF,&buf))errno_exit("VIDIOC_QUERYBUF");

buffers[n_buffers].length=buf.length; //设置映射⽅式为mmap

buffers[n_buffers].start=mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);

if(MAP_FAILED==buffers[n_buffers].start)errno_exit("mmap");

}

}

staticvoidinit_device(void)//初始化设备

{

structv4l2_capabilitycap;structv4l2_formatfmt;unsignedintmin;

if(-1==ioctl(fd,VIDIOC_QUERYCAP,&cap))

{

if(EINVAL==errno)

{

fprintf(stderr,"%sisnoV4L2device\n",dev_name);

exit(EXIT_FAILURE);

}

else

errno_exit("VIDIOC_QUERYCAP");

}

if(!

(cap.capabilities&V4L2_CAP_VIDEO_CAPTURE))

{

fprintf(stderr,"%sisnovideocapturedevice\n",dev_name);exit(EXIT_FAILURE);

}

if(!

(cap.capabilities&V4L2_CAP_STREAMING))

{

fprintf(stderr,"%sdoesnotsupportstreamingi/o\n",dev_name);exit(EXIT_FAILURE);

exit(EXIT_FAILURE);

}

//

CLEAR(fmt); //设置帧格式

fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.width=640;

fmt.fmt.pix.height=480;

fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;fmt.fmt.pix.field=V4L2_FIELD_INTERLACED;

if(-1==ioctl(fd,VIDIOC_S_FMT,&fmt))errno_exit("VIDIOC_S_FMT");printf("Setframeformatsuccessful!

\n");init_mmap();

}

staticvoidclose_device(void) //关闭设备

{

if(-1==close(fd))errno_exit("close");fd=-1;

printf("Closethedevicesuccessful!

\n");

}

staticvoidopen_device(void) //打开设备

{

fd=open(dev_name,O_RDWR,0);if(-1==fd)

{

fprintf(stderr,"Cannotopen%s\n",dev_name);exit(EXIT_FAILURE);

}

printf("Openthe%ssuccessful\n",dev_name);

}

intmain(intargc,char*argv[])

{

dev_name="/dev/video0";

open_device();init_device();start_capturing();mainloop();stop_capturing();uninit_device();close_device();exit(EXIT_SUCCESS);

return0;

}

//---

Makefile编写:

KERNELDIR?

=/home/student/linux-2.6.32.2show:

show.c

gcc-I$(KERNELDIR)-o$@$^

clean:

rmshow

//

将摄像头直接连接到PC机的usb⼝,会在虚拟机linux下有检测到摄像头的提⽰,表⽰摄像头可以使⽤,然后make,./show就可以运⾏完毕

四、对上述show.c程序的说明

⽹上很多程序会把上述相关数据结构整合到⼀个⾃定义的数据结构中,我认为没有必要,因为核⼼是通过mmap映射后的指针,所以相关数据结构只需要函数中局部变量就⾏,没必要整成全局变量,⽽buffers则需要全局变量,便于使⽤。

show.c源程序中最重要的是buffers指针,在init_mmap()函数中,⾸先通过buffers=calloc(req.count,sizeof(*buffers));使它指向

count个内存空间,然后通过

buffers[n_buffers].length=buf.length; //设置映射⽅式为mmap

buffers[n_buffers].start=mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);

length的⼤⼩是640*480*2个字节,即⼀副图像⼤⼩。

将buffers和驱动层的缓存通过mmap联系起来,将驱动层的缓存映射到应⽤层。

最后通过read_frame()函数将buffers指向的地址数据写道fp中,fp指向"test.yuyv"

程序运⾏后会得到⼀个test.yuyv⽂件,通过samba服务器从虚拟机拷贝到Windows,⽤YUVViewer.exe软件打开,设置⼀下格式为

YUYV,640X480然后play即可。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 小学作文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1