0

我正在开发一个录制应用程序,每秒可以获取 10 到 15 个屏幕截图。问题是保存所有图像的速度足够快,这样屏幕截图队列就不会在 RAM 中堆积并耗尽用户的内存。

目前,我可以通过使用两个线程来按顺序保存图像然后收集垃圾来做到这一点。

while (true)
{
    bmp = null;

    Dispatcher.Invoke(new Action(delegate()
    {
        if (images.Count > 0)
        {
            bmp = images[0];
            images.RemoveAt(0);
        }
    }));

    if (bmp != null)
    {
        bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
        bmp.Dispose();
        bmp = null;
        GC.Collect();
    }

    Thread.Sleep(10);
}

问题在于它非常占用 CPU,因此我认为它不会在功能较弱的系统上运行。这种方法在我的 3.31 GHz 进程上占用 30 个 CPU。

当我将 CPU 设置为将所有图像写入一个文件并通过锁定位图的位只写入字节时,我可以将 CPU 降低到 17 左右。

byte[] rgbValues;

IntPtr ptr;

System.Drawing.Rectangle rect;

System.Drawing.Imaging.BitmapData bmpData;

System.Drawing.Imaging.PixelFormat pxf;


pxf = System.Drawing.Imaging.PixelFormat.Format24bppRgb;

//using(FileStream fs = new FileStream("frames.data", FileMode.OpenOrCreate, FileAccess.Write))
while (true)
{
    bmp = null;

    Dispatcher.Invoke(new Action(delegate()
    {
        if (images.Count > 0)
        {
            bmp = images[0];
            images.RemoveAt(0);
        }
    }));


    rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
    bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, pxf);

    ptr = bmpData.Scan0;

    rgbValues = new byte[bmpData.Stride * bmp.Height];

    Marshal.Copy(ptr, rgbValues, 0, rgbValues.Length);

    fs.Write(rgbValues, 0, rgbValues.Length);

    bmp.UnlockBits(bmpData);

    bmp.Dispose();
    bmp = null;
    GC.Collect();
}

这种方法有助于解决 CPU 问题,但因为它不够快。图像队列堆积起来并使内存过载,所以我不知道我还能做些什么来解决这两个问题。

有没有其他可用的方法?

4

1 回答 1

0

首先,使用while带有 a 的循环Thread.Sleep(x);非常占用 CPU,GC.Collect()并且过于频繁地调用新实例。您应该考虑使用线程。

Action action;
public void Main()
{
action = new Action(delegate()
{
    if (images.Count > 0)
    {
        bmp = images[0];
        images.RemoveAt(0);
    }
});
Thread thread = new Thread(SaveBitmap());
thread.Start();
thread.Priority =  ThreadPriority.Highest
}
public void SaveBitmap()
{
    Dispatcher.Invoke(action);

if (bmp != null)
{
    bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
    bmp.Dispose();
    bmp = null;
}
}

尝试使用上述方法,或者至少整合一些部分。

于 2013-10-01T23:59:13.770 回答