基于MFC的网络编程(远程桌面监控)学习笔记(五)图片及视频的传输
在编写整个系统过程中参考了无数csdn的文章,我,,,,找不过来,如有侵权联系我我设私密就好,这个是我自己学习用的谢谢各位csdn的大佬。。。
这一个部分我感觉是整个项目最难的,以我现在的实力最多也就实现到这个份上了,这个视频传输可以供初次接触视频传输的初学者使用,如果您是已经编程好久的大牛,这,您就不用看小弟的blog了。直接跳转自己去设计响应屏幕变化的算法把,加油!
说之前,我先声明这个图片的传输是我的一位很好的老师,匡哥!!!!!教我的!!!
好话不多说,记录一下匡哥的图片传输思想,也是这个项目最难的灵魂!
HWND hwnd = ::GetDesktopWindow();
HDC hDC = ::GetDC(hwnd);
RECT rect;
::GetClientRect(hwnd, &rect);
HDC hdcMem = ::CreateCompatibleDC(hDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rect.right, rect.bottom);
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hdcMem, hBitmap);
::BitBlt(hdcMem, 0, 0, rect.right, rect.bottom, hDC, 0, 0, SRCCOPY);
CImage saveimg;
saveimg.Attach(hBitmap);//截屏并且将其保存在你CImage的变量当中。
IStream* pStmImage = NULL;
HGLOBAL hMemBmp = GlobalAlloc(GMEM_MOVEABLE, 0);
if (hMemBmp == NULL) return 0;
CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmImage);
if (pStmImage == NULL)
{
GlobalFree(hMemBmp);
AfxMessageBox(_T("failure"));
}//这一步是将CImage的图片存入一段数据流当中,便于从内存直接发送,如果要用访问文件的方法,首先会对对方的内存文件是否存在有限制,其次会大大降低传输速度,还会因为反复访问内存导致硬盘消耗
saveimg.Save(pStmImage, Gdiplus::ImageFormatJPEG);
//saveimg.Save(L"D:\\yyj\\1.jpg");
//system("pause");这个就是访问硬盘的语句
saveimg.Detach();
::SelectObject(hdcMem, hOldBitmap);
::DeleteObject(hBitmap);
::DeleteDC(hdcMem);
::DeleteDC(hDC);
CImage sendimg;//这里必须新建一个,就跟你要把粗放进酱油瓶一个道理
res=sendimg.Load(pStmImage);//从内存流当中直接读取图片流
//int res = sendImg(sendimg);
if (res < 0)
{
AfxMessageBox(L"failure");
break;
}
struct imgHead head;
head.with = sendimg.GetWidth();
head.higth = sendimg.GetHeight();
head.BPP = sendimg.GetBPP();
head.step = sendimg.GetPitch();
int step = sendimg.GetPitch();
if (step > 0)
{
head.rowSize = step;
}
else
{
head.rowSize = -step;
}
int res = send(picsocket, (char *)&head, sizeof(head), 0);
if (res < 0)
{
return -1;
}
//2.发送图片的数据部分
unsigned char *pbuf = (unsigned char *)malloc(head.rowSize);
unsigned char * pImg = (unsigned char *)sendimg.GetBits();
for (int i = 0; i < head.higth; i++)
{
//发送一行s
memcpy_s(pbuf, head.rowSize, pImg + i * step, head.rowSize);
int needSend = head.rowSize;
unsigned char *p = pbuf;
while (1)
{
res = send(picsocket, (char *)p, needSend, 0);
if (res <= 0)
{
return -1;
}
needSend -= res;
p += res;
if (needSend == 0)
{
break;
}
}
}
free(pbuf);
pbuf = NULL;
GlobalFree(hMemBmp);
pStmImage->Release();//释放内存开辟的空间
前面的截屏及保存到数据流当中我已注释,下面我想详细记录一下匡哥教我的图片传输
首先图片是由像素点构成的
发送的时候也是将图片从像素点发送,,我们如果要做图片传输时千万不可直接发送整张图片啊,你这就是把硬件逼死了,,,,就算不用那种特别高级的监测变化发送函数,也不能不负责的发一整张图片过去!所以我们先读图片信息,发送图片的“头”,相当于一个情报员,得到图片的大小,然后再用指针的方法将像素一行一行发送过去,指针有个判断语句时用于判断是否一行发完,没发完不能停!然后接受端
发是一行一行发,收当然是一行一行收了!!!!
struct imgHead head;
res = recv(picsocket, (char *)&head, sizeof(head), 0);
if (res < 0)
{
return -1;
}
//2.接收图片的数据部分
CImage vsImg;
vsImg.Create(head.with, head.higth, head.BPP, 0);
unsigned char *pbuf = (unsigned char *)malloc(head.rowSize);
unsigned char * pImg = (unsigned char *)vsImg.GetBits();
//发不是统一发的是一行一行发的
for (int i = 0; i < head.higth; i++)
{
int needRecv = head.rowSize;
unsigned char *p = pbuf;
//这里有一个while true是为了保证它确确实实每一行都收全了
while (1)
{
res = recv(picsocket, (char *)p, needRecv, 0);
if (res < 0)
{
return -1;
}
needRecv -= res;
p += res;
if (needRecv == 0)
{
break;
}
}
memcpy_s(pImg + i * head.step, head.rowSize, pbuf, head.rowSize);
}
//释放掉开辟的空间
free(pbuf);
pbuf = NULL;
pdlg->GetDlgItem(IDC_SHOW)->GetDC()->SetStretchBltMode(COLORONCOLOR);
pdlg->showImgInCtr(IDC_SHOW, vsImg);
也是先收头,然后把图片空间开辟出来,然后一个一个像素点将其画出来。
图片传输就到此为止了,图片会传输了,相信大家离视频传输已经不远了,,,在这里小小提一下,while true,然后利用socket的收发阻塞机制,实现实时传输,,,那么视频传输我就不赘述了!!
上一篇: Kafka集群部署和使用
下一篇: ubuntu装新机无网络解决记录