Chinaunix首页 | 论坛 | 博客
  • 博客访问: 516172
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: LINUX

2008-08-12 19:54:35

最近做一个视频采集,为了调试,先截了图片出来,涉及到图片的转换。调试过程花了一定的时间,现把源代码奉上,供大家参考

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <linux/videodev.h>
#include <sys/ioctl.h>

#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/delay.h>
#include <time.h>

#define ERR_FRAME_BUFFER    1
#define ERR_VIDEO_OPEN        2
#define ERR_VIDEO_GCAP        3
#define ERR_VIDEO_GPIC        4
#define ERR_VIDEO_SPIC        5
#define ERR_SYNC            6
#define ERR_FRAME_USING 7
#define ERR_GET_FRAME 8

typedef struct    _fb_v4l
{
  int fbfd ;                        
  struct fb_var_screeninfo vinfo;        
  struct fb_fix_screeninfo finfo;    
  char *fbp;                        
                                    
  int fd;                                    
  struct video_capability capability;    
  struct video_buffer      buffer;        
  struct video_window      window;        
  struct video_channel      channel[8];    
  struct video_picture      picture;    
  struct video_tuner      tuner;        
  struct video_audio      audio[8];        
  struct video_mmap      mmap;            
  struct video_mbuf      mbuf;            
  unsigned char      *map;                            
  int frame_current;
  int frame_using[VIDEO_MAX_FRAME];
}fb_v41;

struct file_header
{
  unsigned short bfType; // Picture tpye, must set to 19778

  int bfSize; // The file size in bytes

  int bfRev; // Reserved

  int bfOffBits; // the offset from the beginning of the file to the bitmap data.

}__attribute__ ((packed));

struct info_header
{
  int biSize; // info_header's size in bytes

  int biWidth; // width in pixels

  int biHeight;//height in pixels

  short biPlanes; //the number of planes of the target device

  short biBitCount; //the number of bits per pixel

  int biCompression;//the type of compression

  int biSizeImage; //

  int biXPelsPerMeter;//usually set to zero

  int biYPelsPerMeter;//usually set to zero

  int biClrUsed;//the number of colors used in the bitmap

  int biClrImportant;
}__attribute__ ((packed));


struct bmp_file
{
  struct file_header header;
  struct info_header info;
  unsigned char bits[640*480*3];
}__attribute__ ((packed));

#define V4L_FILE "/dev/video0"

int get_grab_frame(fb_v41 *vd, int frame)
{
  if (vd->frame_using[frame])
    {
      fprintf(stderr, "get_grab_frame: frame %d is already used.\n", frame);
      return ERR_FRAME_USING;
    }

  vd->mmap.frame = frame;
  if (ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0)
    {
      perror("v4l_grab_frame");
      return ERR_GET_FRAME;
    }
  vd->frame_using[frame] = 1;
  vd->frame_current = frame;
  return 0;
}


int get_first_frame(fb_v41 *vd)
{
  int ret;
  
  vd->frame_current = 0;
  ret = get_grab_frame( vd, 0 );
  if ( ret<0 )
    return ret;

  if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0)
    {
      perror("v4l_grab_sync");
      return ERR_SYNC;
    }
  vd->frame_using[vd->frame_current] = 0 ;
        
  return (0);
}


int get_next_frame(fb_v41 *vd)
{
  int ret;

  vd->frame_current ^= 1;
  ret = get_grab_frame( vd,vd->frame_current);        
  if( ret < 0 )
    return ret;
        
  if (ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0)
    {
      perror("v4l_grab_sync");
      return ERR_SYNC;
    }
  vd->frame_using[vd->frame_current] = 0 ;
  
  return 0;    
}


unsigned char *get_frame_address(fb_v41 *vd)
{
  return (vd->map + vd->mbuf.offsets[vd->frame_current]);
}

int open_video( char *fileptr,fb_v41 *vd ,int dep,int pal,int width,int height)
{
  if ((vd->fd = open(fileptr, O_RDWR)) < 0)
    {
      perror("v4l_open:");
      return ERR_VIDEO_OPEN;
    }

  if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0)
    {
      perror("v4l_get_capability:");
      return ERR_VIDEO_GCAP;
    }
     
  if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0)
    {
      perror("v4l_get_picture");
      return ERR_VIDEO_GPIC;
    }

  vd->picture.palette = pal;    
  vd->picture.depth = dep;            

  vd->mmap.format = pal;
  if (ioctl(vd->fd, VIDIOCSPICT, &(vd->picture)) < 0)
    {
      perror("v4l_set_palette");
      return ERR_VIDEO_SPIC;
    }
  
  vd->mmap.width = width;     
  vd->mmap.height = height;
  vd->mmap.format = vd->picture.palette;
  vd->frame_current = 0;
  vd->frame_using[0] = 0;
  vd->frame_using[1] = 0;
   
  if (ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf)) < 0)
    {
      perror("v4l_get_mbuf");
      return -1;
    }

  vd->map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0);
  if ( vd->map < 0)
    {
      perror("v4l_mmap_init:mmap");
      return -1;
    }

  printf("The video device was opened successfully.\n");
  return 0;
}

static void cvt_420p_to_rgb(int width, int height, const unsigned char *src, unsigned char *dst)
{
  int r, g, b;
  int rdif, gdif, bdif, y;
  int yy, uu, vv;
  int xoff, yoff;
  int numpix = width*height;
  unsigned char *pout = dst + width*height*3;

  for(yoff=0; yoff<height; yoff++)
    {
      for(xoff=0; xoff<width; xoff++)
    {
     yy = *(src+yoff*640+xoff);
     uu = *(src+(yoff/2)*320+xoff/2+numpix);
     vv = *(src+(yoff/2)*320+xoff/2+numpix+numpix/4);

     uu -= 128;
     vv -= 128;

     r = yy + vv + ((vv*103)>>8);
     g = yy - ((uu*88)>>8) - ((vv*183)>>8);
     b = yy + uu + ((uu*198)>>8);

     if(r>255) { r = 255; }
     if(g>255) { g = 255; }
     if(b>255) { b = 255; }
     if(r<0) { r = 0;}
     if(g<0) { g = 0;}
     if(b<0) { b = 0;}

     *pout = (unsigned char)b;
     pout--;
     *pout = (unsigned char)r;
     pout--;
     *pout = (unsigned char)g;
     pout--;
    }
    }
}

int main( void )
{
  fb_v41 vd;
  int ret,i;
  int k=0;
  unsigned char *imageptr;
  struct bmp_file myfile;
  int fd;

  printf("sizeof short is %d\n", sizeof(short));

  myfile.header.bfType = 19778;
  myfile.header.bfSize = sizeof(struct bmp_file);
  myfile.header.bfRev = 0;
  myfile.header.bfOffBits = 54;

  myfile.info.biSize = 0x28;
  myfile.info.biWidth = 640;
  myfile.info.biHeight = 480;
  myfile.info.biPlanes = 1;
  myfile.info.biBitCount = 24;
  myfile.info.biCompression = 0;
  myfile.info.biSizeImage = 0;
  myfile.info.biClrUsed = 256*256*256;
  myfile.info.biClrImportant = 0;
  myfile.info.biXPelsPerMeter = 2048;
  myfile.info.biYPelsPerMeter = 2048;

  fd = open("./first.bmp", O_RDWR);
  if(fd < 0)
    {
      printf("open file error!\n");
      return 0;
    }
       
    
  ret = open_video( V4L_FILE, &vd, 24, VIDEO_PALETTE_YUV420P, 640, 480);
  if( ret )        
    {
      printf("Open video failed!\n");
      goto err;
    }
        
  printf(vd.capability.name);
  printf(", Type:%d\n",vd.capability.type);
  printf("Maxwidth:%d,Maxheight:%d\n",vd.capability.maxwidth ,vd.capability.maxheight);
  printf("Minwidth:%d,Minheight:%d\n",vd.capability.minwidth,vd.capability.minheight);
  printf("Channels:%d,Audios:%d\n",vd.capability.channels,vd.capability.audios);
 
  for(i=0;i<10;i++)
    {
      imageptr = (unsigned char *)get_frame_address(&vd );    

      if(get_next_frame( &vd ) !=0 )    
    {    
     goto err;
    }

      printf("i = %d\n", i);
    }

  cvt_420p_to_rgb(640, 480, imageptr, myfile.bits);

  write(fd, &myfile, sizeof(struct bmp_file));
        
err:
  if(vd.fbfd)
    close(vd.fbfd);
        
  if(vd.fd)
    close(vd.fd);

  exit(0);

  return 0;
}

 

采集图片大小为640*480,采用24位色。在使用的时候,现要在当前目录下touch一个first.bmp文件,不然运行程序的时候会提示open file error!

图片最后为bmp格式,可以直接在xp下用常用图片软件打开,效果还可以。

说明一下,本程序是由其他程序修改而来,为了避免麻烦,对其中一些没有用的地方并没有删除,但是这样不会影响使用。

大家有问题可以联系我。

阅读(3795) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~