我正在进行一个小屏幕共享项目,并且在主循环中(在第二个线程上)我从连接的套接字读取数据,将其处理为一个小图像(一种块,{{ 1}}和X
属性指示绘制该块的位置),并且需要在上一个图像上重绘它 - 它必须非常快速地更新(至少这是我的目标)。
到目前为止,我从初始图像创建了Y
,并使用Graphics
方法在当前图像上绘制了较小的块(从套接字中不断收到)。
这就是它的样子:
Graphics.DrawImage
我做了一些基准测试,我发现 private void MainScreenThread()
{
ReadData();
initial = bufferToJpeg();
while (true)
{
int pos = ReadData();
x = BlockX();
y = BlockY();
Bitmap block = bufferToJpeg();
Draw(block,new Point(x,y));
this.Invoke(new Action(() => pictureBox1.Refresh()));
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
lock (initial)
{
e.Graphics.DrawImage(initial, 0, 0);
}
}
方法工作得很慢。
绘制800X500图像的平均时间 ~520ms 。
我决定自己实现一个更快的方法,使用不安全的指针来加快访问速度。
DrawImage
现在这个电话看起来像这样:
private unsafe void Draw(Bitmap bmp2, Point point)
{
lock (initial)
{
BitmapData bmData = initial.LockBits(new Rectangle(0, 0, initial.Width, initial.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, initial.PixelFormat);
BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int Width = bmp2.Width;
int Height = bmp2.Height;
int X = point.X;
int Y = point.Y;
for (int y = 0; y < Height; y++)
{
byte* p = (byte*)scan0.ToPointer();
p += (Y + y) * stride + X * 4;//setting pointer according the smaller bitmap bounds.
byte* p2 = (byte*)scan02.ToPointer();
p2 += stride2 * y;
for (int x = 0; x < Width; x++)
{
p[0] = p2[0];//B
p[1] = p2[1];//G
p[2] = p2[2];//R
p += 4;//advance pointer +4
p2 += 4;//advance pointer +4
}
}
initial.UnlockBits(bmData);
bmp2.UnlockBits(bmData2);
}
}
但我一直在
对象目前正在其他地方使用
当我锁定初始图像时......在这一行
while (true)
{
int pos = ReadData();
x = BlockX();
y = BlockY();
Bitmap block = bufferToJpeg();
Draw(block,new Point(x,y));
this.Invoke(new Action(() => pictureBox1.Refresh()));
}
我不确定为什么会发生这种情况......我不会从任何其他来源访问 BitmapData bmData = initial.LockBits(new Rectangle(0, 0, initial.Width, initial.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, initial.PixelFormat);
...
我将不胜感激。
感谢。
答案 0 :(得分:1)
您正在从其他来源访问initial
:即由于您的pictureBox1.Image = initial
我的建议。摆脱pictureBox1.Image = initial
位,并向pictureBox添加一个OnPaint处理程序以手动绘制图像。然后围绕资源的使用添加一些简单的锁定代码,例如在后台线程中,例如:
lock (initial)
{
BitmapData bmData = initial.LockBits(new Rectangle(0, 0, initial.Width, initial.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, initial.PixelFormat);
// ....
initial.UnlockBits(bmData);
}
然后在你的OnPaint处理程序中,执行以下操作:
lock (initial)
{
e.Graphics.DrawImage(initial, 0, 0);
}
这将防止两个线程在尝试访问同一资源时发生冲突。