Windows에서 가장 빠른 화면 캡처 방법
Windows 플랫폼 용 스크린 캐스팅 프로그램을 작성하고 싶지만 화면을 캡처하는 방법을 잘 모르겠습니다. 내가 아는 유일한 방법은 GDI를 사용하는 것입니다. 그러나이 문제를 해결할 다른 방법이 있는지, 그리고 있다면 거기에 가장 적은 오버 헤드가 발생하는지 궁금합니다. 속도가 우선입니다.
스크린 캐스팅 프로그램은 게임 푸티지를 녹화하기위한 것이지만 옵션이 좁아지면이 범위를 벗어나는 다른 제안이 여전히 열려 있습니다. 결국 지식은 나쁘지 않습니다.
편집 : 나는이 기사 를 보았습니다 : 화면을 캡처하는 다양한 방법 . Windows Media API 방식과 DirectX 방식을 소개했습니다. 결론에서 하드웨어 가속을 비활성화하면 캡처 응용 프로그램의 성능을 크게 향상시킬 수 있습니다. 왜 이런지 궁금합니다. 누구든지 나를 위해 누락 된 공백을 채울 수 있습니까?
편집 : Camtasia와 같은 스크린 캐스팅 프로그램은 자체 캡처 드라이버를 사용한다는 것을 읽었습니다. 누군가 어떻게 작동하는지, 왜 더 빠른지에 대해 깊이 설명해 줄 수 있습니까? 그런 식으로 구현하는 데 지침이 필요할 수도 있지만 어쨌든 기존 문서가 있다고 확신합니다.
또한 이제 FRAPS가 화면을 기록하는 방법을 알고 있습니다. 기본 그래픽 API를 후크하여 백 버퍼에서 읽습니다. 내가 이해 한 바에 따르면 비디오 RAM이 아닌 시스템 RAM에서 읽는 것이기 때문에 프론트 버퍼에서 읽는 것보다 빠릅니다. 여기서 기사를 읽을 수 있습니다 .
이것이 단일 프레임을 수집하는 데 사용하는 것이지만, 이것을 수정하고 두 대상을 항상 열어두면 파일 이름에 대한 정적 카운터를 사용하여 디스크에 "스트리밍"할 수 있습니다. -어디서 찾았는지 기억이 나지 않지만 누구에게나 수정되었습니다!
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();
}
편집 : 이것이 첫 번째 편집 링크 아래에 "GDI 방식"으로 표시되어 있음을 알 수 있습니다. 이것은 여전히 해당 사이트의 성능 조언을 사용하는 적절한 방법입니다. 쉽게 생각할 수있는 30fps에 도달 할 수 있습니다.
에서 이 주석 (난, 난 그냥 않는 사람을 참조하고있어 이런 일을 경험이 없음) :
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
// call this once per 'frame'
BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY);
// after the recording is done, release the desktop context you got..
ReleaseDC(NULL, hdc);
// ..delete the bitmap you were using to capture frames..
DeleteObject(hbDesktop);
// ..and delete the context you created
DeleteDC(hDest);
나는 이것이 가장 빠르다고 말하지는 않지만 BitBlt
호환되는 장치 컨텍스트간에 복사하는 경우 일반적으로 작업이 매우 빠릅니다.
참고로, 열기 브로드 소프트웨어 자신의 일환으로이 같은 구현 뭔가 "dc_capture" 오히려 대상 컨텍스트를 만들지 않고 있지만, 방법, hDest
사용 CreateCompatibleDC
그들이을 사용하여 IDXGISurface1
다이렉트 X 10 +와 함께 작동합니다. 이에 대한 지원이없는 경우로 넘어갑니다 CreateCompatibleDC
.
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.
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.
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).
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.
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.
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
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.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?
You can try the c++ open source project WinRobot @git, a powerful screen capturer
CComPtr<IWinRobotService> pService;
hr = pService.CoCreateInstance(__uuidof(ServiceHost) );
//get active console session
CComPtr<IUnknown> pUnk;
hr = pService->GetActiveConsoleSession(&pUnk);
CComQIPtr<IWinRobotSession> pSession = pUnk;
// capture screen
pUnk = 0;
hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk);
// get screen image data(with file mapping)
CComQIPtr<IScreenBufferStream> pBuffer = pUnk;
Support :
- UAC Window
- Winlogon
- DirectShowOverlay
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
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.
With Windows 8, Microsoft introduced the Windows Desktop Duplication API. That is the officially recommended way of doing it. One nice feature it has for screencasting is that it detects window movement, so you can transmit block deltas when windows get moved around, instead of raw pixels. Also, it tells you which rectangles have changed, from one frame to the next.
The Microsoft example code is pretty complex, but the API is actually simple and easy to use. I've put together an example project which is much simpler than the official example:
https://github.com/bmharper/WindowsDesktopDuplicationSample
Docs: https://docs.microsoft.com/en-gb/windows/desktop/direct3ddxgi/desktop-dup-api
Microsoft official example code: https://code.msdn.microsoft.com/windowsdesktop/Desktop-Duplication-Sample-da4c696a
참고URL : https://stackoverflow.com/questions/5069104/fastest-method-of-screen-capturing-on-windows
'IT' 카테고리의 다른 글
Vim에서 사례 보존 대용품 (0) | 2020.06.14 |
---|---|
Jelly Bean DatePickerDialog — 취소 할 수있는 방법이 있습니까? (0) | 2020.06.14 |
펄프 + 웹팩 또는 그냥 웹팩? (0) | 2020.06.14 |
C 런타임 라이브러리 란 무엇입니까? (0) | 2020.06.14 |
Double.MIN_VALUE가 음수가 아닌 이유 (0) | 2020.06.14 |