Home | History | Annotate | Download | only in libvncserver
      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  * zrle.c
     23  *
     24  * Routines to implement Zlib Run-length Encoding (ZRLE).
     25  */
     26 
     27 #include "rfb/rfb.h"
     28 #include "private.h"
     29 #include "zrleoutstream.h"
     30 
     31 
     32 #define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf)                                \
     33 {  char *fbptr = (cl->scaledScreen->frameBuffer                                   \
     34 		 + (cl->scaledScreen->paddedWidthInBytes * ty)                   \
     35                  + (tx * (cl->scaledScreen->bitsPerPixel / 8)));                 \
     36                                                                            \
     37   (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\
     38                      &cl->format, fbptr, (char*)buf,                       \
     39                      cl->scaledScreen->paddedWidthInBytes, tw, th); }
     40 
     41 #define EXTRA_ARGS , rfbClientPtr cl
     42 
     43 #define ENDIAN_LITTLE 0
     44 #define ENDIAN_BIG 1
     45 #define ENDIAN_NO 2
     46 #define BPP 8
     47 #define ZYWRLE_ENDIAN ENDIAN_NO
     48 #include <zrleencodetemplate.c>
     49 #undef BPP
     50 #define BPP 15
     51 #undef ZYWRLE_ENDIAN
     52 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
     53 #include <zrleencodetemplate.c>
     54 #undef ZYWRLE_ENDIAN
     55 #define ZYWRLE_ENDIAN ENDIAN_BIG
     56 #include <zrleencodetemplate.c>
     57 #undef BPP
     58 #define BPP 16
     59 #undef ZYWRLE_ENDIAN
     60 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
     61 #include <zrleencodetemplate.c>
     62 #undef ZYWRLE_ENDIAN
     63 #define ZYWRLE_ENDIAN ENDIAN_BIG
     64 #include <zrleencodetemplate.c>
     65 #undef BPP
     66 #define BPP 32
     67 #undef ZYWRLE_ENDIAN
     68 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
     69 #include <zrleencodetemplate.c>
     70 #undef ZYWRLE_ENDIAN
     71 #define ZYWRLE_ENDIAN ENDIAN_BIG
     72 #include <zrleencodetemplate.c>
     73 #define CPIXEL 24A
     74 #undef ZYWRLE_ENDIAN
     75 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
     76 #include <zrleencodetemplate.c>
     77 #undef ZYWRLE_ENDIAN
     78 #define ZYWRLE_ENDIAN ENDIAN_BIG
     79 #include <zrleencodetemplate.c>
     80 #undef CPIXEL
     81 #define CPIXEL 24B
     82 #undef ZYWRLE_ENDIAN
     83 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
     84 #include <zrleencodetemplate.c>
     85 #undef ZYWRLE_ENDIAN
     86 #define ZYWRLE_ENDIAN ENDIAN_BIG
     87 #include <zrleencodetemplate.c>
     88 #undef CPIXEL
     89 #undef BPP
     90 
     91 
     92 /*
     93  * zrleBeforeBuf contains pixel data in the client's format.  It must be at
     94  * least one pixel bigger than the largest tile of pixel data, since the
     95  * ZRLE encoding algorithm writes to the position one past the end of the pixel
     96  * data.
     97  */
     98 
     99 
    100 /*
    101  * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
    102  */
    103 
    104 rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
    105 {
    106   zrleOutStream* zos;
    107   rfbFramebufferUpdateRectHeader rect;
    108   rfbZRLEHeader hdr;
    109   int i;
    110   char *zrleBeforeBuf;
    111 
    112   if (cl->zrleBeforeBuf == NULL) {
    113 	cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4);
    114   }
    115   zrleBeforeBuf = cl->zrleBeforeBuf;
    116 
    117   if (cl->preferredEncoding == rfbEncodingZYWRLE) {
    118 	  if (cl->tightQualityLevel < 0) {
    119 		  cl->zywrleLevel = 1;
    120 	  } else if (cl->tightQualityLevel < 3) {
    121 		  cl->zywrleLevel = 3;
    122 	  } else if (cl->tightQualityLevel < 6) {
    123 		  cl->zywrleLevel = 2;
    124 	  } else {
    125 		  cl->zywrleLevel = 1;
    126 	  }
    127   } else
    128 	  cl->zywrleLevel = 0;
    129 
    130   if (!cl->zrleData)
    131     cl->zrleData = zrleOutStreamNew();
    132   zos = cl->zrleData;
    133   zos->in.ptr = zos->in.start;
    134   zos->out.ptr = zos->out.start;
    135 
    136   switch (cl->format.bitsPerPixel) {
    137 
    138   case 8:
    139     zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
    140     break;
    141 
    142   case 16:
    143 	if (cl->format.greenMax > 0x1F) {
    144 		if (cl->format.bigEndian)
    145 		  zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
    146 		else
    147 		  zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
    148 	} else {
    149 		if (cl->format.bigEndian)
    150 		  zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
    151 		else
    152 		  zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
    153 	}
    154     break;
    155 
    156   case 32: {
    157     rfbBool fitsInLS3Bytes
    158       = ((cl->format.redMax   << cl->format.redShift)   < (1<<24) &&
    159          (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
    160          (cl->format.blueMax  << cl->format.blueShift)  < (1<<24));
    161 
    162     rfbBool fitsInMS3Bytes = (cl->format.redShift   > 7  &&
    163                            cl->format.greenShift > 7  &&
    164                            cl->format.blueShift  > 7);
    165 
    166     if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
    167         (fitsInMS3Bytes && cl->format.bigEndian)) {
    168 	if (cl->format.bigEndian)
    169 		zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
    170 	else
    171 		zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
    172     }
    173     else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
    174              (fitsInMS3Bytes && !cl->format.bigEndian)) {
    175 	if (cl->format.bigEndian)
    176 		zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
    177 	else
    178 		zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
    179     }
    180     else {
    181 	if (cl->format.bigEndian)
    182 		zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
    183 	else
    184 		zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
    185     }
    186   }
    187     break;
    188   }
    189 
    190   rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
    191       + w * (cl->format.bitsPerPixel / 8) * h);
    192 
    193   if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
    194       > UPDATE_BUF_SIZE)
    195     {
    196       if (!rfbSendUpdateBuf(cl))
    197         return FALSE;
    198     }
    199 
    200   rect.r.x = Swap16IfLE(x);
    201   rect.r.y = Swap16IfLE(y);
    202   rect.r.w = Swap16IfLE(w);
    203   rect.r.h = Swap16IfLE(h);
    204   rect.encoding = Swap32IfLE(cl->preferredEncoding);
    205 
    206   memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
    207          sz_rfbFramebufferUpdateRectHeader);
    208   cl->ublen += sz_rfbFramebufferUpdateRectHeader;
    209 
    210   hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
    211 
    212   memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
    213   cl->ublen += sz_rfbZRLEHeader;
    214 
    215   /* copy into updateBuf and send from there.  Maybe should send directly? */
    216 
    217   for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
    218 
    219     int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
    220 
    221     if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
    222       bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
    223     }
    224 
    225     memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
    226 
    227     cl->ublen += bytesToCopy;
    228     i += bytesToCopy;
    229 
    230     if (cl->ublen == UPDATE_BUF_SIZE) {
    231       if (!rfbSendUpdateBuf(cl))
    232         return FALSE;
    233     }
    234   }
    235 
    236   return TRUE;
    237 }
    238 
    239 
    240 void rfbFreeZrleData(rfbClientPtr cl)
    241 {
    242 	if (cl->zrleData) {
    243 		zrleOutStreamFree(cl->zrleData);
    244 	}
    245 	cl->zrleData = NULL;
    246 
    247 	if (cl->zrleBeforeBuf) {
    248 		free(cl->zrleBeforeBuf);
    249 	}
    250 	cl->zrleBeforeBuf = NULL;
    251 
    252 	if (cl->paletteHelper) {
    253 		free(cl->paletteHelper);
    254 	}
    255 	cl->paletteHelper = NULL;
    256 }
    257 
    258