我正在编写一个从另一台服务器获取更新的服务器,然后允许多个客户端连接并接收增量。我允许客户端要求对增量进行异或。当XOR打开时,我得到加扰数据,这意味着两个位图被错误地异或。但如果我延迟100毫秒,就没有问题了。
接收更新功能:
while (this.updateQueue != null)
{
Frame update;
if (!this.updateQueue.TryDequeue(out update))
{
Thread.Sleep(10);
continue;
}
lock (this.clientFrameLock)
{
//For Each Client connected, if the update Area is not empty
// Union it with the new update area
foreach (string key in this.clientFrames.Keys)
{
if (this.clientFrames[key].Area.IsEmpty)
{
this.clientFrames[key].Area = new Rectangle(update.Area.X, update.Area.Y, update.Area.Width, update.Area.Height);
}
else
{
Rectangle area = Rectangle.Union(this.clientFrames[key].Area, update.Area);
this.clientFrames[key].Area = area;
}
}
// if update from server is XOR'd, unxor and apply it to this.CurrentFrame, else just Apply
lock (this.currentFrameLock)
{
if (update.Mask == Mask.MASK_XOR) this.currentFrame.Buffer.XorBitmaps(update.Buffer, update.Area);
else this.currentFrame.Buffer.Apply(update.Buffer, update.Area);
this.currentFrame.Sequence++;
}
}
update.Dispose();
}
客户端调用以获取下一帧的函数:
public Frame GetNextUpdateFrame(Compression compression, Mask desiredMask, string uuid)
{
Bitmap buffer;
Bitmap newClientBuffer;
Bitmap lastBuffer;
Mask actualMask = Mask.MASK_NONE;
Rectangle rect;
int currentFrameSequence;
Size currentFrameResolution;
lock (this.clientFrameLock)
{
lock (this.currentFrameLock)
{
buffer = this.currentFrame.Buffer.CopyBitmap();
newClientBuffer = buffer.CopyBitmap();
currentFrameSequence = this.currentFrame.Sequence;
currentFrameResolution = this.currentFrame.Resolution;
}
if (!this.clientFrames.ContainsKey(uuid))
{
this.clientFrames.Add(uuid, new Frame(currentFrameSequence, newClientBuffer.CopyBitmap(), new Rectangle(), currentFrameResolution, Mask.MASK_NONE));
var newClientFrame = new Frame(currentFrameSequence, newClientBuffer.CopyBitmap(), new Rectangle(0, 0, currentFrameResolution.Width, currentFrameResolution.Height), currentFrameResolution, Mask.MASK_NONE);
buffer.Dispose();
newClientBuffer.Dispose();
return newClientFrame;
}
Frame lastFrame = this.clientFrames[uuid];
rect = new Rectangle(lastFrame.Area.X, lastFrame.Area.Y, lastFrame.Area.Width, lastFrame.Area.Height);
if (rect.Width == 0 || rect.Height == 0)
{
buffer.Dispose();
newClientBuffer.Dispose();
return null;
}
lastBuffer = lastFrame.Buffer.CopyBitmap();
}
if (desiredMask == Mask.MASK_XOR)
{
buffer.XorBitmaps(lastBuffer, rect, rect);
actualMask = Mask.MASK_XOR;
}
Bitmap smallerBitmap = buffer.CopyBitmap(rect);
buffer.Dispose();
lastBuffer.Dispose();
this.clientFrames[uuid].Dispose();
this.clientFrames.Remove(uuid);
this.clientFrames.Add(uuid, new Frame(currentFrameSequence, newClientBuffer, new Rectangle(), currentFrameResolution, Mask.MASK_NONE));
return new Frame(currentFrameSequence, smallerBitmap, rect, currentFrameResolution, actualMask);
}
异或功能:
internal static void XorBitmaps(this Bitmap sourceBitmap, Bitmap baseBitmap, Rectangle rect, Rectangle rectBase = default (Rectangle))
{
if (baseBitmap == null) return;
if (rectBase == default(Rectangle))
{
rectBase = new Rectangle(0, 0, baseBitmap.Width, baseBitmap.Height);
}
BitmapData bmdSource = sourceBitmap.LockBits(rect, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat);
BitmapData bmdBase = baseBitmap.LockBits(rectBase, ImageLockMode.ReadOnly, baseBitmap.PixelFormat);
unsafe
{
for (int y = 0; y < bmdSource.Height; y++)
{
int* rowSource = (int*)((byte*)bmdSource.Scan0 + (y * bmdSource.Stride));
int* rowBase = (int*)((byte*)bmdBase.Scan0 + (y * bmdBase.Stride));
for (int x = 0; x < bmdSource.Width; x++)
{
rowSource[x] ^= rowBase[x];
}
}
}
baseBitmap.UnlockBits(bmdBase);
sourceBitmap.UnlockBits(bmdSource);
}
CopyBitmap函数(使用Kernal32.dll CopyMemory)
internal static Bitmap CopyBitmap(this Bitmap bitmap)
{
int bbp = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;
PixelFormat pixFormat;
if (bbp != 0) pixFormat = bitmap.PixelFormat;
else
{
pixFormat = PixelFormat.Format32bppRgb;
bbp = 4;
}
Bitmap newBitmap = new Bitmap(bitmap.Width, bitmap.Height, pixFormat);
BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, pixFormat);
BitmapData newBitmapData = newBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, pixFormat);
CopyMemory(newBitmapData.Scan0, bmpdata.Scan0, (uint)(bbp * bitmap.Height * bitmap.Width));
bitmap.UnlockBits(bmpdata);
newBitmap.UnlockBits(newBitmapData);
return newBitmap;
}
internal static Bitmap CopyBitmap(this Bitmap bitmap, Rectangle bounds)
{
Bitmap newBitmap = new Bitmap(bounds.Width, bounds.Height, bitmap.PixelFormat);
BitmapData bmdSrc = bitmap.LockBits(bounds, ImageLockMode.ReadOnly, bitmap.PixelFormat);
BitmapData bmdDst = newBitmap.LockBits(new Rectangle(0, 0, bounds.Width, bounds.Height), ImageLockMode.ReadWrite, newBitmap.PixelFormat);
unsafe
{
for (int y = 0; y < bmdSrc.Height; y++)
{
IntPtr rowSrc = (IntPtr)((byte*)bmdSrc.Scan0 + (y * bmdSrc.Stride));
IntPtr rowDst = (IntPtr)((byte*)bmdDst.Scan0 + (y * bmdDst.Stride));
CopyMemory(rowDst, rowSrc, (uint)bmdDst.Stride);
}
}
newBitmap.UnlockBits(bmdDst);
bitmap.UnlockBits(bmdSrc);
return newBitmap;
}
我几周来一直在研究这个问题,我似乎无法弄清楚这个问题。任何建议都可能有用