欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于MFC的网络编程(远程桌面监控)学习笔记(五)图片及视频的传输

程序员文章站 2024-03-08 20:31:04
...

在编写整个系统过程中参考了无数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的收发阻塞机制,实现实时传输,,,那么视频传输我就不赘述了!!

相关标签: 网络图片传输