C#CopyFromScreen问题

时间:2016-04-04 19:52:42

标签: c# performance screenshot dwm

对于初学者来说,我知道已经有关于此的线索,但我似乎无法找到符合我需求的答案,经过大约4个月的研究后,我决定在这里提问。

对于一个项目,我需要制作截图周期性的。这些屏幕截图是根据用户参数进行的,无论是否使用显示器或截取屏幕截图的区域。 (这意味着屏幕截图只能来自显示屏的一半左右。)

事情是,它的速度很慢...... 是的我知道,如果我想更快地完成它,我必须使用这个库或者directx等等。 但是:我也不知道directx,也没有找到能够返回位图数据条带的开源文件(并且真的更快)。 此外,我已经尝试了一些使用directx制作屏幕截图的教程,但无法使其正常运行。

关于性能问题,当仅使用1个显示器时,性能实际上并不那么糟糕。 (对于1440p分辨率,屏幕截图约为40ms)

真正糟糕的是DWM。 (我猜它的dwm)。 在制作屏幕截图时,一切都是正常的,除非在窗户周围徘徊。就像在youtube上观看视频一样好。但是,当我开始在窗户周围移动时,它的速度很慢。当我拍摄截图时,似乎阻止了拖动动画。

现在提出我的问题(或问题):

  • 有人确实知道这种行为和/或有解决方案吗?
  • 我的选择是什么(严肃的替代方案。我的意思是像30毫秒替代品中的3x 1440p)

编辑:这是我用来制作屏幕截图的方法

public void makeScreenshot(int i)
{
    if (DisplayList[i].UseDisplay)
    {
        // copy from screen into graphics
        this.graphicsList[i].CopyFromScreen(Screen.AllScreens[DisplayList[i].DisplayNo].Bounds.X, AreaTop[i], 0, 0, sizeList[i], CopyPixelOperation.SourceCopy);
        // bitmapData is filled with LockBits from Screenshotted Bmp
        bitmapData[i] = this.bitmapList[i].LockBits(rect[i], ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        // Pointer set to first pixel of Bitmap data
        Iptr[i] = bitmapData[i].Scan0;
        // Now Marshalcopy bitmapData to Pixel Array
        Marshal.Copy(Iptr[i], Pixels[i], 0, Pixels[i].Length);
        // Finaly unlock bits of Bitmap for next run
        this.bitmapList[i].UnlockBits(bitmapData[i]);
    }
}

2 个答案:

答案 0 :(得分:4)

我已经使用了一个非常简单而稳定的解决方案,用于屏幕捕获和实时流媒体,但它确实使用了外部库。也许你可以花几分钟来看看这个。 1600x900截屏时我得到了6-15ms。 所以,你需要 -

  1. Mirage Driver,你可以到这里: http://www.demoforge.com/dfmirage.htm
  2. 此示例应用程序: http://www.demoforge.com/sdk/MirrSharp.zip
  3. 我修改了示例解决方案的代码,以便每次触发桌面更改事件时在PictureBox控件中显示屏幕。像这样:

    private void _mirror_DesktopChange(object sender, DesktopMirror.DesktopChangeEventArgs e)
        {
            Trace.WriteLine(string.Format("Changed rect is {0},{1} ; {2}, {3} ({4})", new object[] { e.x1, e.y1, e.x2, e.y2, e.type }));
    
            var perf = new Stopwatch();
            perf.Start();
            var bitmap = _mirror.GetScreen();
            perf.Stop();
    
            label1.Invoke(new Action<Int64>(i =>
            {
                pictureBox1.Image = bitmap;
                label1.Text = i.ToString();
            }), perf.ElapsedMilliseconds);
        }
    

答案 1 :(得分:0)

如果您关心性能,则不应使用GDI来阅读桌面。

  

DWM: Performance Considerations and Best Practices

     

避免读取或写入显示器DC。尽管受DWM支持,但由于性能下降,我们不推荐使用它。

虽然你没有这样做,但some DirectDraw applications tried to lock the entire desktop window要画画。在Windows 7 applications that attempt that operation will fail中 - 除了缓慢之外:

  

DirectDraw Lock

     
      
  • Windows 7 :针对Windows 7显示的应用程序无法调用DDRAW中的Lock API来锁定主桌面视频缓冲区。这样做会导致错误,并且将返回主要的 NULL 指针。即使未打开桌面窗口管理器组合,也会强制执行此行为。 Windows 7兼容的应用程序不得锁定主视频缓冲区以进行渲染。
  •   
  • Windows Vista(默认):应用程序将能够获取主视频缓冲区上的锁定,因为旧应用程序依赖于此行为。运行该应用程序将关闭桌面窗口管理器。
  •