add libvncserver
[presencevnc] / libvnc / libvncserver / zrleencodetemplate.c
diff --git a/libvnc/libvncserver/zrleencodetemplate.c b/libvnc/libvncserver/zrleencodetemplate.c
new file mode 100644 (file)
index 0000000..6e81b3c
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * BPP should be 8, 16 or 32 depending on the bits per pixel.
+ * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
+ * into the given buffer.  EXTRA_ARGS can be defined to pass any other
+ * arguments needed by GET_IMAGE_INTO_BUF.
+ *
+ * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+ * bigger than the largest tile of pixel data, since the ZRLE encoding
+ * algorithm writes to the position one past the end of the pixel data.
+ */
+
+#include "zrleoutstream.h"
+#include "zrlepalettehelper.h"
+#include <assert.h>
+
+/* __RFB_CONCAT2 concatenates its two arguments.  __RFB_CONCAT2E does the same
+   but also expands its arguments if they are macros */
+
+#ifndef __RFB_CONCAT2E
+#define __RFB_CONCAT2(a,b) a##b
+#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
+#endif
+
+#ifndef __RFB_CONCAT3E
+#define __RFB_CONCAT3(a,b,c) a##b##c
+#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
+#endif
+
+#undef END_FIX
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+#  define END_FIX LE
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define END_FIX BE
+#else
+#  define END_FIX NE
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
+#define BPPOUT 24
+#elif BPP==15
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT 16
+#else
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT BPP
+#endif
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+
+static const int bitsPerPackedPixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+static zrlePaletteHelper paletteHelper;
+
+#endif /* ZRLE_ONCE */
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
+               int zywrle_level, int *zywrleBuf);
+
+#if BPP!=8
+#define ZYWRLE_ENCODE
+#include "zywrletemplate.c"
+#endif
+
+static void ZRLE_ENCODE (int x, int y, int w, int h,
+                 zrleOutStream* os, void* buf
+                  EXTRA_ARGS
+                  )
+{
+  int ty;
+  for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
+    int tx, th = rfbZRLETileHeight;
+    if (th > y+h-ty) th = y+h-ty;
+    for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
+      int tw = rfbZRLETileWidth;
+      if (tw > x+w-tx) tw = x+w-tx;
+
+      GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
+
+      ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
+                     cl->zywrleLevel, cl->zywrleBuf);
+    }
+  }
+  zrleOutStreamFlush(os);
+}
+
+
+void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
+       int zywrle_level, int *zywrleBuf)
+{
+  /* First find the palette and the number of runs */
+
+  zrlePaletteHelper *ph;
+
+  int runs = 0;
+  int singlePixels = 0;
+
+  rfbBool useRle;
+  rfbBool usePalette;
+
+  int estimatedBytes;
+  int plainRleBytes;
+  int i;
+
+  PIXEL_T* ptr = data;
+  PIXEL_T* end = ptr + h * w;
+  *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+  ph = &paletteHelper;
+  zrlePaletteHelperInit(ph);
+
+  while (ptr < end) {
+    PIXEL_T pix = *ptr;
+    if (*++ptr != pix) {
+      singlePixels++;
+    } else {
+      while (*++ptr == pix) ;
+      runs++;
+    }
+    zrlePaletteHelperInsert(ph, pix);
+  }
+
+  /* Solid tile is a special case */
+
+  if (ph->size == 1) {
+    zrleOutStreamWriteU8(os, 1);
+    zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
+    return;
+  }
+
+  /* Try to work out whether to use RLE and/or a palette.  We do this by
+     estimating the number of bytes which will be generated and picking the
+     method which results in the fewest bytes.  Of course this may not result
+     in the fewest bytes after compression... */
+
+  useRle = FALSE;
+  usePalette = FALSE;
+
+  estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
+
+#if BPP!=8
+  if (zywrle_level > 0 && !(zywrle_level & 0x80))
+         estimatedBytes >>= zywrle_level;
+#endif
+
+  plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
+
+  if (plainRleBytes < estimatedBytes) {
+    useRle = TRUE;
+    estimatedBytes = plainRleBytes;
+  }
+
+  if (ph->size < 128) {
+    int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
+
+    if (paletteRleBytes < estimatedBytes) {
+      useRle = TRUE;
+      usePalette = TRUE;
+      estimatedBytes = paletteRleBytes;
+    }
+
+    if (ph->size < 17) {
+      int packedBytes = ((BPPOUT/8) * ph->size +
+                         w * h * bitsPerPackedPixel[ph->size-1] / 8);
+
+      if (packedBytes < estimatedBytes) {
+        useRle = FALSE;
+        usePalette = TRUE;
+        estimatedBytes = packedBytes;
+      }
+    }
+  }
+
+  if (!usePalette) ph->size = 0;
+
+  zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
+
+  for (i = 0; i < ph->size; i++) {
+    zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
+  }
+
+  if (useRle) {
+
+    PIXEL_T* ptr = data;
+    PIXEL_T* end = ptr + w * h;
+    PIXEL_T* runStart;
+    PIXEL_T pix;
+    while (ptr < end) {
+      int len;
+      runStart = ptr;
+      pix = *ptr++;
+      while (*ptr == pix && ptr < end)
+        ptr++;
+      len = ptr - runStart;
+      if (len <= 2 && usePalette) {
+        int index = zrlePaletteHelperLookup(ph, pix);
+        if (len == 2)
+          zrleOutStreamWriteU8(os, index);
+        zrleOutStreamWriteU8(os, index);
+        continue;
+      }
+      if (usePalette) {
+        int index = zrlePaletteHelperLookup(ph, pix);
+        zrleOutStreamWriteU8(os, index | 128);
+      } else {
+        zrleOutStreamWRITE_PIXEL(os, pix);
+      }
+      len -= 1;
+      while (len >= 255) {
+        zrleOutStreamWriteU8(os, 255);
+        len -= 255;
+      }
+      zrleOutStreamWriteU8(os, len);
+    }
+
+  } else {
+
+    /* no RLE */
+
+    if (usePalette) {
+      int bppp;
+      PIXEL_T* ptr = data;
+
+      /* packed pixels */
+
+      assert (ph->size < 17);
+
+      bppp = bitsPerPackedPixel[ph->size-1];
+
+      for (i = 0; i < h; i++) {
+        zrle_U8 nbits = 0;
+        zrle_U8 byte = 0;
+
+        PIXEL_T* eol = ptr + w;
+
+        while (ptr < eol) {
+          PIXEL_T pix = *ptr++;
+          zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
+          byte = (byte << bppp) | index;
+          nbits += bppp;
+          if (nbits >= 8) {
+            zrleOutStreamWriteU8(os, byte);
+            nbits = 0;
+          }
+        }
+        if (nbits > 0) {
+          byte <<= 8 - nbits;
+          zrleOutStreamWriteU8(os, byte);
+        }
+      }
+    } else {
+
+      /* raw */
+
+#if BPP!=8
+      if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
+        ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
+       ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf);
+      }
+      else
+#endif
+      {
+#ifdef CPIXEL
+        PIXEL_T *ptr;
+        for (ptr = data; ptr < data+w*h; ptr++)
+          zrleOutStreamWRITE_PIXEL(os, *ptr);
+#else
+        zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
+#endif
+      }
+    }
+  }
+}
+
+#undef PIXEL_T
+#undef zrleOutStreamWRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef ZYWRLE_ENCODE_TILE
+#undef BPPOUT