v4l使用摄像头
- 格式:wps
- 大小:64.00 KB
- 文档页数:24
Linux V4L2 摄像头视频采集2011-01-05 17:34一,什么是 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,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。
VIDIOC_QUERYCAP,struct v4l2_capability3. 选择视频输入,一个视频设备可以有多个视频输入。
VIDIOC_S_INPUT,struct v4l2_input4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format5. 向驱动申请帧缓冲,一般不超过5个。
struct v4l2_requestbuffers6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。
mmap7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer8. 开始视频的采集。
VIDIOC_STREAMON9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。
VIDIOC_DQBUF10. 将缓冲重新入队列尾,这样可以循环采集。
家庭网关上如何实现视频采集Linux下的图像应用程序设计一般都基于video for linux开发,video for linux简称V4L,现在已经发展到V4L2。
V4L是Linux影像系统与嵌入式影像的基础,是Linux kernel里支持影像设备的一组APIs,配合适当的视频设备与设备驱动程序,V4L可以实现影像采集、AM/FM 无线广播、影像CODEC、频道切换等功能。
1、摄像头驱动的移植考虑到设备的通用性选择的摄像头为中星微的ZC301P型摄像头。
在Linux-2.6.30.9内核中,系统集成了ZC301P的摄像头驱动,要支持它只需要配置video for linux和video capture adapters 项,并进入到video capture adapter 选中所使用的摄像头驱动即可。
配置完成后,重新编译内核,并下载至网关平台即可。
2、视频采集程序设计流程Linux系统中,视频设备被视为一个设备文件,存放在/dev目录下,整路径为:/dev/video0。
接下来,详细讨论视频采集执行的步骤。
(1)视频设备结构描述在程序中,首先定义一个视频设备的数据结构,里边的数据成员是对视频设备和图属性的描述,数据结构如下:struct vdIn{int fd;char* videodevice;struct video_mmap vmmap;struct video_capability videocap;int mmapsize;struct video_mbuf videombuf;struct video_picture videopict;struct video_channel videochan;int cameratype;char* cameraname;char bridge[9];int palette;int grabMethod;unsigned char*pFramebuffer;unsigned char*ptframe;int framesizeIn;int bppIn;int hdrwidth;int hdrheight;int formatIn;};本文中常用的结构体包括:video_capability,包含了设备的基本信息;video_picture,包含了采集的图像的各种属性;video_channel,包含了关于各个信号源的属性,video_mbuf,包含了利用mmap进行映射的帧的信息。
c语言摄像头的编程概述及解释说明1. 引言1.1 概述:本文将介绍C语言摄像头编程的相关知识和技巧。
随着科技的不断进步,摄像头已经成为了我们生活中不可或缺的一部分。
而通过编程控制摄像头,可以实现各种有趣和实用的功能。
本文将引导读者从基础知识开始,逐步深入了解C语言与摄像头的通信方式、驱动选择与安装、图像采集、处理与分析等方面的内容。
1.2 文章结构:本文共分为五个主要部分: 引言、C语言摄像头编程基础知识、C语言中使用摄像头进行图像采集、C语言中对摄像头图像进行处理与分析以及结论和展望。
在引言部分,我们将对整篇文章进行概述,并介绍每个部分所涵盖的内容。
1.3 目的:本文旨在提供给读者一个全面而系统的了解C语言摄像头编程的指南。
通过理论讲解和实践案例,读者可以学习到如何使用C语言控制和操作摄像头,并利用其功能进行各种图像采集、处理与分析任务。
此外,本文还会对未来C语音摄像头编程的发展进行展望,为读者提供一个前景的思考角度。
以上是“1. 引言”部分的内容。
接下来,我们将逐一介绍文章其他章节的具体内容。
2. C语言摄像头编程基础知识:摄像头是一种用于捕捉图像或视频的设备,它在现代计算机应用中扮演着重要的角色。
C语言是一种广泛使用的编程语言,可以与摄像头进行通信并控制其功能。
2.1 摄像头原理简介:摄像头通过感光元件将光线转换为电信号,并通过图像处理器将电信号转换为数字图像或视频。
常见的摄像头类型包括USB摄像头、网络摄像头和嵌入式摄像头。
它们可以用于各种应用领域,如视频会议、安防监控和电子眼镜等。
2.2 C语言与摄像头的通信方式:C语言可以通过调用操作系统提供的API来与摄像头进行通信。
对于不同类型的摄像头,可能需要使用不同的库或驱动程序来访问其功能。
例如,对于USB摄像头,可以使用v4l库(Video for Linux);而对于网络摄像头,则可以使用libcurl 库进行远程访问。
2.3 摄像头驱动的选择与安装:在使用C语言进行摄像头编程之前,需要确定合适的驱动程序以确保正确地连接和控制相机。
Linuxv4l2架构之v4l2-ctl抓取、设置图像一、本开发、测试基于RV1126-1109的SDK上进行。
一个mipi 的摄像头,接到rv1126上看看能不能抓到图。
不需要配置寄存器。
例如这个摄像头参数:raw8,4lanes,512*192,30fps二、v4l2-ctl工具则是针对/dev/video0,/dev/video1等video 设备,它在video设备上进行set_fmt、reqbuf、qbuf、dqbuf、stream_on、stream_off 等一系列操作。
复制一份索尼imx291的代码直接修改,改完之后测试。
测试方法如下:v4l2-ctl -d /dev/video0 --set-fmt-video=width=512,height=192,pixelformat=BG10 --stream-mmap=3 --stream-to=/tmp/bg10.bin --stream-count=1 --stream-poll三、测试方法和步骤如下:执行发现,没有抓到数据也没有timeout,直接退出了。
dmesg 发现出现了如下一条信息rkcif_mipi_lvds: crop size is bigger than input这部分代码如下:rkcif_start_streaming() -> rkcif_sanity_check_fmt(stream, NULL)static int rkcif_sanity_check_fmt(struct rkcif_stream *stream, const struct v4l2_rect *s_crop){struct rkcif_device *dev = stream->cifdev;struct v4l2_device *v4l2_dev = &dev->v4l2_dev;struct v4l2_rect input, *crop;stream->cif_fmt_in = get_input_fmt(dev->active_sensor->sd, &input, stream->id + 1);if (!stream->cif_fmt_in) {v4l2_err(v4l2_dev, "Input fmt is invalid\n");return -EINVAL;}if (s_crop)crop = (struct v4l2_rect *)s_crop;elsecrop = &stream->crop[CROP_SRC_ACT];if (crop->width + crop->left > input.width ||crop->height + crop->top > input.height) {v4l2_err(v4l2_dev, "crop size is bigger than input\n");return -EINVAL;}...}查看代码可以知道input.width及heigth小于crop的width或者heigth。
//#Rockie Cheng#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>#define CLEAR(x) memset (&(x), 0, sizeof (x)) //宏定义清楚struct buffer {void * start;size_t length;}; //定义一个buffer结构体,这个结构体用于盛放申请到的内存首地址和长度static char *dev_name = "/dev/video0";//摄像头设备名static int fd = -1; //文件描述符fdstruct buffer *buffers = NULL;static unsigned int n_buffers = 0;FILE *file_fd; //static unsigned long file_length;static unsigned char *file_name;//获取一帧数据,static int read_frame (void){struct v4l2_buffer buf; //用于盛放一帧数据的信息unsigned int i;CLEAR (buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;int ff = ioctl (fd, VIDIOC_DQBUF, &buf); //从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区if(ff<0)printf("failture\n"); //出列采集的帧缓冲assert (buf.index < n_buffers);printf ("buf.index dq is %d,\n",buf.index);fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd); //将其写入文件中ff=ioctl (fd, VIDIOC_QBUF, &buf); //再将其入列,投放一个空的视频缓冲区到视频缓冲区输入队列中if(ff<0)printf("failture VIDIOC_QBUF\n");return 1;}//主函数int main (int argc,char ** argv){struct v4l2_capability cap;/*储存了硬件的信息,由驱动填写各个元素的值,包含:驱动名称,硬件名称,版本号,硬件支持的功能:V4L2_CAP_VIDEO_CAPTURE(支持视频捕捉接口)*/struct v4l2_format fmt;/*流数据的格式,struct v4l2_format{enum v4l2_buf_type type;union{struct v4l2_pix_format pix;// V4L2_BUF_TYPE_VIDEO_CAPTURE包含每幅图片的一行,一列所占的像素个数,width和heigth;//像素格式与压缩类型pixelformat;一幅图像的数据所用的最大字节数imagesize=bytesline*heigthstruct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAYstruct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTUREstruct v4l2_sliced_vbi_format sliced; // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE__u8 raw_data[200]; // user-defined} fmt;};*/unsigned int i;enum v4l2_buf_type type;//所申请的缓冲区的类型,与struct v4l2_format和struct v4l2_requestbuffers结构体中的type一样,//由用户定义,比如可以为V4L2_BUF_TYPE_VIDEO_CAPTUREfile_fd = fopen("test-mmap.jpg", "w");//以只写方式打开文件,返回值是锁打开的文件的首地址fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);//打开摄像头设备,无阻塞方式打开int ff=ioctl (fd, VIDIOC_QUERYCAP, &cap);//获取硬件的参数,结构会存放在cap中,这是由驱动自动填写的if(ff<0)printf("failture VIDIOC_QUERYCAP\n");struct v4l2_fmtdesc fmt1;int ret;memset(&fmt1, 0, sizeof(fmt1));fmt1.index = 0;fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt1)) == 0) //获取当前驱动支持的视频格式{fmt1.index++;printf("{ pixelformat = '%c%c%c%c', description = '%s' }\n",fmt1.pixelformat & 0xFF, (fmt1.pixelformat >> 8) & 0xFF,(fmt1.pixelformat >> 16) & 0xFF, (fmt1.pixelformat >> 24) & 0xFF,fmt1.description);}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;//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;图像的帧格式确定以后,就可以计算出图像的大小fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; //场交错ff = ioctl (fd, VIDIOC_S_FMT, &fmt); //设置图像格式,将上面设置的帧格式写到fmt 这个结构体中if(ff<0)printf("failture VIDIOC_S_FMT\n");file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; //计算图片大小struct v4l2_requestbuffers req;/*struct v4l2_requestbuffers__u32 count; //这个成员只为了给mmap使用,保存需要请求的缓冲区的个数enum v4l2_buf_type type; //所申请的缓冲区的类型,与struct v4l2_format和struct v4l2_requestbuffers结构体中的type一样,//由用户定义,比如可以为V4L2_BUF_TYPE_VIDEO_CAPTURE enum v4l2_memory memory; //设置内存的访问形式V4L2_MEMORY_MMAP orV4L2_MEMORY_USERPTR.__u32 reserved[2]; //保留*/CLEAR (req);req.count = 1; //申请1个缓冲区req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //必须为这个格式req.memory = V4L2_MEMORY_MMAP; //内存访问形式为mmapioctl (fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量if(ff<0)printf("failture VIDIOC_REQBUFS\n");if (req.count < 1)printf("Insufficient buffer memory\n");buffers = calloc (req.count, sizeof (*buffers));//分配连续的内存给刚才申请的缓冲区,并且初始化为0,返回值是首地址(物理地址)for (n_buffers = 0; n_buffers < req.count; ++n_buffers){struct v4l2_buffer buf; //驱动中的一帧,每帧的大小有驱动填写,从上面的pix.imagesize传过来/*struct v4l2_buffer{__u32 index;enum v4l2_buf_type type; //必须为V4L2_BUF_TYPE_VIDEO_CAPTURE__u32 bytesused; //已用的字节数__u32 flags; //enum v4l2_field field; //struct timeval timestamp; //struct v4l2_timecode timecode; //__u32 sequence; //内存分配的顺序enum v4l2_memory memory;union {__u32 offset;unsigned long userptr;} m;__u32 length;__u32 input;__u32 reserved;};*/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)) //调用这个command以后,驱动将填写buf结构体的index,length,type,offset等元素printf ("VIDIOC_QUERYBUF error\n");buffers[n_buffers].length = buf.length;buffers[n_buffers].start = mmap (NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd, buf.m.offset);//通过mmap建立映射关系。
初识V4l2(⼆)-------浅析video_register_device在V4l2初识(⼀)中,我们已经知道当插上⼀个摄像头的时候,在uvc_driver.c中最终会调⽤函数video_register_device函数。
接下来我们就简要分析这个函数做了哪些事情,揭开其神秘⾯纱。
/* Register video devices. Note that if video_register_device fails,the release() callback of the video_device structure is *not* called, sothe caller is responsible for freeing any data. Usually that means thatyou call video_device_release() on failure. *///该函数的作⽤就是注册video devices,有⼀点注意,video_device_release函数需要开发者⼿动调⽤static inline int video_register_device(struct video_device *vdev,int type, int nr){return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);}就video_register_device函数中的形参进⾏说明:参数⼀:video_devide :即我们想要注册的video_device结构体参数⼆:type :要注册的device类型,其中包括:define VFL_TYPE_GRABBER 0图像采集设备,包括摄像头、调谐器define VFL_TYPE_VBI1 1从视频消隐的时间段取得信息的设备(1)#define VFL_TYPE_RADIO 2 ⽆线电设备#define VFL_TYPE_SUBDEV 3 视频传播设备#define VFL_TYPE_MAX 4参数三:nr:device node number0 == /dev/video0 1 == /dev/video1 ........ -1 == first free__video_register_device深⼊分析过程如下:/*** __video_register_device - register video4linux devices* @vdev: video device structure we want to register* @type: type of device to register* @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...* -1 == first free)* @warn_if_nr_in_use: warn if the desired device node number* was already in use and another number was chosen instead.* @owner: module that owns the video device node** The registration code assigns minor numbers and device node numbers* based on the requested type and registers the new device node with* the kernel.** This function assumes that struct video_device was zeroed when it* was allocated and does not contain any stale date.** An error is returned if no free minor or device node number could be* found, or if the registration of the device node failed.** Zero is returned on success.** Valid types are** %VFL_TYPE_GRABBER - A frame grabber** %VFL_TYPE_VBI - Vertical blank data (undecoded)** %VFL_TYPE_RADIO - A radio card** %VFL_TYPE_SUBDEV - A subdevice*/int __video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use, struct module *owner){int i = 0;int ret;int minor_offset = 0;//次设备号的偏移量,对于不同类型的设备,次设备号的基数是不同的,最终minor = i + minor_offsetint minor_cnt = VIDEO_NUM_DEVICES;const char *name_base; //设备的名称,会根据传⼊的type来选择/* A minor value of -1 marks this video device as neverhaving been registered */vdev->minor = -1; //次设备号为-1,表明这个设备没有被注册/* the release callback MUST be present */if (WARN_ON(!vdev->release)) //如果video_device结构体中没有提供release函数,就会返回出错。
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 V4L2 摄像头视频采集2011-01-05 17:34一,什么是 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,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。
VIDIOC_QUERYCAP,struct v4l2_capability3. 选择视频输入,一个视频设备可以有多个视频输入。
VIDIOC_S_INPUT,struct v4l2_input4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format5. 向驱动申请帧缓冲,一般不超过5个。
struct v4l2_requestbuffers6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。
mmap7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer8. 开始视频的采集。
VIDIOC_STREAMON9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。
VIDIOC_DQBUF10. 将缓冲重新入队列尾,这样可以循环采集。
VIDIOC_QBUF11. 停止视频的采集。
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。
由于毕业设计的关系,本人要做一下在linux系统中视频的相关工作比如采集和传输。
由于本人是菜鸟一个,所以是需要上网搜一搜看大家都是如何做的,当然开始都是理不出一个头绪,但是很多文章都提到了video4linux(v4l),所以我觉得工作的展开可以先从这里开始,。
看了网上的一些文章,其中比较重要的也是比较知名的吧,有戴小鼠写的《基于Video4Linux 的USB 摄像头图像采集实现》,有陈俊宏写的《video stream 初探》的一系列共六篇文章,也找了一些英文的资料,看到过《video4linux programming》但是这篇文章偏重于视频设备在linux中的驱动实现,所以对像我这种低端的只是使用v4l相关系统调用的人来说有些帮助但帮助不大,《Video4Linux Kernel API Reference》详细介绍了v4l中各个重要的结构体的作用。
另外顺着陈俊宏的文章,找到了一个叫EffecTV的软件,其中的有关v4l的源码部分也很值得一看,在后的文章里也会介绍。
翻看了网上的很多文章,多半是使用陈俊宏介绍的相关代码,或者是EffecTV中的,大家都是这么用而且也都用的不错。
我写这个文章一是想为自己的毕业论文积累些素材,二是我想可能会给今后想要了解v4l相关使用知识的人提供一个学习的路线,因为上一段中提到的几篇文章无论谁读起来肯定都会对他有很大的帮助,三是希望我也写篇文章给想学习的人一点帮助,哪怕只有一点点。
文章就分成三个大部分吧:第一个部分介绍一些v4l的基本概念和基本方法,利用系统API完成一系列函数以方便后续应用程序的开发和使用。
第二个部分一些说明如何使用v4l,用一个示例程序说明。
第三个部分想简单说一说对获取和处理图像相关问题的思路。
在这一章可能会谈一谈我的一些理解和体会。
其实网络上的资料很多,我只是稍微整理一下而已。
我的感觉linux内核和驱动开发的那些程序员很厉害因为他们留给我们一个很容易使用的接口而使底层复杂的工作对我们很透明,读过上述我提到的文章后会觉得使用v4l是相对容易的(我希望如果有人读了我的文章也会有这种感觉),相对复杂的是采集到图像数据后我们应该怎么办,我想这也可能是很多人当然也包括我所不是特别清晰和明确的。
所以我想在第三个部分里做一些对采集到图像数据后相关问题的探讨,当然我的水平有限,请您指出文中的错误方法和对概念的错误理解,我非常愿意共同学习和进步。
1.video4linux基础相关1.1 v4l的介绍与一些基础知识的介绍I.首先说明一下video4linux(v4l)。
它是一些视频系统,视频软件,音频软件的基础,经常使用在需要采集图像的场合,如视频监控,webcam,可视电话,经常应用在embedded linux中是linux嵌入式开发中经常使用的系统接口。
它是linux内核提供给用户空间的编程接口,各种的视频和音频设备开发相应的驱动程序后,就可以通过v4l提供的系统API来控制视频和音频设备,也就是说v4l分为两层,底层为音视频设备在内核中的驱动,上层为系统提供的API,而对于我们来说需要的就是使用这些系统的API。
II.Linux系统中的文件操作有关Linux系统中的文件操作不属于本文的内容。
但是还是要了解相关系统调用的作用和使用方法。
其中包括open(),read(),close(),ioctl(),mmap()。
详细的使用不作说明。
在Linux系统中各种设备(当然包括视频设备)也都是用文件的形式来使用的。
他们存在与dev目录下,所以本质上说,在Linux中各种外设的使用(如果它们已经正确的被驱动),与文件操作本质上是没有什么区别的。
1.2 建立一套简单的v4l函数库这一节将一边介绍v4l的使用方法,一边建立一套简单的函数,应该说是一套很基本的函数,它完成很基本的够能但足够展示如何使用v4l。
这些函数可以用来被其他程序使用,封装基本的v4l功能。
本文只介绍一些和摄像头相关的编程方法,并且是最基础和最简单的,所以一些内容并没有介绍,一些与其他视频设备(如视频采集卡)和音频设备有关的内容也没有介绍,本人也不是很理解这方面的内容。
这里先给出接下来将要开发出来函数的一个总览。
相关结构体和函数的定义我们就放到一个名为v4l.h的文件中,相关函数的编写就放在一个名为v4l.c的文件中把。
对于这个函数库共有如下的定义(也就是大体v4l.h中的内容):#ifndef _V4L_H_#define _V4L_H_#include <sys/types.h>#include <linux/videodev.h> //使用v4l必须包含的头文件这个头文件可以在/usr/include/linux下找到,里面包含了对v4l各种结构的定义,以及各种ioctl的使用方法,所以在下文中有关v4l的相关结构体并不做详细的介绍,可以参看此文件就会得到你想要的内容。
下面是定义的结构体,和相关函数,突然给出这么多的代码很唐突,不过随着一点点解释条理就会很清晰了。
struct _v4l_struct{int fd;//保存打开视频文件的设备描述符struct video_capability capability;//该结构及下面的结构为v4l所定义可在上述头文件中找到struct video_picture picture;struct video_mmap mmap;struct video_mbuf mbuf;unsigned char *map;//用于指向图像数据的指针int frame_current;int frame_using[VIDEO_MAXFRAME];//这两个变量用于双缓冲在后面介绍。
};typedef struct _v4l_struct v4l_device;//上面的定义的结构体,有的文中章有定义channel的变量,但对于摄像头来说设置这个变量意义不大通常只有一个channel,本文不是为了写出一个大而全且成熟的函数库,只是为了介绍如何使用v4l,再加上本人水平也有限,能够给读者一个路线我就很知足了,所以并没有设置这个变量同时与channel相关的函数也没有给出。
extern int v4l_open(char *, v4l_device *);extern int v4l_close(v4l_device *);extern int v4l_get_capability(v4l_device *);extern int v4l_get_picture(v4l_device *);extern int v4l_get_mbuf(v4l_device *);extern int v4l_set_picture(v4l_device *, int, int, int, int, int,); extern int v4l_grab_picture(v4l_device *, unsigned int); extern int v4l_mmap_init(v4l_device *);extern int v4l_grab_init(v4l_device *, int, int);extern int v4l_grab_frame(v4l_device *, int);extern int v4l_grab_sync(v4l_device *);上述函数会在下文中逐渐完成,功能也会逐渐介绍,虽然现在看起来没什么感觉只能从函数名上依稀体会它的功能,或许看起来很烦,不过看完下文就会好了。
前面已经说过使用v4l视频编程的流程和对文件操作并没有什么本质的不同,大概的流程如下:1.打开视频设备(通常是/dev/video0)2.获得设备信息。
3.根据需要更改设备的相关设置。
4.获得采集到的图像数据(在这里v4l提供了两种方式,直接通过打开的设备读取数据,使用mmap内存映射的方式获取数据)。
5.对采集到的数据进行操作(如显示到屏幕,图像处理,存储成图片文件)。
6.关闭视频设备。
知道了流程之后,我们就需要根据流程完成相应的函数。
那么我们首先完成第1步打开视频设备,需要完成int v4l_open(char *, v4l_device *);具体的函数如下#define DEFAULT_DEVICE “/dev/video0”int v4l_open(char *dev , v4l_device *vd){if(!dev)dev= DEFAULT_DEVICE;if((vd-fd=open(dev,O_RDWR))<0){perror(“v4l_open:”) ;return -1;}if(v4l_get_capability(vd))return -1;if(v4l_get_picture(vd))return -1;//这两个函数就是即将要完成的获取设备信息的函数return 0}同样对于第6步也十分简单,就是int v4l_close(v4l_device *);的作用。
函数如下:int v4l_close(v4l_device *vd){close(vd->fd);return 0;}现在我们完成第2步中获得设备信息的任务,下面先给出函数在对函数作出相应的说明。
int v4l_get_capability(v4l_device *vd){if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) {perror("v4l_get_capability:");return -1;}return 0;}int v4l_get_picture(v4l_device *vd){if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) {perror("v4l_get_picture:");return -1;}return 0;}对于以上两个函数我们不熟悉的地方可有vd->capability和vd->picture两个结构体,和这两个函数中最主要的语句ioctl。
对于ioctl的行为它是由驱动程序提供和定义的,在这里当然是由v4l所定义的,其中宏VIDIOCGCAP和VIDIOCGPICT的分别表示获得视频设备的capability和picture。
对于其他的宏功能定义可以在你的Linux系统中的/usr/include/linux/videodev.h中找到,这个头文件也包含了capability和picture的定义。