Unsafe Per Pixel access, 30ms access for 1756000 pixels

前端 未结 5 1539
轮回少年
轮回少年 2020-12-28 10:42

So I\'ve been sharing some thoughts on the above topic title on my website about fast, unsafe pixel access. A gentlemen gave me a rough example of how he\'d do it in C++, bu

5条回答
  •  滥情空心
    2020-12-28 11:21

    Unsafe approach with usage of integers instead of Pixels and single loop:

    private static Bitmap GetInvalidFrame(Bitmap oldFrame, Bitmap newFrame)
    {
        if (oldFrame.Size != newFrame.Size)
        {
            throw new ArgumentException();
        }
        Bitmap result = new Bitmap(oldFrame.Width, oldFrame.Height, oldFrame.PixelFormat);
    
        Rectangle lockArea = new Rectangle(Point.Empty, oldFrame.Size);
        PixelFormat format = PixelFormat.Format32bppArgb;
        BitmapData oldData = oldFrame.LockBits(lockArea, ImageLockMode.ReadOnly, format);
        BitmapData newData = newFrame.LockBits(lockArea, ImageLockMode.ReadOnly, format);
        BitmapData resultData = result.LockBits(lockArea, ImageLockMode.WriteOnly, format);
    
        int len = resultData.Height * Math.Abs(resultData.Stride) / 4;
    
        unsafe
        {
            int* pOld = (int*)oldData.Scan0;
            int* pNew = (int*)newData.Scan0;
            int* pResult = (int*)resultData.Scan0;
    
            for (int i = 0; i < len; i++)
            {
                int oldValue = *pOld++;
                int newValue = *pNew++;
                *pResult++ = oldValue != newValue ? newValue : 0 /* replace with 0xff << 24 if you need non-transparent black pixel */;
                // *pResult++ = *pOld++ ^ *pNew++; // if you can use XORs.
            }
        }
    
        oldFrame.UnlockBits(oldData);
        newFrame.UnlockBits(newData);
        result.UnlockBits(resultData);
    
        return result;
    }
    

    I think you really can use XORed frames here and I hope that this can have better performance on both sides.

        private static void XorFrames(Bitmap leftFrame, Bitmap rightFrame)
        {
            if (leftFrame.Size != rightFrame.Size)
            {
                throw new ArgumentException();
            }
    
            Rectangle lockArea = new Rectangle(Point.Empty, leftFrame.Size);
            PixelFormat format = PixelFormat.Format32bppArgb;
            BitmapData leftData = leftFrame.LockBits(lockArea, ImageLockMode.ReadWrite, format);
            BitmapData rightData = rightFrame.LockBits(lockArea, ImageLockMode.ReadOnly, format);
    
            int len = leftData.Height * Math.Abs(rightData.Stride) / 4;
    
            unsafe
            {
                int* pLeft = (int*)leftData.Scan0;
                int* pRight = (int*)rightData.Scan0;
    
                for (int i = 0; i < len; i++)
                {
                    *pLeft++ ^= *pRight++;
                }
            }
    
            leftFrame.UnlockBits(leftData);
            rightFrame.UnlockBits(rightData);
        }
    

    You can use this procedure on both sides in following way:
    On server side you need to evaluate difference between old and new frame, send it to client and replace old frame by new. The server code should look something like this:

      XorFrames(oldFrame, newFrame); // oldFrame ^= newFrame
      Send(oldFrame); // send XOR of two frames
      oldFrame = newFrame;
    

    On client side you need to update your current frame with xor frame recieved from server:

      XorFrames((Bitmap)uxSurface.Image, e.Frame);
    

提交回复
热议问题