Video4Linux(V4L)使用摄像头的实例基础教程与体会


前言.写这篇文章的想法和思路

由于毕业设计的关系,本人要做一下在linux系统中视频的相关工作比如采集和传输。由于本人是菜鸟一个,所以是需要上网搜一搜看大家都是如何做的,当然开始都是理不出一个头绪,但是很多文章都提到了video4linux(v4l),所以我觉得工作的展开可以先从这里开始。看了网上的一些文章,其中比较重要的也是比较知名的吧,有戴小鼠写的《基于Video4Linux 的USB 摄像头图像采集实现》,有陈俊宏写的《video stream 初探》的一系列共六篇文章,也找了一些英文的资料,看到过《video4linux programming》但是这篇文章偏重于视频设备在linux中的驱动实现,所以对像我这种低端的只是使用v4l相关系统调用的人来说有些帮助但帮助不大,《Video4Linux Kernel API Reference》详细介绍了v4l中各个重要的结构体的作用。另外顺着陈俊宏的文章,找到了一个叫EffecTV的软件,其中的有关v4l的源码部分也很值得一看,在后的文章里也会介绍。翻看了网上的很多文章,多半是使用陈俊宏介绍的相关代码,或者是EffecTV中的,大家都是这么用而且也都用的不错。

基于Video4Linux 的USB 摄像头图像采集实现 PDF下载

免费下载地址在 http://linux.bkjia.com/

用户名与密码都是www.bkjia.com

具体下载目录在 /2012年资料/12月/31日/Video4Linux(V4L)使用摄像头的实例基础教程与体会/基于Video4Linux 的USB 摄像头图像采集实现

-------------------------------------------------------------------------------

我写这个文章一是想为自己的毕业论文积累些素材,二是我想可能会给今后想要了解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

}

  • 1
  • 2
  • 3
  • 4
  • 下一页

相关内容