/* *File Name:v4l.c *author:gufeiyang 2.10-3.20 */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <error.h> #include <errno.h>/*errno undeclared*/ #include <linux/videodev.h> #include <sys/mman.h> #include <assert.h> #include <string.h> #include <assert.h> #include <jpeglib.h> /*jpeg*/ #include "v4l.h" /*Get Information*/ /*用ioctl方法取得设备文件的相关信息,存入struct capability结构体*/ int v4l_get_capability(v4l_device *vd) { if(ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) { perror("v4l_get_capability:"); return -1; } return 0; } /*取得视频采集的通道数目*/ int v4l_get_channels(v4l_device *vd) { int i; for(i = 0; i < vd->capability.channels; i++ ) { vd->channel[i].channel = i; if(ioctl(vd->fd, VIDIOCGCHAN, &(vd->channel[i])) < 0){ perror("v4l_get_channels:"); return -1; } } return 0; } /*切换视频采集通道*/ int v4l_switch_channel(v4l_device *vd, int c) { if(ioctl(vd->fd, VIDIOCSCHAN, &(vd->channel[c])) < 0){ perror("v4l_switch_channel:"); return -1; } return 0; } /*获得audios的信息*/ int v4l_get_audios(v4l_device *vd) { int i; for(i = 0; i < vd->capability.audios; i++){ vd->audio[i].audio = i; if(ioctl(vd->fd,VIDIOCGAUDIO, &(vd->audio[i])) < 0){ perror("v4l_get_audios:"); return -1; } } return 0; } /*information end*/
/*Set */ /*获得输入到视频采集卡的影像信息*/ int v4l_get_picture(v4l_device *vd) { if(ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) { perror("v4l_get_picture:"); return -1; } return 0; } /*设置设备的属性*/ //先为分量赋新值,再调用VIDIOCSPICT
int v4l_set_picture(v4l_device *vd){ if(ioctl(vd->fd,VIDIOCSPICT,&(vd->picture))<0) return -1; else return 0; } /*对所有的通道设置norm,完成需v4l_get_capability和v4l_get_picture,确保每个通道都设置成功*/ int v4l_set_norm(v4l_device *vd, int norm) { int i; for (i = 0; i < vd->capability.channels; i++) { vd->channel[i].norm = norm; }
if (v4l_get_capability(vd)) { perror("v4l_set_norm"); return -1; } if (v4l_get_picture(vd)) { perror("v4l_set_norm"); } return 0; } /*打开视频设备*/ int v4l_open(char *dev, v4l_device *vd) { if(!dev) dev = DEFAULT_DEVICE; if((vd->fd = open(dev, O_RDWR)) < 0) { perror("v4l_open:"); return -1; } return 0; } /*关闭*/ int v4l_close(v4l_device *vd) { munmap(vd->map,vd->mbuf.size); close(vd->fd); return 0; }
int v4l_get_mbuf(v4l_device *vd) { if(ioctl(vd->fd,VIDIOCGMBUF, &(vd->mbuf)) < 0){ perror("v4l_get_mbuf:"); return -1; } return 0; } /*初始化mmap,用途是将文件map到内存 *mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0) *0:起始位置 *vd->mbuf.size:长度 *PROT_READ|PROT_WRITE:可读写 *MAP_SHARED:可以与其他进程共享 *vd->fd:file description *0:offset */ int v4l_mmap_init(v4l_device *vd) { if(v4l_get_mbuf(vd) < 0) return -1; if((vd->map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0)) < 0){ perror("v4l_mmap_init:mmap"); return -1; } return 0; } int v4l_grab_frame(v4l_device *vd, int frame) {
if (vd->frame_using[frame]) { fprintf(stderr, "get_grab_frame: frame %d is already used.\n", frame); return -1; }
vd->mmap.frame = frame; if (ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0) { perror("v4l_grab_frame"); return -1; }
vd->frame_using[frame] = 1; vd->frame_current = frame; return 0; } /*根据图像信息初始化mmap里面的设置*/ int v4l_grab_init(v4l_device *vd, int width, int height) { vd->mmap.width = width; vd->mmap.height = height; vd->mmap.format = VIDEO_PALETTE_JPEG; vd->frame_current = 0; vd->frame_using[0] = FALSE; vd->frame_using[1] = FALSE; return v4l_grab_frame(vd, 0); } /*同步,等待图像采集完成*/ int v4l_grab_sync(v4l_device *vd) { if(ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current)) < 0){ perror("v4l_grab_sync"); } vd->frame_using[vd->frame_current] = FALSE; return 0; } /*获取缓冲空间*/ int v4l_get_buffer(v4l_device *vd) { if(ioctl(vd->fd,VIDIOCGFBUF, &(vd->buffer)) < 0){ perror("v4l_get_buffer:"); } return 0; } int v4l_set_buffer(v4l_device *vd) { if(ioctl(vd->fd,VIDIOCSFBUF,&(vd->buffer)) < 0){ perror("v4l_set_buffer:"); return -1; } return 0; } /*开始采集*/ int device_grab_frame(v4l_device *vd) { vd->frame_current = 0; if (v4l_grab_frame(vd, 0) < 0) return -1; return 0; } /*采集下一帧图像*/ int device_next_frame(v4l_device *vd) { vd->frame_current ^= 1; if (v4l_grab_frame(vd, vd->frame_current) < 0) return -1; return 0; } /*获取mmap的地址*/ char * v4l_get_mapaddress( v4l_device *vd,int frame) { char *frameaddress=NULL; frameaddress=vd->map+vd->mbuf.offsets[frame]; if(frameaddress>0){ return frameaddress; } else return NULL; } /* * *img: the address of the data that cam collected * with height : image with height *quality: 0-100 */ 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=0; unsigned char *line; int line_length; if ((fp = fopen(filename,"w")) == NULL ){ 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; } //同步
int v4l_sync(v4l_device *vd){ if(ioctl(vd->fd, VIDIOCSYNC, &(vd->frame_current))<0){ exit(-1); return -1; } vd->frame_using[vd->frame_current] = FALSE; return 0; }
|