请注意:此程序只能驱动v4l1的摄像头,无法驱动v4l2摄像头。拍摄的图片保存在 photo/client1_catch.jpg
/******************main.c*************/
#include "v4l1_camera.h"
void main()
{
Carema_Catch_Picture(); //捕获照片
}
/*****
/////v4l1_camera.h
*****/
#ifndef __V4L1_CAMERA_H__
#define __V4L1_CAMERA_H__
void Carema_Catch_Picture();
#endif
/*****
////v4l1_camera.c
*****/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
/*******/
#include <dirent.h>
/******/
#define VIDEO_PALETTE_JPEG 21
#define BRIDGE_ZC3XX 0
#define MAX_BRIDGE 2
#define JPEG 0
#define UNOW 1
//摄像头信息=============================
struct vdIn
{
int fd;
char *videodevice ;
struct video_mmap vmmap;
struct video_capability videocap;
int mmapsize;
struct video_mbuf videombuf;
struct video_picture videopict;
struct video_channel videochan;
int cameratype ;
char *cameraname;
char bridge[9];
int palette; // available palette
int grabMethod ;
unsigned char *pFramebuffer;
unsigned char *ptframe;
int framesizeIn ;
int bppIn;
int hdrwidth;
int hdrheight;
int formatIn;
};
/*摄像头信息结构体===================================*/
struct vdIn videoIn;
struct bridge_list
{
int num;
const char *name;
};
//初始化摄像头信息
int init_videoIn(struct vdIn *vd,char *device,int width,int height,int format,int grabmethod);
//获取图像
int v4lGrab (struct vdIn *vd,char *filename );
//关闭摄像头
int close_v4l (struct vdIn *vd);
//获取图片大小
int get_jpegsize (unsigned char *buf, int insize);
void exit_fatal(char *messages);
static int init_v4l (struct vdIn *vd);
static int isSpcaChip ( const char * BridgeName );
static int GetStreamId ( const char * BridgeName );
static int GetDepth (int format);
static struct bridge_list Blist[]={
{BRIDGE_ZC3XX,"ZC301-2"},
};
/***************初始化结构体struct vdin函数**********************/
int init_videoIn (struct vdIn *vd, char *device, int width, int height, int format, int grabmethod)
{
int err = -1;
int i;
if (vd == NULL || device == NULL)
return -1;
if (width == 0 || height == 0)
return -1;
if(grabmethod < 0 || grabmethod > 1)
grabmethod = 1; //read by default;
vd->videodevice = NULL;
vd->cameraname = NULL;
vd->videodevice = NULL;
vd->videodevice = (char *) realloc (vd->videodevice, 32); //分配内存
vd->cameraname = (char *) realloc (vd->cameraname, 32);
snprintf (vd->videodevice, 32, "%s", device); //赋值
memset (vd->cameraname, 0, sizeof (vd->cameraname));
memset(vd->bridge, 0, sizeof(vd->bridge));
vd->hdrwidth = width;
vd->hdrheight = height;
vd->formatIn = format;
vd->bppIn = GetDepth (vd->formatIn); //获取深度为8;跳转//=======================》
vd->grabMethod = grabmethod; //采集的方法read , mmap;
vd->pFramebuffer = NULL; //存放采集数据的缓存;
err = init_v4l (vd); //跳转========================》
vd->ptframe = NULL; //存放压缩帧的缓存
vd->ptframe = (unsigned char *) realloc (vd->ptframe, (size_t) vd->framesizeIn ); //分配内存;
return err;
}
/**************关闭函数*****************/
int close_v4l (struct vdIn *vd)
{
int i;
if (vd->grabMethod)
{
munmap (vd->pFramebuffer, vd->mmapsize);
}
else
{
free(vd->pFramebuffer);
vd->pFramebuffer = NULL;
}
close (vd->fd);
if (vd->videodevice)
{
free (vd->videodevice);
vd->videodevice = NULL;
}
if (vd->cameraname)
{
free (vd->cameraname);
vd->cameraname = NULL;
}
if (vd->ptframe)
{
free (vd->ptframe);
vd->ptframe = NULL;
}
}
/*==================================================*/
int convertframe(unsigned char *dst,unsigned char *src, int width,int height, int formatIn, int size)
{
int jpegsize =0;
switch (formatIn)
{
case VIDEO_PALETTE_JPEG:
jpegsize = get_jpegsize(src, size); //获取图像的大小
if (jpegsize < 0)
break;
memcpy(dst,src,jpegsize);
break;
default:
break;
}
return jpegsize;
}
/*****************图片抓取函数*******************/
int v4lGrab(struct vdIn *vd, char *filename)
{
FILE *fp;
static int frame = 0;
int len;
int size;
int erreur = 0;
int jpegsize = 0;
/*mmap*/
if (vd->grabMethod)
{
vd->vmmap.height = vd->hdrheight;
vd->vmmap.width = vd->hdrwidth;
vd->vmmap.format = vd->formatIn;
vd->vmmap.frame=0;
if ((ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap))) < 0)
{
perror ("cmcapture");
}
if (ioctl (vd->fd, VIDIOCSYNC, &vd->vmmap.frame) < 0)
{
perror ("cvsync err\n");
erreur = -1;
}
jpegsize= convertframe(vd->ptframe, vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame], vd->hdrwidth,vd->hdrheight,vd->formatIn,vd->framesizeIn);
//send_frame((void*)vd->ptframe,jpegsize,0,vFrameNo++,sock,(struct sockaddr*)&sa_send,sizeof(sa_send));
}
else //read
{
size = vd->framesizeIn;
/*读函数*/
len = read (vd->fd, vd->pFramebuffer, size);
if (len < 0 )
{
return -1;
}
jpegsize= convertframe(vd->ptframe, vd->pFramebuffer ,vd->hdrwidth,vd->hdrheight,vd->formatIn,vd->framesizeIn);
/*写图片*/
fp = fopen(filename, "wb+"); //创建图片文件保存在本地(开发板),为储存拍摄后的图片做准备,
if(!fp)
return -1;
if(fwrite(vd->ptframe, jpegsize, 1, fp)<0) //将数据写入文件
{
printf("write fail\n");
exit(1);
}
printf("write succuess!\n");
fclose(fp);
}
return erreur;
}
/****************获取图片函数************************/
static int GetVideoPict (struct vdIn *vd)
{
if (ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) < 0)
exit_fatal ("Couldnt get videopict params with VIDIOCGPICT");
return 0;
}
/******************设置图片信息********************/
static int SetVideoPict (struct vdIn *vd)
{
if (ioctl (vd->fd, VIDIOCSPICT, &vd->videopict) < 0)
exit_fatal ("Couldnt set videopict params with VIDIOCSPICT");
return 0;
}
/************v4l()初始化函数******************/
static int init_v4l (struct vdIn *vd)
{
int f;
int erreur = 0;
int err;
/*打开设备*/
if ((vd->fd = open (vd->videodevice, O_RDWR)) == -1)
exit_fatal ("ERROR opening V4L interface");
/*获取设备信息*/
if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1)
exit_fatal ("Couldn't get videodevice capability");
snprintf (vd->cameraname, 32, "%s", vd->videocap.name); //赋值;
erreur = GetVideoPict (vd); //获取图片信息函数,跳转==============================>
/*获取信道信息*/
if (ioctl (vd->fd, VIDIOCGCHAN, &vd->videochan) == -1)
{
vd->cameratype = UNOW;
}
else
{
if (vd->videochan.name)
{
snprintf (vd->bridge, 9, "%s", vd->videochan.name); //赋值;
vd->cameratype = GetStreamId (vd->bridge); //采集的类型,跳转==========================》
}
else
{
vd->cameratype = UNOW;
}
}
vd->videopict.palette = vd->formatIn;
vd->videopict.depth = GetDepth (vd->formatIn);
vd->bppIn = GetDepth (vd->formatIn);
vd->framesizeIn = (vd->hdrwidth * vd->hdrheight >> 2 ); // here alloc the output ringbuffer jpeg only //帧大小;
erreur = SetVideoPict (vd); //设置图片信息=================》
erreur = GetVideoPict (vd); //获得图片信息=================》
if (vd->grabMethod)
{
// MMAP VIDEO acquisition
memset (&(vd->videombuf), 0, sizeof (vd->videombuf));
if (ioctl (vd->fd, VIDIOCGMBUF, &(vd->videombuf)) < 0)
{
perror (" init VIDIOCGMBUF FAILED\n");
}
vd->pFramebuffer =(unsigned char *) mmap (0, vd->videombuf.size, PROT_READ | PROT_WRITE,MAP_SHARED, vd->fd, 0); //内存映射
vd->mmapsize = vd->videombuf.size;
vd->vmmap.height = vd->hdrheight;
vd->vmmap.width = vd->hdrwidth;
vd->vmmap.format = vd->formatIn;
vd->vmmap.frame = 0;
if (ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap))) //获取图像
{
perror ("cmcapture");
}
}
//read
else
{
vd->pFramebuffer =(unsigned char *) realloc (vd->pFramebuffer, (size_t) vd->framesizeIn); //分配内存;
}
return erreur;
}
static int isSpcaChip (const char *BridgeName)
{
int i = -1;
int find = -1;
int size = 0;
for (i = 0; i < MAX_BRIDGE -1; i++)
{
size = strlen (Blist[i].name) ; //跳转================》
if (strncmp (BridgeName, Blist[i].name, size) == 0) //判断名字是否相同;
{
find = i;
break;
}
}
return find;
}
static int GetStreamId (const char *BridgeName)
{
int i = -1;
int match = -1;
if ((match = isSpcaChip (BridgeName)) < 0) //跳转==================>
{
return match;
}
switch (match)
{
case BRIDGE_ZC3XX:
i = JPEG;
break;
break;
}
return i;
}
/*******获取深度函数***********/
static int GetDepth (int format)
{
int depth;
switch (format)
{
case VIDEO_PALETTE_JPEG:
{
depth = 8;
}
break;
default:
depth = -1;
break;
}
return depth;
}
/********调试信息函数************/
void exit_fatal(char *messages)
{
printf("%s \n",messages);
exit(1);
}
/*****************获取图片的大小**************************/
int get_jpegsize (unsigned char *buf, int insize)
{
int i;
for ( i= 1024 ; i< insize; i++)
{
if ((buf[i] == 0xFF) && (buf[i+1] == 0xD9))
return i+2;
}
return -1;
}
/*************主函数*********************/
//int main(int argc, char *argv[])
void Carema_Catch_Picture()
{
char videodevice[] = "/dev/video0"; //设备文件 //摄像头位置
char jpegfile[] = "photo/client1_catch.jpg";//图片名称及位置。
/**************/
if(NULL==opendir("photo")) //打开一个目录,如果没有该目录,则返回null
{
mkdir("photo",0777);//创建一个目录photo
}
/**************/
int grabmethod = 0; //获取图片的方式
int format = VIDEO_PALETTE_JPEG; //格式
int width = 360; //图片宽度
int height = 300; //图片高度
memset(&videoIn, 0, sizeof (struct vdIn)); //将结构体vfIn置0,与 bzero(&videoIn,sizeof (struct vdIn)) 是相同的意思,可互相替换。
//在程序中,对缓冲区清零是为了不影响下一次的输入或输出。也可用于初始化数组或结构体。
/*===========================================*/
/*===========================================*/
if(init_videoIn(&videoIn, videodevice, width, height, format,grabmethod)== 0) //初始化摄像头
{
v4lGrab(&videoIn, jpegfile); //图片抓取函数
if(grabmethod == 1)
{
printf("you use mmap method!\n");
}
else if(grabmethod==0)
{
printf("you use read method!\n");
printf("you have get a picture in %s\n",jpegfile);
}
}
else
{
printf("can't open your camera!\n");
}
close_v4l (&videoIn); //关闭摄像头
// return 0;
}