在linux下使用视频采集卡

在linux下使用视频采集卡

2010-04-10 12:45:12 阅读6 评论0 字号:

 

                                李玉江   珠海  <lidriver@163.com>

        在{dy}部分中介绍了如何在LINUX下安装和使用电视卡。从这一部分起将会介绍

如何在linux中对电视卡编程。开始已经提到过,电视卡使用的是video for linux

驱动,简称v4l,实际上,现在已经有了video for linux two驱动 ,即v4l2.它解决了v4l

中存在的一些问题,并且提高了硬件性能。但是,目前来说,v4l2仍然没有集成到linux的内核中,

要使用v4l2的话,只有去下载v4l2补丁了,以下如无特别说明,所涉及的内容只针对v4l设备而言。

        我们都知道,在linux中,为了屏蔽用户对设备访问的复杂性,采用了设备文件,即可以通过

像访问普通文件一样的方式来对设备进行访问读写。电视卡在linux中和打印机,鼠标一样,属于字符

设备。其主设备号是81,在实际操作上,访问控制电视卡也和一般的设备文件没有什么不同。用open

打开设备,

                int fd;

                fd = open("/dev/video0",O_RDWR);

用一系列的ioctl发命令控制设备。v4l支持的ioctl命令大概有二十几个,为了尽快的编出一个

简单的图象捕捉程序,让我们先来看看几个主要的命令:

1. ioctl(fd,VIDIOCGCAP,&cap);

        该命令主要是为了获取电视卡的功能信息。例如电视卡的名称,类型,channel等。参数cap是

一个结构,当ioctl命令返回时,结构的各成员就被赋值了,结构体的定义为:

struct video_capability

{

        char name[32];

        int type;

        int channels;        /* Num channels */

        int audios;        /* Num audio devices */

        int maxwidth;        /* Supported width */

        int maxheight;        /* And height */

        int minwidth;        /* Supported width */

        int minheight;        /* And height */

};

channel 指的是有几个信号输入源,例如television,composite,s-video等。

2.ioctl(fd,VIDIOCGCHAN,&vc)

3.ioctl(fd,VIDIOCSCHAN.&vc)

这两个命令用来取得和设置电视卡的channel信息,例如使用那个输入源,制式等。

vc 是一个video_channel 结构,其定义为:

struct video_capability

{

        char name[32];

        int type;

        int channels;        /* Num channels */

        int audios;        /* Num audio devices */

        int maxwidth;        /* Supported width */

        int maxheight;        /* And height */

        int minwidth;        /* Supported width */

        int minheight;        /* And height */

};

struct video_channel

{

        int channel;

        char name[32];

        int tuners;//number of tuners for this input

        __u32  flags;

        __u16  type;       

        __u16 norm;               

};

成员channel代表输入源,通常,0: television 1:composite1 2:s-video

name 表示该输入源的名称。

norm 表示制式,通常,0:pal 1:ntsc 2:secam 3:auto

4. ioctl(fd,VIDIOCGMBUF,*mbuf)

获得电视卡缓存的信息,参数mbuf是video_mbuf结构。其定义如下:

struct video_mbuf

{

        int        size;                /* Total memory to map */

        int        frames;                /* Frames */

        int        offsets[VIDEO_MAX_FRAME];

};

size是缓存的大小,frames表明该电视卡的缓存可以容纳的帧数,数组offsets则表明

对应一帧的起始位置,0帧对应offsets[0],1帧对应offsets[1]....

执行完该命令后,就可以用mmap函数将缓存映射到内存中了。大致用法可以参考以下的代

struct video_mbuf mbuf;

unsigned char *buf1,*buf2;

if(ioctl(fd,VIDIOCGMBUF,&mbuf)<0)

{

        perror("VIDIOCGMBUF");

        return -1;

}

printf("the frame number is %d\n",mbuf.frames);

buf1 = (unsigned char*)mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd.0);

buf1 = buf1 + mbuf.offset[0];

buf2 = buf1 + mbuf.offset[1];//当然,如果mbuf.frames=1,就不需要下面的了。

......

5. ioctl(fd.VIDIOCMCAPTURE,&mm)

启动硬件去捕捉图象,mm 是video_mmap 结构,设置捕捉图象需要设置的信息。结构体

如下定义:

struct video_mmap

{

        unsigned        int frame;                /* Frame (0 - n) for double buffer */

        int                height,width;

        unsigned        int format;                /* should be VIDEO_PALETTE_* */

};

frame :设置当前是第几帧

height,width:设置图象的高和宽。

format :颜色模式

要注意的是,该命令是非阻塞的,也就是说,它仅仅设置了硬件,而不负责是否捕捉到图象。

要确定是否捕捉到图象,要用到下一个命令。

6. ioctl(fd,VIDIOCSYNC,&frame)

等待捕捉到这一帧图象。frame 是要等待的图象,它的值应和上一个命令中设置的frame相对应。

好了,说了这么多,读者大概也对视频捕捉有了一个了解,是不是想亲自动手试一下,那就让我们

开始实际程序的编写吧。

下面我们会编一个程序,将捕捉到的图象存为jpeg文件。为此,还要向大家介绍一个函数,

int write_jpeg(char *filename,unsigned char *buf,int quality,int width, int height, int gray)

{

    struct jpeg_compress_struct cinfo;

    struct jpeg_error_mgr jerr;

    FILE *fp;

    int i;

    unsigned char *line;

    int line_length;

   

    if (NULL == (fp = fopen(filename,"w")))

    {

                fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));

                return -1;

    }

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_compress(&cinfo);

    jpeg_stdio_dest(&cinfo, fp);

    cinfo.image_width  = width;

    cinfo.image_height = height;

    cinfo.input_components = gray ? 1: 3;

    cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;

    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, quality, TRUE);

    jpeg_start_compress(&cinfo, TRUE);

    line_length = gray ? width : width * 3;

    for (i = 0, line = buf; i < height; i++, line += line_length)

        jpeg_write_scanlines(&cinfo, &line, 1);

   

    jpeg_finish_compress(&(cinfo));

    jpeg_destroy_compress(&(cinfo));

    fclose(fp);

    return 0;

}

这个函数很通用,它的作用是把buf中的数据压缩成jpeg格式。

/*         下面是一个完整的程序 test.c

*           gcc test.c -o test -ljpeg

*/

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <sys/mman.h>

#include <errno.h>

#include <linux/videodev.h>

         

#include <jpeglib.h>

#define WIDTH  320

#define HEIGHT 240

#define V4L_DEVICE "/dev/video0"

main()

{

   unsigned char* buf;

   int i,j;

   int fd;

   int re;

   struct video_capability vcap;

   struct video_channel    vc;

   struct video_mbuf       mbuf;

   struct video_mmap       mm;

   fd = open(V4L_DEVICE, O_RDWR);

   if(fd<=0)

   {

           perror("open");

             exit(1);

   }

   if(ioctl(fd, VIDIOCGCAP, &vcap)<0)

   {

             perror("VIDIOCGCAP");

             exit(1);

   }

   fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);

   for(i=0;i<vcap.channels;i++)

   {

             vc.channel = i;

             if(ioctl(fd, VIDIOCGCHAN, &vc)<0)

             {

                       perror("VIDIOCGCHAN");

                       exit(1);

             }

             fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);

   }

   vc.channel =1;

   vc.norm=1;

   if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)

   {

             perror("VIDIOCSCHAN");

             exit(1);

   }

  if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)

  {

        perror("VIDIOCGMBUF");

        exit(1);

  }

   fprintf(stderr,"the frames number is %d\n",mbuf.frames);

  buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

   if((int)buf < 0)

   {

             perror("mmap");

             exit(1);

   }

   mm.frame  = 0;

   mm.height = HEIGHT;

   mm.width  = WIDTH;

   mm.format = VIDEO_PALETTE_RGB24;

   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)

   {

             perror("VIDIOCMCAPTURE");

            exit(1);

   }

   if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)

   {

             perror("VIDIOCSYNC");

             exit(1);

   }

if(-1 == (write_jpeg("./pic001.jpeg",buf,75,WIDTH,HEIGHT,0)))

{

        printf("write_jpeg error\n");

        exit(1);

}

   munmap(buf,mbuf.size);

   close(fd);

} 

转自:

<#--{zx1}日志--> <#--推荐日志--> <#--引用记录--> <#--相关日志--> <#--推荐日志--> <#--推荐阅读--> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构-->
郑重声明:资讯 【在linux下使用视频采集卡】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——