技術架構
- 影像擷取:Microsoft VFW (
AVICAP32.DLL),建立捕捉視窗、連接裝置、設定參數、啟用預覽、註冊幀回呼函數逐幀取得畫面。
- 壓縮編碼:每幀繪製至
TBitmap,轉 TJpegImage 壓縮 (品質 10~100),存入 TMemoryStream。
- 網路傳輸:Indy
TIdUDPClient 廣播 (192.168.0.255:9001) 或單播發送 JPEG 位元組流;接收端 TIdUDPServer 讀取 Stream 載入 JPEG 顯示於 TImage。
伺服器端 (擷取/發送) 關鍵程式碼
uses VFW, Jpeg, IdUDPClient, Classes;
var
CapWnd: THandle; CapParms: TCaptureParms; BmpInfo: TBitmapInfo;
procedure TFormServer.StartCapture;
begin
// 1. 建立捕捉視窗
CapWnd := capCreateCaptureWindow('MyCap', WS_CHILD or WS_VISIBLE,
0, 0, PanelVideo.Width, PanelVideo.Height, PanelVideo.Handle, 0);
if CapWnd = 0 then Exit;
// 2. 註冊幀回呼
capSetCallbackOnFrame(CapWnd, @FrameCallback);
// 3. 設定捕捉參數
FillChar(CapParms, SizeOf(CapParms), 0);
CapParms.dwRequestMicroSecPerFrame := 33333; // ~30 fps
CapParms.fYield := True;
CapParms.vKeyAbort := VK_ESCAPE;
capCaptureSetSetup(CapWnd, @CapParms, SizeOf(CapParms));
// 4. 連接裝置 (索引 0)
capDriverConnect(CapWnd, 0);
capGetVideoFormat(CapWnd, @BmpInfo, SizeOf(BmpInfo));
// 5. 啟用預覽 (Overlay 模式較省資源)
capPreviewScale(CapWnd, True);
capOverlay(CapWnd, True);
capPreview(CapWnd, True);
// 6. 開始串流捕捉 (不存檔)
capCaptureSequenceNoFile(CapWnd);
end;
// 幀回呼函數 (VFW 執行緒呼叫,需執行緒安全)
function FrameCallback(hWnd: HWND; lpVHdr: PVideoHdr): LongInt; stdcall;
var
HDC: HDC; Bmp: TBitmap; Jpg: TJpegImage; MS: TMemoryStream; DrawHandle: HDC;
begin
Result := 1; // 繼續捕捉
Bmp := TBitmap.Create;
Jpg := TJpegImage.Create;
MS := TMemoryStream.Create;
try
Bmp.Width := BmpInfo.bmiHeader.biWidth;
Bmp.Height := BmpInfo.bmiHeader.biHeight;
// VFW 畫面繪製至 Bitmap
DrawHandle := DrawDibOpen;
DrawDibDraw(DrawHandle, Bmp.Canvas.Handle, 0, 0,
BmpInfo.bmiHeader.biWidth, BmpInfo.bmiHeader.biHeight,
@BmpInfo.bmiHeader, lpVHdr.lpData, 0, 0,
BmpInfo.bmiHeader.biWidth, BmpInfo.bmiHeader.biHeight, 0);
DrawDibClose(DrawHandle);
// JPEG 壓縮
Jpg.Assign(Bmp);
Jpg.CompressionQuality := 20; // 平衡品質/大小
Jpg.Compress;
Jpg.SaveToStream(MS);
// UDP 廣播發送 (注意 MTU 限制,大封包需分片)
if MS.Size > IdUDPClient1.BufferSize then
IdUDPClient1.SendBuffer('192.168.0.255', 9001, MS.Memory^, IdUDPClient1.BufferSize)
else
IdUDPClient1.SendBuffer('192.168.0.255', 9001, MS.Memory^, MS.Size);
finally
MS.Free; Jpg.Free; Bmp.Free;
end;
end;
procedure TFormServer.StopCapture;
begin
capCaptureAbort(CapWnd);
capDriverDisconnect(CapWnd);
end;
客戶端 (接收/顯示) 關鍵程式碼
procedure TFormClient.IdUDPServer1UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
Jpg: TJpegImage;
begin
Jpg := TJpegImage.Create;
try
Jpg.LoadFromStream(AData);
ImageVideo.Picture.Bitmap.Assign(Jpg);
finally
Jpg.Free;
end;
end;
關鍵技術難點與改進方向
| 問題 | 原因 | 改進方案 |
| UDP 封包大小限制 (MTU ~1500 bytes) | JPEG 若超過 BufferSize 會被截斷,畫面破碎 | 啟用分片重組、或改用 H.264 硬體編碼 + RTP over UDP、或改 TCP 可靠傳輸 |
| VFW 過時、不支援現代攝像頭 (UVC)、無硬體加速 | VFW 為 1990s 技術 | 改用 DirectShow、Media Foundation、OpenCV、FFmpeg (Delphi wrapper) |
| 無音訊支援 | 範例僅處理影像 | 同步捕捉 WaveIn 音訊、Opus/AAC 編碼、RTP 多工傳輸 |
| 廣播僅限同網段,跨路由需組播/中繼伺服器 | UDP 廣播不穿透路由 | 引入 STUN/TURN/ICE (WebRTC) 實現 NAT 穿透 |
| 幀回呼在 VFW 執行緒,VCL 操作需同步 | 直接操作 UI 會導致死結 | 用 TThread.Queue 送回主執行緒更新預覽 |
現代化建議
新專案強烈建議採用 **WebRTC** (DataChannel/VideoTrack) 或 **gRPC + Protobuf** 傳輸編碼後的 H.264/VP8/HEVC 影流,Delphi 可透過 libwebrtc 封裝或 sgcWebSockets (支援 WebRTC) 整合,跨平台、穿透 NAT、硬體加速、低延遲。
- 上一篇文章: Delphi 使用 TUdpSocket 取得本機主機名與 IP 位址
- 下一篇文章: 《熊貓燒香》病毒 Delphi 變種原始碼分析與防範對策
Copyright ©
程式碼之家 All Rights Reserved