教師端擷取桌面畫面 → JPEG 壓縮 → UDP 廣播傳送 → 學生端接收解壓 → 即時顯示。採用非同步 Socket (CAsyncSocket) 避免阻塞 UI,自訂簡易 JPEG 壓縮演算法提升區域網路傳輸效率。
Netss,勾選 Windows Sockets 支援。
class CSendSocket : public CAsyncSocket
{
public:
virtual void OnSend(int nErrorCode); // FD_WRITE 觸發
};
CSendSocket m_sock;
CDC m_memDC; CBitmap m_bmp;
CDC* m_pDeskDC;
int m_nFrameIdx = 1000; // 資料指標
short m_pixelBuf[350000]; // 640x480x2 bytes
char m_frameBuf[5000]; // 壓縮後封包
m_sock.Create(2001, SOCK_DGRAM, FD_WRITE);
BOOL bOpt = TRUE;
m_sock.SetSockOpt(SO_BROADCAST, &bOpt, sizeof(BOOL));
m_sock.SetSockOpt(SO_DONTROUTE, &bOpt, sizeof(BOOL));
m_sock.SetSockOpt(SO_SNDBUF, &eee, sizeof(int)); // 8192
m_sock.AsyncSelect(FD_WRITE);
CWindowDC ddc(GetDesktopWindow());
m_pDeskDC = &ddc;
m_memDC.CreateCompatibleDC(m_pDeskDC);
m_bmp.CreateCompatibleBitmap(m_pDeskDC, 640, 480);
m_memDC.SelectObject(&m_bmp);
void CSendSocket::OnSend(int nErrorCode)
{
if (m_nFrameIdx > 307200) // 一幀結束
{
m_nFrameIdx = 1000;
m_memDC.BitBlt(0,0,640,480, m_pDeskDC,0,0, SRCCOPY);
m_bmp.GetBitmapBits(614400, &m_pixelBuf[1000]);
// 繪製滑鼠游標
POINT pt; GetCursorPos(&pt);
for (int y=0; y<10 && pt.y+y<480; y++)
for (int x=0; x<10 && pt.x+x<640; x++)
m_pixelBuf[(pt.y+y)*640 + pt.x+x + 1000] = 31744;
}
// 簡易 JPEG 壓縮:8 pixel 一組
char* pf = &m_frameBuf[4];
short* pfi = (short*)(pf+1);
int* pa = (int*)m_frameBuf;
*pa = m_nFrameIdx;
while (pf < &m_frameBuf[3836])
{
*pf = 0;
for (int i=0; i<8; i+=2)
{
short cur = m_pixelBuf[m_nFrameIdx];
short left = m_pixelBuf[m_nFrameIdx-1];
short up = m_pixelBuf[m_nFrameIdx-640];
short upleft = m_pixelBuf[m_nFrameIdx-641];
if (cur == left) *pf |= (0x40 >> i);
else if (cur == up) *pf |= (0x80 >> i);
else if (cur == upleft)*pf |= (0xC0 >> i);
else { *pfi = cur; pfi++; }
m_nFrameIdx++;
}
pf = (char*)pfi;
pfi = (short*)(pf+1);
}
AsyncSelect(FD_WRITE); // 繼續監聽
SendTo(m_frameBuf, 3840, 1050, NULL, 0); // 廣播埠 1050
}
Netcc,勾選 Windows Sockets。
class CRecvSocket : public CAsyncSocket
{
public:
virtual void OnReceive(int nErrorCode); // FD_READ 觸發
};
CRecvSocket m_sock;
CDC m_memDC; CBitmap m_bmp;
CDC* m_pViewDC;
short m_pixelBuf[350000];
void CRecvSocket::OnReceive(int nErrorCode)
{
CString strIP; UINT nPort;
ReceiveFrom(m_frameBuf, 3840, strIP, nPort);
char* pf = &m_frameBuf[4];
short* pfi = (short*)(pf+1);
int* pa = (int*)m_frameBuf;
while (pf < &m_frameBuf[3836])
{
for (int i=0; i<8; i+=2)
{
BYTE flag = *pf & (0xC0 >> i);
if (flag == (0x40 >> i)) m_pixelBuf[*pa] = m_pixelBuf[*pa - 1];
else if (flag == (0x80 >> i)) m_pixelBuf[*pa] = m_pixelBuf[*pa - 640];
else if (flag == (0xC0 >> i)) m_pixelBuf[*pa] = m_pixelBuf[*pa - 641];
else { m_pixelBuf[*pa] = *pfi; pfi++; }
(*pa)++;
}
pf = (char*)pfi;
pfi = (short*)(pf+1);
}
if (*pa > 307200) // 一幀完成
{
m_bmp.SetBitmapBits(614400, &m_pixelBuf[1000]);
m_pViewDC->BitBlt(0,0,640,480, &m_memDC,0,0, SRCCOPY);
}
}
CAsyncSocket + FD_WRITE/FD_READ 事件驅動,不阻塞 UI。SO_BROADCAST 讓單一封包到達所有學生端。BitBlt 至視窗,無閃爍。