V4L拍照程序

请注意:此程序只能驱动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;
}

猜你喜欢

转载自blog.csdn.net/Chenger_32123/article/details/81332231