当前位置:   article > 正文

基于Video4linux的视频采集,用SDL显示

基于video4linux的视频采集,用sdl显示

本程序的开发环境是(我当前的系统):操作系统:RedHat 9.0 及 CG300的视频采集卡

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

Video4linux 编程指南
1.视频编程的流程
(1)打开视频设备:
(2)读取设备信息
(3)更改设备当前设置(可以不做)
(4)进行视频采集,两种方法:
 a.内存映射
 b.直接从设备读取
(5)对采集的视频进行处理( 本程序没做,下次再show给大家)
(6)关闭视频设备

  1. //下面我对这些操作做了个简单的函数封装 (o(∩_∩)o...哈哈) #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->fd0 ) ) < 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(); }

代码SHOW完了,下面再附点小信息供大家看看,刚玩LINUX不久,有错误的地方还请大侠们指出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/263196
推荐阅读
相关标签
  

闽ICP备14008679号