基于 Windows GDI 的屏幕录像软件制作过程

我知道,标题不响亮一点你们是不会点进来看的(奸笑),好了言归正传,博主一直都想自己写一个屏幕录像软件,相信大家都用过屏幕录像软件了,专业级别或者商业级别的屏幕录像软件都是自己写驱动来获取显卡数据,或者自己写 Hook 来勾住一些图形函数来获取图形数据等等,不过博主没有这个能耐,唯一可以用的就是 Windows 自带的 GDI 函数了,以前看过一本游戏开发相关的书籍,里面讲解了如何使用 GetDIBits 函数来快速获取 HDC 里面的颜色数据,比起 GetPixel 快了上百个数量级不止,博主灵光一闪,那么是不是意味着只要我能够获取任意的窗体的 HDC,就可以用 GetDIBits 来获取窗体的颜色数据呢,基于这个念头,博主开始实施这个屏幕录像软件,当然,实践出真知,最终结果令人大吃一惊 —— 我成功了 !!我获取了目标窗体的颜色数据,然后保存到文件,然后通过一些代码进行录像回放,进而实现了一个简易的屏幕录像软件,接下来,让咱们看看整个软件的实现过程。

首先,我们来大概预览一下整个屏幕录像软件涉及到的技术点,然后逐一实现:

1. 如何获取全部窗口的信息,包括:句柄、HDC、标题、风格、窗体大小、客户区大小等等

2. 如何从目标窗体的 HDC 里面快速获取颜色数据

3. 如何将颜色数据快速绘制到预览区域

4. 如何将颜色数据保存到文件,并且进行录像回放

好,接下来咱们一个一个问题来解决,首先是第一个,获取全部窗口的信息,这个很简单,用 EnumWindows 函数就可以了,具体实现如下:

 1 //
 2 // 窗体信息
 3 //
 4 struct WINDOW_INFO
 5 {
 6     HWND handle;
 7     DWORD style;
 8     DWORD style_ex;
 9     RECT rect_client;
10     RECT rect_window;
11     core::stringW title;
12     core::stringW class_name;
13 };
14
15 unsigned int enumWindow( core::list< WINDOW_INFO > & window_list )
16 {
17     EnumWindows( EnumThreadWndProc, ( LPARAM ) & window_list );
18
19     return window_list.size( );
20 }
21
22 BOOL CALLBACK EnumThreadWndProc( HWND hwnd, LPARAM lparam )
23 {
24     WINDOW_INFO wi = { 0 };
25     core::list< WINDOW_INFO > * window_list = ( core::list< WINDOW_INFO > * ) lparam;
26
27     wi.handle = hwnd;
28     wi.style = GetWindowLong( hwnd, GWL_STYLE );
29     wi.style_ex = GetWindowLong( hwnd, GWL_EXSTYLE );
30
31     wi.title.alloc( 1024, true );
32     GetWindowTextW( hwnd, wi.title.getBuffer( ), 1024 );
33
34     wi.class_name.alloc( 1024, true );
35     GetClassNameW( hwnd, wi.class_name.getBuffer( ), 1024 );
36
37     GetClientRect( hwnd, & wi.rect_client );
38     GetWindowRect( hwnd, & wi.rect_window );
39
40     if( window_list ) window_list->pushTail( wi );
41
42     return TRUE;
43 }

在上面代码中,WINDOW_INFO 结构体包含了窗体的必须的一些信息,当然,你可以自己扩充一下这个结构体,比如加上 HDC 啊、子控件列表之类的;

enumWindow( ) 函数调用 Windows 的 EnumWindows( ) 函数,然后每当系统发现一个窗体,都会调用一次 EnumThreadWndProc( ) 回调函数,并且把窗体的句柄作为参数传递进去,这样子,我们就可以根据这个窗体句柄来获取窗体数据了,在这个例子里面,我用一个 list 链表保存了全部窗体的信息,这个 list 是我自己写的,所以和 STL 的 std::list 肯定有很大出入,大家不用纠结,知道是链表就可以了;

接下来就是怎么获取目标窗体的颜色数据了,假设我们要对桌面进行录像,那么获取桌面的 HWND 句柄就是 GetDesktopWindow( ) 函数,然后用 GetDC( ) 或者 GetWindowDC( ) 都可以拿到桌面的 HDC,接下来就是重点了 —— 使用 GetDIBits( ) 函数快速获取桌面 HDC 里面的颜色数据;

快速获取桌面 DC 的颜色数据的思路是这样子的,创建一个与桌面相互兼容的 HDC,称之为兼容 DC,创建一个与兼容 DC 互相兼容的位图对象,称之为兼容位图,将兼容位图选入到兼容 DC 内,然后把桌面 DC 的内容,通过 BitBlt( ) 函数快速传送到兼容 DC 内,然后通过 GetDIBits( ) 函数从兼容 DC 里面获取到颜色数据,这些颜色数据其实就是桌面的颜色数据了,说了这么多,还是直接上代码来的直观:

 1 struct CAPTURE_INFO_INTERNAL
 2 {
 3     HDC dlg_dc;
 4     HWND target_wnd;
 5     HDC target_dc;
 6     HDC comp_dc;
 7     HBITMAP comp_bmp;
 8     HBITMAP old_bmp;
 9     int width;
10     int height;
11     BITMAPINFO bmp_info;
12     BYTE * buf;
13 };
14
15 bool prepareForRecord( CAPTURE_INFO_INTERNAL & cii )
16 {
17     BITMAPINFO bi = { 0 };
18
19     cii.width = int( wi->rect_client.right - wi->rect_client.left );
20     cii.height = int( wi->rect_client.bottom - wi->rect_client.top );
21
22     cii.target_wnd = wi->handle;
23     if( NULL == cii.target_wnd )
24         return false;
25
26     cii.target_dc = GetDC( cii.target_wnd );
27     if( NULL == cii.target_dc )
28         return false;
29
30     cii.comp_dc = CreateCompatibleDC( cii.target_dc );
31     if( NULL == cii.comp_dc )
32         return false;
33
34     cii.comp_bmp = CreateCompatibleBitmap(
35         cii.target_dc,
36         cii.width,
37         cii.height );
38     if( NULL == cii.comp_bmp )
39         return false;
40
41     cii.old_bmp = ( HBITMAP ) SelectObject(
42         cii.comp_dc,
43         cii.comp_bmp );
44
45     cii.bmp_info.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
46     cii.bmp_info.bmiHeader.biBitCount = 24;
47     cii.bmp_info.bmiHeader.biCompression = BI_RGB;
48     cii.bmp_info.bmiHeader.biWidth = cii.width;
49     cii.bmp_info.bmiHeader.biHeight = - cii.height;
50     cii.bmp_info.bmiHeader.biPlanes = 1;
51
52     cii.bmp_info.bmiColors[ 0 ].rgbBlue = 8;
53     cii.bmp_info.bmiColors[ 0 ].rgbGreen = 8;
54     cii.bmp_info.bmiColors[ 0 ].rgbRed = 8;
55     cii.bmp_info.bmiColors[ 0 ].rgbReserved = 0;
56
57     bi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
58     bi.bmiHeader.biBitCount = 24;
59     bi.bmiHeader.biCompression = BI_RGB;
60     bi.bmiHeader.biWidth = cii.width;
61     bi.bmiHeader.biHeight = - cii.height;
62     bi.bmiHeader.biPlanes = 1;
63
64     bi.bmiColors[ 0 ].rgbBlue = 8;
65     bi.bmiColors[ 0 ].rgbGreen = 8;
66     bi.bmiColors[ 0 ].rgbRed = 8;
67     bi.bmiColors[ 0 ].rgbReserved = 0;
68
69     GetDIBits( cii.comp_dc, cii.comp_bmp, 0, cii.height, NULL, & bi, DIB_RGB_COLORS );
70
71     cii.buf = new BYTE[ bi.bmiHeader.biSizeImage ];
72
73     return true;
74 }

上面代码中,CAPTURE_INFO_INTERNAL 结构体用来保存一些必须的变量,wi 变量保存了一个 WINDOW_INFO 窗体信息结构体,这个结构体我在枚举窗体的那一段已经讲解过了,prepareForRecord( ) 函数用于初始化 CAPTURE_INFO_INTERNAL 结构体,接下来我会在定时器回调函数中进行颜色数据的获取,请看下面代码:

 1 void onTimer( CAPTURE_INFO_INTERNAL & cii )
 2 {
 3     BitBlt(
 4         preview_info.comp_dc,
 5         0,
 6         0,
 7         preview_info.width,
 8         preview_info.height,
 9         preview_info.target_dc,
10         0,
11         0,
12         SRCCOPY );
13
14     GetDIBits(
15         preview_info.comp_dc,
16         preview_info.comp_bmp,
17         0,
18         preview_info.height,
19         preview_info.buf,
20         & preview_info.bmp_info,
21         DIB_RGB_COLORS );
22 }

没错,就是这么简单,只需要两个 GDI 函数就可以获取到桌面的颜色数据了,其中 cii 是一个 CAPTURE_INFO_INTERNAL 结构体,BitBlt( ) 函数负责将桌面 DC 的颜色数据传送到兼容 DC 里面,然后 GetDIBits( ) 函数负责将颜色数据从兼容 DC 里面取出来,这样子一次性进行数据传输以及数据获取,比起使用 GetPixel( ) 和 SetPixel( ) 快了不知道多少倍,利用这个技巧,甚至可以用来制作一些简单的 2D 游戏,在性能上差不多可以媲美 DirectDraw !!

基于 Windows GDI 的屏幕录像软件制作过程

时间: 2024-10-13 04:51:32

基于 Windows GDI 的屏幕录像软件制作过程的相关文章

小巧的屏幕录像软件oCam

oCam 小巧的屏幕录像软件,支持选择不同视频格式 官方下载地址:http://ohsoft.net 请直接去国外官网下载,因为软件每隔一个季度会自动更新,打开软件也无法保留旧版本,所以不要去下载旧版本. 体积:30 MB 优势:界面简单,免费,无限录制长度. 优势:国内的免费软件3分钟,国内大多数均收费并且界面丑. oCam免费屏幕录像机仅供家庭用户使用(非商业用途) OhSoft的主要产品oCam是一个功能强大的视频录制程序,可以通过您的PC录制要在监视器上播放的视频. 长期以来,世界上许多

redhat(centos)下安装qt-recordDesktop屏幕录像软件

我的操作系统是redhat企业版,因有需要屏幕录像软件,发现qt-recordDesktop这款还不错,下面是这款软件的下载地址和安装步骤: 1.下载地址:http://download.csdn.net/detail/cto_51/6960543 2.安装步骤: 下载之后,解压然后安装顺序依次安装就可以了: rpm -ivhjack-audio-connection-kit-0.118.0-1.el6.x86_64.rpm            rpm -ivh jack-audio-conn

励志:98岁老爷爷用Windows系统自带画图软件制作的神作

哈尔拉斯科,是一位很出名的老爷爷,他70岁才接触MS Paint(就是我们熟知的Windows自带的画图软件).他曾经是一名图形艺术家,但是之前他都是手工创作.他熟知怎么用双手进行艺术创作.但是后来,他的家人给他介绍了微软的画图软件. 现在,老爷爷花了无数时间,在空白的画布加入色彩点.他的工作是结合制作8位像素的点画.你必须亲自看看这些作品. 哈尔是一位老爷爷,而且也是一位像素画家. 什么事情现在做都不晚.就像哈尔一样. 本文由趣爱哟特邀翻译李小艾原创翻译,转载请注明! 转自:http://ww

教你如何快速使用屏幕录像软件

今天就来叫你们如何快速的录制一个网页上的视频,很多时候大家都会选择在网上看视频和教程,那么也会有人经常在电脑上打游戏将游戏过程录制下来,这都是如今社会的正常现象,面对这款屏幕录像软件,今天小编就来叫你们如何快速的使用屏幕录像软件. 屏幕录像工具https://pc.qq.com/detail/4/detail_24144.html 录屏软件http://×××w.xunjieshipin.com/download-luping 软件介绍: 迅捷屏幕录像工具是一款即专业又好用的电脑录屏软件,支持教

屏幕录像软件无法录制电脑视频解决办法

昨天在有一视频,用的MOVIEMKe最后导不出视频,这个视频制作软件经常出这样的问题,没找到的合适的办法,只能在预览窗口把这个视频反录,发现直接打开屏幕录像进行录制,是一片黑. 解决办法:需要保存视频项目,开着录像软件,从新打开movemake这个软件  也就是从新打开被录制的视频窗口  就可以了

屏幕录像软件下载哪个好用

屏幕录像工具下载哪个好?根据小编这几天的使用来说今天的这款软件是可以满足你们的需求的,因为对于一个新手来说它是非常简单的,对于一个使用过很多软件的人来说它的功能也是非常全面的,你们想知道是什么软件吗?今天就来你们详细的介绍这款软件. 桌面录屏软件http://×××w.xunjieshipin.com/download-luping 屏幕录像工具http://×××w.onlinedown.net/soft/1152608.htm 软件介绍: 迅捷屏幕录像工具是一款即专业又好用的电脑录屏软件,支

好用的屏幕录像软件——屏幕录像专家

听大佬们讲课(大型开车现场),听毕业答辩(大型怼人现场) 吃着瓜子,喝着茶,看大型真人宫斗戏.看小菜鸡如何被碾压的体无完肤. what?刚刚大佬说啥了?他刚刚咋怼的? 于是乎,小菜鸡的我,各种找录屏软件啊,word天哪! 废话不说了,先附上屏幕录屏专家的安装包 链接:https://pan.baidu.com/s/1-yPMCN3kxRnCxlK5hcaP_g提取码:9wvq 安装步骤: 第一步:安装软件的正常顺序,运行[.exe]文件,一直点下一步就行了.安装路径可以自己设置一下,这里就安装好

基于windows平台的命令行软件安装工具Chocolatey的安装

本文介绍Chocolatey的安装和使用 Chocolatey 这是基于.NET Framework 4以上的windows安装软件的命令行工具 安装 第一步,打开你的powershell.exe,使用管理员方式运行 第二步,运行命令 Get-ExecutionPolicy 如果返回 Restricted ,那么运行Set-ExecutionPolicy AllSigned 或者 Set-ExecutionPolicy Bypass -Scope Process 第三步,运行命令 Set-Exe

屏幕录像专家2014 v0318 免费版

软件名称: 屏幕录像专家2014软件语言: 简体中文授权方式: 免费试用运行环境: Win8 / Win7 / Vista / WinXP软件大小: 7.9MB图片预览: 软件简介:屏幕录像专家2014是一款专业的屏幕录像制作工具,屏幕录像专家在中国的屏幕录像软件,可以说是NO.1,很多人都在用它,是制作各种屏幕录像.软件教学动画和制作教学课件的首选软件 屏幕录像专家2014,可以轻松地将屏幕上的软件操作过程.网络教学课件.网络电视.网络电影.聊天视频.游戏等录制成FLASH动画.WMV动画.A