关于屏幕截屏,分包发送的问题

wx3046 2009-10-12 05:21:03
截屏和计算包数量等代码


void CClientDlg::OnOK()
{
CDC* pDeskDC = GetDesktopWindow()->GetDC(); //获取桌面画布对象
CRect rc;
GetDesktopWindow()->GetClientRect(rc); //获取屏幕的客户区域

CDC memDC; //定义一个内存画布
memDC.CreateCompatibleDC(pDeskDC); //创建一个兼容的画布
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDeskDC,rc.Width(),rc.Height()); //创建兼容位图
memDC.SelectObject(&bmp); //选中位图对象
BITMAP bitmap;
bmp.GetBitmap(&bitmap);

int panelsize = 0; //记录调色板大小
if (bitmap.bmBitsPixel<16) //判断是否为真彩色位图
panelsize = pow(2,bitmap.bmBitsPixel*sizeof(RGBQUAD));

BITMAPINFO *pBInfo = (BITMAPINFO*)LocalAlloc(LPTR,sizeof(BITMAPINFO)+panelsize);//分配堆空间
pBInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel;
pBInfo->bmiHeader.biClrImportant = 0;
pBInfo->bmiHeader.biCompression = 0;
pBInfo->bmiHeader.biHeight = bitmap.bmHeight;
pBInfo->bmiHeader.biPlanes = bitmap.bmPlanes;
pBInfo->bmiHeader.biSize = sizeof(BITMAPINFO);
pBInfo->bmiHeader.biSizeImage = bitmap.bmWidthBytes*bitmap.bmHeight;
pBInfo->bmiHeader.biWidth = bitmap.bmWidth;
pBInfo->bmiHeader.biXPelsPerMeter = 0;
pBInfo->bmiHeader.biYPelsPerMeter = 0;

memDC.BitBlt(0,0,bitmap.bmWidth,bitmap.bmHeight,pDeskDC,0,0,SRCCOPY);//该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境

char* pData = new char[bitmap.bmWidthBytes* bitmap.bmHeight];
::GetDIBits(memDC.m_hDC,bmp,0,bitmap.bmHeight,pData,pBInfo,DIB_RGB_COLORS);//GetDIBits函数检取指定位图的信息,并将其以指定格式复制到一个缓冲区中

int BufSize = panelsize+ sizeof(BITMAPINFO)+bitmap.bmWidthBytes*bitmap.bmHeight;
Bitmap* mmage;
mmage = Bitmap::FromBITMAPINFO(pBInfo,pData);//使用已经存在的信息来创建一个bitmap,返回值为指针
CLSID clsid;
GetCodecClsid(L"image/jpeg", &clsid);
HGLOBAL m_hMem = GlobalAlloc(GMEM_MOVEABLE, 0);//内存句柄,但不是指针
IStream *pstm=NULL;//一种字节序列,流
CreateStreamOnHGlobal(m_hMem, TRUE, &pstm);//从指定内存创建流对象
mmage->Save(pstm,&clsid,NULL);
m_JpegSize = GlobalSize(m_hMem);
LPBYTE lpData = (LPBYTE)GlobalLock(m_hMem);


m_Addr.sin_family = AF_INET;
m_Addr.sin_port = htons(5002);
m_Addr.sin_addr.S_un.S_addr = inet_addr(m_ServerIP);
m_Bmpsize = GraphSize;


//计算每个位图发送的次数
m_Count = m_JpegSize / GraphSize;
m_Mod = m_JpegSize % GraphSize;
if ( m_Mod != 0)
m_Count+=1;
m_FrameIndex = 0;
memcpy(m_pSendBuf,lpData,m_JpegSize);

//发送数据 块大小 总大小 块数 缓冲区指针
int ret = SendData(m_FrameIndex,m_Mod,GraphSize,m_JpegSize,m_Count,m_pSendBuf,m_Addr);


memDC.DeleteDC();
pDeskDC->DeleteDC();
pstm->Release();
if (mmage)
delete mmage;
delete [] pData;
GlobalUnlock(m_hMem);
GlobalFree(m_hMem);
::LocalFree((HLOCAL)pBInfo);
bmp.DeleteObject();
}









下面是发送函数的代码。

那个序号2位,结束标记2位,JPG数据,JPG数据大小4位,JPG数据总大小4位,数据包大小4位这几个是什么东西。

发送的时候是发送什么类型的数据




int CClientDlg::SendData(UINT index, int mod , int bmpsize , int totalsize ,int frames,
char *pSendBuf, sockaddr_in &addr)
{
/*序号2位||结束标记2位||JPG数据||JPG数据大小4位||JPG数据总大小4位||数据报大小4位*/



char* pPackage;
int packsize = 0;
if ( mod ==0 || index != frames-1)
packsize = 2+2+bmpsize+4+4+4;//这里的包大小是怎么计算的?
else
packsize = 2+2+mod+4+4+4;
pPackage = new char[packsize];
memset(pPackage,0,packsize);

//填充数据报
*(WORD*)&pPackage[0] = index; //填充序号
if (index != frames-1) //填充结束标记
*(WORD*)&pPackage[2] = 0;
else
*(WORD*)&pPackage[2] = 1;
//填充位图数据
pSendBuf += bmpsize*index;
memcpy(&pPackage[4],pSendBuf,packsize-12);
//填充位图大小
*(int*)&pPackage[packsize-12] = bmpsize;
//填充JPG数据总大小
*(int*)&pPackage[packsize-8] = totalsize;
//填充数据报大小
*(int*)&pPackage[packsize-4] = packsize;
m_Confirm = FALSE;
int ret = sendto(m_Socket,pPackage,packsize,0,(sockaddr*)&addr,sizeof(addr));
delete[] pPackage;
return ret;
}



有没有人给我讲讲这个截屏,然后分包,再发送的原理。就是从截屏的时候是BMP格式到转换格式,分包发送这个过程中,bmp这个文件都是转换成什么类型的数据了。谢谢
...全文
148 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsldd 2009-10-14
  • 打赏
  • 举报
回复
在你给的代码逻辑中只有组包,而没有“分包”的概念。
sendto直接一个udp包就丢过去了。
不知楼主从哪里得知这里用了“分包”的。
wx3046 2009-10-13
  • 打赏
  • 举报
回复
谢谢1的回答,我刚刚又仔细的看了一下代码。我的理解是这样的:

分包发送:从代码来看,应该是将bmp文件在内存中转换为jpg文件,返回一个指向该jpg文件所在内存块的首地址,发送的时候就从内存块首地址开始,按固定大小的块来发送,直到将内存块中的jpg文件发送完。所谓的分包,只是将内存中的数据依次按一个固定的大小来发送,这些数据在内存中的位置是连续的,而不是将内存中的数据先分包存储再发送。然后服务器端也是接收到内存中,全部包都接收完了才显示图片

不知道这样对不对?

还有一个问题,就是一个内存中的jpg文件,是分包发送的,但是我没看出来哪一部分的代码是发送下一个包,没有看到哪里有循环发送的。



顶起来,我在线等。。。。。
lsldd 2009-10-12
  • 打赏
  • 举报
回复
基本上是这么几个步骤:
1:
char* pData = new char[bitmap.bmWidthBytes* bitmap.bmHeight];
截bmp图到内存pData (并没有生成文件)

2:
lpData = (LPBYTE)GlobalLock(m_hMem),
CreateStreamOnHGlobal(m_hMem, TRUE, &pstm);//
通过Bitmap和IStream流的中转,最终把bmp数据转成jpg数据流存在申请的内存lpData中,作为参数调用SendData

3:按照/*序号2位||结束标记2位||JPG数据||JPG数据大小4位||JPG数据总大小4位||数据报大小4位*/
的格式,把lpData数据和其他jpg数据信息填充到char* pPackage中进行发送。

至于这里的IStream以及图片格式转换原理我不是很清楚,观望高人讲解。

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧