PageRenderTime 38ms CodeModel.GetById 16ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/apps/desktop/libvncserver/zrleencodetemplate.c

http://ftk.googlecode.com/
C | 272 lines | 180 code | 50 blank | 42 comment | 39 complexity | ebaf4f2ca4623a128df61816512f6da1 MD5 | raw file
  1/*
  2 * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
  3 * Copyright (C) 2003 Sun Microsystems, Inc.
  4 *
  5 * This is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation; either version 2 of the License, or
  8 * (at your option) any later version.
  9 *
 10 * This software is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 * GNU General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU General Public License
 16 * along with this software; if not, write to the Free Software
 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 18 * USA.
 19 */
 20
 21/*
 22 * Before including this file, you must define a number of CPP macros.
 23 *
 24 * BPP should be 8, 16 or 32 depending on the bits per pixel.
 25 * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
 26 * into the given buffer.  EXTRA_ARGS can be defined to pass any other
 27 * arguments needed by GET_IMAGE_INTO_BUF.
 28 *
 29 * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
 30 * bigger than the largest tile of pixel data, since the ZRLE encoding
 31 * algorithm writes to the position one past the end of the pixel data.
 32 */
 33
 34#include "zrleoutstream.h"
 35#include "zrlepalettehelper.h"
 36#include <assert.h>
 37
 38/* __RFB_CONCAT2 concatenates its two arguments.  __RFB_CONCAT2E does the same
 39   but also expands its arguments if they are macros */
 40
 41#ifndef __RFB_CONCAT2E
 42#define __RFB_CONCAT2(a,b) a##b
 43#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
 44#endif
 45
 46#ifdef CPIXEL
 47#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
 48#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
 49#define ZRLE_ENCODE __RFB_CONCAT2E(zrleEncode,CPIXEL)
 50#define ZRLE_ENCODE_TILE __RFB_CONCAT2E(zrleEncodeTile,CPIXEL)
 51#define BPPOUT 24
 52#else
 53#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
 54#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
 55#define ZRLE_ENCODE __RFB_CONCAT2E(zrleEncode,BPP)
 56#define ZRLE_ENCODE_TILE __RFB_CONCAT2E(zrleEncodeTile,BPP)
 57#define BPPOUT BPP
 58#endif
 59
 60#ifndef ZRLE_ONCE
 61#define ZRLE_ONCE
 62
 63static const int bitsPerPackedPixel[] = {
 64  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
 65};
 66
 67static zrlePaletteHelper paletteHelper;
 68
 69#endif /* ZRLE_ONCE */
 70
 71void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os);
 72
 73static void ZRLE_ENCODE (int x, int y, int w, int h,
 74		  zrleOutStream* os, void* buf
 75                  EXTRA_ARGS
 76                  )
 77{
 78  int ty;
 79  for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
 80    int tx, th = rfbZRLETileHeight;
 81    if (th > y+h-ty) th = y+h-ty;
 82    for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
 83      int tw = rfbZRLETileWidth;
 84      if (tw > x+w-tx) tw = x+w-tx;
 85
 86      GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
 87
 88      ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os);
 89    }
 90  }
 91  zrleOutStreamFlush(os);
 92}
 93
 94
 95void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os)
 96{
 97  /* First find the palette and the number of runs */
 98
 99  zrlePaletteHelper *ph;
100
101  int runs = 0;
102  int singlePixels = 0;
103
104  rfbBool useRle;
105  rfbBool usePalette;
106
107  int estimatedBytes;
108  int plainRleBytes;
109  int i;
110
111  PIXEL_T* ptr = data;
112  PIXEL_T* end = ptr + h * w;
113  *end = ~*(end-1); /* one past the end is different so the while loop ends */
114
115  ph = &paletteHelper;
116  zrlePaletteHelperInit(ph);
117
118  while (ptr < end) {
119    PIXEL_T pix = *ptr;
120    if (*++ptr != pix) {
121      singlePixels++;
122    } else {
123      while (*++ptr == pix) ;
124      runs++;
125    }
126    zrlePaletteHelperInsert(ph, pix);
127  }
128
129  /* Solid tile is a special case */
130
131  if (ph->size == 1) {
132    zrleOutStreamWriteU8(os, 1);
133    zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
134    return;
135  }
136
137  /* Try to work out whether to use RLE and/or a palette.  We do this by
138     estimating the number of bytes which will be generated and picking the
139     method which results in the fewest bytes.  Of course this may not result
140     in the fewest bytes after compression... */
141
142  useRle = FALSE;
143  usePalette = FALSE;
144
145  estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
146
147  plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
148
149  if (plainRleBytes < estimatedBytes) {
150    useRle = TRUE;
151    estimatedBytes = plainRleBytes;
152  }
153
154  if (ph->size < 128) {
155    int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
156
157    if (paletteRleBytes < estimatedBytes) {
158      useRle = TRUE;
159      usePalette = TRUE;
160      estimatedBytes = paletteRleBytes;
161    }
162
163    if (ph->size < 17) {
164      int packedBytes = ((BPPOUT/8) * ph->size +
165                         w * h * bitsPerPackedPixel[ph->size-1] / 8);
166
167      if (packedBytes < estimatedBytes) {
168        useRle = FALSE;
169        usePalette = TRUE;
170        estimatedBytes = packedBytes;
171      }
172    }
173  }
174
175  if (!usePalette) ph->size = 0;
176
177  zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
178
179  for (i = 0; i < ph->size; i++) {
180    zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
181  }
182
183  if (useRle) {
184
185    PIXEL_T* ptr = data;
186    PIXEL_T* end = ptr + w * h;
187    PIXEL_T* runStart;
188    PIXEL_T pix;
189    while (ptr < end) {
190      int len;
191      runStart = ptr;
192      pix = *ptr++;
193      while (*ptr == pix && ptr < end)
194        ptr++;
195      len = ptr - runStart;
196      if (len <= 2 && usePalette) {
197        int index = zrlePaletteHelperLookup(ph, pix);
198        if (len == 2)
199          zrleOutStreamWriteU8(os, index);
200        zrleOutStreamWriteU8(os, index);
201        continue;
202      }
203      if (usePalette) {
204        int index = zrlePaletteHelperLookup(ph, pix);
205        zrleOutStreamWriteU8(os, index | 128);
206      } else {
207        zrleOutStreamWRITE_PIXEL(os, pix);
208      }
209      len -= 1;
210      while (len >= 255) {
211        zrleOutStreamWriteU8(os, 255);
212        len -= 255;
213      }
214      zrleOutStreamWriteU8(os, len);
215    }
216
217  } else {
218
219    /* no RLE */
220
221    if (usePalette) {
222      int bppp;
223      PIXEL_T* ptr = data;
224
225      /* packed pixels */
226
227      assert (ph->size < 17);
228
229      bppp = bitsPerPackedPixel[ph->size-1];
230
231      for (i = 0; i < h; i++) {
232        zrle_U8 nbits = 0;
233        zrle_U8 byte = 0;
234
235        PIXEL_T* eol = ptr + w;
236
237        while (ptr < eol) {
238          PIXEL_T pix = *ptr++;
239          zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
240          byte = (byte << bppp) | index;
241          nbits += bppp;
242          if (nbits >= 8) {
243            zrleOutStreamWriteU8(os, byte);
244            nbits = 0;
245          }
246        }
247        if (nbits > 0) {
248          byte <<= 8 - nbits;
249          zrleOutStreamWriteU8(os, byte);
250        }
251      }
252    } else {
253
254      /* raw */
255
256#ifdef CPIXEL
257      PIXEL_T *ptr;
258      for (ptr = data; ptr < data+w*h; ptr++) {
259        zrleOutStreamWRITE_PIXEL(os, *ptr);
260      }
261#else
262      zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
263#endif
264    }
265  }
266}
267
268#undef PIXEL_T
269#undef zrleOutStreamWRITE_PIXEL
270#undef ZRLE_ENCODE
271#undef ZRLE_ENCODE_TILE
272#undef BPPOUT