linux下视频采集代码

本文介绍了一个基于HMM的远程面部检测识别综合控制应用平台中,使用video4linux (V4L)进行视频采集的方法。该平台针对FL2440开发板设计,详细阐述了错误处理机制及视频采集接口实现。
 

/*
 *==============================================================================
 *                    2011挑战杯 便携式HMM远程面部检测识别综合控制应用平台
 *
 * (c) Copyright 2011, 李明浩
 * All Rights Reserved
 *
 * 文件名称:lmh_err.h
 * 文件摘要:本头文件用于声明系统出错处理函数
 *
 * 当前版本:0.1
 * 作   者:李明浩
 * 完成日期:2011/03/24
 *
 * 取代版本:0.0
 * 作   者:李明浩
 * 完成日期:2011/03/10
 *==============================================================================
 */

#ifndef LMH_ERR_H
#define LMH_ERR_H

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>

#define MAXLINE      4096

/*==================================出错处理函数================================*/

extern void ErrRet( const char *fmt, ... );

extern void ErrSys( const char *fmt, ... );

extern void ErrMsg( const char *fmt, ... );

#endif /* LMH_ERR_H */

 

/*
 *============================================================================
 *                    2011挑战杯 便携式HMM远程面部检测识别综合控制应用平台
 *
 * (c) Copyright 2011, 李明浩
 * All Rights Reserved
 *
 * 文件名称:lmh_err.c
 * 文件摘要:本头文件用于实现系统出错处理函数
 *
 * 当前版本:0.1
 * 作   者:李明浩
 * 完成日期:2011/03/24
 *
 * 取代版本:0.0
 * 作   者:李明浩
 * 完成日期:2011/03/10
 *============================================================================
 */

#include "lmh_err.h"

static void   /* 声明静态函数 */
ErrDoit(
     int         errnoflag,
     int         error,
     const char *fmt,
     va_list     ap
     );

/*
 * 出错处理函数,当调用linux下系统调用失败时使用, 目的是使程序终止.
 */
void
ErrSys( const char *fmt, ... )
{
     va_list ap;

     va_start( ap, fmt );
     ErrDoit( 1, errno, fmt, ap );
     va_end( ap );
     exit( EXIT_FAILURE );
}

/*
 * 出错处理函数,打印出错信息,并返回到原程序。
 */
void
ErrRet( const char *fmt, ... )
{
     va_list ap;

     va_start( ap, fmt );
     ErrDoit( 1, errno, fmt, ap );
     va_end( ap );
}

/*
 * 出错处理函数,打印出错信息,并返回到源程序。
 */
void
ErrMsg( const char *fmt, ... )
{
     va_list ap;

     va_start( ap, fmt );
     ErrDoit( 0, 0, fmt, ap );
     va_end( ap );
}

static void
ErrDoit(
     int         errnoflag,
     int         error,
     const char *fmt,
     va_list     ap
     )
{
     char buf[MAXLINE];

     vsnprintf( buf, MAXLINE, fmt, ap );
     if ( errnoflag )
     {
   snprintf(
        buf + strlen( buf ),
        MAXLINE - strlen( buf ),
        ": %s",
        strerror( error )
        );
     }
     strcat( buf, "\n" );
     fflush( stdout );
     fputs( buf, stderr );
     fflush( NULL );
}

 

/*
 *============================================================================
 *                    2011挑战杯 便携式HMM远程面部检测识别综合控制应用平台
 *
 * (c) Copyright 2011, 李明浩
 * All Rights Reserved
 *
 * 文件名称:lmh_v4l.h
 * 文件摘要:本头文件用于声明系统使用video4linux采集视频的接口,用于fl2440开发板
 *
 * 当前版本:0.1
 * 作   者:李明浩
 * 完成日期:2011/03/27
 *
 * 取代版本:0.0
 * 作   者:李明浩
 * 完成日期:2011/03/10
 *============================================================================
 */

#ifndef LMH_V4L_H
#define LMH_V4L_H

/* ISO c headers */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* Linux c headers */
#include <linux/types.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>

#define VIDEO_PALETTE_JPEG 21
#define BRIDGE_ZC3XX        0
#define MAX_BRIDGE          2
#define JPEG                0
#define UNOW                1

/* 默认摄像头设备 */
//#define DEFAULT_DEVICE "/dev/v4l/video0" /* FL2440 */
//#define DEFAULT_DEVICE "/dev/video1" /* PC */
#define DEFAULT_DEVICE "/dev/video0" /* 博创 */

#define PIC_WIDTH   240          /* 图片宽度 */
#define PIC_HEIGHT  289          /* 图片高度 */

#define PIC_FORMAT  VIDEO_PALETTE_JPEG /* 图片格式 */

#define GRAB_METHOD 0  /* 使用read读取一帧图片数据 */

typedef struct bridge_list
{
     int         bl_num;
     const char *bl_name;

} BRIDGE_LIST;

typedef struct v4l_device /* 自定义v4l设备 */
{
     int                     vd_fd;         /* 设备号 */
     char                   *vd_device;     /* 设备名称 */
     struct video_mmap       vd_mmap;       /* 用于mmap */
     int                     vd_mmapsize;
     struct video_capability vd_capability; /* 包含设备的基本信息 */
     struct video_picture    vd_picture;    /* 设备采集图像的各种属性 */
     struct video_mbuf       vd_mbuf;     /* 用于mmap惊醒映射的帧信息 */
     struct video_channel    vd_channel;
     int                     vd_cameratype; /* 摄像头类型 */
     char                   *vd_cameraname; /* 摄像头名称 */
     char                    vd_bridge[9];
     int                     vd_palette;
     int                     vd_grabmethod; /* 采集图像方式 */
     unsigned char          *vd_framebuf;
     unsigned char          *vd_frame;
     int                     vd_framesize;
     int                     vd_bpp;
     int                     vd_width;
     int                     vd_height;
     int                     vd_format;

} V4L_DEVICE;

/*===============================采集视频函数==============================*/

extern int InitV4LDevice(
     V4L_DEVICE *vd,
     char       *device,
     int         width,
     int         height,
     int         format,
     int         grabmethod
     );
 
extern int V4LGrab( V4L_DEVICE *vd );

extern int CloseV4L( V4L_DEVICE *vd );

extern int GetJpegSize( unsigned char *buf, int insize );

#endif /* LMH_V4L_H */

 

/*
 *============================================================================
 *                    2011挑战杯 便携式HMM远程面部检测识别综合控制应用平台
 *
 * (c) Copyright 2011, 李明浩
 * All Rights Reserved
 *
 * 文件名称:lmh_v4l.c
 * 文件摘要:本文件用于实现系统使用video4linux采集人脸的接口,用于fl2440开发板
 *
 * 当前版本:0.1
 * 作   者:李明浩
 * 完成日期:2011/03/27
 *
 * 取代版本:0.0
 * 作   者:李明浩
 * 完成日期:2011/03/10
 *============================================================================
 */

#include "lmh_v4l.h"
#include "lmh_err.h"

/*=================================静态函数声明=================================*/

static int ConvertFrame(
     unsigned char *dst,
     unsigned char *src,
     int            width,
     int            height,
     int            format,
     int            size
     );
static int InitV4L( V4L_DEVICE *vd );
static int IsSpcaChip( const char *bridgename );
static int GetStreamID( const char *bridgename );
static int GetDepth( int format );
static int GetVideoPicture( V4L_DEVICE *vd );
static int SetVideoPicture( V4L_DEVICE *vd );

static BRIDGE_LIST g_list[] =
{
//     { BRIDGE_ZC3XX, "zc3xx"   }, /* pc     */
     { BRIDGE_ZC3XX, "ZC301-2" } /* FL2440 */
};

/*
 * 初始化V4L结构, 成功:返回0,失败:返回-1
 */
int
InitV4LDevice(
     V4L_DEVICE *vd,   
     char       *device,
     int         width,
     int         height,
     int         format,
     int         grabmethod
     )
{
     int ret = -1;

     if ( vd == NULL || device == NULL )
     {
   ErrMsg( "InitV4LDevice error: vd == NULL || device == NULL" );
   return -1;
     }
     if ( width == 0 || height == 0 )
     {
   ErrMsg( "InitV4LDevice error: width == 0 || height == 0" );
   return -1;
     }
     if ( grabmethod < 0 || grabmethod > 1 )
     {
   grabmethod = 1; /* read by default */
     }

     vd->vd_device     = NULL;
     vd->vd_cameraname = NULL;
     vd->vd_device     = (char *)realloc( vd->vd_device, 32 );
     if ( vd->vd_device == NULL )
     {
   ErrSys( "InitV4LDevice realloc vd->vd_device errro" );
     }
     vd->vd_cameraname = (char *)realloc( vd->vd_cameraname, 32 );
     if ( vd->vd_cameraname == NULL )
     {
   ErrSys( "InitV4LDevice realloc vd->vd_cameraname error" );
     }
     snprintf( vd->vd_device, 32, "%s", device );
     memset( vd->vd_cameraname, 0, sizeof (vd->vd_cameraname) );
     memset( vd->vd_bridge, 0, sizeof (vd->vd_bridge) );
     vd->vd_width      = width;
     vd->vd_height     = height;
     vd->vd_format     = format;
     vd->vd_bpp        = GetDepth( vd->vd_format );
     vd->vd_grabmethod = grabmethod;
     vd->vd_framebuf   = NULL;
     ret               = InitV4L( vd );
     vd->vd_frame      = NULL;
     vd->vd_frame      = (unsigned char *)realloc(
   vd->vd_frame, (size_t)vd->vd_framesize
   );

     return ret;
}

/*
 * 关闭摄像头,成功:返回0
 */
int
CloseV4L( V4L_DEVICE *vd )
{
     if ( vd->vd_grabmethod )
     {
   munmap( vd->vd_framebuf, vd->vd_mmapsize );
     }
     else
     {
   free( vd->vd_framebuf );
   vd->vd_framebuf = NULL;
     }

     if ( close( vd->vd_fd ) < 0 )
     {
   ErrRet( "CloseV4L error: close error" );
   return -1;
     }

     /* 释放分配的内存 */
     if ( vd->vd_device != NULL )
     {
   free( vd->vd_device );
   vd->vd_device = NULL;
     }
     if ( vd->vd_cameraname != NULL )
     {
   free( vd->vd_cameraname );
   vd->vd_cameraname = NULL;
     }
     if ( vd->vd_frame != NULL )
     {
   free( vd->vd_frame );
   vd->vd_frame = NULL;
     }

     return 0;
}

int
GetJpegSize( 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;
}


/*
 * 使用V4L抓取一帧图像,成功:返回图像大小,失败:返回-1
 */
int
V4LGrab( V4L_DEVICE *vd )
{
     int        len;
     int        size;
     int        jpegsize = -1;

     if ( vd->vd_grabmethod )
     {
   vd->vd_mmap.height = vd->vd_height;
   vd->vd_mmap.width  = vd->vd_width;
   vd->vd_mmap.format = vd->vd_format;

   if ( ioctl( vd->vd_fd, VIDIOCMCAPTURE, &(vd->vd_mmap) ) < 0 )
   {
        ErrSys( "V4LGrab error/VIDIOCMCAPTURE" );
   }
   if ( ioctl( vd->vd_fd, VIDIOCSYNC, &(vd->vd_mmap.frame) ) < 0 )
   {
        ErrSys( "V4LGrab error/VIDIOCSYNC" );
   }

   jpegsize = ConvertFrame(
        vd->vd_frame,
        vd->vd_framebuf + vd->vd_mbuf.offsets[vd->vd_mmap.frame],
        vd->vd_width,
        vd->vd_height,
        vd->vd_format,
        vd->vd_framesize
        );

   return jpegsize;
     }
     else
     {
   size = vd->vd_framesize;
   len  = read( vd->vd_fd, vd->vd_framebuf, size );
   if ( len < 0 )
   {
        ErrSys( "V4LGrab read error" );
   }
   jpegsize = ConvertFrame(
        vd->vd_frame,
        vd->vd_framebuf,
        vd->vd_width,
        vd->vd_height,
        vd->vd_format,
        vd->vd_framesize
        );

   return jpegsize;
     }

     return -1;
}

/*================================以下是静态函数定义================================*/

/*
 * 摄像头采集图像之前的初始化工作,成功:返回0,失败:终止程序.
 */
static int
InitV4L( V4L_DEVICE *vd )
{
     int ret;

     if ( (vd->vd_fd = open( vd->vd_device, O_RDWR )) < 0 )
     {
   ErrSys( "InitV4L open error" );
     }
     if ( ioctl( vd->vd_fd, VIDIOCGCAP, &vd->vd_capability ) < 0 )
     {
   ErrSys( "InitV4L get video capture error" );
     }
     snprintf( vd->vd_cameraname, 32, "%s", vd->vd_capability.name );

     ret = GetVideoPicture( vd );

     if ( ioctl( vd->vd_fd, VIDIOCGCHAN, &vd->vd_channel ) < 0 )
     {
   vd->vd_cameratype = UNOW;
     }
     else
     {
   if ( vd->vd_channel.name != NULL )
   {
        snprintf( vd->vd_bridge, 9, "%s", vd->vd_channel.name );
        vd->vd_cameratype = GetStreamID( vd->vd_bridge );
   }
   else
   {
        vd->vd_cameratype = UNOW;
   }
     }

     if ( vd->vd_cameratype != JPEG )
     {
   ErrSys( "Not a JPEG webcam sorry Abort!" );
     }
     vd->vd_picture.palette = vd->vd_format;
     vd->vd_picture.depth   = GetDepth( vd->vd_format );
     vd->vd_framesize       = (vd->vd_width * vd->vd_height >> 2);
     ret                    = SetVideoPicture( vd );
     if ( vd->vd_format != vd->vd_picture.palette
       || vd->vd_bpp    != vd->vd_picture.depth )
     {
   ErrSys( "couldn't set video palette Abort!" );
     }
     if ( vd->vd_grabmethod )
     {
   memset( &vd->vd_mbuf, 0, sizeof (vd->vd_mbuf) );
   if ( ioctl( vd->vd_fd, VIDIOCGMBUF, &vd->vd_mbuf ) < 0 )
   {
        ErrSys( "InitV4L get mbuf error" );
   }
   vd->vd_framebuf = (unsigned char *)mmap(
        0,
        vd->vd_mbuf.size,
        PROT_READ | PROT_WRITE,
        MAP_SHARED,
        vd->vd_fd,
        0
        );
   if ( vd->vd_framebuf == MAP_FAILED )
   {
        ErrSys( "InitV4L mmap error" );
   }
   vd->vd_mmapsize    = vd->vd_mbuf.size;
   vd->vd_mmap.height = vd->vd_height;
   vd->vd_mmap.width  = vd->vd_width;
   vd->vd_mmap.format = vd->vd_format;
   vd->vd_mmap.frame  = 0;
   if ( ioctl( vd->vd_fd, VIDIOCMCAPTURE, &vd->vd_mmap ) < 0 )
   {
        ErrSys( "V4LInit get capture error" );
   }
     }
     else
     {
   vd->vd_framebuf = (unsigned char *)realloc(
        vd->vd_framebuf,
        (size_t)vd->vd_framesize
        );
     }

     return ret;
}

/*
 * 转换图像格式,成功:返回图像大小,失败:返回-1
 */
static int
ConvertFrame(
     unsigned char *dst,
     unsigned char *src,
     int            width,
     int            height,
     int            format,
     int            size
     )
{
     int jpegsize = -1;

     switch ( format )
     {
     case VIDEO_PALETTE_JPEG:
   jpegsize = GetJpegSize( src, size );
   if ( jpegsize < 0 )
   {
        jpegsize = -1;
        break;
   }
   memcpy( dst, src, jpegsize );
   break;

     default:
   break;
     }

     return jpegsize;
}

/*
 * 获取图像属性,成功:返回0,失败:终止程序
 */
static int
GetVideoPicture( V4L_DEVICE *vd )
{
     if ( ioctl( vd->vd_fd, VIDIOCGPICT, &vd->vd_picture ) < 0 )
     {
   ErrSys( "GetVideoPicture error" );
     }

     return 0;
}

/*
 * 设置图像属性, 成功:返回0, 失败:终止程序
 */
static int
SetVideoPicture( V4L_DEVICE *vd )
{
     if ( ioctl( vd->vd_fd, VIDIOCSPICT, &vd->vd_picture ) < 0 )
     {
   ErrSys( "SetVideoPicture error" );
     }

     return 0;
}

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( g_list[i].bl_name );
   if ( strncmp( bridgename, g_list[i].bl_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;
     }

     return i;
}

static int
GetDepth( int format )
{
     int depth;

     switch ( format )
     {
     case VIDEO_PALETTE_JPEG:
   depth = 8;
   break;

     default:
   depth = -1;
   break;
     }

     return depth;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值