您的位置:首页 > 其它

V4L2视频采集实现例程

2013-04-01 14:58 218 查看

V4L2视频采集实现例程

http://zhougaofeng.ixiezi.com/2009/12/01/v4l2/#more-59

Video4linux 简介

Video4Linux是为市场现在常见的电视捕获卡和并口及USB口的摄像头提供统一的编程接口。同时也提供无线电通信和文字电视广播解码和垂直消隐的数据接口。本文主要针对USB摄像头设备文件/dev/video0,进行视频图像采集方面的程序设计。

Video4linux 编程指南

1.视频编程的流程

(1)打开视频设备:

(2)读取设备信息

(3)更改设备当前设置(可以不做)

(4)进行视频采集,两种方法:

a.内存映射

b.直接从设备读取

(5)对采集的视频进行处理( 本程序没做,下次再show给大家)

(6)关闭视频设备

//下面我对这些操作做了个简单的函数封装

#ifndef _V4L_H

#define _V4L_H

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <error.h>

#include <assert.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <sys/mman.h>

#include <linux/videodev.h>

#include <sys/types.h>

#include <string.h>

/*采集的图像的最大长和宽*/

#define MAX_WIDTH 400

#define MAX_HEIGHT 300

/*设备文件*/

#define DEFAULT_DEVICE “/dev/video0″

/*自定义数据结构,包含v4l 中用到的数据结构*/

typedef struct v4l_struct

{

int fd;/*设备号*/

struct video_capability capability; //包含设备的基本信息(设备名称、支持的最大最小分辨率、信号源信息等)

struct video_channel channel[8];//信号源个数

struct video_picture picture;//设备采集的图象的各种属性

struct video_mmap mmap;//用于mmap

struct video_mbuf mbuf;//利用mmap进行映射的帧的信息

unsigned char *buffer ;/*图像数据存放区*/

unsigned char *map;/*mmap方式获取数据时,数据的首地址*/

int frame_current;

int frame_using[2]; /*这个帧的状态0 表示可用,1表示不可用*/

}v4l_device;

/**************************************************************

* 函数名:v4l_open

* 功 能: 打开设备

* 输 入: dev,vd

* 输 出: 无

* 返 回: -1—-失败 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 error” );

return -1;

}

return 0;

}

/**************************************************************

* 函数名: v4l_get_capability

* 功 能: 获取设备属性

* 输 入: vd

* 输 出: 无

* 返 回: -1—-失败 0—-成功

**************************************************************/

int v4l_get_capability( v4l_device *vd )

{

if( ioctl( vd->fd, VIDIOCGCAP, &( vd->capability ) ) <0 )

{

perror( “v4l_get_capability” );

return -1 ;

}

return 0;

}

/***************************************************************

* 函数名:v4l_get_picture

* 功 能:获取图片属性

* 输 入: vd

* 输 出: 无

* 返 回: -1—-失败 0—-成功

***************************************************************/

int v4l_get_picture( v4l_device *vd )

{

if( ioctl( vd->fd,VIDIOCGPICT,&( vd->picture ) ) < 0 )

{

return -1;

}

return 0;

}

/**************************************************************

* 函数名: v4l_set_picture

* 功 能: 设置图片属性

* 输 入: vd

* 输 出: 无

* 返 回: -1—-失败 0—-成功

**************************************************************/

int v4l_set_picture( v4l_device *vd )

{

if( ioctl( vd->fd, VIDIOCSPICT, &( vd->picture ) ) < 0 )

{

return -1;

}

return 0;

}

/*************************************************************

* 函数名:v4l_get_channels

* 功 能:获取通道信息

* 输 入: vd

* 输 出: 无

* 返 回: -1—-失败 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_channel” );

return -1;

}

}

return 0;

}

/*************************************************************

* 函数名: v4l_get_mbuf

* 功 能: 获取内存映射信息

* 输 入: vd

* 输 出: 无

* 返 回: -1—-失败 0—-成功

**************************************************************/

int v4l_get_mbuf( v4l_device *vd )

{

if( ioctl ( vd->fd,VIDIOCGMBUF,&( vd->mbuf ) ) <0 )

{

perror( “get_mbuf:” );

return -1;

}

if ( ( vd->map = ( unsigned char * )mmap( 0, vd->mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 0 ) ) < 0 )

{

perror(“v4l_mmap_init:mmap”);

return -1;

}

return 0 ;

}

/*************************************************************

* 函数名: v4l_init_mbuff

* 功 能: 初始化内存映射信息

* 输 入: vd

* 输 出: 无

* 返 回: 0—-成功

**************************************************************/

int v4l_init_mbuf(v4l_device *vd)

{

//vd->mmap.frame = 10 ; //不懂双帧是怎样设置的这个frame 该是当前帧的可mbuf 以又没有设置怎么确定是双帧不是单帧还是更多

vd->mmap.width = MAX_WIDTH;

vd->mmap.height = MAX_HEIGHT;

vd->mmap.format = vd->picture.palette;

vd->frame_current = 0;

vd->frame_using[0] = 0;

vd->frame_using[1] = 0;

return 0;

}

/**************************************************************

* 函数名: v4l_get_address

* 功 能: 获取数据在图像的地址

***************************************************************/

unsigned char *v4l_get_address(v4l_device *vd)

{

return (vd->map + vd->mbuf.offsets[vd->frame_current]);

}

/*************************************************************

* 函数名: v4l_grab_frame

* 功 能: 捕获帧

**************************************************************/

int v4l_grab_frame(v4l_device *vd, int frame)

{

if (vd->frame_using[frame])

{

fprintf(stderr, “v4l_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;

}

/**************************************************************

* 函数名: v4l_grab_sync

* 功 能:与内存映射捕获一致

**************************************************************/

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] = 0;

return 0;

}

/***************************************************************

* 函数名: v4l_munmap

* 功 能:停止内存映射

***************************************************************/

int v4l_munmap( v4l_device *vd )

{

if ( munmap( vd->map, vd->mbuf.size ) < 0 )

{

perror( “v4lmunmap:munmap” );

return -1;

}

return 0;

}

/***************************************************************

* 函数名: v4l_close

* 功 能:关闭设备

***************************************************************/

int v4l_close(v4l_device *vd)

{

close(vd->fd);

return 0;

}

#endif

//简单的封装了关于SDL的相关操作”ScreenSurface.h”

#ifndef SCREEN_SURFACE_H

#define SCREEN_SURFACE_H

#include <stdio.h>

#include <stdlib.h>

#include <SDL/SDL.h>

class ScreenSurface

{

public:

ScreenSurface();

bool screen_init(int w, int h, int b = 0, Uint32 f = 0);//初始化

~ScreenSurface();

SDL_Surface* point() const;

int screen_lock();

void screen_unlock();

void screen_quit();

void screen_set_caption( const char *str );//设置标题

bool flip( unsigned char * src) ;//显示

int startTV();//开始采集

private:

static int screenNum;

int width;

int height;

int bpp;

Uint32 flags;

SDL_Surface* pScreen;

};

#endif

//ScreenSurface.cpp

#include “ScreenSurface.h”

#include “qt_v4l.h”

v4l_device v4l_dev;

/**************************************************************

* 函数名: v4l_grab_movie

* 功 能:捕获连续图像

**************************************************************/

void v4l_grab_movie()

{

v4l_grab_frame(&v4l_dev, v4l_dev.frame_current);/*获取下一 帧*/

v4l_grab_sync(&v4l_dev);/*等待传完一 帧*/

v4l_dev.buffer = v4l_get_address(&v4l_dev);/*得到这一帧的地址*/

v4l_dev.frame_current = (v4l_dev.frame_current+1)%2; /* 下一帧的frame*/

}

//构造函数。如果创建1个以上的screen surface,则会抛出异常

ScreenSurface::ScreenSurface():width(640), height(480), bpp(32), flags(0)

{

pScreen = 0;

v4l_open(DEFAULT_DEVICE, &v4l_dev);/*打开设备*/

v4l_get_capability(&v4l_dev);

v4l_get_picture(&v4l_dev);

v4l_init_mbuf(&v4l_dev);/*初始化设备*/

v4l_get_mbuf(&v4l_dev);/*内存映射*/

}

bool ScreenSurface::screen_init(int w, int h, int b, Uint32 f)

{

width = w ;

height = h ;

bpp = b ;

flags = f ;

if(SDL_Init(SDL_INIT_VIDEO) < 0)

{

printf(“SDL_Init Failed!\n”);

return false;

}

//设置图象模式(宽*高 位数 标志 SDL_SWSURFACE | SDL_DOUBLEBUF)

pScreen = SDL_SetVideoMode(width, height, bpp, flags);

if ( pScreen == 0 )

{

printf(“Could’t set display mode \n”);

SDL_Quit();

return false;

}

SDL_ShowCursor(SDL_DISABLE);

return true;

}

//析构函数。在对象消亡时,退出SDL系统。

ScreenSurface::~ScreenSurface()

{

}

//返回screen surface中SDL_Surface结构的指针,主要提供给SDL的函数调用

SDL_Surface* ScreenSurface::point() const

{

return pScreen;

}

int ScreenSurface::screen_lock()

{

if ( SDL_MUSTLOCK(pScreen))

return SDL_LockSurface(pScreen);

return 0;

}

void ScreenSurface::screen_unlock()

{

if ( SDL_MUSTLOCK(pScreen))

SDL_UnlockSurface(pScreen);

}

void ScreenSurface::screen_quit()

{

SDL_Quit();

v4l_munmap(&v4l_dev) ;

v4l_close(&v4l_dev);

}

void ScreenSurface::screen_set_caption( const char *str )

{

SDL_WM_SetCaption( str, 0 );

}

//显示(弹出flip)screen surface到屏幕上

bool ScreenSurface::flip( unsigned char * src )

{

if ( screen_lock() < 0)

return false;

unsigned char *dest;

dest = ( unsigned char * )pScreen->pixels;

memcpy( dest , src , width * height * 4 );

screen_unlock();

if ( SDL_Flip(pScreen) < 0 )

return false;

else

return true;

}

int ScreenSurface::startTV()

{

bool bFlag = true;

while(bFlag)

{

v4l_grab_movie();

unsigned char *buf= v4l_dev.buffer;

if (buf != NULL)

{

flip(buf);

}

SDL_Event event;

while(SDL_PollEvent(event))

{

if (event.type == SDL_QUIT)

{

//bFlag = false;

screen_quit();

}

}

}

}

//main.cpp

#include “ScreenSurface.h”

void main()

{

ScreenSurface *m_pScreen;

m_pScreen = new ScreenSurface( );

m_pScreen->screen_init(400 , 300 , 32 , SDL_SWSURFACE | SDL_ANYFORMAT);

m_pScreen->screen_set_caption(“DemoTV”);

m_pScreen->startTV();

}
http://zhougaofeng.ixiezi.com/2009/12/01/v4l2/#more-59
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: