V4L2应用程序详解
v4l2框架流程
v4l2框架流程
v4l2(Video For Linux 2)框架是Linux系统中用于处理视频设备的框架,包括了视频设备的控制、图像采集、图像输出等功能。
v4l2框架的流程如下:
1. 驱动初始化:在Linux系统启动时,v4l2框架会初始化其对于视频设备的驱动程序,包括找到设备、设备的分配和配置等。
2. 应用程序打开设备:应用程序需要使用摄像头或其他视频设备时,会使用v4l2的API打开设备进行访问。
3. 设备控制:应用程序对于视频设备进行管控,包括设备的各种设置,如视频格式、帧率等。
4. 图像采集:当视频设备开始采集图像时,v4l2框架会将图像数据传输到应用程序缓冲区。
5. 应用程序处理数据:应用程序从缓冲区中读取图像数据,可以对图像数据进行处理、展示或保存等。
6. 图像输出:当应用程序想要将图像数据输出到设备上,v4l2框架会将图像数据传送到设备的缓冲区。
7. 设备关闭:应用程序使用完设备后,会关闭设备以释放资源。
总的来说,v4l2框架主要涉及到设备的初始化、控制、数据传输等过程,通过对不同视频设备的控制,获取和处理设备所采集的图像数据,并在需要的时候进行输出。
v4l2controller 用法
v4l2controller 是一个用于控制视瓶设备的命令行工具,可以通过该工具来设置视瓶设备的参数、捕获视瓶数据、控制视瓶设备的属性等。
v4l2controller 主要用于 Linux 系统下的视瓶设备,如摄像头、视瓶采集卡等。
一、安装 v4l2controller1. 在终端中输入以下命令安装 v4l2controller:```sudo apt-get install v4l2-ctl```2. 安装完成后,可以通过以下命令来验证 v4l2controller 是否安装成功:```v4l2-ctl --version```二、查看视瓶设备的信息1. 使用以下命令可以列出系统中所有的视瓶设备:```v4l2-ctl --list-devices```2. 通过以下命令可以查看指定视瓶设备的详细信息:```v4l2-ctl -d /dev/video0 --all```三、设置视瓶设备的参数1. 设置视瓶设备的分辨率:```v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=1 ```2. 设置视瓶设备的帧率:```v4l2-ctl -d /dev/video0 --set-parm=30```3. 设置视瓶设备的曝光模式:```v4l2-ctl -d /dev/video0 --set-ctrl=exposure=100```四、捕获视瓶数据1. 使用以下命令可以捕获视瓶设备的实时视瓶数据,并保存为文件:```v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=100 --stream-to=test.yuv```2. 查看捕获的视瓶数据的详细信息:```v4l2-ctl --stream-to=test.yuv --stream-status```五、控制视瓶设备的属性1. 设置视瓶设备的亮度值:```v4l2-ctl -d /dev/video0 --set-ctrl=brightness=50 ```2. 调整视瓶设备的对比度:```v4l2-ctl -d /dev/video0 --set-ctrl=contrast=80 ```3. 关闭视瓶设备的自动白平衡:```v4l2-ctl -d /dev/video0 --set-ctrl=white_balance_temperature_auto=0```六、其他常用命令1. 查看视瓶设备支持的视瓶格式:```v4l2-ctl -d /dev/video0 --list-formats```2. 查看视瓶设备支持的帧率范围:```v4l2-ctl -d /dev/video0 --list-framesizes```3. 重置视瓶设备的所有参数为默认值:```v4l2-ctl -d /dev/video0 --all=default```通过上述介绍,相信读者已经对 v4l2controller 的用法有了初步的了解。
V4L2驱动的移植与应用(三)
三、V4L2的democapture.c是官方示例程序。
capture.c 程序中的process_image 函数:capture.c 程序主要是用来演示怎样使用v4l2 接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用process_image 函数表示了处理图像的代码位置。
process_image 函数只有一个参数,就是存储视频帧的内存的地址指针,但是在真正的应用中,通常还需要知道该指针指向的数据的大小。
因此可以修改函数,改成void process_image ( const void * p, int len ) ,但是每次调用process_image 的时候,第 2 个参数该传递什么值?考虑到程序中对buffer 的定义struct buffer {void * start;size_t length};如果将buffer.length 作为第 2 个参数传递到修改后的process_image 函数中,这样做是不正确的。
process_image 需要的第二个参数应该是每帧图像的大小,仔细阅读代码后会发现,buffer.length 并不一定就等于图像帧的大小。
(buffer 的大小,还需要考虑其他的一些因素,比如内存对齐等)。
capture.c只是一个示例程序,仅仅是演示怎样使用v4l2中最基本的接口。
尤其是在main函数中的那几个函数调用,表明了在使用v4l2时的最基本的一个流程,包括open_device,init_device,start_capturing,mainloop,stop_capturing,uninit_device,close_device。
在写程序的时候,可以充分的利用这几个基本模块,把他们分散在不同的代码位置上,灵活的调用,有兴趣的可以看一下gstreamer 中v4l2src的源代码或者其他的大型程序的相关部分。
总之一句话,capture.c仅仅是一个演示程序,不要局限于它的代码结构,要灵活的使用。
v4l2loopback-ctl用法
文章标题:深度探讨v4l2loopback-ctl的用法及应用在今天的文章中,我们将更深入地探讨v4l2loopback-ctl的用法及应用。
v4l2loopback-ctl是一个非常有用的工具,它可以帮助我们在Linux系统下创建虚拟视频设备,并且可以对这些虚拟设备进行一些配置和控制。
通过对v4l2loopback-ctl的深入了解,我们可以更好地利用它为我们的工作和学习带来便利。
下面,让我们一起来深入探讨v4l2loopback-ctl的用法及应用。
1. v4l2loopback-ctl的基本概念让我们回顾一下v4l2loopback-ctl的基本概念。
v4l2loopback-ctl是一个基于V4L2(Video for Linux 2)框架的工具,它可以用来创建虚拟视频设备,并且可以通过命令行对这些虚拟设备进行配置和控制。
通过v4l2loopback-ctl,我们可以模拟出多个虚拟摄像头,这些虚拟摄像头可以被应用于视频会议、视频录制、视频流等各种场景中。
2. v4l2loopback-ctl的安装和基本用法接下来,让我们来了解一下v4l2loopback-ctl的安装和基本用法。
我们需要在Linux系统中安装v4l2loopback-ctl的相关软件包,可以通过apt-get或者yum等包管理工具进行安装。
安装完成后,我们可以使用v4l2loopback-ctl命令来创建虚拟视频设备,并且可以通过参数来配置这些虚拟设备的分辨率、帧率、格式等属性。
3. v4l2loopback-ctl的高级用法及应用场景除了基本的用法之外,v4l2loopback-ctl还有一些高级的用法和应用场景。
我们可以通过v4l2loopback-ctl将实际摄像头的视频流导入到虚拟设备中,从而实现视频流的转发和分发。
另外,我们还可以通过v4l2loopback-ctl将虚拟设备的视频流导出到网络,实现远程视频监控的功能。
V4L2(video 4 linux 2)视频采集接口使用说明
V4L2(video 4 linux 2)视频采集接口使用说明主要功能:使程序有发觉设备的能力和操作设备.它主要是用过一系列的回调函数来实现这些功能.像设置高频头的频率,帧频,视频格式和图像像参数等等(在我写的FM驱动中就主要是设置频率,设置音量等)可以支持多种设备,它可以有以下几种接口: 1. 视频采集接口(veo capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的. 2. 视频输出接口(video output interface):可以驱动计算机的外围视频图像设备--像可以输出电视信号格式的设备. 3. 挺直传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号挺直输出到输出设备之上,而不用经过系统的CPU.4. 视频间隔消隐信号接口(VBI interface):它可以使应用可以拜访传输消隐期的视频信号. 5. 收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流.(因为只写过FM 的驱动所以下面着重讲解这种应用.)一,什么是video4linuxVideo4linux(简称V4L),是linux中关于视频设备的内核驱动,现在已有Video4linux2,还未加入linux内核,用法需自己下载补丁。
在Linux中,视频设备是设备文件,可以像拜访一般文件一样对其举行读写,摄像头在/dev/videoN下,N可能为0,1,2,3... 普通0. 另,推举一个用于播放从摄像头采集到的raw数据的播放器RawPlayer,只需要把采集的数据保存到文件***.yuv就OK了。
二,V4L2采集视频流程 1. 打开设备文件。
int fd=open(”/dev/video0″,O_RDWR);2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。
V4L2讲解学习
一,功能参考目录V4L2 close()- 关闭一个V4L2设备V4L2 ioctl()- 创建的V4L2设备ioctl VIDIOC_CROPCAP - 视频裁剪和缩放功能信息ioctl VIDIOC_DBG_G_REGISTER,VIDIOC_DBG_S_REGISTER - 读或写硬件注册表ioctl VIDIOC_ENCODER_CMD,VIDIOC_TRY_ENCODER_CMD - 执行编码器命令ioctl VIDIOC_ENUMAUDIO - 枚举音频输入ioctl VIDIOC_ENUMAUDOUT - 枚举音频输出ioctl VIDIOC_ENUM_FMT - 枚举图像格式ioctl VIDIOC_ENUM_FRAMESIZES - 枚举外形尺寸ioctl VIDIOC_ENUM_FRAMEINTERVALS - 枚举帧间隔ioctl VIDIOC_ENUMINPUT - 枚举视频输入ioctl VIDIOC_ENUMOUTPUT - 枚举视频输出ioctl VIDIOC_ENUMSTD - 枚举支持的视频标准ioctl VIDIOC_G_AUDIO,VIDIOC_S_AUDIO - 查询或选择当前的音频输入和它的属性ioctl VIDIOC_G_AUDOUT,VIDIOC_S_AUDOUT - 查询或选择当前的音频输出ioctl VIDIOC_G_CHIP_IDENT –识别电视卡的芯片ioctl VIDIOC_G_CROP,VIDIOC_S_CROP - 获取或设置当前裁剪矩形ioctl VIDIOC_G_CTRL,VIDIOC_S_CTRL - 获取或设置控件的值ioctl VIDIOC_G_ENC_INDEX - 获取关于压缩视频流的元数据ioctl VIDIOC_G_EXT_CTRLS,VIDIOC_S_EXT_CTRLS,VIDIOC_TRY_EXT_CTRLS - 获取或设置控件的值数,尽量控制值ioctl VIDIOC_G_FBUF,VIDIOC_S_FBUF - 获取或设置参数帧缓冲区覆盖ioctl VIDIOC_G_FMT,VIDIOC_S_FMT,VIDIOC_TRY_FMT - 获取或设置数据格式,试验格式ioctl VIDIOC_G_FREQUENCY,VIDIOC_S_FREQUENCY - 获取或设置调谐器或射频调制器ioctl VIDIOC_G_INPUT,VIDIOC_S_INPUT - 查询或选择当前视频输入ioctl VIDIOC_G_JPEGCOMP,VIDIOC_S_JPEGCOMP -ioctl VIDIOC_G_MODULATOR,VIDIOC_S_MODULATOR - 调制器,获取或设置属性ioctl VIDIOC_G_OUTPUT,VIDIOC_S_OUTPUT - 查询或选择当前视频输出ioctl VIDIOC_G_PARM,VIDIOC_S_PARM - 获取或设置流参数ioctl VIDIOC_G_PRIORITY,VIDIOC_S_PRIORITY - 查询或要求访问的优先级与文件描述符关联ioctl VIDIOC_G_SLICED_VBI_CAP - 查询切片的VBI功能ioctl VIDIOC_G_STD,VIDIOC_S_STD - 查询或选择当前输入视频标准ioctl VIDIOC_G_TUNER,VIDIOC_S_TUNER - 获取或设置调谐器属性ioctl VIDIOC_LOG_STATUS - 记录驱动程序的状态信息ioctl VIDIOC_OVERLAY - 启动或停止视频覆盖ioctl VIDIOC_QBUF,VIDIOC_DQBUF - 交流与驱动程序缓冲区ioctl VIDIOC_QUERYBUF - 查询一个缓冲区的状态ioctl VIDIOC_QUERYCAP - 查询设备的功能ioctl VIDIOC_QUERYCTRL,VIDIOC_QUERYMENU - 枚举控制和菜单控制项目ioctl VIDIOC_QUERYSTD –识别由目前的输入接收的视频标准ioctl VIDIOC_REQBUFS - 启动用户指针或内存映射的I / Oioctl VIDIOC_STREAMON,VIDIOC_STREAMOFF - 启动或停止流I / OV4L2 mmap()- 映射设备内存到应用程序的地址空间V4L2 munmap()- 取消映射设备内存V4L2 open()- 打开的V4L2设备V4L2调查()- 等待某些事件对一个文件描述符V4L2阅读()- 读取V4L2设备V4L2选择()- 同步I / O复用V4L2写()- 写入V4L2设备V4L2 close()名称V4L2 的关闭- 关闭一个V4L2设备概要#include <unistd.h>int close(int fd);fd打开()返回的文件描述符。
V4L2视频采集程序框架
V4L2应用程序框架V4L2较V4L有较大的改动,并已成为2.6的标准接口,函盖video\dvb\FM...,多数驱动都在向V4l2迁移。
更好地了解V4L2先从应用入手,然后再深入到内核中结合物理设备/接口的规范实现相应的驱动。
本文先就V4L2在视频捕捉或camera方面的应用框架。
V4L2采用流水线的方式,操作更简单直观,基本遵循打开视频设备、设置格式、处理数据、关闭设备,更多的具体操作通过ioct l函数来实现。
1.打开视频设备在V4L2中,视频设备被看做一个文件。
使用open函数打开这个设备:// 用非阻塞模式打开摄像头设备int cameraFd;cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);// 如果用阻塞模式打开摄像头设备,上述代码变为://cameraFd = open("/dev/video0", O_RDWR, 0);应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。
2. 设定属性及采集方式打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。
这一步是可选的。
在Linux编程中,一般使用ioctl 函数来对设备的I/O通道进行管理:int ioctl (int __fd, unsigned long int __request, .../*args*/) ;在进行V4L2开发中,常用的命令标志符如下(some are optional):∙VIDIOC_REQBUF S:分配内存∙VIDIOC_QUERYBUF:把VIDIOC_REQBUF S中分配的数据缓存转换成物理地址∙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。
Linux摄像头V4L2编程
一、摘要在Linux操作系统下,摄像头的工作都要遵循V4L2的机制,下面介绍如何从无到有,编写代码去使能摄像头拍照。
使用V4L2基本上就是使用内核提供的函数接口,填充相应的函数,主要依靠ioctl()函数填充函数域,然后按照一定操作顺序(工作流程),就能拍照了。
二、操作顺序(工作流程)前奏:1、打开USB摄像头设备文件2、获取驱动信息(VIDIOC_QUERYCAP)3、设置图像格式(VIDIOC_S_FMT)帧缓冲:4、申请帧缓冲(VIDIOC_REQBUFS)5、获取帧缓冲地址长度信息(VIDIOC_QUERYBUF)6、使用mmap吧内核空间的帧缓冲映射到用户空间7、帧缓冲入队列8、开始采集图像(VIDIOC_STREAMON)9、取出帧缓冲(VIDIOC_DQBUF)10、访问帧缓冲(可以读写操作等等)11、帧缓冲入队列,重新入队(VIDIOC_QBUF)写代码的时候按照这个编写就行了。
如果用在嵌入式板子上,只用交叉编译以后就能用了#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>struct buffer {void * start;size_t length;};struct buffer *buffers;unsigned long n_buffers;unsigned long file_length;int file_fd;char *dev_name = "/dev/video3"; //这是我摄像头节点,根据自己的节点填写int fd;static int read_frame (void){struct v4l2_buffer buf;/*帧出列*/buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;ioctl (fd, VIDIOC_DQBUF, &buf);write(file_fd,buffers[buf.index].start,buffers[buf.index].length);/*buf入列*/ioctl(fd, VIDIOC_QBUF, &buf);return 1;}int main (int argc,char ** argv){struct v4l2_capability cap;struct v4l2_format fmt;struct v4l2_requestbuffers req;struct v4l2_buffer buf;unsigned int i;enum v4l2_buf_type type;file_fd = open("test.jpg", O_RDWR | O_CREAT, 0777); //用来保存图片 fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);/*获取驱动信息*/ioctl (fd, VIDIOC_QUERYCAP, &cap); //驱动信息保存在cap结构体printf("Driver Name:%s/n Card Name:%s/n Businfo:%s/n/n",cap.driver,cap.card,cap.bus_info);/*设置图像格式*/fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //这是设置传输流类型fmt.fmt.pix.width = 320; //设置分辨率fmt.fmt.pix.height = 240;fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //图像格式,此处是jpg ioctl (fd, VIDIOC_S_FMT, &fmt) ;/*申请图像缓冲区*/req.count = 4;req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;ioctl (fd, VIDIOC_REQBUFS, &req);buffers = calloc (req.count, sizeof (*buffers));for (n_buffers = 0; n_buffers < req.count; ++n_buffers){/*获取图像缓冲区的信息*/buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = n_buffers;ioctl (fd, VIDIOC_QUERYBUF, &buf);buffers[n_buffers].length = buf.length;// 把内核空间中的图像缓冲区映射到用户空间buffers[n_buffers].start = mmap (NULL , //通过mmap建立映射关系buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED ,fd,buf.m.offset);}/*图像缓冲入队*/for (i = 0; i < n_buffers; ++i){buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;ioctl (fd, VIDIOC_QBUF, &buf);}//开始捕捉图像数据type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ioctl (fd, VIDIOC_STREAMON, &type);fd_set fds;FD_ZERO (&fds);FD_SET (fd, &fds);select(fd + 1, &fds, NULL, NULL, NULL);/*读取一幅图像*/read_frame();for (i = 0; i < n_buffers; ++i)munmap (buffers[i].start, buffers[i].length);close (fd);close (file_fd);printf("Camera Done./n");return 0;}。
v4l2 框架流程
v4l2 框架流程
1. 应用程序初始化
- 打开视频设备文件 (`/dev/video*`)
- 查询设备功能和能力
- 设置视频捕获参数
2. 分配缓冲区
- 使用 `mmap` 或 `userptr` 分配缓冲区
- 将缓冲区排队以便视频流传输到这些缓冲区3. 启动视频捕获
- 发出 `VIDIOC_STREAMON` 请求开始视频捕获4. 从缓冲区中获取帧数据
- 使用 `select()` 或 `poll()` 等待帧可用
- 通过从缓冲区队列中取出缓冲区来获取帧数据 - 处理帧数据(解码、渲染等)
- 将已用缓冲区重新排队以供视频设备使用5. 停止视频捕获
- 发出 `VIDIOC_STREAMOFF` 请求停止视频捕获
6. 释放资源
- 解除映射缓冲区
- 关闭视频设备文件
这个流程概括了使用v4l2 框架进行视频捕获的一般步骤。
具体的实现细节可能因硬件和软件环境的不同而有所变化。
V4L2超详细讲解
本文内容主要来源于网络1. 定义V4L2(Video For Linux Two) 是内核提供应应用程序访问音、视频驱动的统一接口。
2. 工作流程:打开设备-> 检查和设置设备属性-> 设置帧格式-> 设置一种输入输出方法〔缓冲区管理〕-> 循环获取数据-> 关闭设备。
3. 设备的打开和关闭:#include <ftl.h>int open(constchar *device_name, int flags);#include <unistd.h>int clo se(int fd);例:int fd=open(“/dev/video0〞,O_RDWR); // 打开设备close(fd); // 关闭设备注意:V4L2 的相关定义包含在头文件<linux/videodev2.h> 中.4. 查询设备属性:VIDIOC_QUERYCAP相关函数:int ioctl(int fd, int request, struct v4l2_capability *argp);相关结构体:struct v4l2_capability{u8 driver[16]; // 驱动名字u8 card[32]; // 设备名字u8 bus_info[32]; // 设备在系统中的位置u32 version; // 驱动版本号u32 capabilities; // 设备支持的操作u32 reserved[4]; // 保存字段};capabilities 常用值:V4L2_CAP_VIDEO_CAPTURE // 是否支持图像获取例:显示设备信息struct v4l2_capability cap;ioctl(fd,VIDIOC_QUERYCAP,&cap);printf(“Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n〞,cap.driver,cap.card,cap.bus_info,(cap.version>>1 6)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF);5. 设置视频的制式和帧格式制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
v4l2-ctl 常用参数
v4l2-ctl 常用参数摄像头是现代电子设备中的重要组成部分,广泛应用于视频通信、图像采集等领域。
在Linux系统中,v4l2-ctl是一个常用的命令行工具,用于控制和配置视频 4 Linux 2(V4L2)设备的参数。
本文将介绍v4l2-ctl的常用参数,并详细说明它们的用途和配置方法。
1. --list-devices:列出系统中的视频设备列表该参数用于列出系统中所有可用的视频设备,包括摄像头和视频采集卡等。
通过执行命令`v4l2-ctl --list-devices`,可以查看系统中所有视频设备的名称和路径。
这对于多个摄像头的选择和配置非常有用。
2. --list-formats:列出设备支持的视频格式该参数用于列出指定视频设备所支持的视频格式。
通过执行命令`v4l2-ctl --list-formats -d /dev/video0`,可以查看摄像头支持的视频格式和对应的分辨率。
这对于选择合适的视频格式和配置摄像头的分辨率非常重要。
3. --set-fmt-video:设置视频格式和分辨率该参数用于设置视频设备的视频格式和分辨率。
例如,执行命令`v4l2-ctl --set-fmt-video=width=1280,height=720,pixelformat=YUYV -d /dev/video0`可以将摄像头的视频格式设置为YUYV,并将分辨率设置为1280x720。
通过调整视频格式和分辨率,可以满足不同应用场景的需求。
4. --set-ctrl:设置设备的控制参数该参数用于设置视频设备的各种控制参数,如对比度、亮度、饱和度等。
通过执行命令`v4l2-ctl --set-ctrl=brightness=100 -d /dev/video0`,可以将摄像头的亮度设置为100。
通过调整控制参数,可以改善图像质量和适应不同的环境条件。
5. --get-ctrl:获取设备的控制参数该参数用于获取视频设备的各种控制参数的当前值。
嵌入式Linux下Camera编程--V4L2
最近有个需求,要在ARM Linux上实现USB Camera 拍照功能。
0. 背景知识:首先要确认的是,Kernel是否支持USB Camera。
因为Linux下,USB协议除了电气协议和标准,还有很多Class。
这些Class就是为了支持和定义某一类设备接口和交互数据格式。
只要符合这类标准,则不同厂商的USB设备,不需要特定的driver就能在Linux下使用。
例如:USB Input class,则使所有输入设备都可以直接使用。
还有类似Audio Class,Pring Class,Ma ss Storage Class,video class等。
其中Video Class 就是我们常说的UVC(USB Video Class). 只要USB Camera符合UVC标准。
理论上在2.6 Kernel Linux 就可以正常使用。
网络上有人谈到怎样判断是否UVC Camera设备:#lsusbBus 001 Device 010: ID 046d:0825 Logitech, Inc.#lsusb -d 046d:0825 -v | grep "14 Video"如果出现:bInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 VideobInterfaceClass 14 Video则说明是支持UVC.1. Kernel配置:Device Drivers ---> <*> Multimedia support ---> <M> Video For LinuxDevice Drivers ---> <*> Multimedia support ---> [*] Video captureadapters ---> [*] V4L USB devices ---> <M> USB Video Class (UVC)--- V4L USB devices : 这里还有很多特定厂商的driver.可供选择。
V4L2简介
V4L2简介V4L2 简介2011-03-15 16:41:55| 分类: android相关 |字号订阅1.什么是video4linuxVideo4linux(简称V4L),是linux中关于视频设备的内核驱动,现在已有Video4linux2,还未加入linux内核,使用需自己下载补丁。
在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。
2.Video4linux下视频编程的流程(1)打开视频设备:(2)读取设备信息(3)更改设备当前设置(没必要的话可以不做)(4)进行视频采集,两种方法:a.内存映射b.直接从设备读取(5)对采集的视频进行处理(6)关闭视频设备。
为程序定义的数据结构typedef struct v4l_struct{int fd;struct video_capability capability;struct video_channel channel[4];struct video_picture picture;struct video_window window;struct video_capture capture;struct video_buffer buffer;struct video_mmap mmap;struct video_mbuf mbuf;unsigned char *map;int frame;int framestat[2];}vd;3.Video4linux支持的数据结构及其用途(1) video_capability 包含设备的基本信息(设备名称、支持的最大最小分辨率、信号源信息等),包含的分量:name[32] //设备名称maxwidth ,maxheight,minwidth,minheightChannels //信号源个数type //是否能capture,彩色还是黑白,是否能裁剪等等。
v4l2 userptr 例子
v4l2 userptr 例子在视频处理领域,v4l2 userptr 是一个重要的概念。
它主要用于在Linux 系统中处理视频数据,能够实现高效的内存管理和数据传输。
本文将以 v4l2 userptr 为主题,介绍其基本概念和实际应用例子。
一、v4l2 userptr 的基本概念1.1 什么是 v4l2 userptr?v4l2 userptr 是Video4Linux2(V4L2)框架中的一个重要组成部分,用于在用户空间和内核空间之间传递视频数据。
通过使用 userptr,用户空间的应用程序可以直接访问内核缓冲区中的视频数据,避免了数据的复制和额外的内存分配操作,从而提高了数据传输的效率。
1.2 v4l2 userptr 的工作原理当应用程序需要获取视频数据时,它可以通过调用相应的V4L2 接口,将视频数据的指针传递给内核空间。
内核空间会通过 userptr 指针访问用户空间的数据,然后将数据传输到设备中。
这样一来,用户空间和内核空间之间就实现了高效的数据传输,避免了数据的复制和额外的内存分配操作。
1.3 v4l2 userptr 的优点使用 v4l2 userptr 有以下几个优点:(1)减少数据传输的开销:由于用户空间和内核空间之间直接访问数据,避免了数据复制和额外的内存分配操作,因此可以减少数据传输的开销,提高数据传输的效率。
(2)降低系统负载:由于避免了数据复制和额外的内存分配操作,可以降低系统的负载,提高系统的响应速度和稳定性。
(3)提高应用程序的性能:使用 v4l2 userptr 可以提高应用程序对视频数据的处理性能,从而实现更加流畅和高效的视频处理。
二、v4l2 userptr 的实际应用例子2.1 采集摄像头数据并显示一个常见的使用 v4l2 userptr 的例子是采集摄像头数据并将其显示在屏幕上。
在这个应用中,用户空间的应用程序需要通过 v4l2 userptr 接口从摄像头设备中获取视频数据,并将其传输到内核空间。
V4L2驱动的移植与应用(二)
二、V4L2的应用下面简单介绍一下V4L2驱动的应用流程。
1、视频采集的基本流程一般的,视频采集都有如下流程:2、打开视频设备在V4L2中,视频设备被看做一个文件。
使用open函数打开这个设备:// 用非阻塞模式打开摄像头设备int cameraFd;cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);// 如果用阻塞模式打开摄像头设备,上述代码变为://cameraFd = open("/dev/video0", O_RDWR, 0);关于阻塞模式和非阻塞模式:应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。
3、设定属性及采集方式打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。
这一步是可选的。
在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;__request:具体的命令标志符。
在进行V4L2开发中,一般会用到以下的命令标志符: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。
V4L2视频采集实现例程
V4L2视频采集实现例程V4L2视频采集实现例程Video4linux 简介Video4Linux是为市场现在常见的电视捕获卡和并⼝及USB⼝的摄像头提供统⼀的编程接⼝。
同时也提供⽆线电通信和⽂字电视⼴播解码和垂直消隐的数据接⼝。
本⽂主要针对USB摄像头设备⽂件/dev/video0,进⾏视频图像采集⽅⾯的程序设计。
Video4linux 编程指南1.视频编程的流程(1)打开视频设备:(2)读取设备信息(3)更改设备当前设置(可以不做)(4)进⾏视频采集,两种⽅法:a.内存映射b.直接从设备读取(5)对采集的视频进⾏处理( 本程序没做,下次再show给⼤家)(6)关闭视频设备//下⾯我对这些操作做了个简单的函数封装#ifndef _V4L_H#define _V4L_H#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <error.h>#include <assert.h>#include <fcntl.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/mman.h>#include <linux/videodev.h>#include <sys/types.h>#include <string.h>/*采集的图像的最⼤长和宽*/#define MAX_WIDTH 400#define MAX_HEIGHT 300/*设备⽂件*/#define DEFAULT_DEVICE “/dev/video0″/*⾃定义数据结构,包含v4l 中⽤到的数据结构*/typedef struct v4l_struct{int fd;/*设备号*/struct video_capability capability; //包含设备的基本信息(设备名称、⽀持的最⼤最⼩分辨率、信号源信息等)struct video_channel channel[8];//信号源个数struct video_picture picture;//设备采集的图象的各种属性struct video_mmap mmap;//⽤于mmapstruct video_mbuf mbuf;//利⽤mmap进⾏映射的帧的信息unsigned char *buffer ;/*图像数据存放区*/unsigned char *map;/*mmap⽅式获取数据时,数据的⾸地址*/int frame_current;int frame_using[2]; /*这个帧的状态0 表⽰可⽤,1表⽰不可⽤*/}v4l_device;/*************************************************************** 函数名:v4l_open* 功 能: 打开设备* 输 ⼊: dev,vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功**************************************************************/int v4l_open( char *dev, v4l_device *vd ){if( !dev ){dev=DEFAULT_DEVICE ;}if( ( vd->fd = open( dev, O_RDWR ) ) < 0 ){perror( “v4l_open error” );return -1;}return 0;}/*************************************************************** 函数名: v4l_get_capability* 功 能: 获取设备属性* 输 ⼊: vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功**************************************************************/int v4l_get_capability( v4l_device *vd ){if( ioctl( vd->fd, VIDIOCGCAP, &( vd->capability ) ) <0 ) {perror( “v4l_get_capability” );return -1 ;}return 0;}* 功 能:获取图⽚属性* 输 ⼊: vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功***************************************************************/int v4l_get_picture( v4l_device *vd ){if( ioctl( vd->fd,VIDIOCGPICT,&( vd->picture ) ) < 0 ){return -1;}return 0;}/*************************************************************** 函数名: v4l_set_picture* 功 能: 设置图⽚属性* 输 ⼊: vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功**************************************************************/int v4l_set_picture( v4l_device *vd ){if( ioctl( vd->fd, VIDIOCSPICT, &( vd->picture ) ) < 0 ){return -1;}return 0;}/************************************************************** 函数名:v4l_get_channels* 功 能:获取通道信息* 输 ⼊: vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功*************************************************************/int v4l_get_channels( v4l_device *vd ){int i;for( i=0;i < vd->capability.channels ; i++ ){vd->channel[i].channel = i; //确定通道if( ioctl( vd->fd , VIDIOCGCHAN, &( vd->channel[i] ) ) <0 ) {perror( “v4l_get_channel” );return -1;}}return 0;}* 功 能: 获取内存映射信息* 输 ⼊: vd* 输 出: ⽆* 返 回: -1—-失败 0—-成功**************************************************************/int v4l_get_mbuf( v4l_device *vd ){if( ioctl ( vd->fd,VIDIOCGMBUF,&( vd->mbuf ) ) <0 ){perror( “get_mbuf:” );return -1;}if ( ( vd->map = ( unsigned char * )mmap( 0, vd->mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 0 ) ) < 0 ) {perror(“v4l_mmap_init:mmap”);return -1;}return 0 ;}/************************************************************** 函数名: v4l_init_mbuff* 功 能: 初始化内存映射信息* 输 ⼊: vd* 输 出: ⽆* 返 回: 0—-成功**************************************************************/int v4l_init_mbuf(v4l_device *vd){//vd->mmap.frame = 10 ; //不懂双帧是怎样设置的这个frame 该是当前帧的可mbuf 以⼜没有设置怎么确定是双帧不是单帧还是更多vd->mmap.width = MAX_WIDTH;vd->mmap.height = MAX_HEIGHT;vd->mmap.format = vd->picture.palette;vd->frame_current = 0;vd->frame_using[0] = 0;vd->frame_using[1] = 0;return 0;}/*************************************************************** 函数名: v4l_get_address* 功 能: 获取数据在图像的地址***************************************************************/unsigned char *v4l_get_address(v4l_device *vd){return (vd->map + vd->mbuf.offsets[vd->frame_current]);}* 功 能: 捕获帧**************************************************************/int v4l_grab_frame(v4l_device *vd, int frame){if (vd->frame_using[frame]){fprintf(stderr, “v4l_grab_frame: frame %d is already used.\n”, frame); return -1;}vd->mmap.frame = frame;if ( ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap ) ) < 0 ){perror( “v4l_grab_frame” );return -1;}vd->frame_using[frame] = 1;vd->frame_current = frame;return 0;}/*************************************************************** 函数名: v4l_grab_sync* 功 能:与内存映射捕获⼀致**************************************************************/int v4l_grab_sync(v4l_device *vd){if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0){perror(“v4l_grab_sync”);}vd->frame_using[vd->frame_current] = 0;return 0;}/**************************************************************** 函数名: v4l_munmap* 功 能:停⽌内存映射***************************************************************/int v4l_munmap( v4l_device *vd ){if ( munmap( vd->map, vd->mbuf.size ) < 0 ){perror( “v4lmunmap:munmap” );return -1;}return 0;}* 函数名: v4l_close* 功 能:关闭设备***************************************************************/int v4l_close(v4l_device *vd){close(vd->fd);return 0;}#endif//简单的封装了关于SDL的相关操作”ScreenSurface.h”#ifndef SCREEN_SURFACE_H#define SCREEN_SURFACE_H#include <stdio.h>#include <stdlib.h>#include <SDL/SDL.h>class ScreenSurface{public:ScreenSurface();bool screen_init(int w, int h, int b = 0, Uint32 f = 0);//初始化 ~ScreenSurface();SDL_Surface* point() const;int screen_lock();void screen_unlock();void screen_quit();void screen_set_caption( const char *str );//设置标题bool flip( unsigned char * src) ;//显⽰int startTV();//开始采集private:static int screenNum;int width;int height;int bpp;Uint32 flags;SDL_Surface* pScreen;};#endif//ScreenSurface.cpp#include “ScreenSurface.h”#include “qt_v4l.h”v4l_device v4l_dev;/*************************************************************** 函数名: v4l_grab_movie* 功 能:捕获连续图像**************************************************************/void v4l_grab_movie(){v4l_grab_frame(&v4l_dev, v4l_dev.frame_current);/*获取下⼀ 帧*/v4l_grab_sync(&v4l_dev);/*等待传完⼀ 帧*/v4l_dev.buffer = v4l_get_address(&v4l_dev);/*得到这⼀帧的地址*/v4l_dev.frame_current = (v4l_dev.frame_current+1)%2; /* 下⼀帧的frame*/ }//构造函数。
V4L2驱动的移植与应用(一)
V4L2(video for linux) 可以支持多种设备,它可以有以下5种接口:1、视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.下面也是着重讲解这种应用;2、视频输出接口(video output interface):可以驱动计算机的外围视频图像设备——像可以输出电视信号格式的设备;3、直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU;4、视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号;5、收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流;V4L2驱动的主要功能是使程序有发现设备的能力和操作设备.它主要是用过一系列的回调函数来实现这些功能.像设置高频头的频率,帧频,视频压缩格式和图像像参数等等.一、V4L2的移植V4L2提供了三种不同的API来传输外围设备和用户空间的数据。
下面就vivi(drivers/media/video/vivi.c)来讲解一个V4L2驱动的编写。
注意它是一个虚拟的设备驱动,没有与实际的硬件打交道。
1、分析几个重要数据结构:vivi.c包含头文件v4l2-device.h和v4l2-ioctl.h,其中v4l2-device.h中包含了v4l2-subdev.h,v4l2-subdev.h中又包含了v4l2-common.h,v4l2-common.h中包含了v4l2-dev.h。
在v4l2-dev.h中定义了结构体video_device和v4l2_file_operations;在v4l2-ioctl.h中定义了结构体v4l2_ioctl_ops;在v4l2-device.h中定义了结构体v4l2_device;1) vivi_fopsstatic const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE,.open = vivi_open,.release = vivi_close,.read = vivi_read,.poll = vivi_poll,.ioctl = video_ioctl2, /* V4L2 ioctl handler */.mmap = vivi_mmap,};2) vivi_ioctl_opsstatic const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_querycap = vidioc_querycap,.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,.vidioc_reqbufs = vidioc_reqbufs,.vidioc_querybuf = vidioc_querybuf,.vidioc_qbuf = vidioc_qbuf,.vidioc_dqbuf = vidioc_dqbuf,.vidioc_s_std = vidioc_s_std,.vidioc_enum_input = vidioc_enum_input,.vidioc_g_input = vidioc_g_input,.vidioc_s_input = vidioc_s_input,.vidioc_queryctrl = vidioc_queryctrl,.vidioc_g_ctrl = vidioc_g_ctrl,.vidioc_s_ctrl = vidioc_s_ctrl,.vidioc_streamon = vidioc_streamon,.vidioc_streamoff = vidioc_streamoff,#ifdef CONFIG_VIDEO_V4L1_COMPAT.vidiocgmbuf = vidiocgmbuf,#endif};3) vivi_templatestatic struct video_device vivi_template = {.name = "vivi",.fops = &vivi_fops,.ioctl_ops = &vivi_ioctl_ops,.minor = -1,.release = video_device_release,.tvnorms = V4L2_STD_525_60,.current_norm = V4L2_STD_NTSC_M,};其中函数vivi_xxx和vidioc_xxx都是在vivi.c中实现的。
V4l2驱动的流程说明
V4l2 基础知识,附图说明 时间:2011-05-17 作者:网络编辑:hawk 点击:176 [ 评论]V4l2 基础知识,附图说明,易于理解Video for Linux two(Video4Linux2)简称V4L2,是V4L的改进版。
V4L2是linux 操作系统下用于采集图片、视频和音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现图片、视频、音频等的采集。
在远程会议、可视电话、视频监控系统和嵌入式多媒体终端中都有广泛的应用。
一、Video for Linux two在Linux下,所有外设都被看成一种特殊的文件,成为“设备文件”,可以象访问普通文件一样对其进行读写。
一般来说,采用V4L2驱动的摄像头设备文件是/dev/v4l/video0。
为了通用,可以建立一个到/dev/video0的链接。
V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。
V4L2在include/linux/videodev.h文件中定义了一些重要的数据结构,在采集图像的过程中,就是通过对这些数据的操作来获得最终的图像数据。
Linux系统V4L2的能力可在Linux内核编译阶段配置,默认情况下都有此开发接口。
V4L2从Linux 2.5.x版本的内核中开始出现。
V4L2规范中不仅定义了通用API元素(Common API Elements),图像的格式(Image Formats),输入/输出方法(Input/Output),还定义了Linux内核驱动处理视频信息的一系列接口(Interfaces),这些接口主要有:视频采集接口——Video Capture Interface;视频输出接口——Video Output Interface;视频覆盖/预览接口——Video Overlay Interface;视频输出覆盖接口——Video Output Overlay Interface;编解码接口——Codec Interface。
V L 驱动程序架构
clk_enable(ctrl->clock);//使能时钟 //注册 V4L2 驱动 ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); } s3c_fimc_register_contoller 函数主要用来分配资源与申请中断 static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev) { ctrl->vd = &s3c_fimc_video_device[id]; //申请中断 ctrl->irq = platform_get_irq(pdev, 0); if(request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) }; struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = { [0] = {
switch (type) { case VFL_TYPE_GRABBER: minor_offset = 0; minor_cnt = 64; break; case VFL_TYPE_RADIO: minor_offset = 64; minor_cnt = 64; break; case VFL_TYPE_VTX: minor_offset = 192; minor_cnt = 32;
const struct v4l2_file_operations *fops; struct cdev *cdev;//字符设备 struct device *parent;//父设备 struct v4l2_device *v4l2_dev;//父 v4l2_device char name[32];//名称 int vfl_type;//类型 int minor;//次设备号 /*释放回调*/ void (*release)(struct video_device *vdev); /*ioctl 回调*/ const struct v4l2_ioctl_ops *ioctl_ops; } 常用的结构 参见/include/linux/videodev2.h 1)设备能力结构 struct v4l2_capability { __u8 driver[16];//驱动名 __u8 card[32];//例如 Hauppauge winTV __u8 bus_info[32];//PCI 总线信息 __u32 version;//内核版本 __u32 capabilities;//设备能力 __u32 reserved[4]; }; 2)数据格式结构 struct v4l2_format { enum v4l2_buf_type type;//本结构的数据类型 }; 3)像素格式结构 struct v4l2_pix_format { __u32 width;//宽度 __u32 height;//高度 } 4)请求缓冲 struct v4l2_requestbuffers { __u32 count;//缓存数量
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/** V4L2 video capture example** This program can be used and distributed without restrictions.*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <getopt.h> /* getopt_long() */#include <fcntl.h> /* low-level i/o */#include <unistd.h> /*getpid()*/#include <error.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> /* for videodev2.h */#include <linux/videodev2.h>#define CLEAR(x) memset(&(x), 0, sizeof (x))typedef enum {IO_METHOD_READ,IO_METHOD_MMAP,IO_METHOD_USERPTR,} io_method;struct buffer {void *start;size_t length;};static char * dev_name = NULL;static io_method io = IO_METHOD_MMAP; static int fd = -1;struct buffer * buffers = NULL;static unsigned int n_buffers = 0;static void errno_exit(const char *s){fprintf(stderr, "%s error %d, %s\n",s, errno, strerror(errno));exit(EXIT_FAILURE);}static int xioctl(int fd,int request,void *arg){int r;do r = ioctl(fd, request, arg);while (-1 == r && EINTR == errno);return r;}static void process_image(const void *p){FILE* fp;fp = fopen("test","w+"); //w+:打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。
若文件不存在则建立该文件。
fputs(p, fp); //成功,返回一个非负整数;出错,返回EOF。
fputs(const char *s,FILE *stream)作用:向指定文件写入一个字符串,缓冲区S中保存的是以‘/0’结尾的字符串,fputs将该字符串写入stream,但不写入结尾的’/0’。
fclose(fp);// fflush(stdout); // fflush(stdout):清空输出缓冲区,并把缓冲区内容输出}static int read_frame(void)//用来读取一帧数据{struct v4l2_buffer buf;unsigned int i;switch (io){case IO_METHOD_READ:if (-1 == read(fd, buffers[0].start, buffers[0].length)){switch (errno){case EAGAIN: //当使用不可阻断(O_NONBLOCK)打开文件后,read呼叫无可读取的数据return 0;case EIO: //设备文件读取文件时发生输出输入错误/* Could ignore EIO, see spec. *//* fall through */default:errno_exit("read");}}process_image(buffers[0].start); //保存读到的数据break;/* V4L2有一个数据缓存,存放req.count数量的缓存数据。
数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。
这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF*/ case IO_METHOD_MMAP:CLEAR (buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;/*出队列以取得采集数据的帧缓冲,取得原始的采集数据*/if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)){switch (errno){case EAGAIN:return 0;case EIO:/* Could ignore EIO, see spec. *//* fall through */default:errno_exit("VIDIOC_DQBUF");}}assert(buf.index < n_buffers); //assert的作用是计算括号内的表达式,如果其值为0,就先向stderr打印一条出错信息,然后通过abort来终止程序运行process_image(buffers[buf.index].start);if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) //重新放入缓存队列errno_exit("VIDIOC_QBUF");break;case IO_METHOD_USERPTR:CLEAR(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_USERPTR;if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)){switch (errno){case EAGAIN:return 0;case EIO:/* Could ignore EIO, see spec. *//* fall through */default:errno_exit("VIDIOC_DQBUF");}}for (i = 0; i < n_buffers; ++i)if (erptr == (unsigned long) buffers[i].start&& buf.length == buffers[i].length)break;assert(i < n_buffers);process_image((void *) erptr);if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))errno_exit("VIDIOC_QBUF");break;}return 1;}/*完成图像的连续采集*/4. static void mainloop(void){unsigned int count;count = 100;while (count-- > 0){for (;;){fd_set fds;struct timeval tv;int r;FD_ZERO(&fds); //初始化fd_set结构体变量FD_SET(fd, &fds);//在fd_set结构体上注册文件描述/* Timeout. */_sec = 2; //时间“2S”_usec = 0;r = select (fd + 1, &fds, NULL, NULL, &tv); //判断是否可读(即摄像头是否准备好)tv是定时if (-1 == r) {if (EINTR == errno)continue;errno_exit("select");}if (0 == r) { //时间到,返回0fprintf(stderr, "select timeout\n");exit(EXIT_FAILURE);}if (read_frame()) //如果可读,执行read_frame函数,并跳出循环break;/* EAGAIN - continue select loop. */}}}5. static void stop_capturing(void)//停止视频的采集{enum v4l2_buf_type type;switch (io){case IO_METHOD_READ:/* Nothing to do. */break;case IO_METHOD_MMAP:case IO_METHOD_USERPTR:type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))errno_exit("VIDIOC_STREAMOFF");break;}}3. static void start_capturing(void) //开始视频采集{unsigned int i;enum v4l2_buf_type type;switch (io){case IO_METHOD_READ:/* Nothing to do. */break;case IO_METHOD_MMAP:for (i = 0; i < n_buffers; ++i){struct v4l2_buffer buf;CLEAR(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) //申请到的缓冲进入列队errno_exit("VIDIOC_QBUF");}/*for循环的作用是:将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer*/type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据errno_exit("VIDIOC_STREAMON");break;case IO_METHOD_USERPTR:for (i = 0; i < n_buffers; ++i){struct v4l2_buffer buf;CLEAR(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_USERPTR;buf.index = i;erptr = (unsigned long) buffers[i].start;buf.length = buffers[i].length;if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))errno_exit("VIDIOC_QBUF");}type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))errno_exit("VIDIOC_STREAMON");break;}}6. static void uninit_device(void)//注销设备文件{unsigned int i;switch (io) {case IO_METHOD_READ:free(buffers[0].start); //原型void free(void *ptr);参数ptr为指向先前由malloc()、calloc()或realloc()所返回的内存指针。