第10课 利用windows API捕获桌面图像并通过FFmpeg分享

在上一章,我们已经实现了一对一音视频对话功能。在实际应用中,我们常需要把自己的电脑桌面分享给他人以实现桌面共享功能,这种功能在视频会议、在线教学等场景中很常见,这种功能如何实现呢?这节课我们就来解决这个问题。

1.备份demo9并修改demo9为demo10。

2.在fmle.cpp的init函数中添加捕获屏幕的线程:

复制代码
//capCamHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)capCamThread, (LPVOID)this, 0, NULL);
capScrHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)capScrThread, (LPVOID)this, 0, NULL);

3.添加捕获桌面的功能:

cpp 复制代码
cv::Mat hwndToMat(HWND hwnd)
{	
	HDC hwindowDC, hwindowCompatibleDC;
	int height, width, srcheight, srcwidth;
	HBITMAP hbwindow;
	cv::Mat src;
	BITMAPINFOHEADER  bi;
	hwindowDC = GetDC(hwnd);
	hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
	SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);
	RECT windowsize; 
	GetClientRect(hwnd, &windowsize);

	srcheight = windowsize.bottom;
	srcwidth = windowsize.right;
	height = windowsize.bottom;
	width = windowsize.right;

	src.create(height, width, CV_8UC4);
	
	hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = width;
	bi.biHeight = -height;
	bi.biPlanes = 1;
	bi.biBitCount = 32;
	bi.biCompression = BI_RGB;
	bi.biSizeImage = 0;
	bi.biXPelsPerMeter = 0;
	bi.biYPelsPerMeter = 0;
	bi.biClrUsed = 0;
	bi.biClrImportant = 0;	
	SelectObject(hwindowCompatibleDC, hbwindow);	
	StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, 0, 0, srcwidth, srcheight, SRCCOPY | CAPTUREBLT);
	GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO *)&bi, DIB_RGB_COLORS); 	
	DeleteObject(hbwindow); DeleteDC(hwindowCompatibleDC); ReleaseDC(hwnd, hwindowDC);

	return src;
}


int fmle::capScr(){
	
	HWND hwnd = GetDesktopWindow();
	cv::Mat scrMat;
	while (true)
	{
		scrMat = hwndToMat(hwnd);		
		if (scrMat.cols != backWidth || scrMat.rows != backHeight){
			resize(scrMat, scrMat, cv::Size(backWidth, backHeight));
		}

		if (scrMat.data&&!scrMat.empty()){		
			cvtColor(scrMat, scrMat, CV_BGRA2BGR);
			mainDlg->drawMatOfPub(scrMat);
			EnterCriticalSection(&videoQueLock);
			tmpVideoQueObj.type = 1;
			tmpVideoQueObj.tmpMat = scrMat;
			tmpVideoQueObj.dataLen = scrMat.cols*scrMat.rows * 3;
			inVideoQue.push(tmpVideoQueObj);
			if (inVideoQue.size() >videoDataArrNum){
				inVideoQue.front().dataLen = 0;
				inVideoQue.front().tmpMat.release();
				inVideoQue.front().dataLen = NULL;
				inVideoQue.pop();
			}
			LeaveCriticalSection(&videoQueLock);

		}
		Sleep(40);
	}

	scrMat.release();	
	return 0;
}

4.调试运行,如能正常发送和播放桌面流则表示成功。

相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
weilx12342 天前
C++笔记-文件IO-<fcntl.h>
c++
AI的探索之旅2 天前
97 个 OpenCV 实例(三十):双目立体,从标定到点云
人工智能·opencv·计算机视觉
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
rockmelodies2 天前
# Windows Server2008 R2 Standard(SP1镜像U盘)重置本地管理员密码【完整详细步骤】
windows·密码破解
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
Smileyqp沛沛2 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·2 天前
C++ 萌新语法入门篇
c++·算法比赛