13
\$\begingroup\$

I am trying to capture screenshots as fast as possible from when it's displayed, meaning that I want the latency to be minimal.

Currently, I am using user32.dll to capture a window. So, if I have a game, I capture that window along with borders and everything. It's very fast, but I wonder if hooking into the API (DirectX) and getting the buffer will be faster than this (I don't know how to do that, though).

Here's how I'm doing it:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);


private static MemoryStream PrintWindow(string prcname)
{
    IntPtr hwnd;
    using (var proc = Process.GetProcessesByName(prcname)[0])
    {
        hwnd = proc.MainWindowHandle;
    }
    Rect rc;
    NativeMethods.GetWindowRect(hwnd, out rc);
    using (Bitmap bmp = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
    {
        using (Graphics gfxBmp = Graphics.FromImage(bmp))
        {
            IntPtr hdcBitmap = gfxBmp.GetHdc();
            try
            {
                NativeMethods.PrintWindow(hwnd, hdcBitmap, 0);
            }
            finally
            {
                gfxBmp.ReleaseHdc(hdcBitmap);
            }
        }
        MemoryStream ms = new MemoryStream();
        bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        return ms;
    }
}

I give it a process name and it will hook to that certain window. And as I've said, it's not slow; it's fast. But I think it may be slower than what can be achieved, especially since the actual render of the game is often different from the screen (for example, 30FPS on the game, and it's 60HZ on the screen, meaning 50% of the images will be duplicates).

Any ideas about this?

\$\endgroup\$
  • 1
    \$\begingroup\$ For inspiration, I would have a look at how OBS does it. One important aspect to remember is that not all games do use DirectX - you may want to create an additional class to capture OpenGL, too. \$\endgroup\$ – hangy Dec 13 '13 at 12:29
9
\$\begingroup\$

It's very fast, but I wonder if hooking into the API (DirectX) and getting the buffer will be faster than this (I don't know how to do that, though).

I don't know either.

What you have here, probably hasn't been reviewed yet, because there's essentially nothing blatantly wrong with it.


What you've done well

Pretty much everything, as far as I can tell:

  • Every IDisposable is wrapped in a using block and thus, whether it blows up or not, things get disposed correctly.

  • try...finally is the best thing you could do here; if there's an exception, it will bubble up, and the finally block will run in all cases, ensuring the resources cleanly get released.

  • You're working everything in a MemoryStream, which is the only logical thing to do (hitting the file system would be utter nonsense).

Question marks

  • Returning the MemoryStream means closing and disposing the stream isn't the responsibility of the method that created it - that's a potential issue. I would try to Freeze() the bitmap and return a Bitmap object instead, although there might be a performance penalty in doing that.

  • If the method is called in a tight loop, does the result of NativeMethods.GetWindowRect(hwnd, out rc); change at all between calls? Perhaps the method could take a Rect as a parameter?

  • It being static scares me a little, but it's private and you're not showing the class it's a member of... You'll want the method wrapped in an object that you can create and pass around, not just a global/static "helper" method that's part of some undefined ambient context.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.