該程序可以用於兩個人在LAN/Intranet(或者 Internet)上進行視頻 會議。現在有許多視頻會議程序,每個都有各自的性能提升技術。主要的問題是視頻會議視頻幀的尺寸對於傳輸來說太大。因此,性能依賴於對幀的編解碼。我使用快速h263編碼庫來達到更好的壓縮率提高速度。該程序做些小改動也可以在Internet上使用。
音頻的錄製與播放
我在以前的語音會議程序中使用了RecordSound和PlaySound類,這裏我將提供摘要說明RecordSound和PlaySound類的使用。
// Create and Start Recorder Thread record=new RecordSound(this); record->CreateThread(); // Create and Start Player Thread play=new PlaySound1(this); play->CreateThread(); // Start Recording record->PostThreadMessageWM_RECORDSOUND_STARTRECORDING,0,0); // Start Playing play->PostThreadMessage(WM_PLAYSOUND_STARTPLAYING,0,0); // During audio recording, data will be available in the OnSoundData // callback function of the RecordSound class. Here, you can place // your code to send the data to remote host... // To play the data received from the remote host play->PostThreadMessage(WM_PLAYSOUND_PLAYBLOCK,size,(LPARAM)data); // Stop Recording record->PostThreadMessage(WM_RECORDSOUND_STOPRECORDING,0,0); // Stop Playing play->PostThreadMessage(WM_PLAYSOUND_STOPPLAYING,0,0); // At last, to Stop the Recording Thread record->PostThreadMessage(WM_RECORDSOUND_ENDTHREAD,0,0); // To stop playing thread... play->PostThreadMessage(WM_PLAYSOUND_ENDTHREAD,0,0); |
視頻捕獲
使用VFW(Video For Windows)API進行視頻捕獲,它提供了通過webcam進行視頻捕獲。VideoCapture.h 和VideoCapture.cpp包含了處理視頻捕獲的代碼。
如下代碼說明了如何使用該類:
// Create instance of Class vidcap=new VideoCapture(); // This is later used to call display function of the main // dialog class when the frame is captured... vidcap->SetDialog (this); // This does lot of work, including connecting to the driver // and setting the desired video format. Returns TRUE if // successfully connected to videocapture device. vidcap->Initialize(); // If successfully connected, you can get the BITMAPINFO // structure associated with the video format. This is later // used to display the captured frame... this->m_bmpinfo=&vidcap->m_bmpinfo; // Now you can start the capture.... vidcap->StartCapture(); // Once capture is started, frames will arrive in the "OnCaptureVideo" // callback function of the VideoCapture class. Here you call the // display function to display the frame. // To stop the capture vidcap->StopCapture(); // If your job is over....just destroy it.. 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();
// Then call this function with suitable parameters.... ::DrawDibBegin(hdib,...);
// Now, if you are ready with the frame data, just invoke this
// function to display the frame ::DrawDibDraw(hdib,...);
// Finally, termination... ::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); // If you need conversion from RGB24 to YUV420, call this InitLookupTable(); // Set up the callback function // OwnWriteFunction is the global function called during // encoding to return the encoded data... WriteByteFunction = OwnWriteFunction; // For compression, data must be in the YUV420 format... // Hence, before compression, invoke this method ConvertRGB2YUV(IMAGE_WIDTH,IMAGE_HEIGHT,data,yuv); // Compress the frame..... cparams.format = CPARAM_QCIF; cparams.inter = CPARAM_INTRA; cparams.Q_intra = 8; cparams.data=yuv; // Data in YUV format... CompressFrame(&cparams, &bits); // You can get the compressed data from the callback function/ // that you have registerd at the begining... // Finally, terminate the encoder // ExitH263Encoder(); |
解碼器:
這是tmndecoder(H.263解碼器)的修改版。使用ANSI C編寫,我將它轉換到C++使其方便在Windows應用程序中使用。我移除了一些用於顯示和文件處理的文件,移除了不必要的代碼並增加了一些新文件。
原始的庫中一些文件不適合於實時的解碼。我已經做了修改使其適合實時的解碼處理。現在,可以使用該庫來解碼H263幀,該庫非常快,性能不錯。
解碼的使用方法:
//Initialize the decoder InitH263Decoder(); // Decompress the frame.... // > rgbdata must be large enough to hold the output data... // > decoder produces the image data in YUV420 format. After // decoding, it is converted into RGB24 format... DecompressFrame (data,size,rgbdata,buffersize); // Finaly, terminate the decoder ExitH263Decoder(); |
如何運行程序
拷貝可執行文件到局域網上兩臺不同的機器中:A和 B,運行他們。在機器A(或B)中選擇connect菜單條,在彈出的對話框 中輸入機器B的名字或IP地址然後按connect按鈕,在另外一臺機器(B)顯示出accept/reject對話框,按accept按鈕。在機器A將顯示一個通知對話框,按OK後開始會議。