linux 下視頻設備設置的幾個參數 v4l video4linux v4l2 ioctl

用一系列的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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章