Login
升级VIP 登录 注册 安全退出
当前位置: 首页 > word文档 > 其他文档 > 嵌入式Linux下Camera编程--V4L2

嵌入式Linux下Camera编程--V4L2

收藏

本作品内容为嵌入式Linux下Camera编程--V4L2,格式为 docx ,大小 30835 KB ,页数为 11页

嵌入式Linux下Camera编程--V4L2


('最近有个需求,要在ARMLinux上实现USBCamera拍照功能。0.背景知识:首先要确认的是,Kernel是否支持USBCamera。因为Linux下,USB协议除了电气协议和标准,还有很多Class。这些Class就是为了支持和定义某一类设备接口和交互数据格式。只要符合这类标准,则不同厂商的USB设备,不需要特定的driver就能在Linux下使用。例如:USBInputclass,则使所有输入设备都可以直接使用。还有类似AudioClass,PringClass,MassStorageClass,videoclass等。其中VideoClass就是我们常说的UVC(USBVideoClass).只要USBCamera符合UVC标准。理论上在2.6KernelLinux就可以正常使用。网络上有人谈到怎样判断是否UVCCamera设备:#lsusbBus001Device010:ID046d:0825Logitech,Inc.#lsusb-d046d:0825-vgrep"14Video"如果出现:bInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14VideobInterfaceClass14Video则说明是支持UVC.1.Kernel配置:DeviceDrivers---><>Multimediasupport--->VideoForLinuxDeviceDrivers---><>Multimediasupport--->[]Videocaptureadapters--->[]V4LUSBdevices--->USBVideoClass(UVC)---V4LUSBdevices:这里还有很多特定厂商的driver.可供选择。分析:"USBVideoClass(UVC)":对应的driver是:uvcvideo.ko"VideoForLinux":对应driver是:videodev.ko安装driver顺序如下:insmodv4l1_compat.koinsmodvideodev.koinsmoduvcvideo.kodriver会创建一个或多个主设备号为81,次设备号:0-255的设备。除了camera会创建为:/dev/videoX之外,还有VBI设备-/dev/vbiX.Radio设备--/dev/radioX.2.V4L2一些概念:2.1:VideoInputandOutput:videoinputandoutput是指device物理连接。只有video和VBIcapture拥有input.Radio设备则没有videoinput和output.2.2:VideoStandards:VideoDevice支持一个或多个Video标准。3.使用V4L2编程:使用V4L2(VideoforLinux2)API的过程大致如下:OpeningthedeviceChangingdeviceproperties,selectingavideoandaudioinput,videostandard,picturebrightnessa.o.NegotiatingadataformatNegotiatinganinput/outputmethodTheactualinput/outputloopClosingthedevice3.1:打开设备:fd=open("/dev/video0",O_RDWR,0);//以阻塞模式打开设想头3.2:查询设备能力:QueryingCapabilities:因为V4L2可以对多种设备编程,所以并不是所有API可以对所有设备编程,哪怕是同类型的设备,使用ioctl--VIDIOC_QUERYCAP去询问支持什么功能。structv4l2_capabilitycap;rel=ioctl(fdUsbCam,VIDIOC_QUERYCAP,&cap);if(rel!=0){perror("ioctlVIDIOC_QUERYCAP");return-1;}结构体如下:structv4l2_capability{__u8driver[16];__u8card[32];__u8bus_info[32];__u32version;__u32capabilities;__u32reserved[4];};这里面最重要的是:capabilities:头文件linux/videodev2.h和kernel头文件linux/videodev2.h中都有描述:#defineV4L2_CAP_VIDEO_CAPTURE0x00000001#defineV4L2_CAP_VIDEO_OUTPUT0x00000002#defineV4L2_CAP_VIDEO_OVERLAY0x00000004#defineV4L2_CAP_VBI_CAPTURE0x00000010#defineV4L2_CAP_VBI_OUTPUT0x00000020#defineV4L2_CAP_SLICED_VBI_CAPTURE0x00000040#defineV4L2_CAP_SLICED_VBI_OUTPUT0x00000080#defineV4L2_CAP_RDS_CAPTURE0x00000100#defineV4L2_CAP_VIDEO_OUTPUT_OVERLAY0x00000200#defineV4L2_CAP_HW_FREQ_SEEK0x00000400#defineV4L2_CAP_RDS_OUTPUT0x00000800#defineV4L2_CAP_TUNER0x00010000#defineV4L2_CAP_AUDIO0x00020000#defineV4L2_CAP_RADIO0x00040000#defineV4L2_CAP_MODULATOR0x00080000#defineV4L2_CAP_READWRITE0x01000000#defineV4L2_CAP_ASYNCIO0x02000000#defineV4L2_CAP_STREAMING0x04000000这里要说到VBI,VerticalBlankingInterval的缩写。电视信号包括一部分非可视信号,它不传送可视信息,因此被称为ⅦI(垂直消隐期间)。VBI可以用于传送其他信息,通常是一种专用字幕信号这和Blog重显率中所说暗合。在这里,V4L2_CAP_VIDEO_CAPTURE说明设备是个图像采集设备,V4L2_CAP_STREAMING说明是个Streaming设备。通常,摄像头都支持以上两个能力。3.3:查询当前捕获格式:memset(&fmt,0,sizeof(structv4l2_format));fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;if(ioctl(fdUsbCam,VIDIOC_G_FMT,&fmt)<0){printf("getformatfailed\\n");return-1;}注意,此处,fmt是个in/out参数。参见Kernel代码v4l2_ioctl.c中。此ioctl,它会首先判断fmt.type.type类型和含义如下:V4L2_BUF_TYPE_VIDEO_CAPTURE:vid-capV4L2_BUF_TYPE_VIDEO_OVERLAY:vid-overlayV4L2_BUF_TYPE_VIDEO_OUTPUT:vid-outV4L2_BUF_TYPE_VBI_CAPTURE:vbi-capV4L2_BUF_TYPE_VBI_OUTPUT:vbi-outV4L2_BUF_TYPE_SLICED_VBI_CAPTURE:sliced-vbi-capV4L2_BUF_TYPE_SLICED_VBI_OUTPUT:sliced-vbi-outV4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:vid-out-overlay咱们是使用VideoCam的。所以用V4L2_BUF_TYPE_VIDEO_CAPTUREstructv4l2_format{enumv4l2_buf_typetype;union{structv4l2_pix_formatpix;structv4l2_windowwin;structv4l2_vbi_formatvbi;structv4l2_sliced_vbi_formatsliced;__u8raw_data[200];}fmt;};我们得到的信息在v4l2_pix_format中。你可以看到,宽,高,像素格式。其中像素格式包括:#defineV4L2_PIX_FMT_RGB332v4l2_fourcc(\'R\',\'G\',\'B\',\'1\')#defineV4L2_PIX_FMT_RGB555v4l2_fourcc(\'R\',\'G\',\'B\',\'O\')#defineV4L2_PIX_FMT_RGB565v4l2_fourcc(\'R\',\'G\',\'B\',\'P\')#defineV4L2_PIX_FMT_RGB555Xv4l2_fourcc(\'R\',\'G\',\'B\',\'Q\')#defineV4L2_PIX_FMT_RGB565Xv4l2_fourcc(\'R\',\'G\',\'B\',\'R\')#defineV4L2_PIX_FMT_BGR24v4l2_fourcc(\'B\',\'G\',\'R\',\'3\')#defineV4L2_PIX_FMT_RGB24v4l2_fourcc(\'R\',\'G\',\'B\',\'3\')#defineV4L2_PIX_FMT_BGR32v4l2_fourcc(\'B\',\'G\',\'R\',\'4\')#defineV4L2_PIX_FMT_RGB32v4l2_fourcc(\'R\',\'G\',\'B\',\'4\')#defineV4L2_PIX_FMT_GREYv4l2_fourcc(\'G\',\'R\',\'E\',\'Y\')#defineV4L2_PIX_FMT_YVU410v4l2_fourcc(\'Y\',\'V\',\'U\',\'9\')#defineV4L2_PIX_FMT_YVU420v4l2_fourcc(\'Y\',\'V\',\'1\',\'2\')#defineV4L2_PIX_FMT_YUYVv4l2_fourcc(\'Y\',\'U\',\'Y\',\'V\')#defineV4L2_PIX_FMT_UYVYv4l2_fourcc(\'U\',\'Y\',\'V\',\'Y\')#defineV4L2_PIX_FMT_YUV422Pv4l2_fourcc(\'4\',\'2\',\'2\',\'P\')#defineV4L2_PIX_FMT_YUV411Pv4l2_fourcc(\'4\',\'1\',\'1\',\'P\')#defineV4L2_PIX_FMT_Y41Pv4l2_fourcc(\'Y\',\'4\',\'1\',\'P\')#defineV4L2_PIX_FMT_NV12v4l2_fourcc(\'N\',\'V\',\'1\',\'2\')#defineV4L2_PIX_FMT_NV21v4l2_fourcc(\'N\',\'V\',\'2\',\'1\')#defineV4L2_PIX_FMT_YUV410v4l2_fourcc(\'Y\',\'U\',\'V\',\'9\')#defineV4L2_PIX_FMT_YUV420v4l2_fourcc(\'Y\',\'U\',\'1\',\'2\')#defineV4L2_PIX_FMT_YYUVv4l2_fourcc(\'Y\',\'Y\',\'U\',\'V\')#defineV4L2_PIX_FMT_HI240v4l2_fourcc(\'H\',\'I\',\'2\',\'4\')#defineV4L2_PIX_FMT_HM12v4l2_fourcc(\'H\',\'M\',\'1\',\'2\')#defineV4L2_PIX_FMT_SBGGR8v4l2_fourcc(\'B\',\'A\',\'8\',\'1\')#defineV4L2_PIX_FMT_MJPEGv4l2_fourcc(\'M\',\'J\',\'P\',\'G\')#defineV4L2_PIX_FMT_JPEGv4l2_fourcc(\'J\',\'P\',\'E\',\'G\')#defineV4L2_PIX_FMT_DVv4l2_fourcc(\'d\',\'v\',\'s\',\'d\')#defineV4L2_PIX_FMT_MPEGv4l2_fourcc(\'M\',\'P\',\'E\',\'G\')#defineV4L2_PIX_FMT_WNVAv4l2_fourcc(\'W\',\'N\',\'V\',\'A\')#defineV4L2_PIX_FMT_SN9C10Xv4l2_fourcc(\'S\',\'9\',\'1\',\'0\')#defineV4L2_PIX_FMT_PWC1v4l2_fourcc(\'P\',\'W\',\'C\',\'1\')#defineV4L2_PIX_FMT_PWC2v4l2_fourcc(\'P\',\'W\',\'C\',\'2\')#defineV4L2_PIX_FMT_ET61X251v4l2_fourcc(\'E\',\'6\',\'2\',\'5\')fxxk,真TNND多。请注意,此时取到的宽,高,像素格式均正确。但不知为何,bytesperline却为0。3.4:设置当前捕获格式fmt.fmt.pix.width=640;fmt.fmt.pix.height=480;fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;rel=ioctl(fdUsbCam,VIDIOC_S_FMT,&fmt);if(rel<0){printf("\\nSetformatfailed\\n");return-1;}此时,再取当前捕获格式,则一切正常。包括bytesperline3.5:读取Stream设置。structv4l2_streamparmsetfps;setfps=(structv4l2_streamparm)calloc(1,sizeof(structv4l2_streamparm));memset(setfps,0,sizeof(structv4l2_streamparm));setfps->type=V4L2_BUF_TYPE_VIDEO_CAPTURE;rel=ioctl(fdUsbCam,VIDIOC_G_PARM,setfps);if(rel==0){printf("\\nFramerate:%u/%u\\n",setfps->parm.capture.timeperframe.denominator,setfps->parm.capture.timeperframe.numerator);}else{perror("Unabletoreadoutcurrentframerate");return-1;}注意:ioctl(fdUsbCam,VIDIOC_G_PARM,setfps);参数3也是i/o参数。必须要首先其type.structv4l2_streamparm{enumv4l2_buf_typetype;union{structv4l2_captureparmcapture;structv4l2_outputparmoutput;__u8raw_data[200];}parm;};type字段描述的是在涉及的操作的类型。对于视频捕获设备,应该为V4L2_BUF_TYPE_VIDEO_CAPTURE。对于输出设备应该为V4L2_BUF_TYPE_VIDEO_OUTPUT。它的值也可以是V4L2_BUF_TYPE_PRIVATE,在这种情况下,raw_data字段用来传递一些私有的,不可移植的,甚至是不鼓励的数据给内核。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,V4L2_BUF_TYPE_PRIVATE=0x80,};咱们当然选用V4L2_BUF_TYPE_VIDEO_CAPTURE对于捕获设备而言,parm.capture字段是要关注的内容,这个结构体如下:structv4l2_captureparm{__u32capability;__u32capturemode;structv4l2_fracttimeperframe;__u32extendedmode;__u32readbuffers;__u32reserved[4];};timeperframe字段用于指定想要使用的帧频率,它又是一个结构体:structv4l2_fract{__u32numerator;__u32denominator;};numerator和denominator所描述的系数给出的是成功的帧之间的时间间隔。numerator分子,denominator分母。主要表达每次帧之间时间间隔。numerator/denominator秒一帧。3.6:设置Stream参数。(主要是采集帧数)setfps->parm.capture.timeperframe.numerator=1;setfps->parm.capture.timeperframe.denominator=60;rel=ioctl(fdUsbCam,VIDIOC_S_PARM,setfps);if(rel!=0){printf("\\nUnabletoSetFPS");return-1;}当然,setfps的其它项目,都是之前使用VIDIOC_G_PARM取得的。3.7:创建一组缓冲区(buf)structv4l2_requestbuffersrb;memset(&rb,0,sizeof(structv4l2_requestbuffers));rb.count=3;rb.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;rb.memory=V4L2_MEMORY_MMAP;rel=ioctl(fdUsbCam,VIDIOC_REQBUFS,&rb);if(rel<0){printf("Unabletoallocatebuffers:%d.\\n",errno);return-1;}其中参数rb为:structv4l2_requestbuffers:structv4l2_requestbuffers{__u32count;enumv4l2_buf_typetype;enumv4l2_memorymemory;__u32reserved[2];};type字段描述的是完成的I/O操作的类型。通常它的值要么是视频获得设备的V4L2_BUF_TYPE_VIDEO_CAPTURE,要么是输出设备的V4L2_BUF_TYPE_VIDEO_OUTPUTstructv4l2_memory:enumv4l2_memory{V4L2_MEMORY_MMAP=1,V4L2_MEMORY_USERPTR=2,V4L2_MEMORY_OVERLAY=3,};想要使用内存映谢的缓冲区,它将会把memory字段置为V4L2_MEMORY_MMAP,count置为它想要使用的缓冲区的数目。顺便看看USBTOSerail:DeviceDrivers--->[]USBsupport--->USBSerialConvertersupport--->USBProlific2303SinglePortSerialDriverUSBProlific2303SinglePortSerialDriver是指出支持pl2303芯片的USB2serial.pl2303.koUSBSerialConvertersupport是基础driver.对应usbserial.ko注1:ioctl中常用的cmd.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:检查当前视频设备支持的标准,例如PAL或NTSC。VIDIOC_G_PARM:得到Stream信息。如帧数等。VIDIOC_S_PARM:设置Stream信息。如帧数等。注2:如何判断某ioctlcmd所用参数类型:例如:ioctl-cmd:VIDIOC_QUERYCAP.它的返回参数类型ioctl(fd,cmd,参数)。首先想到的是从kernelSourcev4l2_ioctl.c中看。但这比较麻烦,又个简单办法:可以在video2dev.h中看到:#defineVIDIOC_QUERYCAP_IOR(\'V\',0,structv4l2_capability)即使用cmd为VIDIOC_QUERYCAP时,参数为structv4l2_capability',)


  • 编号:1700774499
  • 分类:其他文档
  • 软件: wps,office word
  • 大小:11页
  • 格式:docx
  • 风格:商务
  • PPT页数:30835 KB
  • 标签:

广告位推荐

相关其他文档更多>