织梦CMS - 轻松建站从此开始!

罗索

在linux下使用视频采集卡

落鹤生 发布于 2010-05-05 21:47 点击:次 
这一部分将会介绍如何在 linux 中对电视卡编程。 开始已经提到过,电视卡使用的是video for linux驱动,简称v4l,实际上,现在已经有了video for linux two驱动 ,即v4l2.它解决了v4l中存在的一些问题,并且提高了硬件性能。但是,目前来说,v4l2仍然没有集成到linux的
TAG:

这一部分将会介绍如何在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命令返回时,结构的各成员就被赋值了,结构体的定义为:
 
  1. struct video_capability 
  2.         char name[32]; 
  3.         int type; 
  4.         int channels;        /* Num channels */ 
  5.         int audios;        /* Num audio devices */ 
  6.         int maxwidth;        /* Supported width */ 
  7.         int maxheight;        /* And height */ 
  8.         int minwidth;        /* Supported width */ 
  9.         int minheight;        /* And height */ 
  10. }; 
channel 指的是有几个信号输入源,例如television,composite,s-video等。

2.ioctl(fd,VIDIOCGCHAN,&vc)
3.ioctl(fd,VIDIOCSCHAN.&vc)
这两个命令用来取得和设置电视卡的channel信息,例如使用那个输入源,制式等。
vc 是一个video_channel结构,其定义为:
  1. struct video_capability 
  2.         char name[32]; 
  3.         int type; 
  4.         int channels;        /* Num channels */ 
  5.         int audios;        /* Num audio devices */ 
  6.         int maxwidth;        /* Supported width */ 
  7.         int maxheight;        /* And height */ 
  8.         int minwidth;        /* Supported width */ 
  9.         int minheight;        /* And height */ 
  10. }; 
  11. struct video_channel 
  12.         int channel; 
  13.         char name[32]; 
  14.         int tuners;//number of tuners for this input 
  15.         __u32  flags; 
  16.         __u16  type;        
  17.         __u16 norm;                
  18. }; 
成员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函数将缓存映射到内存中了。大致用法可以参考以下的代码......
  1. struct video_mbuf mbuf; 
  2. unsigned char *buf1,*buf2; 
  3.  
  4. if(ioctl(fd,VIDIOCGMBUF,&mbuf)<0) 
  5.         perror("VIDIOCGMBUF"); 
  6.         return -1; 
  7.  
  8. printf("the frame number is %d\n",mbuf.frames); 
  9.  
  10. buf1 = (unsigned char*)mmap(0,mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd.0); 
  11.  
  12. buf1 = buf1 + mbuf.offset[0]; 
  13. buf2 = buf1 + mbuf.offset[1];//当然,如果mbuf.frames=1,就不需要下面的了。 

5. ioctl(fd.VIDIOCMCAPTURE,&mm)
   启动硬件去捕捉图象,mm 是video_mmap 结构,设置捕捉图象需要设置的信息。结构体
如下定义:
  1. struct video_mmap 
  2.         unsigned        int frame;                /* Frame (0 - n) for double buffer */ 
  3.         int                height,width; 
  4.         unsigned        int format;                /* should be VIDEO_PALETTE_* */ 
  5. }; 

frame :设置当前是第几帧
height,width:设置图象的高和宽。
format :颜色模式

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

6. ioctl(fd,VIDIOCSYNC,&frame)
等待捕捉到这一帧图象。frame 是要等待的图象,它的值应和上一个命令中设置的frame相对应。

好了,说了这么多,读者大概也对视频捕捉有了一个了解,是不是想亲自动手试一下,那就让我们
开始实际程序的编写吧。
  1. /*         下面是一个完整的程序 test.c 
  2. *           gcc test.c -o test -ljpeg 
  3. */ 
  4.  
  5. #include <stdio.h> 
  6. #include <stdlib.h> 
  7. #include <sys/types.h> 
  8. #include <sys/stat.h> 
  9. #include <fcntl.h> 
  10. #include <sys/ioctl.h> 
  11. #include <sys/mman.h> 
  12. #include <errno.h> 
  13. #include <linux/videodev.h> 
  14.           
  15. #include <jpeglib.h> 
  16.  
  17. #define WIDTH  320 
  18. #define HEIGHT 240 
  19. #define V4L_DEVICE "/dev/video0" 
  20.  
  21. main() 
  22.    unsigned char* buf; 
  23.    int i,j; 
  24.    int fd; 
  25.    int re; 
  26.  
  27.    struct video_capability vcap; 
  28.    struct video_channel    vc; 
  29.    struct video_mbuf       mbuf; 
  30.    struct video_mmap       mm; 
  31.  
  32.    fd = open(V4L_DEVICE, O_RDWR); 
  33.    if(fd<=0) 
  34.    { 
  35.      perror("open"); 
  36.      exit(1); 
  37.    } 
  38.  
  39.    if(ioctl(fd, VIDIOCGCAP, &vcap)<0) 
  40.    { 
  41.      perror("VIDIOCGCAP"); 
  42.      exit(1); 
  43.    } 
  44.  
  45.    fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name); 
  46.  
  47.    for(i=0;i<vcap.channels;i++) 
  48.    { 
  49.      vc.channel = i; 
  50.      if(ioctl(fd, VIDIOCGCHAN, &vc)<0){ 
  51.       perror("VIDIOCGCHAN"); 
  52.       exit(1); 
  53.     } 
  54.   fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name); 
  55.  
  56. vc.channel =1; 
  57. vc.norm=1; 
  58.  
  59. if(ioctl(fd, VIDIOCSCHAN, &vc) < 0) 
  60.   perror("VIDIOCSCHAN"); 
  61.   exit(1); 
  62.  
  63. if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0) 
  64.   perror("VIDIOCGMBUF"); 
  65.   exit(1); 
  66. fprintf(stderr,"the frames number is %d\n",mbuf.frames); 
  67.  
  68. buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
  69. if((int)buf < 0) 
  70.   perror("mmap"); 
  71.   exit(1); 
  72. mm.frame  = 0; 
  73. mm.height = HEIGHT; 
  74. mm.width  = WIDTH; 
  75. mm.format = VIDEO_PALETTE_RGB24; 
  76.  
  77. if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0) 
  78.   perror("VIDIOCMCAPTURE"); 
  79.   exit(1); 
  80.  
  81. if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0) 
  82.   perror("VIDIOCSYNC"); 
  83.   exit(1); 
  84.  
  85. if(-1 == (write_jpeg("./pic001.jpeg",buf,75,WIDTH,HEIGHT,0))) 
  86.   printf("write_jpeg error\n"); 
  87.   exit(1); 
  88.  
  89. munmap(buf,mbuf.size); 
  90. close(fd); 

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

  1. int write_jpeg(char *filename,unsigned char *buf,int quality,int width, int height, int gray) 
  2.     struct jpeg_compress_struct cinfo; 
  3.     struct jpeg_error_mgr jerr; 
  4.     FILE *fp; 
  5.     int i; 
  6.     unsigned char *line; 
  7.     int line_length; 
  8.     
  9.     if (NULL == (fp = fopen(filename,"w"))) 
  10.     { 
  11.     fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno)); 
  12.     return -1; 
  13.     } 
  14.     cinfo.err = jpeg_std_error(&jerr); 
  15.     jpeg_create_compress(&cinfo); 
  16.     jpeg_stdio_dest(&cinfo, fp); 
  17.     cinfo.image_width  = width; 
  18.     cinfo.image_height = height; 
  19.     cinfo.input_components = gray ? 1: 3; 
  20.     cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB; 
  21.     jpeg_set_defaults(&cinfo); 
  22.     jpeg_set_quality(&cinfo, quality, TRUE); 
  23.     jpeg_start_compress(&cinfo, TRUE); 
  24.  
  25.     line_length = gray ? width : width * 3; 
  26.     for (i = 0, line = buf; i < height; i++, line += line_length) 
  27.         jpeg_write_scanlines(&cinfo, &line, 1); 
  28.     
  29.     jpeg_finish_compress(&(cinfo)); 
  30.     jpeg_destroy_compress(&(cinfo)); 
  31.     fclose(fp); 
  32.  
  33.     return 0; 

这 个函数很通用,它的作用是把buf中的数据压缩成jpeg格式。
(songok2007)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201005/9342.html]
本文出处:CSDN博客 作者:songok2007
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容