学 员 通 道
注册名:
密 码:
  你的位置:网校首页>>第二课堂>>网校专题

共享电视卡,收看世界杯

电脑报远程教育中心 唐明理

  世人关注的世界杯足球赛开始了,中国队的首次参赛更增加这次球赛的看点。坐在计算机旁,一边看球赛一边上网发表你的高论;确是一件惬意的事情。是说不得这几天电视卡买得火爆。但是在公众计算机场所,怕是不能每台计算机都配上电视卡的。共享嘛,软件可以共享,硬件不是一样可以共享吗。这里我们首先给出一个局域网上的电视转播的思路和相关的资源,这样在一个机房、网吧,用一块电视卡接收的足球赛就可以广播出去,使局域网内的所有计算机都行收看,哈,在这种环境看世界不是更COOL。好,让你来做一个电视卡的共享软件,你有兴趣吗?

一、设计思路:(共享电视卡,收看世界杯)

  1.捕获视频输入(获取电视卡的输入)。这在微软的API函数库中有一系列的视频捕获处理的函数,可供我们在Windows上轻易地启动电视卡,接收播放电视。
  2.分离视频数据流,真正获取我们需要传输的电视图形。我们还是使用API函数中视频捕获的回调功能就可以搞定了。
  3.电视一帧画面是352*288像素,16位色时就有200多K,如果我们一秒钟在网上发送10帧就有2M的数据量!压缩,又是调用API函数库中现有的视频压缩功能。选择好的压缩格式,一帧图形可以压缩到20多K。这样就可以在网上传输了。
  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(); //释放压缩缓存
6.VARIANT BytetoVar(void * pBuf,int Size);
//转换发送数据:输入 1待发数据区指针,2数据长度。返回装有数据的变体
7.char * CreateBufFromVar(const VARIANT FAR& var,int *pSize);
//转换接收数据:输入 1接收数据的变体, 2数据长度, 返回接收到的数据指针。
8.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); //将1K的图形拷到发送块
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源程序
  欢迎大家下载:影像转播.zip
  欢迎交流,作者信箱:tml@cpcw.com

ml>