全部博文(668)
分类:
2009-08-04 15:00:41
用一系列的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 #include #include #include #include #include #include #include #include #include #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 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); } |