/// <summary> /// /// </summary> /// <param name="arg"></param> public void compressSend(Object arg) { // Now send this update off UInt32 hdr; byte[] hdrbuf; streamThread parent = (streamThread)arg; Debug.Assert(buf != null); try { if (buf.Length == -1) { buf = parent._mirror.GetRect(x, y, w, h); } } catch { Trace.WriteLine("getRect failed"); return; } if (buf == null) { return; } outbuf = new MemoryStream(); int checkSum = 1; using (DeflateStream compress = new DeflateStream(outbuf, CompressionMode.Compress #if USE_IONIC_ZLIB , CompressionLevel.BestSpeed /* CompressionLevel.BestCompression */)){ compress.FlushMode = FlushType.Sync;
/// <summary> /// Send updates. if newStream is not null, send to just this streams, otherwise everyone gets this update /// </summary> /// <param name="newStream"></param> /// <param name="buf"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="w"></param> /// <param name="h"></param> public sendUpdate(NetworkStream newStream, GCbuf buf, int x, int y, int w, int h) // , int width, int height, int maskX, int maskY, int maskWidth, int maskHeight) { { this.newStream = newStream; this.buf = buf; this.x = x; this.y = y; this.w = w; this.h = h; // this.width = width; // this.height = height; // this.maskX = maskX; // this.maskY = maskY; // this.maskWidth = maskWidth; // this.maskHeight = maskHeight; }
/// <summary> /// /// </summary> /// <param name="newStream"></param> private void sendIframe(NetworkStream newStream) { try { GCbuf screenbuf = new GCbuf(); #if USE_BITMAP_COMPRESS int ptr = DesktopMirror._bitmapWidth * DesktopMirror._bitmapHeight, num = 0; for (int i = 0; i < ptr; i++) { screenbuf.buf[num++] = 0xFF; } for (int i = 0; i < (ptr * 4); i += 4) { screenbuf.buf[num++] = _mirror.screen[i]; screenbuf.buf[num++] = _mirror.screen[i + 1]; screenbuf.buf[num++] = _mirror.screen[i + 2]; } #else Buffer.BlockCopy(_mirror.screen, 0, screenbuf.buf, 0, _mirror.screen.Length); #endif // screenbuf.buf = _mirror.screen; screenbuf.Length = _mirror.screen.Length; sendUpdate upd; if (Program.maskValid == true) { upd = new sendUpdate(newStream, screenbuf, Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); } else { upd = new sendUpdate(newStream, screenbuf, 0, 0, DesktopMirror._bitmapWidth, DesktopMirror._bitmapHeight); } lock (streamer.updates.SyncRoot) { streamer.updates.Enqueue(upd); } } catch (IOException) { Trace.WriteLine("DEBUG: Event creator causes an internal Win32 exception. Just ignore"); } }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="dce"></param> static private unsafe void _DesktopChange(object sender, DesktopChangeEventArgs dce) { if (streamer.clients.Count > 0) // No one is listening, why bother to process updates { try { lock (streamer.updates.SyncRoot) { if (streamer.updates.Count == 0) { if (numUpdates++ > 5) { // Send the iFrame GCbuf screenbuf = new GCbuf(); #if USE_BITMAP_COMPRESS int ptr = DesktopMirror._bitmapWidth * DesktopMirror._bitmapHeight, num = 0; for (int i = 0; i < ptr; i++) { screenbuf.buf[num++] = 0xFF; } for (int i = 0; i < (ptr * 4); i += 4) { screenbuf.buf[num++] = _mirror.screen[i]; screenbuf.buf[num++] = _mirror.screen[i + 1]; screenbuf.buf[num++] = _mirror.screen[i + 2]; } #else Buffer.BlockCopy(_mirror.screen, 0, screenbuf.buf, 0, _mirror.screen.Length); // for (int i = 0; i < _mirror.screen.Length; i++) // screenbuf.buf[i] = _mirror.screen[i]; #endif screenbuf.Length = _mirror.screen.Length; streamer.updates.Enqueue(new sendUpdate(null, screenbuf, maskX, maskY, maskWidth, maskHeight)); numUpdates = 0; } else { if (maskValid == true) { System.Drawing.Rectangle cur = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); cur.Intersect(mask); if (cur.IsEmpty) { return; } else { streamer.updates.Enqueue(new sendUpdate(null, null, cur.X, cur.Y, cur.Width, cur.Height)); } } else { streamer.updates.Enqueue(new sendUpdate(null, null, dce.x, dce.y, dce.w, dce.h)); } } } else { System.Drawing.Rectangle orig = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); if (maskValid == true) { System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); orig.Intersect(mask); if (orig.IsEmpty) { return; } } for (int i = streamer.updates.Count; i > 0; i--) { sendUpdate upd = (sendUpdate)streamer.updates.Dequeue(); System.Drawing.Rectangle cur = new System.Drawing.Rectangle(upd.x, upd.y, upd.w, upd.h); /* I don't think that I need to do this * if (maskValid == true) { * cur.Intersect(mask); * if (cur.IsEmpty) * continue; * } */ cur.Intersect(orig); if (cur.IsEmpty) { // Move this update to the back of the line? Okay because all pending updates are disjoint streamer.updates.Enqueue(upd); // Moved to the front of the for loop // upd = (sendUpdate)streamer.updates.Dequeue(); } else { cur.X = upd.x; cur.Y = upd.y; cur.Width = upd.w; cur.Height = upd.h; System.Drawing.Rectangle combined = System.Drawing.Rectangle.Union(orig, cur); Boolean anymoreCombine = true; // int count = 0; while (anymoreCombine) { anymoreCombine = false; for (int j = streamer.updates.Count; j > 0; j--) { sendUpdate u = (sendUpdate)streamer.updates.Dequeue(); System.Drawing.Rectangle nxt = new System.Drawing.Rectangle(u.x, u.y, u.w, u.h); /* I don't think that I need this either * if (maskValid == true) { * nxt.Intersect(mask); * if (nxt.IsEmpty) * continue; * } */ nxt.Intersect(combined); if (nxt.IsEmpty) { streamer.updates.Enqueue(u); } else { nxt.X = u.x; nxt.Y = u.y; nxt.Width = u.w; nxt.Height = u.h; combined = System.Drawing.Rectangle.Union(combined, nxt); anymoreCombine = true; Trace.WriteLine("DEBUG: ----"); break; } } } streamer.updates.Enqueue(new sendUpdate(null, null, combined.X, combined.Y, combined.Width, combined.Height)); // Trace.WriteLine("DEBUG: need to make sure that this update does not overlap with prior non-overlapping rectangles"); // Actually don't need to because of the way that Queue's work? return; } } if (maskValid == true) { System.Drawing.Rectangle cur = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); cur.Intersect(mask); if (cur.IsEmpty) { return; } streamer.updates.Enqueue(new sendUpdate(null, null, cur.X, cur.Y, cur.Width, cur.Height)); } else { streamer.updates.Enqueue(new sendUpdate(null, null, dce.x, dce.y, dce.w, dce.h)); } } } } catch (System.IO.IOException) { Trace.WriteLine("DEBUG: An internal Win32 exception is caused by update while creating event handler. Ignoring"); // Environment.Exit(1); } catch (Exception e) { MessageBox.Show("DEBUG: Error while capturing update coordinates " + e.StackTrace); } } }
/// <summary> /// /// </summary> /// <param name="newStream"></param> private void sendIframe(NetworkStream newStream) { try { GCbuf screenbuf = new GCbuf(); #if USE_BITMAP_COMPRESS int ptr = DesktopMirror._bitmapWidth * DesktopMirror._bitmapHeight, num = 0; for (int i = 0; i < ptr; i++) screenbuf.buf[num++] = 0xFF; for (int i = 0; i < (ptr * 4); i += 4) { screenbuf.buf[num++] = _mirror.screen[i]; screenbuf.buf[num++] = _mirror.screen[i + 1]; screenbuf.buf[num++] = _mirror.screen[i + 2]; } #else Buffer.BlockCopy(_mirror.screen, 0, screenbuf.buf, 0, _mirror.screen.Length); #endif // screenbuf.buf = _mirror.screen; screenbuf.Length = _mirror.screen.Length; sendUpdate upd; if (Program.maskValid == true) upd = new sendUpdate(newStream, screenbuf, Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); else upd = new sendUpdate(newStream, screenbuf, 0, 0, DesktopMirror._bitmapWidth, DesktopMirror._bitmapHeight); lock (streamer.updates.SyncRoot) { streamer.updates.Enqueue(upd); } } catch (IOException) { Trace.WriteLine("DEBUG: Event creator causes an internal Win32 exception. Just ignore"); } }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="dce"></param> private static unsafe void _DesktopChange(object sender, DesktopChangeEventArgs dce) { if (streamer.clients.Count > 0) { // No one is listening, why bother to process updates try { lock (streamer.updates.SyncRoot) { if (streamer.updates.Count == 0) { if (numUpdates++ > 5) { // Send the iFrame GCbuf screenbuf = new GCbuf(); #if USE_BITMAP_COMPRESS int ptr = DesktopMirror._bitmapWidth * DesktopMirror._bitmapHeight, num = 0; for (int i = 0; i < ptr; i++) screenbuf.buf[num++] = 0xFF; for (int i = 0; i < (ptr * 4); i += 4) { screenbuf.buf[num++] = _mirror.screen[i]; screenbuf.buf[num++] = _mirror.screen[i + 1]; screenbuf.buf[num++] = _mirror.screen[i + 2]; } #else Buffer.BlockCopy(_mirror.screen, 0, screenbuf.buf, 0, _mirror.screen.Length); // for (int i = 0; i < _mirror.screen.Length; i++) // screenbuf.buf[i] = _mirror.screen[i]; #endif screenbuf.Length = _mirror.screen.Length; streamer.updates.Enqueue(new sendUpdate(null, screenbuf, maskX, maskY, maskWidth, maskHeight)); numUpdates = 0; } else { if (maskValid == true) { System.Drawing.Rectangle cur = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); cur.Intersect(mask); if (cur.IsEmpty) return; else streamer.updates.Enqueue(new sendUpdate(null, null, cur.X, cur.Y, cur.Width, cur.Height)); } else streamer.updates.Enqueue(new sendUpdate(null, null, dce.x, dce.y, dce.w, dce.h)); } } else { System.Drawing.Rectangle orig = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); if (maskValid == true) { System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); orig.Intersect(mask); if (orig.IsEmpty) return; } for (int i = streamer.updates.Count; i > 0; i--) { sendUpdate upd = (sendUpdate)streamer.updates.Dequeue(); System.Drawing.Rectangle cur = new System.Drawing.Rectangle(upd.x, upd.y, upd.w, upd.h); /* I don't think that I need to do this if (maskValid == true) { cur.Intersect(mask); if (cur.IsEmpty) continue; } */ cur.Intersect(orig); if (cur.IsEmpty) { // Move this update to the back of the line? Okay because all pending updates are disjoint streamer.updates.Enqueue(upd); // Moved to the front of the for loop // upd = (sendUpdate)streamer.updates.Dequeue(); } else { cur.X = upd.x; cur.Y = upd.y; cur.Width = upd.w; cur.Height = upd.h; System.Drawing.Rectangle combined = System.Drawing.Rectangle.Union(orig, cur); Boolean anymoreCombine = true; // int count = 0; while (anymoreCombine) { anymoreCombine = false; for (int j = streamer.updates.Count; j > 0; j--) { sendUpdate u = (sendUpdate)streamer.updates.Dequeue(); System.Drawing.Rectangle nxt = new System.Drawing.Rectangle(u.x, u.y, u.w, u.h); /* I don't think that I need this either if (maskValid == true) { nxt.Intersect(mask); if (nxt.IsEmpty) continue; } */ nxt.Intersect(combined); if (nxt.IsEmpty) streamer.updates.Enqueue(u); else { nxt.X = u.x; nxt.Y = u.y; nxt.Width = u.w; nxt.Height = u.h; combined = System.Drawing.Rectangle.Union(combined, nxt); anymoreCombine = true; Trace.WriteLine("DEBUG: ----"); break; } } } streamer.updates.Enqueue(new sendUpdate(null, null, combined.X, combined.Y, combined.Width, combined.Height)); // Trace.WriteLine("DEBUG: need to make sure that this update does not overlap with prior non-overlapping rectangles"); // Actually don't need to because of the way that Queue's work? return; } } if (maskValid == true) { System.Drawing.Rectangle cur = new System.Drawing.Rectangle(dce.x, dce.y, dce.w, dce.h); System.Drawing.Rectangle mask = new System.Drawing.Rectangle(Program.maskX, Program.maskY, Program.maskWidth, Program.maskHeight); cur.Intersect(mask); if (cur.IsEmpty) return; streamer.updates.Enqueue(new sendUpdate(null, null, cur.X, cur.Y, cur.Width, cur.Height)); } else streamer.updates.Enqueue(new sendUpdate(null, null, dce.x, dce.y, dce.w, dce.h)); } } } catch (System.IO.IOException) { Trace.WriteLine("DEBUG: An internal Win32 exception is caused by update while creating event handler. Ignoring"); // Environment.Exit(1); } catch (Exception e) { MessageBox.Show("DEBUG: Error while capturing update coordinates " + e.StackTrace); } } }
/// <summary> /// /// </summary> private void pollingThreadProc() { // Why bother to poll while there is no one to receive the updates while (DesktopChange == null) Thread.Sleep(1); while (true) { if (restartingDriver == false) { var getChangesBuffer = (GetChangesBuffer)Marshal.PtrToStructure(_getChangesBuffer, typeof(GetChangesBuffer)); // Moved it inside the loop in hope of fixing the hibernation bug var buffer = (ChangesBuffer)Marshal.PtrToStructure(getChangesBuffer.Buffer, typeof(ChangesBuffer)); // Initialize oldCounter if (oldCounter == long.MaxValue) oldCounter = buffer.counter; if (oldCounter != buffer.counter) { // Trace.WriteLine("Updates: " + (buffer.counter - oldCounter)); for (long currentChange = oldCounter; currentChange != buffer.counter; currentChange++) { if (currentChange >= ChangesBuffer.MAXCHANGES_BUF) currentChange = 0; #if PRODUCTION DesktopChange(this, new DesktopChangeEventArgs(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, buffer.pointrect[currentChange].rect.x2, buffer.pointrect[currentChange].rect.y2, (OperationType)buffer.pointrect[currentChange].type)); #else int x, y, w, h; x = buffer.pointrect[currentChange].rect.x1; y = buffer.pointrect[currentChange].rect.y1; w = (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1); h = (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1); #if DEBUG_EXP_1 if (log == null) { log = new StreamWriter("c:/mmsys_1.txt"); log.AutoFlush = true; } diffT = (DateTime.Now - startTime); log.WriteLine(diffT.TotalMilliseconds + " " + x + " " + y + " " + w + " " + h); continue; #endif #if DEBUG_EXP_2 if (log == null) { log = new StreamWriter("c:/3.txt"); log.AutoFlush = true; } int a0Len, a255Len, rgbLen, vanillaLen, origLen, bitmapLen; origLen = w * h * sizeof(UInt32); diffT = (DateTime.Now - startTime); GCbuf a0 = GetRect(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1), (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1), CompressionType.ALPHA0); int same = 0, diff = 0; for (int i = 0; i < a0.Length; i+=sizeof(UInt32)) if (a0.buf[i+3] == 0) same++; else diff++; compressor a0C = new compressor(a0); Thread a0t = new Thread(new ThreadStart(a0C.compressData)); a0t.Start(); GCbuf bitmap = new GCbuf(); Buffer.BlockCopy(a0.buf, 0, bitmap.buf, 0, a0.Length); bitmap.Length = a0.Length; compressor bC = new compressor(bitmap); Thread bT = new Thread(new ThreadStart(bC.bitmapCompressData)); bT.Start(); GCbuf vanilla = GetRect(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1), (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1), CompressionType.VANILLA); compressor vC = new compressor(vanilla); Thread vt = new Thread(new ThreadStart(vC.compressData)); vt.Start(); GCbuf rgb = GetRect(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1), (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1), CompressionType.RGB16); compressor rC = new compressor(rgb); Thread rt = new Thread(new ThreadStart(rC.compressData)); rt.Start(); GCbuf a255 = GetRect(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1), (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1), CompressionType.ALPHA255); compressor a2C = new compressor(a255); Thread a2t = new Thread(new ThreadStart(a2C.compressData)); a2t.Start(); a0t.Join(); a0Len = a0C.retvalue; vt.Join(); vanillaLen = vC.retvalue; rt.Join(); rgbLen = rC.retvalue; a2t.Join(); a255Len = a2C.retvalue; bT.Join(); bitmapLen = bC.retvalue; log.WriteLine(diffT.TotalMilliseconds + " S " + same + " D " + diff + " O " + (w * h * sizeof(UInt32)) + " R " + rgbLen + " A0 " + a0Len + " A255 " + a255Len + " V " + vanillaLen + " B " + bitmapLen); a0.Dispose(); a255.Dispose(); rgb.Dispose(); vanilla.Dispose(); bitmap.Dispose(); continue; #endif #if DEBUG_EXP_3 if (log == null) { log = new StreamWriter("c:/mmsys_3.txt"); log.AutoFlush = true; } diffT = (DateTime.Now - startTime); GCbuf bitmap = GetRect(buffer.pointrect[currentChange].rect.x1, buffer.pointrect[currentChange].rect.y1, (buffer.pointrect[currentChange].rect.x2 - buffer.pointrect[currentChange].rect.x1), (buffer.pointrect[currentChange].rect.y2 - buffer.pointrect[currentChange].rect.y1), CompressionType.ALPHA0); compressor bC = new compressor(bitmap); bC.bitmapCompressData(); log.WriteLine(diffT.TotalMilliseconds + " " + bC.retvalue); bitmap.Dispose(); #endif #endif } oldCounter = buffer.counter; idleCount = 0; } else { #if PRODUCTION if (idleCount++ == (1000 / PollInterval)) { // One second DesktopChange(this, new DesktopChangeEventArgs(0, 0, _bitmapWidth, _bitmapHeight, OperationType.dmf_dfo_IGNORE)); // Trace.WriteLine("DEBUG: Sending iFrame oldCount: " + oldCounter + " buffer " + buffer.counter); idleCount = 0; } #endif } } // Just to prevent 100-percent CPU load and to provide thread-safety use manual reset event instead of simple in-memory flag. if (_terminatePollingThread.WaitOne(PollInterval, false)) { Trace.WriteLine("The thread now exits"); break; } } // We can be sure that _pollingThreadTerminated exists _pollingThreadTerminated.Set(); }
public compressor(GCbuf data) { this.data = data; }
/// <summary> /// Get the pixels within the update rectangle in CompressionType encoding /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="w"></param> /// <param name="h"></param> /// <param name="type"></param> /// <returns></returns> private GCbuf GetRect(int x, int y, int w, int h, CompressionType type) { if (loaded == false) return null; GCbuf retRect = null; try { retRect = new GCbuf(); } catch (Exception e) { // One reason for failure is when the client stops accepting new updates MessageBox.Show("FATAL: Memory allocation failed " + e.Message); Environment.Exit(1); } try { GetChangesBuffer getChangesBuffer = (GetChangesBuffer)Marshal.PtrToStructure(_getChangesBuffer, typeof(GetChangesBuffer)); IntPtr start; byte[] membuf = new byte[w * sizeof(UInt32)]; int bmCount = 0; int dtCount = w * h; if (type == CompressionType.RGB16) retRect.Length = w * h * sizeof(UInt16); else if (type == CompressionType.BITMAP) retRect.Length = w * h * sizeof(byte); // Just the space for the bitmap else retRect.Length = w * h * sizeof(UInt32); // buffers are always width*height - we waste the remaining to ease in memory management and fragmentation unsafe { start = new IntPtr(((Int32*)getChangesBuffer.UserBuffer) + ((y * _bitmapWidth) + x)); } for (int j = 0; j < h; j++) { try { switch (type) { case CompressionType.BITMAP: Marshal.Copy(start, membuf, 0, w * sizeof(UInt32)); int indx = ((y + j) * _bitmapWidth + x) * sizeof(UInt32); for (int i = 0; i < (w * sizeof(UInt32)); i += sizeof(UInt32), indx += sizeof(UInt32)) { if ((membuf[i] == screen[indx]) && (membuf[i + 1] == screen[indx + 1]) && (membuf[i + 2] == screen[indx + 2])) retRect.buf[bmCount++] = 0x00; else { retRect.buf[bmCount++] = 0xFF; retRect.buf[dtCount++] = screen[indx] = membuf[i]; retRect.buf[dtCount++] = screen[indx + 1] = membuf[i + 1]; retRect.buf[dtCount++] = screen[indx + 2] = membuf[i + 2]; retRect.Length += 3; } } break; #if !PRODUCTION case CompressionType.RGB16: Marshal.Copy(start, membuf, 0, w * sizeof(UInt32)); for (int i = 0; i < (w * sizeof(UInt32)); i += sizeof(UInt32)) { UInt16 rgb; rgb = (ushort)(membuf[i] & 0xF8); // Blue rgb += (ushort)((membuf[i + 1] & 0xFE) << 5); // Green rgb += (ushort)((membuf[i + 2] * 0xF8) << 11); // Red retRect.buf[j * w * sizeof(UInt16) + i] = (byte)((rgb & 0xFF00) >> 8); retRect.buf[j * w * sizeof(UInt16) + i + 1] = (byte)(rgb & 0x00FF); } break; case CompressionType.ALPHA0: case CompressionType.ALPHA255: Marshal.Copy(start, retRect.buf, j * w * sizeof(UInt32), w * sizeof(UInt32)); int indx = ((y + j) * _bitmapWidth + x) * sizeof(UInt32); int ind = (j * w) * sizeof(UInt32); for (int i = 0; i < (w * sizeof(UInt32)); i += sizeof(UInt32)) { if ((retRect.buf[ind] == screen[indx]) && (retRect.buf[ind + 1] == screen[indx + 1]) && (retRect.buf[ind + 2] == screen[indx + 2])) { if (type == CompressionType.ALPHA0) { retRect.buf[ind] = 0x00; retRect.buf[ind + 1] = 0x00; retRect.buf[ind + 2] = 0x00; } if (type == CompressionType.ALPHA255) { retRect.buf[ind] = 0xFF; retRect.buf[ind + 1] = 0xFF; retRect.buf[ind + 2] = 0xFF; } retRect.buf[ind + 3] = 0; } else { if (type == CompressionType.ALPHA255) { screen[indx] = retRect.buf[ind]; screen[indx + 1] = retRect.buf[ind + 1]; screen[indx + 2] = retRect.buf[ind + 2]; } retRect.buf[ind + 3] = 0xFF; } indx += sizeof(UInt32); ind += sizeof(UInt32); } break; #endif } } catch (Exception e) { MessageBox.Show("FATAL: Failure to copy framebuffer data " + e.StackTrace); Environment.Exit(1); } unsafe { start = new IntPtr((Int32*)start + _bitmapWidth); } } return retRect; } catch (Exception e) { // Debug.WriteLine("FATAL: Failed to capture pixmap. Please report to Surendar Chandra. Ignoring for now"); MessageBox.Show("FATAL: Failed to capture pixmap. Please report to [email protected] " + e.Message); // myNotifyIcon.ShowBalloonTip(500, "Title", "Tip text", ToolTipIcon.Info); } return retRect; }
/// <summary> /// /// </summary> /// <param name="arg"></param> public void compressSend(Object arg) { // Now send this update off UInt32 hdr; byte[] hdrbuf; streamThread parent = (streamThread)arg; Debug.Assert(buf != null); try { if (buf.Length == -1) buf = parent._mirror.GetRect(x, y, w, h); } catch { Trace.WriteLine("getRect failed"); return; } if (buf == null) return; outbuf = new MemoryStream(); int checkSum = 1; using (DeflateStream compress = new DeflateStream(outbuf, CompressionMode.Compress #if USE_IONIC_ZLIB , CompressionLevel.BestSpeed /* CompressionLevel.BestCompression */)){ compress.FlushMode = FlushType.Sync; #else )) { #endif hdr = ((UInt32)DesktopMirror._bitmapWidth << 16) + ((UInt32)DesktopMirror._bitmapHeight & 0xFFFF); hdrbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int32)hdr)); compress.Write(hdrbuf, 0, hdrbuf.Length); checkSum = Adler32.ComputeChecksum(checkSum, hdrbuf, 0, hdrbuf.Length); hdr = ((UInt32)Program.maskX << 16) + ((UInt32)Program.maskY & 0xFFFF); hdrbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int32)hdr)); compress.Write(hdrbuf, 0, hdrbuf.Length); checkSum = Adler32.ComputeChecksum(checkSum, hdrbuf, 0, hdrbuf.Length); hdr = ((UInt32)Program.maskWidth << 16) + ((UInt32)Program.maskHeight & 0xFFFF); hdrbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int32)hdr)); compress.Write(hdrbuf, 0, hdrbuf.Length); checkSum = Adler32.ComputeChecksum(checkSum, hdrbuf, 0, hdrbuf.Length); hdr = ((UInt32)x << 16) + ((UInt32)y & 0xFFFF); hdrbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int32)hdr)); compress.Write(hdrbuf, 0, hdrbuf.Length); checkSum = Adler32.ComputeChecksum(checkSum, hdrbuf, 0, hdrbuf.Length); hdr = ((UInt32)w << 16) + ((UInt32)h & 0xFFFF); hdrbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int32)hdr)); compress.Write(hdrbuf, 0, hdrbuf.Length); checkSum = Adler32.ComputeChecksum(checkSum, hdrbuf, 0, hdrbuf.Length); /* #if USE_BITMAP_COMPRESS byte[] bm = new byte[buf.Length / 4]; byte[] dt = new byte[buf.Length]; int bi = 0, di = 0; for (int i = 0; i < buf.Length; i += sizeof(UInt32)) if (buf.buf[i + 3] == 0) bm[bi++] = 0x00; else { bm[bi++] = 0xFF; dt[di++] = buf.buf[i]; dt[di++] = buf.buf[i + 1]; dt[di++] = buf.buf[i + 2]; } compress.Write(bm, 0, bi); compress.Write(dt, 0, di); #else compress.Write(buf.buf, 0, buf.Length); #endif */ compress.Write(buf.buf, 0, buf.Length); } byte[] compHdr = new byte[] { 0x58, 0x85 }; byte[] compData = outbuf.ToArray(); checkSum = Adler32.ComputeChecksum(checkSum, buf.buf, 0, buf.Length); int ncheckSum = IPAddress.HostToNetworkOrder(checkSum); // byte[] compCheckSum = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(ncheckSum)); byte[] compCheckSum = BitConverter.GetBytes(ncheckSum); hdr = (UInt32)(compHdr.Length + compData.Length + compCheckSum.Length); hdrbuf = BitConverter.GetBytes(hdr); // Trace.WriteLine("Size: " + (compData.Length)); // buf.Dispose(); // Trying to reduce the memory footprint // GC.Collect(0, GCCollectionMode.Optimized); // GC.Collect(0, GCCollectionMode.Forced); #if SHOW_STATS if (DateTime.Now.Second != parent.prevSec) { parent.prevSec = DateTime.Now.Second; Trace.WriteLine("DEBUG: Mbps - " + (parent.dataBytes * 8) / 1000000); parent.dataBytes = 0; } parent.dataBytes += (hdrbuf.Length + compHdr.Length + compData.Length + compCheckSum.Length); #endif try { this.proceedToSend.WaitOne(); // Wait till I am told to proceed to send // this.proceedToSend.Dispose(); // I no longer need this trigger. Dispose now rather than wait for Dispose() lock (events.SyncRoot) { // Reuse events.Add(proceedToSend); proceedToSend = null; } } catch (Exception e) { MessageBox.Show(e.StackTrace); Environment.Exit(1); } if (this.newStream == null) { #if !SHOW_STATS // Deleting inplace causes invalid invocation exception because it is inside the enumerator ArrayList failures = new ArrayList(); foreach (System.Net.Sockets.NetworkStream clnt in parent.clients) { try { clnt.Write(hdrbuf, 0, hdrbuf.Length); clnt.Write(compHdr, 0, compHdr.Length); clnt.Write(compData, 0, compData.Length); clnt.Write(compCheckSum, 0, compCheckSum.Length); } catch (IOException ioe) { Trace.WriteLine("TIMEOUT : " + ioe.Message); // Could've been a timeout of could've been an actual error clnt.Close(); failures.Add(clnt); } } if (failures.Count > 0) { foreach (System.Net.Sockets.NetworkStream clnt in failures) { parent.clients.Remove(clnt); } } #endif } else { if (parent.clients.Count == 0) // Its been a while parent._mirror.fillScreen(); parent.clients.Add(this.newStream); try { this.newStream.Write(hdrbuf, 0, hdrbuf.Length); this.newStream.Write(compHdr, 0, compHdr.Length); this.newStream.Write(compData, 0, compData.Length); this.newStream.Write(compCheckSum, 0, compCheckSum.Length); } catch (IOException) { this.newStream.Close(); parent.clients.Remove(this.newStream); } } buf.Dispose(); buf = null; try { parent.proceedToNext.Set(); } catch (Exception e) { MessageBox.Show(e.StackTrace); Environment.Exit(1); } } }
/// <summary> /// Send updates. if newStream is not null, send to just this streams, otherwise everyone gets this update /// </summary> /// <param name="newStream"></param> /// <param name="buf"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="w"></param> /// <param name="h"></param> public sendUpdate(NetworkStream newStream, GCbuf buf, int x, int y, int w, int h) { // , int width, int height, int maskX, int maskY, int maskWidth, int maskHeight) { this.newStream = newStream; this.buf = buf; this.x = x; this.y = y; this.w = w; this.h = h; // this.width = width; // this.height = height; // this.maskX = maskX; // this.maskY = maskY; // this.maskWidth = maskWidth; // this.maskHeight = maskHeight; }