Самый быстрый способ поймать экран? Любой язык - PullRequest
6 голосов
/ 13 апреля 2009

Мне нужно очень-очень быстро снимать экраны приложения Windows, чтобы сделать из него видео ... Я использовал C # полностью, но я открыт для любого языка, на котором этот процесс может быстрее.

Я использовал много техник:

  • .net функций: Bitmap.CopyFromScreen ()
  • GDI
  • Direct3d / DirectX

Самое быстрое, что я получил, это использование GDI, и все же я получаю менее 10 фотограмм в секунду. Мне нужно немного больше, по крайней мере, 20 или 30 ...

Мне кажется очень странным, что такая простая операция требует больших усилий. И похоже, что использование более быстрого процессора не меняет ситуацию.

Что я могу сделать? Можно ли напрямую захватить рисунок приложения, используя gdi или что-то еще? Или, может быть, даже низкоуровневые функции для захвата информации, которая выводится на видеокарту?

Любой свет по этому вопросу будет в значительной степени оценен. Большое спасибо

Ответы [ 2 ]

1 голос
/ 13 апреля 2009

Вы, вероятно, хотите использовать что-то вроде Camtasia . Зависит от того, почему вы делаете видео.

Я использую переписанную версию удобной для пользователя обработки исключений Джеффа , и он использует BitBlt из GDI для захвата скриншотов. Мне это кажется достаточно быстрым, но я не проверил его, и мы просто используем его для единичных снимков, когда возникает необработанное исключение.

#region Win32 API screenshot calls

// Win32 API calls necessary to support screen capture
[DllImport("gdi32", EntryPoint = "BitBlt", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int BitBlt(int hDestDC, int x, int y, int nWidth, int nHeight, int hSrcDC, int xSrc,
                                 int ySrc, int dwRop);

[DllImport("user32", EntryPoint = "GetDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int GetDC(int hwnd);

[DllImport("user32", EntryPoint = "ReleaseDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int ReleaseDC(int hwnd, int hdc);

#endregion

private static ImageFormat screenshotImageFormat = ImageFormat.Png;

/// <summary>
/// Takes a screenshot of the desktop and saves to filename and format specified
/// </summary>
/// <param name="fileName"></param>
private static void TakeScreenshotPrivate(string fileName)
{
    Rectangle r = Screen.PrimaryScreen.Bounds;

    using (Bitmap bitmap = new Bitmap(r.Right, r.Bottom))
    {
        const int SRCCOPY = 13369376;

        using (Graphics g = Graphics.FromImage(bitmap))
        {
            // Get a device context to the windows desktop and our destination  bitmaps
            int hdcSrc = GetDC(0);
            IntPtr hdcDest = g.GetHdc();

            // Copy what is on the desktop to the bitmap
            BitBlt(hdcDest.ToInt32(), 0, 0, r.Right, r.Bottom, hdcSrc, 0, 0, SRCCOPY);

            // Release device contexts
            g.ReleaseHdc(hdcDest);
            ReleaseDC(0, hdcSrc);

            string formatExtension = screenshotImageFormat.ToString().ToLower();
            string expectedExtension = string.Format(".{0}", formatExtension);

            if (Path.GetExtension(fileName) != expectedExtension)
            {
                fileName += expectedExtension;
            }

            switch (formatExtension)
            {
                case "jpeg":
                    BitmapToJPEG(bitmap, fileName, 80);
                    break;
                default:
                    bitmap.Save(fileName, screenshotImageFormat);
                    break;
            }

            // Save the complete path/filename of the screenshot for possible later use
            ScreenshotFullPath = fileName;
        }
    }
}

/// <summary>
/// Save bitmap object to JPEG of specified quality level
/// </summary>
/// <param name="bitmap"></param>
/// <param name="fileName"></param>
/// <param name="compression"></param>
private static void BitmapToJPEG(Image bitmap, string fileName, long compression)
{
    EncoderParameters encoderParameters = new EncoderParameters(1);
    ImageCodecInfo codecInfo = GetEncoderInfo("image/jpeg");

    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, compression);
    bitmap.Save(fileName, codecInfo, encoderParameters);
}
1 голос
/ 13 апреля 2009

Многие программы используют драйвер и позволяют вашему приложению подключаться к процедурам отображения нижнего уровня. Я не совсем уверен, как это сделать, но это возможно. Вот отправная точка при написании драйвера для Windows. http://msdn.microsoft.com/en-us/library/ms809956.aspx

Вот что я только что нашел через Google: http://www.hmelyoff.com/index.php?section=17

...