Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#从屏幕复制问题_C#_Performance_Screenshot_Dwm - Fatal编程技术网

C#从屏幕复制问题

C#从屏幕复制问题,c#,performance,screenshot,dwm,C#,Performance,Screenshot,Dwm,首先,我知道已经有关于这方面的线索,但我似乎找不到适合我需要的答案,经过大约4个月的研究,我决定在这里问一个问题 对于一个项目,我需要做截图。这些屏幕截图是根据用户参数制作的,用户参数包括是否使用显示器或截图的拍摄区域。(这意味着屏幕截图可能仅由显示屏的一半左右组成。) 问题是,它很慢。。。 是的,我知道,如果我想做得更快,我必须使用这个库或那个directx等等。 但是:我既不知道directx,也找不到能够返回位图数据条带的开源lirary(realy更快)。 此外,我还尝试了一些使用dir

首先,我知道已经有关于这方面的线索,但我似乎找不到适合我需要的答案,经过大约4个月的研究,我决定在这里问一个问题

对于一个项目,我需要做截图。这些屏幕截图是根据用户参数制作的,用户参数包括是否使用显示器或截图的拍摄区域。(这意味着屏幕截图可能仅由显示屏的一半左右组成。)

问题是,它很慢。。。 是的,我知道,如果我想做得更快,我必须使用这个库或那个directx等等。 但是:我既不知道directx,也找不到能够返回位图数据条带的开源lirary(realy更快)。 此外,我还尝试了一些使用directx制作屏幕截图的教程,但未能使其正常运行

关于性能方面,当只使用1个显示器时,性能实际上并没有那么差。(对于1440p分辨率,截图时间约为40ms)

真正糟糕的是DWM。(我猜是dwm)。 在制作屏幕截图时,除了在窗口周围拖动外,一切都正常。比如,在youtube上看视频就可以了。但是,当我开始在窗户周围走动时,它会慢得像地狱一样。在我截图时,拖动动画似乎被阻止了

现在请回答我的问题:

  • 有人知道这种行为和/或有解决方案吗
  • 我的备选方案是什么(严肃的备选方案。我的意思是30毫秒备选方案中的3倍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]);
    }
}

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

  • 幻影司机,你可以到这里:
  • 此示例应用程序:
  • 我修改了示例解决方案的代码,以便在每次触发桌面更改事件时在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);
        }
    
    private void\u mirror\u DesktopChange(对象发送方,DesktopMirror.DesktopChangeEventArgs e)
    {
    Trace.WriteLine(string.Format(“更改的rect为{0},{1};{2},{3}({4})”),新对象[]{e.x1,e.y1,e.x2,e.y2,e.type});
    var perf=新秒表();
    性能启动();
    var bitmap=_mirror.GetScreen();
    性能停止();
    标签1.Invoke(新操作(i=>
    {
    pictureBox1.Image=位图;
    label1.Text=i.ToString();
    }),性能ElapsedMills);
    }
    
    如果您关心性能,则不应使用GDI读取桌面

    避免读取或写入显示器DC。虽然DWM支持,但由于性能下降,我们不建议使用它

    虽然你没有这样做,但还是画画。除此之外,除了速度缓慢之外:

    DirectDraw锁

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

    你有代码示例吗?你使用的是像屏幕录制器库一样的库吗?将其附在主帖子上。你已经说过你不会为其他选择而烦恼,那么为什么要问呢?@JoePhilllips我没有说我不会尝试其他任何东西。我说我没有找到任何严肃的选择。如果有人知道一个好的,我不介意尝试一些图书馆或directx教程。你会注意到,尽可能地猛烈抨击DWM并不是一个好策略。商业屏幕录音机使用黑色Moocho艺术,他们不与任何人分享他们的秘密。买,不要建造。这是一件伟大的事情。在过去的半个小时里我一直在玩弄它。我很想使用它,但不幸的是,它不能与Windows10正常工作。(我想windows 8也会出现同样的错误)。屏幕上的一些白色平面没有正确记录。。。(它们在保存的位图上显示为黑色)我希望对于那些愿意使用此软件并尝试录制多个屏幕(或在我的情况下记录所有屏幕)的人,会有一个支持新操作系统的更新:在DesktopMirror::Load上有一个PrimaryScreen.Width分配。将其更改为下限和上限(您可以通过对所有屏幕进行分级来找到)将允许您投射所有屏幕。