Chinaunix首页 | 论坛 | 博客
  • 博客访问: 855996
  • 博文数量: 290
  • 博客积分: 511
  • 博客等级: 下士
  • 技术积分: 1590
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-29 13:14
文章分类

全部博文(290)

文章存档

2018年(28)

2017年(19)

2016年(8)

2015年(1)

2014年(14)

2013年(12)

2012年(22)

2011年(186)

分类:

2011-06-09 15:42:11

原文地址:video4linux编程 作者:y307921462

今日想将摄像头采集的图像实时显示在LCD上,上网找了些资料和去图书馆借了书看了,整理得如下源码,可以采集到图像,保存为jog格式,下一步用minigui调用图片显示在LCD上:
以防日后忘记,写上注释
 

/*
*File Name:v4l.h
*author:gufeiyang 2.10-3.20
*/

#ifndef _MYV4L_H_
#define _MYV4L_H_
#include <linux/videodev.h>
/*定义硬件用到的结构体*/
struct _v4l_struct
{
  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];
};
typedef struct _v4l_struct v4l_device;
#define DEFAULT_DEVICE "/dev/video0"
#define FALSE 0
#ifndef TRUE
#define TRUE -1
#endif
#define WIDTH 320
#define HEIGHT 240

#ifndef VIDEO_PALETTE_JPEG
#define VIDEO_PALETTE_JPEG 21
#endif

extern int v4l_open(char *dev, v4l_device *vd);
extern int v4l_close(v4l_device *);
extern int v4l_get_capability(v4l_device *vd);
extern int v4l_set_norm(v4l_device *, int);
extern int v4l_get_channels(v4l_device *);
extern int v4l_get_audios(v4l_device *);
extern int v4l_get_picture(v4l_device *);
extern int v4l_grab_init(v4l_device *, int, int);
extern int v4l_grab_frame(v4l_device *, int);
extern int v4l_grab_sync(v4l_device *);
extern int v4l_mmap_init(v4l_device *);
extern int v4l_get_mbuf(v4l_device *);
extern int v4l_get_buffer(v4l_device *vd);
extern int v4l_set_buffer(v4l_device *vd);
extern int v4l_get_picture(v4l_device *vd);
extern int v4l_set_picture(v4l_device *vd);
extern int v4l_grab_picture(v4l_device *, unsigned int);
extern int v4l_set_buffer(v4l_device *);
extern int v4l_get_buffer(v4l_device *);
extern int v4l_switch_channel(v4l_device *, int);
extern int write_jpeg(char *filename, unsigned char * img, int width, int height, int quality, int gray);
extern char * v4l_get_mapaddress( v4l_device *vd,int frame);
#endif


/*
*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;
}


/*
*File Name:main.c
*author:gufeiyang 2.10-3.20
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <error.h>
#include <linux/videodev.h>
#include "v4l.h"
static v4l_device v4l_dev;
int device_init(char *dev, v4l_device *vd, int norm,int channel)
{
  int i;
  if(dev == NULL)
    dev = "/dev/video0";
  if(v4l_open(dev , vd))
    return -1;
  if(v4l_get_capability(vd))
    return -1;
  if(v4l_get_channels(vd))
    return -1;
  if(v4l_get_audios(vd))
    return -1;
  if(v4l_get_picture(vd))
    return -1;
  if(v4l_set_picture(vd))
    return -1;
  if(v4l_get_mbuf(vd))
    return -1;
   if (v4l_mmap_init(vd))
    return -1;
  
 if(v4l_grab_init(vd,WIDTH,HEIGHT))
   return -1;

 
 printf("Device's Information!\n");
 printf("%s: initialization OK... %s\n"
     "%d chnanels \n"
     "%d audios\n",
 dev, vd->capability.name,vd->capability.channels,vd->capability.audios);
 printf("v4l: mmap's address = %p\n", vd->map);
 printf("v4l: mmap's buffer size = 0x%x\n", vd->mbuf.size);
 printf("v4l: mmap's frames = %d (%d max)\n", vd->mbuf.frames, VIDEO_MAX_FRAME);
 for (i = 0; i < vd->mbuf.frames; i++) {
   printf("v4l: frames %d's offset = 0x%x\n", i, vd->mbuf.offsets[i]);
 }
  return 0;
}
int main()
{
  char *address;
  
  if(device_init(DEFAULT_DEVICE, &v4l_dev, 1, 0)){
    perror("device_init:failed...\n");
    exit(1);
  } else {
    while(1)
    {
// printf("Start Saveing Image...\n");

    v4l_sync(&v4l_dev);
    address = v4l_get_mapaddress(&v4l_dev,0);
    if( address==(char *)NULL){
      perror(" get mapaddress Failed!\n");
      exit(-1);
    }
    if(-1 == (write_jpeg("1.jpg",address,50,WIDTH,HEIGHT,FALSE)))
    {
      printf("write_jpeg error\n");
      exit(1);
    }
// printf("The Image has saved!\n");

  }
  v4l_grab_init(&v4l_dev,WIDTH,HEIGHT);
  }
  v4l_close(&v4l_dev);
  exit(0);
}


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