|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Contents
IntroductionSome times, we want to capture the contents of the entire screen programmatically. The following explains how it can be done. Typically, the immediate options we have, among others, are using GDI and/or DirectX. Another option that is worth considering is Windows Media API. Here, we would consider each of them and see how they can be used for our purpose. In each of these approaches, once we get the screenshot into our application defined memory or bitmap, we can use it in generating a movie. Refer to the article Create Movie From HBitmap for more details about creating movies from bitmap sequences programmatically. Capture it the GDI wayWhen performance is not an issue and when all that we want is just a snapshot of the desktop, we can consider the GDI option. This mechanism is based on the simple principle that the desktop is also a window - that is it has a window Handle (
ExampleVoid CaptureScreen()
{
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,
hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
SaveCapturedBitmap(hCaptureBitmap); //Place holder - Put your code
//here to save the captured image to disk
ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}
In the above code snippet, the function And the DirectX way of doing itCapturing the screenshot with DirectX is a pretty easy task. DirectX offers a neat way of doing this. Every DirectX application contains what we call a buffer, or a surface to hold the contents of the video memory related to that application. This is called the back buffer of the application. Some applications might have more than one back buffer. And there is another buffer that every application can access by default - the front buffer. This one, the front buffer, holds the video memory related to the desktop contents, and so essentially is the screen image. By accessing the front buffer from our DirectX application, we can capture the contents of the screen at that moment. Accessing the front buffer from the DirectX application is pretty easy and straightforward. The interface extern IDirect3DDevice9* g_pd3dDevice; Void CaptureScreen() { IDirect3DSurface9* pSurface; g_pd3dDevice->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL); g_pd3dDevice->GetFrontBufferData(0, pSurface); D3DXSaveSurfaceToFile("Desktop.bmp",D3DXIFF_BMP,pSurface,NULL,NULL); pSurface->Release(); } In the above, extern void* pBits; extern IDirect3DDevice9* g_pd3dDevice; IDirect3DSurface9* pSurface; g_pd3dDevice->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL); g_pd3dDevice->GetFrontBufferData(0, pSurface); D3DLOCKED_RECT lockedRect; pSurface->LockRect(&lockedRect,NULL, D3DLOCK_NO_DIRTY_UPDATE| D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))); for( int i=0 ; i < ScreenHeight ; i++) { memcpy( (BYTE*) pBits + i * ScreenWidth * BITSPERPIXEL / 8 , (BYTE*) lockedRect.pBits + i* lockedRect.Pitch , ScreenWidth * BITSPERPIXEL / 8); } g_pSurface->UnlockRect(); pSurface->Release(); In the above, for( int i=0 ; i < ScreenHeight ; i++) { memcpy((BYTE*) pBits +( ScreenHeight - i - 1) * ScreenWidth * BITSPERPIXEL/8 , (BYTE*) lockedRect.pBits + i* lockedRect.Pitch , ScreenWidth* BITSPERPIXEL/8); } This may come handy when you are converting between top-down and bottom-up bitmaps. While the above technique of The sample source code provided with this article implements the technique of copying the contents of an off-screen plain surface onto a user created bitmap for capturing the screen contents at regular intervals, and creates a movie out of the captured image sequences. However, a point worth noting when using this technique for screen capture is the caution mentioned in the documentation: The Windows Media API for capturing the screenWindows Media 9.0 supports screen captures using the Windows Media Encoder 9 API. It includes a codec named Windows Media Video 9 Screen codec that has been specially optimized to operate on the content produced through screen captures. The Windows Media Encoder API provides the interface Working with the Windows Media Encoder API for screen captures is pretty straightforward. First, we need to start with the creation of an IWMEncoder2* g_pEncoder=NULL;
CoCreateInstance(CLSID_WMEncoder,NULL,CLSCTX_INPROC_SERVER,
IID_IWMEncoder2,(void**)&g_pEncoder);
The IWMEncProfile2* g_pProfile=NULL;
CoCreateInstance(CLSID_WMEncProfile2,NULL,CLSCTX_INPROC_SERVER,
IID_IWMEncProfile2,(void**)&g_pProfile);
We need to specify the target audience for the encoder in the profile. Each profile can hold multiple number of audience configurations, which are objects of the interface extern IWMEncAudienceObj* pAudience; #define VIDEOCODEC MAKEFOURCC('M','S','S','2') //MSS2 is the fourcc for the screen codec long lCodecIndex=-1; g_pProfile->GetCodecIndexFromFourCC(WMENC_VIDEO,VIDEOCODEC, &lCodecIndex); //Get the Index of the Codec pAudience->put_VideoCodec(0,lCodecIndex); The fourcc is a kind of unique identifier for each codec in the world. The fourcc for the Windows Media Video 9 Screen codec is MSS2. The Once we have completed configuring the profile object, we can choose that profile into our encoder by using the method extern IWMEncVideoSource2* pSrcVid; pSrcVid->SetInput(CComBSTR("ScreenCap://ScreenCapture1"); The destination output can be configured to save into a video file (wmv movie) by using the method IWMEncFile* pOutFile=NULL; g_pEncoder->get_File(&pOutFile); pOutFile->put_LocalFileName(CComBSTR(szOutputFileName); Now, once all the necessary configurations have been done on the encoder object, we can use the method While this deals with full screen capture, we can alternately select the regions of capture by adjusting the properties of input video source stream. For this, we need to use the #define WMSCRNCAP_WINDOWLEFT CComBSTR("Left") #define WMSCRNCAP_WINDOWTOP CComBSTR("Top") #define WMSCRNCAP_WINDOWRIGHT CComBSTR("Right") #define WMSCRNCAP_WINDOWBOTTOM CComBSTR("Bottom") #define WMSCRNCAP_FLASHRECT CComBSTR("FlashRect") #define WMSCRNCAP_ENTIRESCREEN CComBSTR("Screen") #define WMSCRNCAP_WINDOWTITLE CComBSTR("WindowTitle") extern IWMEncVideoSource2* pSrcVid; int nLeft, nRight, nTop, nBottom; pSrcVid->QueryInterface(IID_IPropertyBag,(void**)&pPropertyBag); CComVariant varValue = false; pPropertyBag->Write(WMSCRNCAP_ENTIRESCREEN,&varValue); varValue = nLeft; pPropertyBag->Write( WMSCRNCAP_WINDOWLEFT, &varValue ); varValue = nRight; pPropertyBag->Write( WMSCRNCAP_WINDOWRIGHT, &varValue ); varValue = nTop; pPropertyBag->Write( WMSCRNCAP_WINDOWTOP, &varValue ); varValue = nBottom; pPropertyBag->Write( WMSCRNCAP_WINDOWBOTTOM, &varValue ); The accompanied source code implements this technique for capturing the screen. One point that might be interesting, apart from the nice quality of the produced output movie, is that in this, the mouse cursor is also captured. (By default, GDI and DirectX are unlikely to capture the mouse cursor). Note that your system needs to be installed with Windows Media 9.0 SDK components to create applications using the Window Media 9.0 API. To run your applications, end users must install the Windows Media Encoder 9 Series. When you distribute applications based on the Windows Media Encoder SDK, you must also include the Windows Media Encoder software, either by redistributing Windows Media Encoder in your setup, or by requiring your users to install Windows Media Encoder themselves. The Windows Media Encoder 9.0 can be downloaded from: ConclusionAll the variety of techniques discussed above are aimed at a single goal - capturing the contents of the screen. However, as can be guessed easily, the results vary depending upon the particular technique that is being employed in the program. If all that we want is just a random snapshot occasionally, the GDI approach is a good choice, given its simplicity. However, using Windows Media would be a better option if we want more professional results. One point worth noting is, the quality of the content captured through these mechanisms might depend on the settings of the system. For example, disabling hardware acceleration (Desktop properties | Settings | Advanced | Troubleshoot) might drastically improve the overall quality and performance of the capture application. | ||||||||||||||||||||