共享电视卡,齐看世界杯
软件世界
《电脑报》18期头版文章《共享软件的春天》刊出后,在一些读者心中引起了躁动;不少人向往程序员的生涯,想了解更多的共享软件开发过程和方法。这不仅仅是经济杠杆的驱动原因,更重要的是在国内软件业处于低迷的今天,大家仿佛看到了一线新的曙光。软件业还存在展示个人才华的舞台,这毕竟是市场需求所决定的一种生存模式。就像软件业在微软的超级垄断下还有无数软件公司照样存在一样,因为社会对软件的需求是无限扩张的。
作为抛砖引玉,笔者就先献丑了。如果各位编程爱好者和高手们乐于参与,愿意给进入编程领域的初学者提供更多更实际的东西,笔者就是先入地狱也为之安乐了(注:本文适合于有一定VC编程基础的读者)。
世人关注的世界杯足球赛开始了,中国队的首次参赛更增加这次世界杯的看点。坐在计算机旁,一边看球赛一边上网发表你的高论,确是一件惬意的事情。难怪这几天电视卡卖得火爆。但是在公众计算机场所,是不可能每台计算机都配上电视卡的。共享嘛,软件可以共享,硬件不是一样可以共享吗。这里我们首先给出一个局域网上的电视转播的思路和相关的资源。这样,在一个机房、网吧,用一块电视卡接收的足球赛节目就可以广播出去,使局域网内的所有计算机都能收看,哈,在这种环境看世界杯不是更COOL。好,让你来做一个电视卡的共享软件,你有兴趣吗?
一、设计思路
1.捕获视频输入(获取电视卡的输入)。这在微软的API函数库中有一系列的视频捕获处理的函数,可供我们在Windows上轻易地启动电视卡,接收播放电视。
2.分离视频数据流,真正获取我们需要传输的电视图形。我们还是使用API函数中视频捕获的回调功能就可以搞定了。
3.电视一帧画面是352×288像素,16位色时就有200多KB,如果我们一秒钟在网上发送10帧就有2MB的数据量!压缩,又是调用API函数库中现有的视频压缩功能。选择好的压缩格式,一帧图形可以压缩到20多KB。这样就可以在网上传输了。
4. 网上传输。网络编程是当今最诱人的领域,我们这里对大家提供一个UDP广播协议的高速收发控件,可以将你捕获并压缩后的图像发送出去,并可靠地接收。
二、相关资源和程序段
A.capdll.dll 影像转播的库文件,有以下功能:
1.HWND CreaCapWin(CWnd * pWnd,int x,int y,int w,int h):
//设置预视窗口:输入 1窗口句柄,2设置窗口的位置x,y,3窗口的大小w,h
//返回 采集窗口句柄。
2.BOOL SetCap(HWND hCapWnd,int n):
//连接视频驱动设备:输入1采集窗口句柄2第n个视频设备
3.CString GetMyName():
//获取本机名:返回本机名。
4.void SetCom(long mmio):
//设置压缩格式: 输入压缩格式。
//注:压缩格式为mmioFOURCC('d', 'i', 'v', '3')四字节表达式。div3就是现在流行的mpg4的压缩格式。
5.LPBITMAPINFOHEADER Compress(BYTE *tmp):
//压缩图形:输入图形数据指针。
6.void DelCom()://释放压缩缓存。
7.VARIANT BytetoVar(void * pBuf,int Size):
//转换发送数据:输入 1待发数据区指针,2数据长度。返回装有数据的变体
8.char * CreateBufFromVar(const VARIANT FAR& var,int *pSize):
//转换接收数据:输入 1接收数据的变体, 2数据长度, 返回接收到的数据指针。
9.void DestroyBuf(char ** ppBuffer):
//释放接收数据指针:输入 接收数据的指针。
B.UDP广播接收控件 HPSOCK.DLL,有以下功能:
1.CString GetLocalAddress(int n)
//获取本机的ip地址:输入第n个网卡,返回指定的本机ip地址。
2.Multicast(CString Address, int Port, CString MyAddress,CString MyName,int Flag)
//建立UDP传送(接收或发送):输入
a.Address传送地址224.0.0.0--239.255.255.255
b.Port多点传送网络端口
c.MyAddress本机ip地址
d.MyName本机名字
e.Flag建立标志( 0-只接收 1-只发送 2-收发)
3.SendData(VARIANT& var)
//发送数据:
//输入var发送的数据(变体结构,可以是各种数据)
4.OnReceiveData(sName,sIPAddress,var)
//响应接收数据事件:(须在程序中建立相关机制)
接收到的数据
a.sName 发送方名字
b.sIPAddress发送方IP地址
c.var接收到的数据(变体结构)
C.几个关键程序段:
1.视频捕获回调函数(在此获取每帧图形数据):
BYTE *tmp://定义一个全局指针
static LRESULT PASCAL cbFrame(HWND hWnd, LPVIDEOHDR lpVHdr)
{if(tmp!=NULL) return S_OK://数据还没处理,返回
tmp=(BYTE *)new BYTE[lpVHdr->dwBufferLength]://建立图形缓存区
CopyMemory(tmp,lpVHdr->lpData-40,lpVHdr->dwBufferLength):
//将图形拷贝到图形缓存区。在此我们就可以对得到的图形数据任意处理了。处理完后释放图形缓存区 delete [] tmp。获取下一帧。
return S_OK;
}
2. 这里是用一个消息接收函数来压缩发送数据缓存区中的图形。
LRESULT CMyDlg::OnStatus(WPARAM wParam, LPARAM lParam)
{ if(tmp==NULL) return 1;
bi1=m_capdll.Compress(tmp);//压缩图形
char c1[30];
BYTE *buf=(BYTE *)new BYTE[1026];//建立发送数据块
LPBYTE faso;
faso=(unsigned char *)bi1;//改变图形区的数据类型
int len=bi1->biSize+bi1->biSizeImage;//图形数据的长度
int biy=1024; //图形发送块的长度
if(len<= biy) biy=len;//图形长度小于发送块时
aa0: memcpy(buf,faso,biy);//将1KB的图形拷到发送块
send(buf,biy); //进行广播发送
len-=biy;//图形长度减一个块的长度
faso+=biy;
if (len>biy) goto aa0;//还有,继续。
else{ memcpy(buf,faso,len);//当不足一个块时,发送剩下的。
send(buf,len);//进行广播发送
}
sprintf(c1,"end,%d",bi1->biSize+bi1->biSizeImage);
//准备结束标,图形数据长度。
memcpy(buf,c1,strlen(c1));//拷入发送块
send(buf,strlen(c1));//进行广播发送
m_capdll.DelCom();//释放压缩缓存
delete [] tmp:tmp=NULL;//删除图形缓存区
delete [] buf;//删除发送块
return 1;
}
3. 广播发送:(因为发送数据类型可能是多样的,所以UDP控件发送数据类型为变体结构,这里需要转换)
void CMyDlg::send(BYTE *buf,int len)//广播发送
{VARIANT var=m_capdll.BytetoVar(buf,len);//转换发送数据为变体
m_udp.SendData(var);//调控件发送数据
SafeArrayDestroy(m_capdll.psa);//释放变体
}
4.接收程序中的接收数据程序段:
void CMyDlg::OnOnReceiveDataHpsockudp1(LPCTSTR sName,LPCTSTR sIPAddress,const VARIANT FAR& var)
{char *pBuffer;int size=0;
pBuffer=m_capdll.CreateBufFromVar(var,&size);//转换接收到的数据
if(si>40960) {si=0:diou=0:goto aa;}//数据接收块的安全检查
if(memcmp(pBuffer,"end",3)!=0)//本次接收的不是结束标志。
{memcpy(buf+si,pBuffer,size);//连接到接收块中
si+=size;goto aa;//接收数据块长度增加,继续。
}
else//本次接收到的是结束标志。
{if (si!=atoi(pBuffer+4)) //接收到的数据长度校验
{diou++;si=0;goto aa;}//长度不符,不能显示。
LPBITMAPINFOHEADER bi=(BITMAPINFOHEADER *)buf;//转换数据类型
CClientDC dc(this);//开始显示图形
int xw=bi->biWidth;int hy=bi->biHeight;//取图形宽、高
HDRAWDIB m_HDD = DrawDibOpen();//打开DRAW
if (m_HDD) DrawDibDraw(m_HDD,dc.m_hDC,4,25,xw,hy,
(BITMAPINFOHEADER *)bi,NULL,0,0,xw,hy,0);
DrawDibClose(m_HDD);//关闭DRAW
si=0;//数据区指针归0
}
aa:m_capdll.DestroyBuf(&pBuffer);//释放图形区
}
三、影像转播程序的结构:
1.发送:
a.建立DUP发送Multicast,建立视频窗口CreaCapWin,连接视频捕获设备SetCap,建立视频回调函数capSetCallbackOnFrame。
b.在视频回调函数capSetCallbackOnFrame中获取当前帧的图形,由tmp指示。向消息接收函数cbFrame发出消息。
c.在消息接收函数cbFrame中将tmp指示的图形压缩,用UDP控件分块发送数据。
2.接收:
a.建立DUP接收Multicast,建立UDP接收函数OnOnReceiveData。
b.当网上有指定(地址、端口)信息出现时,UDP接收函数响应。在UDP接收函数OnOnReceiveData中分块接收图形,一帧图形收完后在屏幕上显示。
四、获取本文的相关资料
本文的相关文件:
capdll.dll、capdll.h、capdll.lib
HPSOCK.DLL、HPSOCK.BAT
影像转播发送和接收的VC源程序放在电脑报函授学校网站上。
网址:http://www.pcwclub.com/school
无条件上网的读者可以汇款20元到电脑报函授学校邮购磁盘。在磁盘上还有本文的详细示范和演示文档。
收款人:重庆渝中区双钢路 3号电脑报函授学校
邮编:400013
电话:023-63658811、63658798
E-mail:tml@cpcw.com