title: Unsafe Per Pixel access, 30ms access for 1756000 pixels
body: <p>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++, but that doesn't help me in C# unless I can interop it, and the interop is fast as well. I had found a class in the internet that was written using MSDN help, to unsafely access pixels. The class is exceptionally fast, but it's not fast enough. Here's the class:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Drawing;
  using System.Drawing.Imaging;
  
  namespace DCOMProductions.Desktop.ScreenViewer {
  public unsafe class UnsafeBitmap {
      Bitmap bitmap;
  
      // three elements used for MakeGreyUnsafe
      int width;
      BitmapData bitmapData = null;
      Byte* pBase = null;
  
      public UnsafeBitmap(Bitmap bitmap) {
          this.bitmap = new Bitmap(bitmap);
      }
  
      public UnsafeBitmap(int width, int height) {
          this.bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
      }
  
      public void Dispose() {
          bitmap.Dispose();
      }
  
      public Bitmap Bitmap {
          get {
              return (bitmap);
          }
      }
  
      private Point PixelSize {
          get {
              GraphicsUnit unit = GraphicsUnit.Pixel;
              RectangleF bounds = bitmap.GetBounds(ref unit);
  
              return new Point((int)bounds.Width, (int)bounds.Height);
          }
      }
  
      public void LockBitmap() {
          GraphicsUnit unit = GraphicsUnit.Pixel;
          RectangleF boundsF = bitmap.GetBounds(ref unit);
          Rectangle bounds = new Rectangle((int)boundsF.X,
        (int)boundsF.Y,
        (int)boundsF.Width,
        (int)boundsF.Height);
  
          // Figure out the number of bytes in a row
          // This is rounded up to be a multiple of 4
          // bytes, since a scan line in an image must always be a multiple of 4 bytes
          // in length. 
          width = (int)boundsF.Width * sizeof(Pixel);
          if (width % 4 != 0) {
              width = 4 * (width / 4 + 1);
          }
          bitmapData =
        bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
  
          pBase = (Byte*)bitmapData.Scan0.ToPointer();
      }
  
      public Pixel GetPixel(int x, int y) {
          Pixel returnValue = *PixelAt(x, y);
          return returnValue;
      }
  
      public void SetPixel(int x, int y, Pixel colour) {
          Pixel* pixel = PixelAt(x, y);
          *pixel = colour;
      }
  
      public void UnlockBitmap() {
          bitmap.UnlockBits(bitmapData);
          bitmapData = null;
          pBase = null;
      }
      public Pixel* PixelAt(int x, int y) {
          return (Pixel*)(pBase + y * width + x * sizeof(Pixel));
      }
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Basically what I am doing is copying the entire screen and comparing each pixel to and old copy. On a 1680x1050 bitmap, this takes approximately 300 milliseconds using the following code.</p>
  
  <pre><code>private Bitmap GetInvalidFrame(Bitmap frame) {
          Stopwatch sp = new Stopwatch();
          sp.Start();
  
          if (m_FrameBackBuffer == null) {
              return frame;
          }
  
          Int32 pixelsToRead = frame.Width * frame.Height;
          Int32 x = 0, y = 0;
  
          UnsafeBitmap unsafeBitmap = new UnsafeBitmap(frame);
          UnsafeBitmap unsafeBuffBitmap = new UnsafeBitmap(m_FrameBackBuffer);
          UnsafeBitmap retVal = new UnsafeBitmap(frame.Width, frame.Height);
  
          unsafeBitmap.LockBitmap();
          unsafeBuffBitmap.LockBitmap();
          retVal.LockBitmap();
  
          do {
              for (x = 0; x &lt; frame.Width; x++) {
                  Pixel newPixel = unsafeBitmap.GetPixel(x, y);
                  Pixel oldPixel = unsafeBuffBitmap.GetPixel(x, y);
  
                  if (newPixel.Alpha != oldPixel.Alpha || newPixel.Red != oldPixel.Red || newPixel.Green != oldPixel.Green || newPixel.Blue != oldPixel.Blue) {
                     retVal.SetPixel(x, y, newPixel);
                  }
                  else {
                      // Skip pixel
                  }
              }
  
              y++;
          } while (y != frame.Height);
  
          unsafeBitmap.UnlockBitmap();
          unsafeBuffBitmap.UnlockBitmap();
          retVal.UnlockBitmap();
  
          sp.Stop();
  
          System.Diagnostics.Debug.WriteLine(sp.Elapsed.Milliseconds.ToString());
  
          sp.Reset();
  
          return retVal.Bitmap;
      }
  </code></pre>
  
  <p>Is there any possible method/means/approach that I could speed this up to about 30ms? I can copy the screen in about 30ms using Graphics.CopyFromScreen(), so that produces approximately 30 frames each second. However, a program only runs as fast as its slower counterpart, so the 300ms delay in GetInvalidFrame, slows this down to about 1 - 3 frames each second. This isn't good for a meeting software.</p>
  
  <p>Any advice, approaches, pointers in the right direction would be absolutely wonderful! Also, the code that is used to draw the bitmap on the client-side is below as well.</p>
  
  <p>To comment on Dmitriy's answer/comment:</p>
  
  <pre><code>#region RootWorkItem
  
      private ScreenClient m_RootWorkItem;
      /// &lt;summary&gt;
      /// Gets the RootWorkItem
      /// &lt;/summary&gt;
      public ScreenClient RootWorkItem {
          get {
              if (m_RootWorkItem == null) {
                  m_RootWorkItem = new ScreenClient();
                  m_RootWorkItem.FrameRead += new EventHandler&lt;FrameEventArgs&gt;(RootWorkItem_FrameRead);
              }
              return m_RootWorkItem;
          }
      }
  
      #endregion
  
      private void RootWorkItem_FrameRead(Object sender, FrameEventArgs e) {
          if (e.Frame != null) {
              if (uxSurface.Image != null) {
                  Bitmap frame = (Bitmap)uxSurface.Image;
  
                  Graphics g = Graphics.FromImage(frame);
                  g.DrawImage(e.Frame, 0, 0); // Draw only updated pixels
  
                  uxSurface.Image = frame;
              }
              else {
                  uxSurface.Image = e.Frame; // Draw initial, full image
              }
          }
          else {
              uxSurface.Image = null;
          }
      }
  </code></pre>