在局域网/内网(甚至可能在互联网上)进行视频会议是现代通信技术的一项重要应用。目前市面上存在多种视频会议应用程序,每种程序都有其独特的性能增强技术。视频会议中的主要问题在于视频帧的大小对于传输来说过大。因此,性能基于用于编码和解码帧的编解码器。使用的是Fast h263 Encoder库,它在高速下提供更好的压缩率。这个应用程序也可以稍作修改后在互联网上使用。
使用了之前在语音会议应用中使用的相同的RecordSound和PlaySound类。在这里,将简要概述如何使用这些类。
创建并启动录音器线程:
record = new RecordSound(this);
record->CreateThread();
创建并启动播放器线程:
play = new PlaySound1(this);
play->CreateThread();
开始录音:
record->PostThreadMessage(WM_RECORDSOUND_STARTRECORDING, 0, 0);
开始播放:
play->PostThreadMessage(WM_PLAYSOUND_STARTPLAYING, 0, 0);
在音频录制期间,数据将在RecordSound类的OnSoundData回调函数中可用。在这里,可以放置代码以将数据发送到远程主机...
要播放从远程主机接收到的数据:
play->PostThreadMessage(WM_PLAYSOUND_PLAYBLOCK, size, (LPARAM)data);
停止录音:
record->PostThreadMessage(WM_RECORDSOUND_STOPRECORDING, 0, 0);
停止播放:
play->PostThreadMessage(WM_PLAYSOUND_STOPPLAYING, 0, 0);
最后,停止录音线程:
record->PostThreadMessage(WM_RECORDSOUND_ENDTHREAD, 0, 0);
要停止播放线程...
play->PostThreadMessage(WM_PLAYSOUND_ENDTHREAD, 0, 0);
视频捕获是通过VFW(Video For Windows)API完成的。它提供了从网络摄像头捕获视频的支持。VideoCapture.h和VideoCapture.cpp是包含完整视频捕获过程代码的文件。
创建类的实例:
vidcap = new VideoCapture();
这稍后用于在捕获帧时调用主对话框类的显示函数...
vidcap->SetDialog(this);
这包括很多工作,包括连接到驱动程序和设置所需的视频格式。如果成功连接到视频捕获设备,则返回TRUE。
vidcap->Initialize();
如果成功连接,那么可以获取与视频格式关联的BITMAPINFO结构。这稍后用于显示捕获的帧...
this->m_bmpinfo = &vidcap->m_bmpinfo;
现在可以开始捕获了...
vidcap->StartCapture();
一旦开始捕获,帧将在VideoCapture类的OnCaptureVideo回调函数中到达。在这里调用显示函数以显示帧。
要停止捕获:
vidcap->StopCapture();
如果工作结束了...就销毁它。
vidcap->Destroy();
如果做了这么多工作,代码将会编译得很好...但链接器会给带来麻烦。必须链接合适的库...
#pragma comment(lib,"vfw32")
#pragma comment(lib,"winmm")
有多种方法和API用于显示捕获的帧。可以使用SetDIBitsToDevice()方法直接显示帧。但由于它基于图形设备接口(GDI)函数,所以相当慢。更好的方法是使用DrawDib API来绘制帧。DrawDib函数为设备无关位图(DIBs)提供了高性能的图像绘制功能。
DrawDib函数直接写入视频内存,因此提供更好的性能。
以下是如何使用DrawDib API显示帧的简要视图:
Initialize DIB for drawing...
HDRAWDIB hdib = ::DrawDibOpen();
然后调用这个函数,使用合适的参数...
::DrawDibBegin(hdib,...);
现在如果准备好了帧数据,只需调用这个函数来显示帧
::DrawDibDraw(hdib,...);
最后终止...
::DrawDibEnd(hdib);
::DrawDibClose(hdib);
编码器:
使用了快速h.263编码器库进行编码。这个库是Tmndecoder的修改版本,使其更适合实时编码。已将其从C转换为C++,以便它可以轻松集成到任何Windows应用程序中。从快速h263库中移除了一些不必要的代码/文件。还移动了定义和声明到它们适当的.h和.cpp文件中。
快速h263编码器库的简要使用视图:
Initialize the compressor
CParam cparams;
cparams.format = CPARAM_QCIF;
InitH263Encoder(&cparams);
如果需要从RGB24转换到YUV420,那么调用这个
InitLookupTable();
设置回调函数
OwnWriteFunction是全局函数,在编码过程中被调用以返回编码数据...
WriteByteFunction = OwnWriteFunction;
压缩数据必须是YUV420格式...
因此,在压缩之前调用这个方法
ConvertRGB2YUV(IMAGE_WIDTH, IMAGE_HEIGHT, data, yuv);
压缩帧。。。
cparams.format = CPARAM_QCIF;
cparams.inter = CPARAM_INTRA;
cparams.Q_intra = 8;
cparams.data = yuv;
数据是YUV格式...
CompressFrame(&cparams, &bits);
可以从回调函数中获取压缩数据,已经在开始时注册了...
最后终止编码器
ExitH263Encoder();
解码器:
这是tmndecoder(H.263解码器)的修改版本。它原本是ANSI C。已将其转换为C++,以便它可以集成到任何Windows应用程序中。移除了一些具有显示和文件存储功能的文件。移除了一些不必要的代码,并添加了一些新文件。
原始库处理文件。它不适合用于实时解码。做了一些重大更改,使其可以轻松集成到应用程序中,用于实时解码过程。现在,可以使用这个库来解码H263帧。这个库相当快,并且提供更好的性能。
解码器的使用。。。
Initialize the decoder
InitH263Decoder();
解压缩帧。。。
DecompressFrame(data, size, rgbdata, buffersize);
最后终止解码器
ExitH263Decoder();
将可执行文件复制到两台不同的机器A和B上,它们位于局域网上。在两台机器上运行应用程序。从机器A(或B)中,选择连接菜单项,在弹出的对话框中输入另一台主机(B)的名称或IP地址,然后按连接按钮。在另一台机器(B)上,将出现接受/拒绝对话框。按接受按钮。在机器A上,将显示通知对话框。按OK开始会议。
就是这样...享受吧!
nsry2002@yahoo.co.in