第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.调试运行,如能正常发送和播放桌面流则表示成功。

相关推荐
羑悻的小杀马特40 分钟前
OpenCV 引擎:驱动实时应用开发的科技狂飙
人工智能·科技·opencv·计算机视觉
蹦蹦跳跳真可爱5892 小时前
Python----计算机视觉处理(Opencv:道路检测之提取车道线)
python·opencv·计算机视觉
SKYDROID云卓小助手2 小时前
三轴云台之相机技术篇
运维·服务器·网络·数码相机·音视频
yunteng5213 小时前
音视频(一)ZLMediaKit搭建部署
音视频·zlmediakit·安装搭建
niandb5 小时前
The Rust Programming Language 学习 (九)
windows·rust
Merokes6 小时前
关于Gstreamer+MPP硬件加速推流问题:视频输入video0被占用
c++·音视频·rk3588
请来次降维打击!!!7 小时前
优选算法系列(5.位运算)
java·前端·c++·算法
别NULL8 小时前
机试题——统计最少媒体包发送源个数
c++·算法·媒体
嘤国大力士8 小时前
C++11&QT复习 (七)
java·c++·qt
背影疾风8 小时前
C++学习之路:指针基础
c++·学习