Fastest method of screen capturing

Fastest method of screen capturing up vote 75 down vote favorite 59 I want to write a screencasting program for the Windows platform, but am unsure of how to capture the screen. The only method I'm aware of is to use GDI, but I'm curious whether there are other ways to go about this, and, if there are, which incurs the least overhead? Speed is a priority. The screencasting program will be for recording game footage, although, if this does narrow down the options, I'm still open for any other suggestions that fall out of this scope. Knowledge isn't bad, after all. Edit: I came across this article: Various methods for capturing the screen. It has introduced me to the Windows Media API way of doing it and the DirectX way of doing it. It mentions in the Conclusion that disabling hardware acceleration could drastically improve the performance of the capture application. I'm curious as to why this is. Could anyone fill in the missing blanks for me? Edit: I read that screencasting programs such as Camtasia use their own capture driver. Could someone give me an in-depth explanation on how it works, and why it is faster? I may also need guidance on implementing something like that, but I'm sure there is existing documentation anyway. Also, I now know how FRAPS records the screen. It hooks the underlying graphics API to read from the back buffer. From what I understand, this is faster than reading from the front buffer, because you are reading from system RAM, rather than video RAM. You can read the article here. c++ c windows share|improve this question edited Apr 27 '13 at 5:37 icktoofay 52.3k472102 asked Feb 21 '11 at 17:22 someguy 2,13521333 Have you considered, rather than graphically recording the contents of the screen, using a replay system? – Benjamin Lindley Feb 21 '11 at 18:20 @PigBen That was an interesting read, but I don't think it would work. I would have to somehow hook the events, which isn't feasible using a generic application, and it sounds like I would have to do a bit of hacking. Same goes for rendering. – someguy Feb 21 '11 at 18:34 1 You don't have to hook anything. You just have to write your input events so that they don't control the game directly, but instead call other functions. For example, if the player pushes the left key, you don't simply decrement the players x position. Instead, you call a function, like MovePlayerLeft(). And you also record the time and duration of key presses and other input. Then, when you're in playback mode, you simply ignore the input, and instead read the recorded data. If, in the data, you see a left key press, you call MovePlayerLeft(). – Benjamin Lindley Feb 21 '11 at 18:45 1 @PigBen This will be a generic application for recording game footage. It's not for a specific game. Someone pressing the left key could mean move right, for all I know. Also, you haven't considered events that aren't influenced by the user. 'And what about rendering? – someguy Feb 21 '11 at 18:57 Oh, okay. I didn't understand that part(about this being an external application). But as for events that aren't influenced by the user, those would be recorded too. Anything in your game that is not deterministic would have to be recorded. And rendering would be handled by the game engine the same as if someone is playing. (this, of course, doesn't apply to your situation as I understand it now) – Benjamin Lindley Feb 21 '11 at 19:01 show 10 more comments 10 Answers active oldest votes up vote 24 down vote +25 This is what I use to collect single frames, but if you modify this and keep the two targets open all the time then you could "stream" it to disk using a static counter for the file name. - I can't recall where I found this, but it has been modified, thanks to whoever! void dump_buffer() { IDirect3DSurface9* pRenderTarget=NULL; IDirect3DSurface9* pDestTarget=NULL; const char file[] = "Pickture.bmp"; // sanity checks. if (Device == NULL) return; // get the render target surface. HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget); // get the current adapter display mode. //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode); // create a destination surface. hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width, DisplayMde.Height, DisplayMde.Format, D3DPOOL_SYSTEMMEM, &pDestTarget, NULL); //copy the render target to the destination surface. hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget); //save its contents to a bitmap file. hr = D3DXSaveSurfaceToFile(file, D3DXIFF_BMP, pDestTarget, NULL, NULL); // clean up. pRenderTarget->Release(); pDestTarget->Release(); } share|improve this answer answered Feb 28 '11 at 15:14 Brandrew 41435 Thanks. I heard about this method a while ago that was said to be faster than reading from the front buffer. Do you honestly do it that way and does it work properly? – someguy Feb 28 '11 at 16:54 The problem with front buffer is one of access, that is, trying to copy a plain that currently being rendered "interrupts" the copy. It works well enough for me and eats my hard drive! – Brandrew Feb 28 '11 at 17:21 I suggest you use png. – bobobobo Jul 20 '11 at 17:25 @bobobobo I don't know how it would work out exactly, but I was thinking of using something like Huffyuv. Edit: Or perhaps let the user choose from available directshow filters. – someguy Jul 20 '11 at 18:09 use pRenderTarget->GetDesc to get info to CreateOffscreenPlainSurface – Immueggpain Mar 22 '13 at 20:31 show 4 more comments up vote 11 down vote EDIT: I can see that this is listed under your first edit link as "the GDI way". This is still a decent way to go even with the performance advisory on that site, you can get to 30fps easily I would think. From this comment (I have no experience doing this, I'm just referencing someone who does): HDC hdc = GetDC(NULL); // get the desktop device context HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself // get the height and width of the screen int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); // create a bitmap HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height); // use the previously created device context with the bitmap SelectObject(hDest, hbDesktop); // copy from the desktop device context to the bitmap device context BitBlt( hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY); I'm not saying this is the fastest, but the BitBlt operation is generally very fast if you're copying between compatible device contexts. For reference, Open Broadcaster Software implements something like this as part of their "WindowCapture" method, although rather than creating the destination context hDest using CreateCompatibleDC, they use a D3D10Texture. To change it to use a specific application, you need to change the first line to GetDC(game) where game is the handle of the game's window, and then set the right height and width of the game's window too. Once you have the pixels in hDest/hbDesktop, you still need to save it to a file, but if you're doing screen capture then I would think you would want to buffer a certain number of them in memory and save to the video file in chunks, so I will not point to code for saving a static image to disk. share|improve this answer edited Sep 19 '13 at 2:09 answered Mar 2 '11 at 6:44 darvids0n 7,30711744 I thought creating a memory device context was to reduce flickering (i.e. via double buffering). If you don't use CreateCompatibleDC, will it really have to convert between contexts (what is this other context anyway)? This is just something trivial I want to know. – someguy Mar 2 '11 at 16:13 3 msdn.microsoft.com/en-us/library/dd183370%28VS.85%29.aspx Excerpt: If the color formats of the source and destination device contexts do not match, the BitBlt function converts the source color format to match the destination format. – darvids0n Mar 4 '11 at 2:08 Ah, I see. Thank you. – someguy Mar 8 '11 at 15:42 2 DON'T use GDI for writing a screencasting program - it's too slow!!!!! – user206705 Jun 3 '12 at 0:57 1 Some evidence to substantiate that would be good. Have you published a performance comparison somewhere, or seen an accurate one? – darvids0n Jun 4 '12 at 0:22 show 4 more comments up vote 8 down vote I use d3d9 to get the backbuffer, and save that to a png file using the d3dx library: IDirect3DSurface9 *surface ; // GetBackBuffer idirect3ddevice9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &surface ) ; // save the surface D3DXSaveSurfaceToFileA( "filename.png", D3DXIFF_PNG, surface, NULL, NULL ) ; SAFE_RELEASE( surface ) ; To do this you should create your swapbuffer with d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots. (So you guarantee the backbuffer isn't mangled before you take the screenshot). share|improve this answer answered Jul 20 '11 at 17:24 bobobobo 14.3k1180154 Makes sense, thanks. Do you know what the difference between this and GetRenderTarget is? – someguy Jul 20 '11 at 18:08 That just gets the current render target (could be another offscreen surface if someone is rendering to texture at the moment you call). – bobobobo Jul 20 '11 at 19:16 +1 for saving in .png – dk123 Oct 26 '13 at 11:01 add comment up vote 7 down vote For C++ you can use: http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html This may hower not work on all types of 3D applications/video apps. Then this link may be more useful as it describes 3 different methods you can use. Old answer (C#): You can use System.Drawing.Graphics.Copy, but it is not very fast. A sample project I wrote doing exactly this: http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/ I'm planning to update this sample using a faster method like Direct3D: http://spazzarama.wordpress.com/2009/02/07/screencapture-with-direct3d/ And here is a link for capturing to video: How to capture screen to be video using C# .Net? share|improve this answer edited Feb 21 '11 at 17:40 answered Feb 21 '11 at 17:34 Tedd Hansen 4,68722247 2 Ah, I forgot to mention I'm programming in C (possibly C++) and am not planning to use .NET. Terribly sorry :/. – someguy Feb 21 '11 at 17:35 Ah, ok. Then you want pinvoke.net/default.aspx/gdi32/BitBlt.html – Tedd Hansen Feb 21 '11 at 17:37 I was already aware of BitBlt (GDI). I'll look into Direct3D, though. Thanks! – someguy Feb 21 '11 at 17:41 I was looking into this a few weeks back, but haven't gotten around to implementing it yet. Direct3D is !!way!! faster than the C# builtin method which is using GDI+. – Tedd Hansen Feb 21 '11 at 17:47 1 GDI is slow, so it's not suitable to the problem domain, DirectX, or OpenGL would be the only sensible recommendation. – user206705 Jun 3 '12 at 0:41 show 2 more comments up vote 6 down vote A few things I've been able to glean: apparently using a "mirror driver" is fast though I'm not aware of an OSS one. Why is RDP so fast compared to other remote control software? Also apparently using some convolutions of StretchRect are faster than BitBlt http://betterlogic.com/roger/2010/07/fast-screen-capture/comment-page-1/#comment-5193 And the one you mentioned (fraps hooking into the D3D dll's) is probably the only way for D3D applications, but won't work with Windows XP desktop capture. So now I just wish there were a fraps equivalent speed-wise for normal desktop windows...anybody? (I think with aero you might be able to use fraps-like hooks, but XP users would be out of luck). Also apparently changing screen bit depths and/or disabling hardware accel. might help (and/or disabling aero). https://github.com/rdp/screen-capture-recorder-program includes a reasonably fast BitBlt based capture utility, and a benchmarker as part of its install, which can let you benchmark BitBlt speeds to optimize them. VirtualDub also has an "opengl" screen capture module that is said to be fast and do things like change detection http://www.virtualdub.org/blog/pivot/entry.php?id=290 share|improve this answer edited May 9 '12 at 19:09 answered Jul 19 '11 at 21:21 rogerdpack 11k64262 add comment up vote 5 down vote I wrote a class that implemented the GDI method for screen capture. I too wanted extra speed so, after discovering the DirectX method (via GetFrontBuffer) I tried that, expecting it to be faster. I was dismayed to find that GDI performs about 2.5x faster. After 100 trials capturing my dual monitor display, the GDI implementation averaged 0.65s per screen capture, while the DirectX method averaged 1.72s. So GDI is definitely faster than GetFrontBuffer, according to my tests. I was unable to get Brandrew's code working to test DirectX via GetRenderTargetData. The screen copy came out purely black. However, it could copy that blank screen super fast! I'll keep tinkering with that and hope to get a working version to see real results from it. share|improve this answer answered Mar 11 '11 at 7:32 rotanimod 22727 Thank you for the information. I haven't tested out Brandrew's code, but I know that taking the GetRenderTargetData approach works. Maybe I'll write my own answer when I finish my application. Or, you could update yours once you've gotten everything working. – someguy Mar 20 '11 at 10:42 0.65 per Screencapture?! A good GDI implementation (keeping devices around, etc.) should do 30fps in 1920x1200 easily on a modern computer. – Christopher Oezbek May 8 '12 at 14:54 I assume the image quality rendered by GDI is definitely poorer than DX – zinking Jun 6 '12 at 1:53 I have performed this test in C# with SlimDX and, surprisingly, found the same results. Perhaps this may have to do with the fact that, using SlimDX, one has to create a new stream and a new bitmap for every frame update, instead of creating it once, rewinding and keep overwriting the same location. – Cesar Jan 6 '13 at 2:21 Brandrew's code also gave me a black screen. – Cesar Jan 6 '13 at 2:38 show 2 more comments up vote 5 down vote +100 In my Impression, the GDI approach and the DX approach are different in its nature. painting using GDI applies the FLUSH method, the FLUSH approach draws the frame then clear it and redraw another frame in the same buffer, this will result in flickering in games require high frame rate. WHY DX quicker? in DX (or graphics world), a more mature method called double buffer rendering is applied, where two buffers are present, when present the front buffer to the hardware, you can render to the other buffer as well, then after the frame 1 is finished rendering, the system swap to the other buffer( locking it for presenting to hardware , and release the previous buffer ), in this way the rendering inefficiency is greatly improved. WHY turning down hardware acceleration quicker? although with double buffer rendering, the FPS is improved, but the time for rendering is still limited. modern graphic hardware usually involves a lot of optimization during rendering typically like anti-aliasing, this is very computation intensive, if you don't require that high quality graphics, of course you can just disable this option. and this will save you some time. I think what you really need is a replay system, which I totally agree with what people discussed. share|improve this answer answered Jun 5 '12 at 7:55 zinking 959721 See the discussion as to why a replay system isn't feasible. The screencasting program isn't for any specific game. – someguy Jun 5 '12 at 11:42 add comment up vote 5 down vote I wrote a video capture software, similar to FRAPS for DirectX applications. The source code is available and my article explains the general technique. Look at http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/ Respect to your questions related to performance, DirectX should be faster than GDI except when you are reading from the frontbuffer which is very slow. My approach is similar to FRAPS (reading from backbuffer). I intercept a set of methods from Direct3D interfaces. For video recording in realtime (with minimal application impact), a fast codec is essential. FRAPS uses it's own lossless video codec. Lagarith and HUFFYUV are generic lossless video codecs designed for realtime applications. You should look at them if you want to output video files. Another approach to recording screencasts could be to write a Mirror Driver. According to Wikipedia: When video mirroring is active, each time the system draws to the primary video device at a location inside the mirrored area, a copy of the draw operation is executed on the mirrored video device in real-time. See mirror drivers at MSDN: http://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx. share|improve this answer answered Jul 24 '13 at 16:46 Hernán 2,2091129 add comment up vote 2 down vote i myself do it with directx and think it's as fast as you would want it to be. i don't have a quick code sample, but i found this which should be useful. the directx11 version should not differ a lot, directx9 maybe a little more, but thats the way to go share|improve this answer answered Feb 25 '11 at 14:12 cppanda 600721 add comment up vote 1 down vote I realize the following suggestion doesn't answer your question, but the simplest method I have found to capture a rapidly-changing DirectX view, is to plug a video camera into the S-video port of the video card, and record the images as a movie. Then transfer the video from the camera back to an MPG, WMV, AVI etc. file on the computer. share|improve this answer answered Mar 6 '13 at 15:44 Pierre 462310 add comment

이 블로그의 인기 게시물

둘 중 누군가 그녀를 죽였다, 범인 해설

[MAC OS X] mds_stores 100% CPU usage

tips more on unity ...