VideoNet 是一個基於 LAN/Intranet(亦可擴展至 Internet)的點對點視訊會議程式,採用 H.263 視訊編碼、G.711/G.723 音訊編碼、UDP 即時傳輸。本文詳細解析其核心模組:音訊擷取/播放、視訊擷取 (VFW)、幀顯示 (DrawDib)、H.263 編解碼庫整合與網路傳輸架構。
// 建立並啟動錄音執行緒
RecordSound* pRecord = new RecordSound(this);
pRecord->CreateThread();
// 建立並啟動播放執行緒
PlaySound1* pPlay = new PlaySound1(this);
pPlay->CreateThread();
// 開始錄音
pRecord->PostThreadMessage(WM_RECORDSOUND_STARTRECORDING, 0, 0);
// 開始播放
pPlay->PostThreadMessage(WM_PLAYSOUND_STARTPLAYING, 0, 0);
// 錄音回呼:取得 PCM 資料 → 封包 → UDP 發送
void OnSoundData(BYTE* pData, int nSize) {
SendAudioPacket(pData, nSize);
}
// 收到遠端音訊 → 送入播放佇列
void OnAudioPacketReceived(BYTE* pData, int nSize) {
pPlay->PostThreadMessage(WM_PLAYSOUND_PLAYBLOCK, nSize, (LPARAM)pData);
}
關鍵點:雙執行緒隔離音訊 I/O 與 UI,避免阻塞;使用 waveInOpen/waveOutOpen (MME) 或 IAudioClient (WASAPI) 低延遲路徑。
// VideoCapture 類別封裝 VFW API
VideoCapture* pCap = new VideoCapture();
pCap->SetDialog(this); // 設定回呼視窗
pCap->Initialize(); // 連接裝置、協商格式 (I420/YUY2/RGB24)
BITMAPINFO* pBmi = &pCap->m_bmpinfo; // 取得格式資訊
pCap->StartCapture(); // 開始預覽,回呼 OnCaptureVideo
// OnCaptureVideo 回呼中:
void OnCaptureVideo(BYTE* pFrame, int nSize) {
// 1. 本地預覽
DisplayFrame(pFrame, pBmi);
// 2. 編碼
EncodeAndSend(pFrame, pBmi);
}
GDI SetDIBitsToDevice 效能不足,改用 DrawDib 直接寫入顯示記憶體:
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "winmm.lib")
HDRAWDIB hdd = DrawDibOpen();
DrawDibBegin(hdd, hdc, 0, 0, width, height, pBmi, 0, 0, width, height, 0);
DrawDibDraw(hdd, hdc, 0, 0, width, height, pBmi, pFrame, 0, 0, width, height, 0);
DrawDibEnd(hdd);
DrawDibClose(hdd);
支援 YUV420P → RGB24 硬體加速色彩轉換,CPU 佔用極低。
CParam param;
param.format = CPARAM_QCIF; // 176x144
param.Q_intra = 8; // 量化步長
InitH263Encoder(¶m);
InitLookupTable(); // RGB24 -> YUV420 查表
WriteByteFunction = MyWriteCallback; // 設定位元流輸出回呼
// 每幀編碼流程
ConvertRGB2YUV(WIDTH, HEIGHT, rgbFrame, yuvFrame); // 色彩空間轉換
param.data = yuvFrame;
param.inter = CPARAM_INTRA; // I-frame
CompressFrame(¶m, &bits); // 輸出透過 MyWriteCallback 回呼
InitH263Decoder();
// 接收端:收到位元流 → 解碼
DecompressFrame(bitstream, bitstreamSize, rgbOutput, bufferSize);
// 輸出為 RGB24,直接送 DrawDib 顯示
ExitH263Decoder();
優化重點:移除原始庫的檔案 I/O、顯示相關代碼,專注即時串流處理;查表法加速色彩轉換;固定 QCIF 解析度降低運算量。
Seq | Timestamp | PayloadType | Size | Data。Q_intra、解析度 (QCIF/CIF/4CIF)、幀率。VideoNet.exe 至兩台機器 A、B。RecordSound/PlaySound 類別。TmN Decoder (H.263 解碼器)。專案採用開源友善授權,歡迎貢獻代碼、回報 Issue、移植至現代平台 (WebRTC, FFmpeg, Qt)。
| 模組 | 現代替代方案 | 效益 |
|---|---|---|
| VFW | Media Foundation / DirectShow / V4L2 (Linux) / AVFoundation (macOS) | 硬體加速編碼、多格式支援、跨平台 |
| DrawDib | Direct2D / Direct3D 11 / OpenGL / Vulkan / Metal | GPU 繪製、零拷貝、高解析度支援 |
| H.263 | H.264 / H.265 / VP8 / VP9 / AV1 (FFmpeg, libvpx, OpenH264) | 壓縮效率提升 2-4x、硬體編解碼普及 |
| UDP 自訂 | WebRTC (SRTP, ICE, DTLS, SCTP) / SRT / RIST | 端到端加密、NAT 穿透標準化、擁塞控制 |
| 音訊 MME | WASAPI (共享/獨佔模式) / AudioWorklet (Web) | 超低延遲 (<10ms)、格式協商彈性 |
VideoNet 展示了 2000 年代初期視訊會議核心技術棧,理解其架構有助於掌握現代 WebRTC/媒體伺服器設計精髓。