Introduction
My code snippet takes a screenshot with "RDP Encoder Mirror Driver". Capturing screen with mirror driver is a very high performance method, but relying on a mirror driver. "RDP Encoder Mirror Driver" is included in Windows 7, and using it to take screenshots has no need to install other mirror driver.
Background
When I do my work to drive LED Display, I need to have a screenshot and send the bitmap data to the hardware which communicates with computer in UDP. It is easy to take a screenshot with GDI API, but its performance is poor. I know that using Mirror Driver is a good idea and develop my mirror driver. When I wrote a testing program to list out all the display devices, I found "RDP Encoder Mirror Driver" in the list. After I tested the "RDP Encoder Mirror Driver", I found it works well.
Using the Code
At first, we need to detect whether the "RDP Encoder Mirror Driver" exists. If the "RDP Encoder Mirror Driver" exists, it can be used to take screenshots.
int Detect_MirrorDriver(vector<DISPLAY_DEVICE>& devices,map<int,DEVMODE>& settings)
{
CString all_mirror_divers[2] = {
_T("RDP Encoder Mirror Driver"), _T("LEDXXX Mirror Driver") };
DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
int n = 0;
while(EnumDisplayDevices(NULL, n, &dd, EDD_GET_DEVICE_INTERFACE_NAME))
{
n++;
devices.push_back(dd);
}
for(int i=0;i<(int)devices.size();i++)
{
DEVMODE dm;
ZeroMemory(&dm, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE);
dm.dmDriverExtra = 0;
if(EnumDisplaySettingsEx(devices[i].DeviceName,ENUM_CURRENT_SETTINGS,&dm,EDS_ROTATEDMODE))
{
settings.insert(map<int,DEVMODE>::value_type(i,dm));
}
}
for(int m =0;m<2;m++)
{
for(int i=0;i<(int)devices.size();i++)
{
CString drv(devices[i].DeviceString);
if(drv == all_mirror_divers[m])
{
return m;
}
}
}
return -1;}
Using the "RDP Encoder Mirror Driver" to take screenshots is very simple:
class RDPCapture
{
int mw;
int mh;
int mx0;
int my0;
DEVMODE myDM;
DISPLAY_DEVICE myDev;
HDC m_driverDC;
CDC m_cdc;
BITMAPINFO m_BmpInfo;
HBITMAP m_Bitmap;
HBITMAP Old_bitmap;
DEVMODE oldDM;
public:
RDPCapture(){}
RDPCapture(DISPLAY_DEVICE dev,DEVMODE dm)
{
myDev = dev;
myDM = dm;
oldDM = dm;
m_driverDC = NULL;
}
~RDPCapture()
{
SelectObject(m_cdc,Old_bitmap);
DeleteObject(m_Bitmap);
m_cdc.DeleteDC();
if(m_driverDC != NULL) DeleteDC(m_driverDC);
oldDM.dmDeviceName[0] = 0;
ChangeDisplaySettingsEx(myDev.DeviceName,&oldDM, 0, 0, 0);
}
virtual bool Init(int x0,int y0,int width,int height)
{
mx0 = x0;
my0 = y0;
mw = (width + 3)&0xFFFC;
mh = height;
DEVMODE dm;
dm = myDM;
WORD drvExtraSaved = dm.dmDriverExtra;
memset(&dm, 0, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE);
dm.dmDriverExtra = drvExtraSaved;
dm.dmPelsWidth = 2048;
dm.dmPelsHeight = 1280;
dm.dmBitsPerPel = 24;
dm.dmPosition.x = 0;
dm.dmPosition.y = 0;
dm.dmDeviceName[0] = '\0';
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH |
DM_PELSHEIGHT | DM_POSITION;
if(ChangeDisplaySettingsEx(myDev.DeviceName, &dm, 0, CDS_UPDATEREGISTRY, 0))
{
ChangeDisplaySettingsEx(myDev.DeviceName, &dm, 0, 0, 0);
}
ZeroMemory(&m_BmpInfo, sizeof(BITMAPINFO));
m_BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_BmpInfo.bmiHeader.biBitCount = 24;
m_BmpInfo.bmiHeader.biCompression = BI_RGB;
m_BmpInfo.bmiHeader.biPlanes = 1;
m_BmpInfo.bmiHeader.biWidth = mw;
m_BmpInfo.bmiHeader.biHeight = -mh;
m_BmpInfo.bmiHeader.biSizeImage= mw*mh*3;
HDC Top = ::GetDC(GetDesktopWindow());
m_cdc.CreateCompatibleDC(NULL); m_Bitmap = CreateCompatibleBitmap(Top, mw,mh); Old_bitmap = (HBITMAP)SelectObject(m_cdc, m_Bitmap); ::ReleaseDC(GetDesktopWindow(),Top);
m_driverDC = CreateDC(myDev.DeviceName, 0, 0, 0);
return true;
};
virtual bool GetData(unsigned char *buf)
{
BitBlt(m_cdc,0,0,mw,mh,m_driverDC,mx0,my0,SRCCOPY|CAPTUREBLT);
GetDIBits(m_cdc,m_Bitmap,0,mh,buf, &m_BmpInfo, DIB_RGB_COLORS);
return true;
};
};
To use the class "RDPCapture
", you can write code like below:
RDPCapture* rdp_capture = NULL;
vector<DISPLAY_DEVICE> devices;
map<int,DEVMODE>& settings;
int res = Detect_MirrorDriver(devices,settings);
if(res ==0)
{
rdp_capture = new RDPCapture(devices[0],settings[0]);
}
Points of Interest
When I wrote this article, I found it interesting to use a mirror driver with GDI API.
History
-
2014/1/27 First version
- 2014/1/27 Remove the base class of RDPCapture