首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

2.4  SDK视频采集方案

在开发视频监控系统时,通常需要使用一些专用的监控卡。为了让用户能够进行二次开发,某些监控卡提供了SDK开发包,使用开发包提供的函数,用户可以根据需要自行设计监控软件,而不必依赖监控卡厂商提供的监控软件。本节将介绍有关监控卡SDK开发包相关知识。

2.4.1  监控卡选购分析

在开发视频监控系统时,需要选择一款适宜的监控卡。为了方便用户选购,下面列出选购监控卡时需要注意的几个方面:

l          具有SDK开发包

在购买监控卡时,一定要选购具有SDK开发包的监控卡。这样,开发人员可以方便地进行二次开发。否则,只有支持WDM驱动的监控卡才可以进行二次开发(使用Direct Show)。

l          监控卡的性能

购买的监控卡需要满足用户的需求。例如,监控卡的分辨率、高级的监控卡分辨率可以达到720*516,捕捉的画面接近DVD的质量。监控卡是否支持硬件压缩,支持硬件压缩的监控卡,用户不用编写算法进行软件压缩,这样,数据压缩的过程不经过CPU,能够提供系统的捕捉效率。此外,还需要考虑监控卡能够实现多少路视频捕捉、一台计算机可以同时安装几个监控卡等。

l          环境需求

对于不同厂家、不同类型的监控卡,其硬件要求通常是不同的。在监控卡的使用手册中,会有监控卡详细的环境需求描述,

多数监控卡对于计算机的硬件配置要求比较“苛刻”。尤其是对显卡、CPU、内存的要求。以天敏的VC4000为例,显卡要求支持DirectDraw和Overlay技术,显卡内存建议32MB以上。由于VC4000采用的是软压缩技术,因此对CPU的要求比较高。对于8路的视频需求,要求CPU为赛扬2.4G以上,对于16路的视频需求,要求CPU为赛扬2.8G以上,而对于24路(VC4000支持的视频需求上限)视频需求,要求CPU为P42.8G以上。至于内存的要求,也是随着视频需求的提高而提高,在8路和16路环境下,内存应在256M以上,在24路环境下,内存要求在512MB以上。

l          价格因素

高级的监控卡价格比较昂贵,性能比较突出。在购买监控卡时,需要从自身或用户的角度考虑,即要满足需求又要节约成本。

2.4.2  监控卡安装

在购买监控卡后,厂家会随同提供监控卡的驱动程序及产品说明书。用户首先需要仔细阅读产品说明书,将监控卡安装到主板上。监控卡多数都采用PCI插槽,例如,图2.33、图2.34分别显示的是天敏的VC4000监控卡和德加拉的监控卡。

图2.33  VC4000监控卡

图2.34  德加拉监控卡

下面以天敏的VC4000为例,介绍监控卡的安装过程。

(1)关闭计算机电源,打开机箱,将监控卡安装在一个空的PCI插槽上,如图2.35所示。

图2.35  安装监控卡

(2)从监控卡包装盒中取出螺丝,将监控卡固定在机箱上,如图2.36所示。

利用螺丝将监控卡固定在机箱上

 

图2.36  固定监控卡

(3)将摄像头的信号线连接到监控卡上,如图2.37所示。

图2.37  连接信号线

至此,完成了监控卡的硬件安装,此外,还需要进行软件安装。安装监控卡使用的驱动程序、MPEG编码器、解码器等。具体步骤如下:

(1)安装DirectX 9.0或以上版本。许多监控卡都要求安装DirectX才能够使用监控卡。

(2)安装并注册MPEG编码器、解码器。

(3)将监控卡的安装盘放入光驱,会弹出如图2.38所示。

图2.38  监控卡驱动列表

(4)选择VC4000监控卡驱动,如图2.39所示。

图2.39  VC4000驱动程序

(5)依次选择“安装驱动程序”、“安装SDK开发包”、“安装应用程序 客户端 服务器端”。

(6)重新启动计算机,完成软件的安装。

2.4.3  系统部署方案

根据视频监控系统的作用范围不同,系统部署方式可以分为局域网部署和广域网部署。在局域网部署方式中,视频服务器与客户机处于同一个网络内,视频服务器和客户机的IP,可以根据需要自行设置,客户机可以通过视频服务器的IP和端口号来连接服务器。局域网部署方式结构图如图2.40所示。

图2.40  局域网部署方式结构图

在广域网部署方式下,客户机与视频服务器之间的通信是通过Internet实现的,因此视频服务器可能存在两种类型的IP地址,即静态IP和动态IP。如果视频服务器采用静态IP,则客户端可以通过IP地址和端口号来访问视频服务器。视频服务器静态IP结构图如图2.41所示。

图2.41  视频服务器静态IP结构图

如果视频服务器采用动态IP,即IP地址由ADSL拨号而获得,那么对于远程访问的客户机来说,是不可能随时知道视频服务器的IP地址的。此时,可以通过域名解析系统来实现。首先申请一个域名,可以是付费的或免费的。然后客户端通过域名和端口号来访问视频服务器。视频服务器动态IP结构图如图2.42所示。

图2.42  视频服务器动态IP结构图

这里有一点需要说明,通常ADSL拨号是由路由器完成的,而不是视频服务器,因此视频服务器没有直接处于公网上,需要通过路由器建立端口映射来实现数据的传输。

2.4.4  开发包分析

在购买具有SDK开发包的监控卡时,会附带有监控卡的使用手册,其中包含有SDK开发包的详细说明。下面以天敏VC4000监控卡为例,介绍其主要函数及开发流程。

天敏VC4000监控卡的SDK主要由Sa7134Capture.dll、MediaTransmit.dll、MPG4c32.dll、Sa7134Capture.lib、MediaTransmit.lib、Sa7134Capture.h和MediaTransmit.h等几个文件组成。在使用开发包提供的函数前,需要将这些文件添加到当前工程中。天敏VC4000监控卡的SDK包含了近百个函数,下面介绍开发视频监控经常使用的函数。

1.VCAInitSdk

该函数用于初始化开发包。在使用SDK开发包中的函数前,首先需要调用该函数进行初始化。VCAInitSdk函数语法如下:

BOOL  WINAPI VCAInitSdk( HWND hWndMain, DISPLAYTRANSTYPE eDispTransType =

PCI_VIEDOMEMORY, BOOL bInitAudDev = FALSE  );

参数说明:

hWndMain:表示视频显示多路小窗口的父窗口。

eDispTransType:表示显示类型。

bInitAudDev:表示是否初始化音频设备。

2.VCAUnInitSdk

该函数用于释放调用VCAInitSdk函数分配的系统资源,通常在程序结束时调用该函数。VCAUnInitSdk函数原型如下:

void  WINAPI VCAUnInitSdk()

3.VCAGetDevNum

该函数用于获得监控卡中芯片的数量。通常,监控卡支持多少路视频,将会存在多少个芯片。VCAGetDevNum函数语法如下:

LONG  WINAPI VCAGetDevNum()

返回值:表示系统中安装监控卡上的芯片数量。

4.VCARegVidCapCallBack

该函数用于注册视频捕捉的回调函数。如果用户在进行视频捕捉时执行某些动作,可以调用该函数注册一个回调函数。VCARegVidCapCallBack函数语法如下:

BOOL  WINAPI VCARegVidCapCallBack( DWORD dwCard, PrcVidCapCallBack ppCall )

参数说明:

dwCard:表示视频捕捉的卡号。

ppCall:表示回调函数指针,其定义如下:

typedef void (CALLBACK *PrcVidCapCallBack)( DWORD dwCard, BYTE *pbuff, DWORD dwSize )

其中,dwCard表示视频捕捉的卡号,pbuff表示视频数据,dwSize表示视频数据的大小。

5.VCARegVidMpegCallBack

该函数用于注册视频MPEG数据压缩的回调函数。VCARegVidMpegCallBack函数语法如下:

BOOL  WINAPI VCARegVidMpegCallBack( DWORD dwCard, PrcVidMpegCallBack ppCall )

参数说明:

dwCard:表示视频捕捉的卡号。

ppCall:表示回调函数指针,其定义如下:

typedef void (CALLBACK *PrcVidMpegCallBack)

( DWORD dwCard, BYTE *pbuff, DWORD dwSize, BOOL isKeyFrm )

其中, dwCard表示视频捕捉的卡号,pbuff表示视频MPEG数据,dwSize表示视频数据的大小。isKeyFrm表示是否使用关键帧。

6.VCAOpenDevice

该函数用于打开视频预览窗口。语法如下:

BOOL  WINAPI VCAOpenDevice( DWORD dwCard,HWND hPreviewWnd )

参数说明:

dwCard:表示视频捕捉的卡号。

hPreviewWnd:表示视频预览窗口句柄。

7.VCAStartVideoPreview

该函数用于打开视频预览窗口。语法如下:

BOOL  WINAPI VCAStartVideoPreview( DWORD dwCard )

参数说明:

dwCard:表示预览的视频卡号。

8.VCAStopVideoPreview

该函数用于停止视频预览。语法如下:

BOOL  WINAPI VCAStopVideoPreview( DWORD dwCard )

参数说明:

dwCard:表示停止预览的视频卡号。

9.VCAUpdateOverlayWnd

该函数用于更新视频预览窗口。当预览窗口的父窗口大小或位置改变时,需要调用该函数进行调整。VCAUpdateOverlayWnd函数语法如下:

BOOL  WINAPI VCAUpdateOverlayWnd(HWND hOverlayWnd)

参数说明:

hOverlayWnd:表示预览窗口的父窗口

10.VCAUpdateVideoPreview

该函数用于更新视频预览窗口。当预览窗口的大小和位置需要调整时调用该函数。通常,在调用该函数前,需要调用VCAUpdateOverlayWnd函数。VCAUpdateVideoPreview语法如下:

BOOL  WINAPI VCAUpdateVideoPreview( DWORD dwCard, HWND hPreviewWnd )

参数说明:

dwCard:表示视频卡号。

hPreviewWnd:表示视频预览窗口。

11.VCASetVidCapSize

该函数用于设置视频捕捉的大小。语法如下:

BOOL  WINAPI VCASetVidCapSize( DWORD dwCard, DWORD dwWidth, DWORD dwHeight )

参数说明:

dwCard:表示视频卡号。

dwWidth:视频捕捉图像的宽度,建议为16的整数倍。

dwHeight:视频捕捉图像的高度,建议为16的整数倍。

12.VCASetVidCapFrameRate

该函数用于设置视频捕捉帧率。语法如下:

BOOL  WINAPI VCASetVidCapFrameRate( DWORD dwCard, DWORD dwFrameRate,

BOOL bFrameRateReduction = FALSE )

参数说明:

dwCard:表示视频卡号。

dwFrameRate:表示设置的捕捉帧率,PCL信号最大帧率为25,NTSC最大帧率为30。

bFrameRateReduction:该参数是保留的,未被使用。

13.VCASetBitRate

该函数用于设置MPEG压缩的位率。语法如下:

BOOL  WINAPI VCASetBitRate( DWORD dwCard, DWORD dwBitRate)

参数说明:

dwCard:表示视频卡号。

dwBitRate:表示MPEG的压缩位率。范围在56KBPS~10MBPS之间。

14.VCAStartVideoCapture

该函数用于开始视频捕捉。语法如下:

BOOL  WINAPI VCAStartVideoCapture( DWORD dwCard,

APMODEL           enCapMode, MP4MODEL enMp4Mode,  LPCTSTR      lpFileName );

参数说明:

dwCard:表示视频卡号。

enCapMode:表示视频捕捉模式。

enMp4Mode:表示MPEG压缩模式,只有在enCapMode参数为CAP_MPEG4_STREAM时,该参数才起作用。

lpFileName:表示视频捕捉的文件名称。

15.VCAStopVideoCapture

该函数用于停止视频捕捉。语法如下:

BOOL  WINAPI VCAStopVideoCapture( DWORD dwCard )

参数说明:

dwCard:表示视频卡号。

16.MTALoadLibrary

该函数用于初始化网络开发包。语法如下:

MEDIATRANSMIT_API BOOL MTALoadLibrary(WORD usLocalPort, WORD usRole);  

参数说明:

usLocalPort:表示本地端口号。

usRole:表示角色,为WORK_AS_SERVER,表示初始服务器端。为WORK_AS_CLIENT,表示初始化客户端。为WORK_AS_SUPPLY,表示初始化代理端。

17.MTAWriteVideo

该函数用于向客户端传递视频数据。语法如下:

MEDIATRANSMIT_API BOOL MTAWriteVideo(BYTE  nCardNo, BYTE *pData,

LONG  lSize,   BOOL  bIFrm)

参数说明:

nCardNo:表示欲传递数据的视频卡号。

pData:表示传递的视频数据。

lSize:表示视频数据的大小。

bIFrm:表示是否为I帧。

18.MTACreateVideoDevice

该函数用于创建视频显示窗口。语法如下:

MEDIATRANSMIT_API int  MTACreateVideoDevice(HWND hParentWnd, HWND hNotifyWnd,

RECT rect, int  nWidth, int  nHeight, int  nSpace, BOOL bUseOverlay);

参数说明:

hParentWnd:表示视频显示窗口的父窗口句柄。

hNotifyWnd:表示视频显示通知消息接收的窗口句柄。

19.MTASetSplitMode

该函数用于设置视频显示窗口的切分模式。语法如下:

MEDIATRANSMIT_API int  MTASetSplitMode(int nMode);

参数说明:

nMode:表示视频窗口的显示模式,取值范围1到4。

20.MTANewCall

该函数用于申请呼叫资源。在访问远程视频服务器时,需要调用该函数进行连接。MTANewCall函数语法如下:

MEDIATRANSMIT_API int   MTANewCall(char  *pRemoteIp, WORD    usRemotePort,

BYTE   biCardNo);

参数说明:

pRemoteIp:表示远程视频服务器的IP地址。

usRemotePort:表示远程视频服务器的端口号。

biCardNo:表示视频服务器的视频卡号。

返回值:表示本地的呼叫号。

21.MTASetVideoOut

该函数用于将呼叫的视频信号显示在视频显示窗口的指定位置。语法如下:

MEDIATRANSMIT_API BOOL MTASetVideoOut(int nCallID,int nIndex);

参数说明:

nCallID:表示呼叫号,通常为MTANewCall函数的返回值。

nIndex:表示显示位置相对的索引号,索引从0开始,最大值为15。

22.MTAMakeCall

该函数用于请求媒体传输服务。语法如下:

MEDIATRANSMIT_API BOOL  MTAMakeCall(int  nCallID, BYTE   biReqType, BOOL bWANCall,

BYTE* lpSndData, BYTE   biSndSize, HANDLE   hEventNotify, vCmdRespond   evCallNotify)

参数说明:

nCallID:表示呼叫号,通常为MTANewCall函数的返回值。

biReqType:表示请求类型,为REQ_AV_STREAM,表示请求音频、视频传输,为REQ_VI_STREAM,表示请求视频传输,为REQ_AU_STREAM,表示请求音频传输。

23.MTANewPlayBack

该函数用于视频回放时分配系统资源。语法如下:

MEDIATRANSMIT_API int   MTANewPlayBack(LPCTSTR lpFileName)

参数说明:

lpFileName:表示初始化回放文件名,可以为NULL。

返回值:如果函数执行成功,返回值为回放ID,如果函数执行失败,返回值为-1。

24.MTAOpenFile

该函数用于打开回放文件。语法如下:

MEDIATRANSMIT_API BOOL  MTAOpenFile(int nPlayBackID,LPCTSTR lpFileName)

参数说明:

nPlayBackID:表示视频回放资源ID。

lpFileName:表示回放文件名。

25.MTAStartPlay

该函数表示在当前位置开始播放文件。语法如下:

MEDIATRANSMIT_API BOOL  MTAStartPlay(int nPlayBackID,DWORD dwMode)

参数说明:

nPlayBackID:表示回放资源ID。

dwMode:表示回放模式,为PLAY_VIDEO_DATA,表示回放视频数据。为PLAY_AUDIO_DATA,表示回放音频数据。

26.MTACloseFile

该函数用于关闭回放文件。语法如下:

MEDIATRANSMIT_API void  MTACloseFile(int nPlayBackID)

参数说明:

nPlayBackID:表示回放资源ID。

27.MTAFreePlayBack

该函数用于释放回放系统资源。语法如下:

MEDIATRANSMIT_API void  MTAFreePlayBack(int nPlayBackId)

参数说明:

nPlayBackId:表示欲释放的回放资源ID。

28.MTASetWndPos

该函数用于设置视频显示窗口的位置。语法如下:

MEDIATRANSMIT_API BOOL MTASetWndPos(RECT rc);

参数说明:

rc:表示视频窗口新的位置。

29.MTAPageDown

该函数用于向下翻页,直到当前显示模式下的最后一页。语法如下:

MEDIATRANSMIT_API int  MTAPageDown();

返回值:如果函数执行成功,返回值为前一次的页号,否则返回小于1的错误码。

30.MTAPageUp

该函数用于向上翻页,直到当前显示模式下的第一页。语法如下:

MEDIATRANSMIT_API int  MTAPageUp();   

返回值:如果函数执行成功,返回值为前一次的页号,否则返回小于1的错误码。

2.4.5  视频开发设计方案

在开发视频监控系统时,首先需要了解开发包的操作流程,才能够进行视频开发。以天敏VC4000为例,其基本开发思路如下:

视频服务器端首先调用VCAInitSdk函数初始化开发包,然后调用VCAGetDevNum函数 获得系统中可以显示多少路视频,通过该数据值创建相应的视频显示窗口,接着调用VCARegVidCapCallBack和VCARegVidMpegCallBack函数注册视频捕捉及压缩回调函数,然后调用VCAOpenDevice函数打开设备,调用VCAStartVideoPreview函数开始预览,调用MTALoadLibrary函数初始化网络包。最后在系统退出时调用VCAUnInitSdk函数释放开发包资源。

视频服务器效果如图2.43所示。

图2.43  视频服务器效果图

客户端程序首先调用MTACreateVideoDevice函数创建视频显示窗口,调用MTASetSplitMode函数设置窗口切分模式。然后调用MTALoadLibrary函数初始化网络库,调用MTANewCall函数申请呼叫资源,接着调用MTAMakeCall函数请求媒体传输服务,调用MTASetVideoOut函数设置视频显示窗口,最后调用MTAClearCall函数释放网络包资源。

客户端程序效果如图2.44所示。

图2.44  视频捕捉客户端

下面以一个具体实例介绍视频监控程序的设计方法。服务器端程序设计步骤如下:

*  实例位置光盘\mr\2\2.4\2.4.5\01

(1)创建一个基于对话框的应用程序,在对话框中添加按钮控件,如图2.45所示。

图2.45  对话框设计

(2)将Sa7134Capture.dll、MPG4c32.dll、MediaTransmit.dll、MediaTransmit.lib、MediaTransmit.lib、Sa7134Capture.h和MediaTransmit.h文件添加到当前工程中。

(3)从CStatic类派生一个子类CPreView,作为视频显示的子窗口。在该类中添加如下成员变量:

BOOL         m_Selected;   //当前是否被选中

static int  m_CurIndex;  //预览窗口当前索引

int          m_Index;      //本窗口索引

BOOL        m_ShowImage; //是否显示图像,即该路是否有信号

BOOL         m_Dbled;      //双击时窗口是否填充父窗口

PreState    m_Stop;       //预览状态

CBitmap     m_Bitmap;     //无信号是显示的位图资源

(4)处理CPreView类的WM_PAINT消息,当窗口关联的视频卡号有信号并处于选中状态,绘制绿色的边框,在窗口关联的视频卡号无信号时,绘制一幅位图表示当前无信号。

void CPreView::OnPaint()

{

   CPaintDC dc(this);

   CRect rc;

   GetClientRect(rc);

   if (m_Index==m_CurIndex)

       m_Selected = TRUE;

   else

       m_Selected = FALSE;

   if (m_Selected)

   {

       CPen pen(PS_SOLID,1,RGB(0,255,0));

       dc.SelectObject(&pen);

       dc.Rectangle(rc);

   }

   else

   {

       CPen pen(PS_SOLID,1,RGB(55,55,55));

       dc.SelectObject(&pen);

       dc.Rectangle(rc);

   }

   if (m_ShowImage)

   {

       CBrush brush (RGB(255,0,255));

       dc.SelectObject(&brush);

       rc.DeflateRect(1,1,1,1);

       dc.FillRect(rc,&brush);

   }

   else

   {

       CDC memDC;

       memDC.CreateCompatibleDC(&dc);

       memDC.SelectObject(&m_Bitmap);

       BITMAP bInfo;

       m_Bitmap.GetBitmap(&bInfo);

       int x = bInfo.bmWidth;

       int y = bInfo.bmHeight;

       dc.StretchBlt(1,1,rc.Width()-2,rc.Height()-2,&memDC,1,1,x,y,SRCCOPY);

       memDC.DeleteDC();

   }

}

(5)处理CPreView类的WM_LBUTTONDOWN消息,将当前窗口标记为选中状态(具有绿色的边框)。

void CPreView::OnLButtonDown(UINT nFlags, CPoint point)

{

   int preIndex = m_CurIndex ;

   if (m_CurIndex==-1)

       preIndex = m_Index;

   m_CurIndex = m_Index;

   ((CPanel*)GetParent())->RefreshWnd(preIndex,m_Index);       

   CStatic::OnLButtonDown(nFlags, point);

}

(6)处理CPreView类的WM_SIZE消息,在窗口大小改变时更新视频显示窗口。

void CPreView::OnSize(UINT nType, int cx, int cy)

{

   if (m_ShowImage)

   {        

       if (!m_Stop)

       {

              VCAUpdateOverlayWnd(m_hWnd);

              VCAUpdateVideoPreview(m_Index,m_hWnd);

       }

   }

   CStatic::OnSize(nType, cx, cy);

}

(7)处理CPreView类的WM_LBUTTONDBLCLK消息,当用户双击某个窗口时,将窗口放大到父窗口的大小或者恢复窗口为原来的大小。

void CPreView::OnLButtonDblClk(UINT nFlags, CPoint point)

{

   if (m_Stop)  //在停止预览时禁止双击

       return;

   m_Dbled = ! m_Dbled;

   //记录原始区域大小

   CRect rc,prc;

   GetClientRect(rc);

   this->MapWindowPoints(GetParent(),rc);

   GetParent()->GetClientRect(prc);

   int div = ((CPanel*)GetParent())->m_Div;

   prc.DeflateRect(div,div,div,div);

   if (m_Dbled)

   {

       ((CPanel*)GetParent())->ShowOnly(m_Index);

        SetWindowPos(&wndTop,prc.left,prc.top,prc.Width(),

prc.Height(),SWP_SHOWWINDOW);

       Invalidate();

       if (m_ShowImage)

       {

              VCAUpdateOverlayWnd(m_hWnd);

              VCAUpdateVideoPreview(m_Index,m_hWnd);

       }

   }

   else

   {

       ((CPanel*)GetParent())->ShowAll();

       ((CPanel*)GetParent())->OnSize(0,0,0);

       Invalidate();

       if (m_ShowImage)

       {

              VCAUpdateOverlayWnd(m_hWnd);

              VCAUpdateVideoPreview(m_Index,m_hWnd);

       }     

   }

   CStatic::OnLButtonDblClk(nFlags, point);

}

(8)创建一个对话框类CPanel,作为预览窗口的父窗口。修改对话框资源的风格为“Child”,边框为“Thin”。

(9)向CPanel类中添加如下成员变量:

CPreView * m_pList;    //预览窗口

UINT       m_Num;       //记录预览窗口的数量

UINT       m_UnitNum;  //m_Num的开平方

UINT       m_Div;       //预览窗口的间隔

CRect      m_PreRC;    //所有预览窗口的显示区域

(10)向CPanel类中添加CreatePreWnd方法创建预览窗口。

BOOL CPanel::CreatePreWnd(UINT uNum)

{

   if (uNum==0)

       return FALSE;

   m_UnitNum = uNum;

   m_Num = pow(uNum,2);

   m_pList = new CPreView[m_Num ];

   CRect rc;

   GetClientRect(rc);

   //预览窗口的宽度

   int width = (rc.Width()-(uNum+1)*m_Div)/uNum;

   //预览窗口的高度

   int height = (rc.Height()-(uNum+1)*m_Div)/uNum;

   for (int i =0; i<m_Num; i++)

   {

       int row = i/uNum+1;

       int col = i % uNum+1;

       int x = col*m_Div+(col-1)*width;

       int y = row*m_Div+(row-1)*height;

       CRect rect(x,y,x+width,y+height);

       m_pList[i].Create("www",WS_CHILD|WS_VISIBLE|SS_BLACKFRAME|SS_NOTIFY,rect,this);

       m_pList[i].m_Index = i;

   }

   return TRUE;

}

(11)向CPanel类中添加RefreshWnd方法刷新窗口。

void CPanel::RefreshWnd(int preIndex,int curIndex)

{

   m_pList[preIndex].Invalidate();

   m_pList[curIndex].Invalidate();

}

(12)向CPanel类中添加ShowOnly方法显示窗口。

void CPanel::ShowOnly(int Index)

{

   for (int i =0; i<m_Num; i++)

   {

       if (i==Index)

       {

              m_pList[i].ShowWindow(SW_SHOW);

       }

       else

       {

              m_pList[i].ShowWindow(SW_HIDE);

       }

   }

}

(13)处理CPanel类的WM_SIZE消息,在窗口大小改变时,调整预览窗口的大小。

void CPanel::OnSize(UINT nType, int cx, int cy)

{

   CDialog::OnSize(nType, cx, cy);

   if (m_Num>0)  //创建了预览窗口

   {

       CRect rc;

       GetClientRect(rc);

      

       m_PreRC = rc;

       m_PreRC.DeflateRect(m_Div,m_Div,m_Div,m_Div);

       //预览窗口的宽度

       int width  = (rc.Width()-(m_UnitNum+1)*m_Div)/m_UnitNum;

       //预览窗口的高度

       int height = (rc.Height()-(m_UnitNum+1)*m_Div)/m_UnitNum;

       for (int i =0; i<m_Num; i++)

       {

              int row = i / m_UnitNum+1;

              int col = i % m_UnitNum+1;

              int x = col*m_Div+(col-1)*width;

              int y = row*m_Div+(row-1)*height;

              CRect rect(x,y,x+width,y+height);

              if (m_pList[i].IsWindowVisible())

              {

                 if (!m_pList[i].m_Dbled)

                 {

                     m_pList[i].MoveWindow(rect);

                     m_pList[i].Invalidate();

                 }

                 else

                 {

                     m_pList[i].MoveWindow(m_PreRC);

                     m_pList[i].Invalidate();

                 }

              }

       }

   }

}

(14)在主对话框中添加如下成员变量。

int  m_DevNum;         //当前芯片数,也就是有多少路

BOOL m_bStopPreview; //是否停止预览

BOOL m_bStartCap;     //是否开始捕捉

CPanel  m_Frame;      //预览窗口的父窗口

(15)在主对话框初始化时初始化SDK开发包。

BOOL CCaptureDlg::OnInitDialog()

{

   CDialog::OnInitDialog();

   CButton* pBmpButton = (CButton*) GetDlgItem(IDC_BMP);

   pBmpButton->SetCheck(1);

   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

   ASSERT(IDM_ABOUTBOX < 0xF000);

   CMenu* pSysMenu = GetSystemMenu(FALSE);

   if (pSysMenu != NULL)

   {

       CString strAboutMenu;

       strAboutMenu.LoadString(IDS_ABOUTBOX);

       if (!strAboutMenu.IsEmpty())

       {

              pSysMenu->AppendMenu(MF_SEPARATOR);

              pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

       }

   }

   SetIcon(m_hIcon, TRUE);   

   SetIcon(m_hIcon, FALSE);

  

   CString strTemp;

   m_Frame.Create(IDD_PANEL_DIALOG,NULL);

   CRect rc;

   GetWindowRect(rc);

   m_Frame.SetWindowPos(&wndTop,0,0,rc.Width()-120,rc.Height()-10,SWP_SHOWWINDOW);

   m_Frame.ShowWindow(SW_SHOW);

   //初始化网络开发包

   MTALoadLibrary(1001,WORK_AS_SERVER);

   CButton* pVGAButton = (CButton*) GetDlgItem(IDC_VGA);

   CButton* pPCIButton = (CButton*) GetDlgItem(IDC_PCI);

   CString str= "temp";

   GetPrivateProfileString("显卡设置","类型","VGA"

,str.GetBuffer(0), 10, "./syssetting.ini");

  

   BOOL ret;

   if (str=="VGA")

   {

       pVGAButton->SetCheck(1);

       pPCIButton->SetCheck(0);

       //初始化SDK

       ret = VCAInitSdk(m_Frame.m_hWnd,PCI_VIEDOMEMORY);

   }

   else

   {

       ret = VCAInitSdk(m_Frame.m_hWnd,PCI_MEMORY_VIDEOMEMORY);

       pVGAButton->SetCheck(0);

       pPCIButton->SetCheck(1);

   } 

   if (ret)

   {

       //获得几路视频

       m_DevNum =  VCAGetDevNum();

       m_Frame.CreatePreWnd((int)sqrt(m_DevNum));

       for (int i = 0; i<m_DevNum; i++)

       {

              VCARegVidCapCallBack(i,CapCallBack);

              VCARegVidMpegCallBack(i,VCAPrcVidMpegCallBack);

             

              VCAOpenDevice(i,m_Frame.m_pList[i].m_hWnd);

              BOOL ret = VCAStartVideoPreview(i);  

              m_Frame.UpdateAllPreView();

              // VCAUpdateOverlayWnd(m_Frame.GetSafeHwnd());

              // VCAUpdateVideoPreview(i,m_Frame.m_pList[i].m_hWnd);

       }

       m_bStopPreview = FALSE;

       m_bStartCap    = FALSE; 

   }

   SetTimer(1,1000,NULL);

   return TRUE;

}

(16)处理主对话框的WM_TIMER消息,判断某一路是否有视频信号。

void CCaptureDlg::OnTimer(UINT nIDEvent)

{

   //判断某一路是否有信号

   eFieldFrequency frequency;

   for (int i = 0; i< m_DevNum; i++)

   {

       VCAGetVidFieldFrq(i,frequency);

       if (frequency==FIELD_FREQ_0HZ)  //无信号

       {

              if (m_Frame.m_pList[i].m_ShowImage == TRUE)

              {

                 m_Frame.m_pList[i].m_ShowImage = FALSE;

                 m_Frame.m_pList[i].Invalidate();

              }

       }

       else

       {

              if (m_Frame.m_pList[i].m_ShowImage==FALSE)

              {

                 m_Frame.m_pList[i].m_ShowImage = TRUE;

                 m_Frame.m_pList[i].Invalidate();

                 VCAUpdateOverlayWnd(m_Frame.m_pList[i].m_hWnd);

                 VCAUpdateVideoPreview(i,m_Frame.m_pList[i].m_hWnd);   

              }

       }

   }

   CDialog::OnTimer(nIDEvent);

}

(17)处理主对话框的WM_SIZE消息,在对话框大小改变时调整视频显示窗口的父窗口,从而间接调整预览窗口。

void CCaptureDlg::OnSize(UINT nType, int cx, int cy)

{

   CDialog::OnSize(nType, cx, cy); 

   CRect rc,frc;

   GetClientRect(rc);

   m_Frame.GetClientRect(frc);

   m_Frame.SetWindowPos(NULL,0,0,frc.Width(),rc.Height(),0);

   m_Frame.ShowWindow(SW_SHOW);

}

(18)处理“停止预览”按钮的单击事件,停止或开始视频预览。

void CCaptureDlg::OnStoppreview()

{

   int Index = m_Frame.IsDbled();

   if (!m_bStopPreview)

   {

       m_bStopPreview = !m_bStopPreview;

       for (int i =0 ; i< m_DevNum; i++)

       {

              if (m_Frame.m_pList[i].m_ShowImage)

              {

                 m_Frame.m_pList[i].m_Stop = psStop;

                 VCAStopVideoPreview(i);

                 VCAUpdateOverlayWnd(m_Frame.m_hWnd);

                 m_Frame.m_pList[i].Invalidate();

              }

       }

       m_StopPreview.SetWindowText("开始预览");

   }

   else

   {

       m_bStopPreview = !m_bStopPreview;

       m_StopPreview.SetWindowText("停止预览");

      

       for (int i =0 ; i< m_DevNum; i++)

       {

              if (m_Frame.m_pList[i].m_ShowImage)

              {

             

                 if (Index == -1)

                 {

                     VCAStartVideoPreview(i);

                     VCAUpdateVideoPreview(i,m_Frame.m_pList[i].m_hWnd);

                     m_Frame.m_pList[i].m_Stop = psPreview;

                 }

                 else

                 {

                     m_Frame.m_pList[i].m_Stop = psPreview;

                     VCAStartVideoPreview(Index);

                     VCAUpdateVideoPreview(Index,m_Frame.m_pList[Index].m_hWnd);               

                 }

                 m_Frame.m_pList[i].Invalidate();

              }

       }

   }

}

(19)处理“网传”按钮的单击事件,开始或停止网络传输。

void CCaptureDlg::OnCapture()

{

   if (!m_bStartCap)  //开始捕捉

   {

       m_bStartCap = !m_bStartCap; 

       m_Capture.SetWindowText("停止");

       for (int i= 0 ; i< m_DevNum; i++)

       {

              if (m_Frame.m_pList[i].m_ShowImage)

              {

                 char data[10];

                 memset(data,0,10);

                 itoa(i,data,10);

                 char buffer[50]= "C:\\WW";

                 strcat(buffer,data);

                 strcat(buffer,".avi");

                 VCASetVidCapSize(i,240,320);

                 VCASetVidCapFrameRate(i,25);

                 VCASetBitRate(i,256);

                 BOOL ret = VCAStartVideoCapture(i,

CAP_ORIGIN_MPEG4_STREAM,MPEG4_AVIFILE_CALLBACK ,buffer);

              }

       }

   }

   else

   {

       m_bStartCap = !m_bStartCap;

       m_Capture.SetWindowText("网传");

       for (int i= 0; i< m_DevNum; i++)

       {

              if (m_Frame.m_pList[i].m_ShowImage)

              { 

                 VCAStopVideoCapture(i);           

              }

       }

   }

}

(20)处理“快照”按钮的单击事件,截取当前预览图像,并存成文件。

void CCaptureDlg::OnSnapshot()

{

   if (CPreView::m_CurIndex != -1)

       if (m_Frame.m_pList[CPreView::m_CurIndex].m_ShowImage)

       {

              CButton* pBmpButton = (CButton*) GetDlgItem(IDC_BMP);

              if (pBmpButton->GetCheck() != 0)

              {

                 CFileDialog fDlg(FALSE,"bmp","one",OFN_HIDEREADONLY |

OFN_OVERWRITEPROMPT,"位图|*.bmp",this);

                 if (fDlg.DoModal()==IDOK)

                 {

                     CString fName = fDlg.GetPathName();

                     VCASaveAsBmpFile(CPreView::m_CurIndex,fName);     

                 }

              }

              else

              {

                 CFileDialog fDlg(FALSE,"jpg","one",OFN_HIDEREADONLY |

OFN_OVERWRITEPROMPT,"JPG文件|*.JPG",this);

                 if (fDlg.DoModal()==IDOK)

                 {

                     CString fName = fDlg.GetPathName();

                     VCASaveAsJpegFile(CPreView::m_CurIndex,fName);    

                 }     

              }

       }

       else

       {

              MessageBox("当前选择的图像不能预览!","提示");

       }

}

(21)处理“显卡类型”按钮的单击事件,设置显卡类型,将其存储在INI文件中。

void CCaptureDlg::OnSetting()

{

   CButton* pVGAButton = (CButton*) GetDlgItem(IDC_VGA);

   int sel = pVGAButton->GetCheck();   

   if (sel)

   {

       WritePrivateProfileString("显卡设置","类型","VGA","./syssetting.ini");

   }

   else

   {

       WritePrivateProfileString("显卡设置","类型","PCI","./syssetting.ini");

   } 

   MessageBox("要使显卡设置生效,需要重新启动应用程序!","提示");

}

(22)处理对话框的WM_WINDOWPOSCHANGED消息,在对话框位置改变时,更新视频预览窗口。

void CCaptureDlg::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)

{

   CDialog::OnWindowPosChanged(lpwndpos);

   for (UINT i = 0 ; i< m_DevNum; i++)

   {

       if (m_Frame.m_pList[i].m_ShowImage)

       {     

              if (m_Frame.m_pList[i].m_Stop==psStop)

              {

                 VCAStopVideoPreview(i);

                 VCAUpdateOverlayWnd(m_Frame.GetSafeHwnd());

              }

              else if (m_Frame.m_pList[i].m_Stop==psPreview)

              {     

                 m_Frame.m_pList[i].Invalidate();

                 VCAUpdateOverlayWnd(m_Frame.m_hWnd);

                 VCAUpdateVideoPreview(i,m_Frame.m_pList[i].m_hWnd);

              }

       }

   }

}

客户端程序设计步骤如下:

*  实例位置光盘\mr\2\2.4\2.4.5\02

(1)创建一个基于对话框的工程,向对话框中添加按钮控件。

(2)将Sa7134Capture.dll、MPG4c32.dll、MediaTransmit.dll、MediaTransmit.lib、MediaTransmit.lib、Sa7134Capture.h和MediaTransmit.h文件添加到当前工程中。

(3)创建一个对话框类CServerInfo,用于设置连接的服务器信息。对话框资源如图2.46所示。

图2.46  连接服务器窗口

(4)在主对话框中定义如下成员变量:

int             m_CardID;    //卡号

int             m_CurIndex;

int             m_BackID;

CString         m_ServerIP; //服务器IP

int             m_Port;      //服务器端口

int             m_Chanel;    //视频通道

BOOL            m_Captured; //是否开始捕捉

BOOL            m_BackPlay; //是否进行视频回放

(5)在主对话框初始化时创建视频窗口。

CRect rc;

m_Panel.GetClientRect(rc);

MTACreateVideoDevice(m_Panel.GetSafeHwnd(),m_hWnd,rc,320,240,2,FALSE);

MTASetSplitMode(1);

(6)处理“连接服务器”按钮的单击事件,开始连接服务器。

void CClientDlg::OnLinkServer()

{

   CServerInfo ServerDlg;

   if (ServerDlg.DoModal()==IDOK)

   {

       m_ServerIP = ServerDlg.m_ServerIP;

       m_Port     = ServerDlg.m_Port;

       m_Chanel   = ServerDlg.m_Chanel-1;

       MTASetMpeg4Version(MPEG4_V1);

       if (!MTALoadLibrary(1008,WORK_AS_CLIENT))

       {

              MessageBox("加载网络库失败!");

              MTAFreeLibrary();

              return;

       }

       MTAClearCall(m_CardID,FALSE);

       CRect rc;

       m_Panel.GetClientRect(rc);

       MTACreateVideoDevice(m_Panel.GetSafeHwnd(),m_hWnd,rc,240,320,2,FALSE);

       MTASetSplitMode(1);

       m_CurIndex = 0;

       m_CardID = MTANewCall(m_ServerIP.GetBuffer(0),m_Port,m_Chanel);

       if (m_CardID==-1)

       {

              MessageBox("连接服务器失败!");

       }

       MTASetVideoOut(m_CardID,0);

       unsigned char data[] = "Admin";

       MTAMakeCall(m_CardID,REQ_VI_STREAM,FALSE,data,10,NULL,CmdRespond);

   }

}

(7)处理“录像”按钮的单击事件,开始或停止录像。

void CClientDlg::OnCapture()

{

   if (!m_Captured)

   {

       CFileDialog fDlg(FALSE,"avi","one",OFN_HIDEREADONLY |

 OFN_OVERWRITEPROMPT,"AVI|*.avi",this);

       if (fDlg.DoModal()==IDOK)

       {

              m_Captured = TRUE;

              CString file = fDlg.GetPathName();

              MTAStartCapture(m_CardID,file.GetBuffer(0),SAVE_VIDEO_DATA,NULL);

              m_Capture.SetWindowText("停止录像");

       }

   }

   else

   {

       m_Captured = FALSE;

       m_Capture.SetWindowText("录像");

       MTAStopCapture(m_CardID);

   }

}

(8)处理“视频回放”按钮的单击事件,回放录制的视频文件。

void CClientDlg::OnBackplay()

{

   if (!m_BackPlay)

   {

       CFileDialog fDlg(TRUE,"","",OFN_HIDEREADONLY |

OFN_OVERWRITEPROMPT,"AVI|*.avi",this);

       if (fDlg.DoModal()==IDOK)

       {

              m_BackPlay = TRUE;

              m_Play.SetWindowText("停止回放");

              CString file = fDlg.GetPathName();

              //分配系统资源

              m_BackID = MTANewPlayBack(file);

              //MTASetVideoOut(m_BackID ,0);

             

              //打开回放文件

              BOOL ret = MTAOpenFile(m_BackID,file);

             

              Sleep(1000);

              MTASetPlayPosition(m_BackID,1);

             

              //开始播放

              MTAStartPlay(m_BackID,PLAY_VIDEO_DATA|PLAY_AUDIO_DATA);

              MTASetVideoOut(m_BackID ,0);

             

       }

   }

   else

   {

       m_BackPlay = FALSE;

       m_Play.SetWindowText("视频回放");

       // 关闭打开的文件

       MTACloseFile(m_BackID);

       // 释放回放资源

       MTAFreePlayBack(m_BackID);

   }

}

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论