41 #ifdef LIBVNCSERVER_HAVE_LIBPNG 44 #include "turbojpeg.h" 48 #define TIGHT_MIN_TO_COMPRESS 12 51 #define MIN_SPLIT_RECT_SIZE 4096 52 #define MIN_SOLID_SUBRECT_SIZE 2048 53 #define MAX_SPLIT_TILE_SIZE 16 62 #elif defined(_MSC_VER) 63 #define TLS __declspec(thread) 76 typedef struct TIGHT_CONF_s {
85 { 65536, 2048, 6, 0, 0, 0, 4, 24 },
86 { 65536, 2048, 32, 1, 1, 1, 96, 24 },
87 { 65536, 2048, 32, 3, 3, 2, 96, 96 },
88 { 65536, 2048, 32, 7, 7, 5, 96, 256 }
91 #ifdef LIBVNCSERVER_HAVE_LIBPNG 92 typedef struct TIGHT_PNG_CONF_s {
93 int png_zlib_level, png_filters;
96 static TIGHT_PNG_CONF tightPngConf[10] = {
97 { 0, PNG_NO_FILTERS },
98 { 1, PNG_NO_FILTERS },
99 { 2, PNG_NO_FILTERS },
100 { 3, PNG_NO_FILTERS },
101 { 4, PNG_NO_FILTERS },
102 { 5, PNG_ALL_FILTERS },
103 { 6, PNG_ALL_FILTERS },
104 { 7, PNG_ALL_FILTERS },
105 { 8, PNG_ALL_FILTERS },
106 { 9, PNG_ALL_FILTERS },
110 static TLS int compressLevel = 1;
111 static TLS int qualityLevel = 95;
112 static TLS int subsampLevel = TJ_444;
114 static const int subsampLevel2tjsubsamp[4] = {
115 TJ_444, TJ_420, TJ_422, TJ_GRAYSCALE
121 typedef struct COLOR_LIST_s {
127 typedef struct PALETTE_ENTRY_s {
132 typedef struct PALETTE_s {
139 static TLS int paletteNumColors = 0;
140 static TLS int paletteMaxColors = 0;
141 static TLS uint32_t monoBackground = 0;
142 static TLS uint32_t monoForeground = 0;
147 static TLS int tightBeforeBufSize = 0;
148 static TLS char *tightBeforeBuf = NULL;
150 static TLS int tightAfterBufSize = 0;
151 static TLS char *tightAfterBuf = NULL;
153 static TLS tjhandle j = NULL;
157 if (tightBeforeBufSize) {
158 free (tightBeforeBuf);
159 tightBeforeBufSize = 0;
160 tightBeforeBuf = NULL;
162 if (tightAfterBufSize) {
163 free (tightAfterBuf);
164 tightAfterBufSize = 0;
165 tightAfterBuf = NULL;
177 static rfbBool SendRectEncodingTight(rfbClientPtr cl,
int x,
int y,
179 static void FindBestSolidArea (rfbClientPtr cl,
int x,
int y,
int w,
int h,
180 uint32_t colorValue,
int *w_ptr,
int *h_ptr);
181 static void ExtendSolidArea (rfbClientPtr cl,
int x,
int y,
int w,
int h,
183 int *x_ptr,
int *y_ptr,
int *w_ptr,
int *h_ptr);
184 static rfbBool CheckSolidTile (rfbClientPtr cl,
int x,
int y,
int w,
int h,
185 uint32_t *colorPtr,
rfbBool needSameColor);
186 static rfbBool CheckSolidTile8 (rfbClientPtr cl,
int x,
int y,
int w,
int h,
187 uint32_t *colorPtr,
rfbBool needSameColor);
188 static rfbBool CheckSolidTile16 (rfbClientPtr cl,
int x,
int y,
int w,
int h,
189 uint32_t *colorPtr,
rfbBool needSameColor);
190 static rfbBool CheckSolidTile32 (rfbClientPtr cl,
int x,
int y,
int w,
int h,
191 uint32_t *colorPtr,
rfbBool needSameColor);
193 static rfbBool SendRectSimple (rfbClientPtr cl,
int x,
int y,
int w,
int h);
194 static rfbBool SendSubrect (rfbClientPtr cl,
int x,
int y,
int w,
int h);
196 static rfbBool SendSolidRect (rfbClientPtr cl);
197 static rfbBool SendMonoRect (rfbClientPtr cl,
int x,
int y,
int w,
int h);
198 static rfbBool SendIndexedRect (rfbClientPtr cl,
int x,
int y,
int w,
int h);
199 static rfbBool SendFullColorRect (rfbClientPtr cl,
int x,
int y,
int w,
int h);
201 static rfbBool CompressData (rfbClientPtr cl,
int streamId,
int dataLen,
202 int zlibLevel,
int zlibStrategy);
204 static void FillPalette8 (
int count);
205 static void FillPalette16 (
int count);
206 static void FillPalette32 (
int count);
207 static void FastFillPalette16 (rfbClientPtr cl, uint16_t *data,
int w,
209 static void FastFillPalette32 (rfbClientPtr cl, uint32_t *data,
int w,
212 static void PaletteReset (
void);
213 static int PaletteInsert (uint32_t rgb,
int numPixels,
int bpp);
215 static void Pack24 (rfbClientPtr cl,
char *buf,
rfbPixelFormat *fmt,
218 static void EncodeIndexedRect16 (uint8_t *buf,
int count);
219 static void EncodeIndexedRect32 (uint8_t *buf,
int count);
221 static void EncodeMonoRect8 (uint8_t *buf,
int w,
int h);
222 static void EncodeMonoRect16 (uint8_t *buf,
int w,
int h);
223 static void EncodeMonoRect32 (uint8_t *buf,
int w,
int h);
225 static rfbBool SendJpegRect (rfbClientPtr cl,
int x,
int y,
int w,
int h,
227 static void PrepareRowForImg(rfbClientPtr cl, uint8_t *dst,
int x,
int y,
int count);
228 static void PrepareRowForImg24(rfbClientPtr cl, uint8_t *dst,
int x,
int y,
int count);
229 static void PrepareRowForImg16(rfbClientPtr cl, uint8_t *dst,
int x,
int y,
int count);
230 static void PrepareRowForImg32(rfbClientPtr cl, uint8_t *dst,
int x,
int y,
int count);
232 #ifdef LIBVNCSERVER_HAVE_LIBPNG 233 static rfbBool SendPngRect(rfbClientPtr cl,
int x,
int y,
int w,
int h);
234 static rfbBool CanSendPngRect(rfbClientPtr cl,
int w,
int h);
248 int maxRectSize, maxRectWidth;
249 int subrectMaxWidth, subrectMaxHeight;
256 maxRectSize = tightConf[compressLevel].
maxRectSize;
259 if (w > maxRectWidth || w * h > maxRectSize) {
260 subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
261 subrectMaxHeight = maxRectSize / subrectMaxWidth;
262 return (((w - 1) / maxRectWidth + 1) *
263 ((h - 1) / subrectMaxHeight + 1));
277 return SendRectEncodingTight(cl, x, y, w, h);
288 return SendRectEncodingTight(cl, x, y, w, h);
293 SendRectEncodingTight(rfbClientPtr cl,
302 int x_best, y_best, w_best, h_best;
307 compressLevel = cl->tightCompressLevel;
308 qualityLevel = cl->turboQualityLevel;
309 subsampLevel = cl->turboSubsampLevel;
320 if (qualityLevel != -1) {
321 if (compressLevel < 1) compressLevel = 1;
322 if (compressLevel > 2) compressLevel = 2;
327 else if (compressLevel > 1) compressLevel = 1;
335 if (cl->tightCompressLevel == 9) compressLevel = 3;
337 if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
338 cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
339 usePixelFormat24 =
TRUE;
341 usePixelFormat24 =
FALSE;
345 return SendRectSimple(cl,
x,
y, w, h);
349 if (!tightBeforeBuf || tightBeforeBufSize < 4) {
350 if (tightBeforeBuf == NULL)
351 tightBeforeBuf = (
char *)malloc(4);
353 char *reallocedBeforeEncBuf = (
char *)realloc(tightBeforeBuf, 4);
354 if (!reallocedBeforeEncBuf)
return FALSE;
355 tightBeforeBuf = reallocedBeforeEncBuf;
359 rfbLog(
"SendRectEncodingTight: failed to allocate memory\n");
362 tightBeforeBufSize = 4;
368 int maxRectSize, maxRectWidth, nMaxWidth;
370 maxRectSize = tightConf[compressLevel].
maxRectSize;
372 nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
373 nMaxRows = maxRectSize / nMaxWidth;
382 if (dy -
y >= nMaxRows) {
383 if (!SendRectSimple(cl,
x,
y, w, nMaxRows))
390 MAX_SPLIT_TILE_SIZE : (
y + h - dy);
394 dw = (dx + MAX_SPLIT_TILE_SIZE <=
x + w) ?
395 MAX_SPLIT_TILE_SIZE : (
x + w - dx);
397 if (CheckSolidTile(cl, dx, dy, dw, dh, &colorValue,
FALSE)) {
399 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) {
400 uint32_t r = (colorValue >> 16) & 0xFF;
401 uint32_t g = (colorValue >> 8) & 0xFF;
402 uint32_t b = (colorValue) & 0xFF;
403 double y = (0.257 * (double)r) + (0.504 * (double)g)
404 + (0.098 * (double)b) + 16.;
405 colorValue = (int)y + (((
int)
y) << 8) + (((int)y) << 16);
410 FindBestSolidArea(cl, dx, dy, w - (dx -
x), h - (dy -
y),
411 colorValue, &w_best, &h_best);
416 if ( w_best * h_best != w * h &&
422 x_best = dx; y_best = dy;
423 ExtendSolidArea(cl,
x,
y, w, h, colorValue,
424 &x_best, &y_best, &w_best, &h_best);
429 !SendRectSimple(cl,
x,
y, w, y_best-
y) )
432 !SendRectEncodingTight(cl,
x, y_best,
441 fbptr = (cl->scaledScreen->frameBuffer +
442 (cl->scaledScreen->paddedWidthInBytes * y_best) +
443 (x_best * (cl->scaledScreen->bitsPerPixel / 8)));
445 (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
446 &cl->format, fbptr, tightBeforeBuf,
447 cl->scaledScreen->paddedWidthInBytes, 1, 1);
449 if (!SendSolidRect(cl))
454 if ( x_best + w_best !=
x + w &&
455 !SendRectEncodingTight(cl, x_best + w_best, y_best,
456 w - (x_best-
x) - w_best, h_best) )
458 if ( y_best + h_best !=
y + h &&
459 !SendRectEncodingTight(cl,
x, y_best + h_best,
460 w, h - (y_best-
y) - h_best) )
474 return SendRectSimple(cl,
x,
y, w, h);
479 FindBestSolidArea(rfbClientPtr cl,
490 int w_best = 0, h_best = 0;
497 MAX_SPLIT_TILE_SIZE : (
y + h - dy);
499 MAX_SPLIT_TILE_SIZE : w_prev;
501 if (!CheckSolidTile(cl,
x, dy, dw, dh, &colorValue,
TRUE))
504 for (dx =
x + dw; dx <
x + w_prev;) {
505 dw = (dx + MAX_SPLIT_TILE_SIZE <=
x + w_prev) ?
506 MAX_SPLIT_TILE_SIZE : (
x + w_prev - dx);
507 if (!CheckSolidTile(cl, dx, dy, dw, dh, &colorValue,
TRUE))
513 if (w_prev * (dy + dh -
y) > w_best * h_best) {
515 h_best = dy + dh -
y;
525 ExtendSolidArea(rfbClientPtr cl,
539 for ( cy = *y_ptr - 1;
540 cy >=
y && CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue,
TRUE);
542 *h_ptr += *y_ptr - (cy + 1);
546 for ( cy = *y_ptr + *h_ptr;
548 CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue,
TRUE);
550 *h_ptr += cy - (*y_ptr + *h_ptr);
553 for ( cx = *x_ptr - 1;
554 cx >=
x && CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue,
TRUE);
556 *w_ptr += *x_ptr - (cx + 1);
560 for ( cx = *x_ptr + *w_ptr;
562 CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue,
TRUE);
564 *w_ptr += cx - (*x_ptr + *w_ptr);
575 static rfbBool CheckSolidTile(rfbClientPtr cl,
int x,
int y,
int w,
int h, uint32_t* colorPtr,
rfbBool needSameColor)
577 switch(cl->screen->serverFormat.bitsPerPixel) {
579 return CheckSolidTile32(cl,
x,
y, w, h, colorPtr, needSameColor);
581 return CheckSolidTile16(cl,
x,
y, w, h, colorPtr, needSameColor);
583 return CheckSolidTile8(cl,
x,
y, w, h, colorPtr, needSameColor);
588 #define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ 591 CheckSolidTile##bpp(rfbClientPtr cl, int x, int y, int w, int h, \ 592 uint32_t* colorPtr, rfbBool needSameColor) \ 594 uint##bpp##_t *fbptr; \ 595 uint##bpp##_t colorValue; \ 598 fbptr = (uint##bpp##_t *)&cl->scaledScreen->frameBuffer \ 599 [y * cl->scaledScreen->paddedWidthInBytes + x * (bpp/8)]; \ 601 colorValue = *fbptr; \ 602 if (needSameColor && (uint32_t)colorValue != *colorPtr) \ 605 for (dy = 0; dy < h; dy++) { \ 606 for (dx = 0; dx < w; dx++) { \ 607 if (colorValue != fbptr[dx]) \ 610 fbptr = (uint##bpp##_t *)((uint8_t *)fbptr \ 611 + cl->scaledScreen->paddedWidthInBytes); \ 614 *colorPtr = (uint32_t)colorValue; \ 623 SendRectSimple(rfbClientPtr cl,
int x,
int y,
int w,
int h)
625 int maxBeforeSize, maxAfterSize;
626 int maxRectSize, maxRectWidth;
627 int subrectMaxWidth, subrectMaxHeight;
631 maxRectSize = tightConf[compressLevel].
maxRectSize;
634 maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
635 maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
637 if (!tightBeforeBuf || tightBeforeBufSize < maxBeforeSize) {
638 if (tightBeforeBuf == NULL)
639 tightBeforeBuf = (
char *)malloc(maxBeforeSize);
641 char *reallocedBeforeEncBuf = (
char *)realloc(tightBeforeBuf, maxBeforeSize);
642 if (!reallocedBeforeEncBuf)
return FALSE;
643 tightBeforeBuf = reallocedBeforeEncBuf;
646 tightBeforeBufSize = maxBeforeSize;
649 if (!tightAfterBuf || tightAfterBufSize < maxAfterSize) {
650 if (tightAfterBuf == NULL)
651 tightAfterBuf = (
char *)malloc(maxAfterSize);
653 char *reallocedAfterEncBuf = (
char *)realloc(tightAfterBuf, maxAfterSize);
654 if (!reallocedAfterEncBuf)
return FALSE;
655 tightAfterBuf = reallocedAfterEncBuf;
658 tightAfterBufSize = maxAfterSize;
661 if (!tightBeforeBuf || !tightAfterBuf)
663 rfbLog(
"SendRectSimple: failed to allocate memory\n");
667 if (w > maxRectWidth || w * h > maxRectSize) {
668 subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
669 subrectMaxHeight = maxRectSize / subrectMaxWidth;
671 for (dy = 0; dy < h; dy += subrectMaxHeight) {
672 for (dx = 0; dx < w; dx += maxRectWidth) {
673 rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
674 rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
675 if (!SendSubrect(cl, x + dx, y + dy, rw, rh))
680 if (!SendSubrect(cl, x, y, w, h))
688 SendSubrect(rfbClientPtr cl,
698 if (cl->ublen > 128) {
706 fbptr = (cl->scaledScreen->frameBuffer
707 + (cl->scaledScreen->paddedWidthInBytes *
y)
708 + (
x * (cl->scaledScreen->bitsPerPixel / 8)));
710 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1)
711 return SendJpegRect(cl,
x,
y, w, h, qualityLevel);
714 if(qualityLevel != -1)
716 if ( paletteMaxColors < 2 &&
717 w * h >= tightConf[compressLevel].monoMinRectSize ) {
718 paletteMaxColors = 2;
721 if (cl->format.bitsPerPixel == cl->screen->serverFormat.bitsPerPixel &&
722 cl->format.redMax == cl->screen->serverFormat.redMax &&
723 cl->format.greenMax == cl->screen->serverFormat.greenMax &&
724 cl->format.blueMax == cl->screen->serverFormat.blueMax &&
725 cl->format.bitsPerPixel >= 16) {
729 switch (cl->format.bitsPerPixel) {
731 FastFillPalette16(cl, (uint16_t *)fbptr, w,
732 cl->scaledScreen->paddedWidthInBytes / 2, h);
735 FastFillPalette32(cl, (uint32_t *)fbptr, w,
736 cl->scaledScreen->paddedWidthInBytes / 4, h);
739 if(paletteNumColors != 0 || qualityLevel == -1) {
740 (*cl->translateFn)(cl->translateLookupTable,
741 &cl->screen->serverFormat, &cl->format, fbptr,
743 cl->scaledScreen->paddedWidthInBytes, w, h);
747 (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
748 &cl->format, fbptr, tightBeforeBuf,
749 cl->scaledScreen->paddedWidthInBytes, w, h);
751 switch (cl->format.bitsPerPixel) {
756 FillPalette16(w * h);
759 FillPalette32(w * h);
763 switch (paletteNumColors) {
766 if (qualityLevel != -1) {
767 success = SendJpegRect(cl,
x,
y, w, h, qualityLevel);
769 success = SendFullColorRect(cl,
x,
y, w, h);
774 success = SendSolidRect(cl);
778 success = SendMonoRect(cl,
x,
y, w, h);
782 success = SendIndexedRect(cl,
x,
y, w, h);
807 memcpy(&cl->updateBuf[cl->ublen], (
char *)&rect,
814 + w * (cl->format.bitsPerPixel / 8) * h);
824 SendSolidRect(rfbClientPtr cl)
828 if (usePixelFormat24) {
829 Pack24(cl, tightBeforeBuf, &cl->format, 1);
832 len = cl->format.bitsPerPixel / 8;
839 cl->updateBuf[cl->ublen++] = (char)(rfbTightFill << 4);
840 memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
849 SendMonoRect(rfbClientPtr cl,
856 int paletteLen, dataLen;
858 #ifdef LIBVNCSERVER_HAVE_LIBPNG 859 if (CanSendPngRect(cl, w, h)) {
861 return SendPngRect(cl,
x,
y, w, h);
873 dataLen = (w + 7) / 8;
876 if (tightConf[compressLevel].monoZlibLevel == 0 &&
878 cl->updateBuf[cl->ublen++] =
879 (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
881 cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
882 cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
883 cl->updateBuf[cl->ublen++] = 1;
886 switch (cl->format.bitsPerPixel) {
889 EncodeMonoRect32((uint8_t *)tightBeforeBuf, w, h);
891 ((uint32_t *)tightAfterBuf)[0] = monoBackground;
892 ((uint32_t *)tightAfterBuf)[1] = monoForeground;
893 if (usePixelFormat24) {
894 Pack24(cl, tightAfterBuf, &cl->format, 2);
899 memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
900 cl->ublen += paletteLen;
905 EncodeMonoRect16((uint8_t *)tightBeforeBuf, w, h);
907 ((uint16_t *)tightAfterBuf)[0] = (uint16_t)monoBackground;
908 ((uint16_t *)tightAfterBuf)[1] = (uint16_t)monoForeground;
910 memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
916 EncodeMonoRect8((uint8_t *)tightBeforeBuf, w, h);
918 cl->updateBuf[cl->ublen++] = (char)monoBackground;
919 cl->updateBuf[cl->ublen++] = (char)monoForeground;
923 return CompressData(cl, streamId, dataLen,
924 tightConf[compressLevel].monoZlibLevel,
929 SendIndexedRect(rfbClientPtr cl,
938 #ifdef LIBVNCSERVER_HAVE_LIBPNG 939 if (CanSendPngRect(cl, w, h)) {
940 return SendPngRect(cl,
x,
y, w, h);
945 paletteNumColors * cl->format.bitsPerPixel / 8 >
952 if (tightConf[compressLevel].idxZlibLevel == 0 &&
954 cl->updateBuf[cl->ublen++] =
955 (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
957 cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
958 cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
959 cl->updateBuf[cl->ublen++] = (char)(paletteNumColors - 1);
962 switch (cl->format.bitsPerPixel) {
965 EncodeIndexedRect32((uint8_t *)tightBeforeBuf, w * h);
967 for (i = 0; i < paletteNumColors; i++) {
968 ((uint32_t *)tightAfterBuf)[i] =
971 if (usePixelFormat24) {
972 Pack24(cl, tightAfterBuf, &cl->format, paletteNumColors);
977 memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf,
978 paletteNumColors * entryLen);
979 cl->ublen += paletteNumColors * entryLen;
981 3 + paletteNumColors * entryLen);
985 EncodeIndexedRect16((uint8_t *)tightBeforeBuf, w * h);
987 for (i = 0; i < paletteNumColors; i++) {
988 ((uint16_t *)tightAfterBuf)[i] =
992 memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
993 cl->ublen += paletteNumColors * 2;
995 3 + paletteNumColors * 2);
1002 return CompressData(cl, streamId, w * h,
1003 tightConf[compressLevel].idxZlibLevel,
1004 Z_DEFAULT_STRATEGY);
1008 SendFullColorRect(rfbClientPtr cl,
1017 #ifdef LIBVNCSERVER_HAVE_LIBPNG 1018 if (CanSendPngRect(cl, w, h)) {
1019 return SendPngRect(cl,
x,
y, w, h);
1028 if (tightConf[compressLevel].rawZlibLevel == 0 &&
1030 cl->updateBuf[cl->ublen++] = (char)(rfbTightNoZlib << 4);
1032 cl->updateBuf[cl->ublen++] = 0x00;
1035 if (usePixelFormat24) {
1036 Pack24(cl, tightBeforeBuf, &cl->format, w * h);
1039 len = cl->format.bitsPerPixel / 8;
1041 return CompressData(cl, streamId, w * h * len,
1042 tightConf[compressLevel].rawZlibLevel,
1043 Z_DEFAULT_STRATEGY);
1047 CompressData(rfbClientPtr cl,
1057 memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
1058 cl->ublen += dataLen;
1066 pz = &cl->zsStruct[streamId];
1069 if (!cl->zsActive[streamId]) {
1070 pz->zalloc = Z_NULL;
1072 pz->opaque = Z_NULL;
1074 err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
1075 MAX_MEM_LEVEL, zlibStrategy);
1079 cl->zsActive[streamId] =
TRUE;
1080 cl->zsLevel[streamId] = zlibLevel;
1084 pz->next_in = (Bytef *)tightBeforeBuf;
1085 pz->avail_in = dataLen;
1086 pz->next_out = (Bytef *)tightAfterBuf;
1087 pz->avail_out = tightAfterBufSize;
1090 if (zlibLevel != cl->zsLevel[streamId]) {
1091 if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
1094 cl->zsLevel[streamId] = zlibLevel;
1098 if (deflate(pz, Z_SYNC_FLUSH) != Z_OK ||
1099 pz->avail_in != 0 || pz->avail_out == 0) {
1104 tightAfterBufSize - pz->avail_out);
1112 cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
1114 if (compressedLen > 0x7F) {
1115 cl->updateBuf[cl->ublen-1] |= 0x80;
1116 cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
1118 if (compressedLen > 0x3FFF) {
1119 cl->updateBuf[cl->ublen-1] |= 0x80;
1120 cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
1126 for (i = 0; i < compressedLen; i += portionLen) {
1127 if (i + portionLen > compressedLen) {
1128 portionLen = compressedLen - i;
1134 memcpy(&cl->updateBuf[cl->ublen], &buf[i], portionLen);
1135 cl->ublen += portionLen;
1148 FillPalette8(
int count)
1150 uint8_t *data = (uint8_t *)tightBeforeBuf;
1154 paletteNumColors = 0;
1157 for (i = 1; i < count && data[i] == c0; i++);
1159 paletteNumColors = 1;
1163 if (paletteMaxColors < 2)
1169 for (i++; i < count; i++) {
1170 if (data[i] == c0) {
1172 }
else if (data[i] == c1) {
1179 monoBackground = (uint32_t)c0;
1180 monoForeground = (uint32_t)c1;
1182 monoBackground = (uint32_t)c1;
1183 monoForeground = (uint32_t)c0;
1185 paletteNumColors = 2;
1190 #define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ 1193 FillPalette##bpp(int count) { \ 1194 uint##bpp##_t *data = (uint##bpp##_t *)tightBeforeBuf; \ 1195 uint##bpp##_t c0, c1, ci; \ 1196 int i, n0, n1, ni; \ 1199 for (i = 1; i < count && data[i] == c0; i++); \ 1201 paletteNumColors = 1; \ 1205 if (paletteMaxColors < 2) { \ 1206 paletteNumColors = 0; \ 1213 for (i++; i < count; i++) { \ 1217 } else if (ci == c1) { \ 1224 monoBackground = (uint32_t)c0; \ 1225 monoForeground = (uint32_t)c1; \ 1227 monoBackground = (uint32_t)c1; \ 1228 monoForeground = (uint32_t)c0; \ 1230 paletteNumColors = 2; \ 1235 PaletteInsert (c0, (uint32_t)n0, bpp); \ 1236 PaletteInsert (c1, (uint32_t)n1, bpp); \ 1239 for (i++; i < count; i++) { \ 1240 if (data[i] == ci) { \ 1243 if (!PaletteInsert (ci, (uint32_t)ni, bpp)) \ 1249 PaletteInsert (ci, (uint32_t)ni, bpp); \ 1255 #define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp) \ 1258 FastFillPalette##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, \ 1261 uint##bpp##_t c0, c1, ci, mask, c0t, c1t, cit; \ 1262 int i, j, i2 = 0, j2, n0, n1, ni; \ 1264 if (cl->translateFn != rfbTranslateNone) { \ 1265 mask = cl->screen->serverFormat.redMax \ 1266 << cl->screen->serverFormat.redShift; \ 1267 mask |= cl->screen->serverFormat.greenMax \ 1268 << cl->screen->serverFormat.greenShift; \ 1269 mask |= cl->screen->serverFormat.blueMax \ 1270 << cl->screen->serverFormat.blueShift; \ 1273 c0 = data[0] & mask; \ 1274 for (j = 0; j < h; j++) { \ 1275 for (i = 0; i < w; i++) { \ 1276 if ((data[j * pitch + i] & mask) != c0) \ 1282 paletteNumColors = 1; \ 1285 if (paletteMaxColors < 2) { \ 1286 paletteNumColors = 0; \ 1291 c1 = data[j * pitch + i] & mask; \ 1293 i++; if (i >= w) {i = 0; j++;} \ 1294 for (j2 = j; j2 < h; j2++) { \ 1295 for (i2 = i; i2 < w; i2++) { \ 1296 ci = data[j2 * pitch + i2] & mask; \ 1299 } else if (ci == c1) { \ 1307 (*cl->translateFn)(cl->translateLookupTable, \ 1308 &cl->screen->serverFormat, &cl->format, \ 1309 (char *)&c0, (char *)&c0t, bpp/8, 1, 1); \ 1310 (*cl->translateFn)(cl->translateLookupTable, \ 1311 &cl->screen->serverFormat, &cl->format, \ 1312 (char *)&c1, (char *)&c1t, bpp/8, 1, 1); \ 1315 monoBackground = (uint32_t)c0t; \ 1316 monoForeground = (uint32_t)c1t; \ 1318 monoBackground = (uint32_t)c1t; \ 1319 monoForeground = (uint32_t)c0t; \ 1321 paletteNumColors = 2; \ 1326 PaletteInsert (c0t, (uint32_t)n0, bpp); \ 1327 PaletteInsert (c1t, (uint32_t)n1, bpp); \ 1330 i2++; if (i2 >= w) {i2 = 0; j2++;} \ 1331 for (j = j2; j < h; j++) { \ 1332 for (i = i2; i < w; i++) { \ 1333 if ((data[j * pitch + i] & mask) == ci) { \ 1336 (*cl->translateFn)(cl->translateLookupTable, \ 1337 &cl->screen->serverFormat, \ 1338 &cl->format, (char *)&ci, \ 1339 (char *)&cit, bpp/8, 1, 1); \ 1340 if (!PaletteInsert (cit, (uint32_t)ni, bpp)) \ 1342 ci = data[j * pitch + i] & mask; \ 1349 (*cl->translateFn)(cl->translateLookupTable, \ 1350 &cl->screen->serverFormat, &cl->format, \ 1351 (char *)&ci, (char *)&cit, bpp/8, 1, 1); \ 1352 PaletteInsert (cit, (uint32_t)ni, bpp); \ 1363 #define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF)) 1364 #define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF)) 1370 paletteNumColors = 0;
1376 PaletteInsert(uint32_t rgb,
1382 int hash_key, idx, new_idx, count;
1386 pnode = palette.
hash[hash_key];
1388 while (pnode != NULL) {
1389 if (pnode->
rgb == rgb) {
1391 new_idx = idx = pnode->
idx;
1395 palette.
entry[new_idx] = palette.
entry[new_idx-1];
1401 pnode->
idx = new_idx;
1404 return paletteNumColors;
1407 pnode = pnode->
next;
1411 if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
1412 paletteNumColors = 0;
1417 for ( idx = paletteNumColors;
1425 pnode = &palette.
list[paletteNumColors];
1426 if (prev_pnode != NULL) {
1427 prev_pnode->
next = pnode;
1429 palette.
hash[hash_key] = pnode;
1437 return (++paletteNumColors);
1447 static void Pack24(rfbClientPtr cl,
1454 int r_shift, g_shift, b_shift;
1456 buf32 = (uint32_t *)buf;
1458 if (!cl->screen->serverFormat.bigEndian == !fmt->
bigEndian) {
1470 *buf++ = (char)(pix >> r_shift);
1471 *buf++ = (char)(pix >> g_shift);
1472 *buf++ = (char)(pix >> b_shift);
1481 #define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ 1484 EncodeIndexedRect##bpp(uint8_t *buf, int count) { \ 1485 COLOR_LIST *pnode; \ 1486 uint##bpp##_t *src; \ 1487 uint##bpp##_t rgb; \ 1490 src = (uint##bpp##_t *) buf; \ 1494 while (count && *src == rgb) { \ 1495 rep++, src++, count--; \ 1497 pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \ 1498 while (pnode != NULL) { \ 1499 if ((uint##bpp##_t)pnode->rgb == rgb) { \ 1500 *buf++ = (uint8_t)pnode->idx; \ 1502 *buf++ = (uint8_t)pnode->idx; \ 1507 pnode = pnode->next; \ 1516 #define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ 1519 EncodeMonoRect##bpp(uint8_t *buf, int w, int h) { \ 1520 uint##bpp##_t *ptr; \ 1522 unsigned int value, mask; \ 1523 int aligned_width; \ 1524 int x, y, bg_bits; \ 1526 ptr = (uint##bpp##_t *) buf; \ 1527 bg = (uint##bpp##_t) monoBackground; \ 1528 aligned_width = w - w % 8; \ 1530 for (y = 0; y < h; y++) { \ 1531 for (x = 0; x < aligned_width; x += 8) { \ 1532 for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ 1536 if (bg_bits == 8) { \ 1540 mask = 0x80 >> bg_bits; \ 1542 for (bg_bits++; bg_bits < 8; bg_bits++) { \ 1544 if (*ptr++ != bg) { \ 1548 *buf++ = (uint8_t)value; \ 1556 for (; x < w; x++) { \ 1557 if (*ptr++ != bg) { \ 1562 *buf++ = (uint8_t)value; \ 1576 SendJpegRect(rfbClientPtr cl,
int x,
int y,
int w,
int h,
int quality)
1578 unsigned char *srcbuf;
1579 int ps = cl->screen->serverFormat.bitsPerPixel / 8;
1580 int subsamp = subsampLevel2tjsubsamp[subsampLevel];
1581 unsigned long size = 0;
1582 int flags = 0, pitch;
1583 unsigned char *tmpbuf = NULL;
1585 if (cl->screen->serverFormat.bitsPerPixel == 8)
1586 return SendFullColorRect(cl, x, y, w, h);
1589 rfbLog(
"Error: JPEG requires 16-bit, 24-bit, or 32-bit pixel format.\n");
1593 if ((j = tjInitCompress()) == NULL) {
1594 rfbLog(
"JPEG Error: %s\n", tjGetErrorStr());
1599 if (!tightAfterBuf || tightAfterBufSize < TJBUFSIZE(w, h)) {
1600 if (tightAfterBuf == NULL)
1601 tightAfterBuf = (
char *)malloc(TJBUFSIZE(w, h));
1603 char *reallocedAfterEncBuf = (
char *)realloc(tightAfterBuf, TJBUFSIZE(w, h));
1604 if (!reallocedAfterEncBuf)
return FALSE;
1605 tightAfterBuf = reallocedAfterEncBuf;
1609 rfbLog(
"SendJpegRect: failed to allocate memory\n");
1612 tightAfterBufSize = TJBUFSIZE(w, h);
1616 uint16_t *srcptr, pix;
1618 int inRed, inGreen, inBlue, i, j;
1620 if((tmpbuf = (
unsigned char *)malloc(w * h * 3)) == NULL)
1621 rfbLog(
"Memory allocation failure!\n");
1622 srcptr = (uint16_t *)&cl->scaledScreen->frameBuffer
1623 [y * cl->scaledScreen->paddedWidthInBytes + x * ps];
1625 for(j = 0; j < h; j++) {
1626 uint16_t *srcptr2 = srcptr;
1627 unsigned char *dst2 = dst;
1628 for (i = 0; i < w; i++) {
1630 inRed = (int) (pix >> cl->screen->serverFormat.redShift
1631 & cl->screen->serverFormat.redMax);
1632 inGreen = (int) (pix >> cl->screen->serverFormat.greenShift
1633 & cl->screen->serverFormat.greenMax);
1634 inBlue = (int) (pix >> cl->screen->serverFormat.blueShift
1635 & cl->screen->serverFormat.blueMax);
1636 *dst2++ = (uint8_t)((inRed * 255
1637 + cl->screen->serverFormat.redMax / 2)
1638 / cl->screen->serverFormat.redMax);
1639 *dst2++ = (uint8_t)((inGreen * 255
1640 + cl->screen->serverFormat.greenMax / 2)
1641 / cl->screen->serverFormat.greenMax);
1642 *dst2++ = (uint8_t)((inBlue * 255
1643 + cl->screen->serverFormat.blueMax / 2)
1644 / cl->screen->serverFormat.blueMax);
1646 srcptr += cl->scaledScreen->paddedWidthInBytes / ps;
1653 if (cl->screen->serverFormat.bigEndian && ps == 4)
1654 flags |= TJ_ALPHAFIRST;
1655 if (cl->screen->serverFormat.redShift == 16
1656 && cl->screen->serverFormat.blueShift == 0)
1658 if (cl->screen->serverFormat.bigEndian)
1660 pitch = cl->scaledScreen->paddedWidthInBytes;
1661 srcbuf = (
unsigned char *)&cl->scaledScreen->frameBuffer
1662 [y * pitch + x * ps];
1665 if (tjCompress(j, srcbuf, w, pitch, h, ps, (
unsigned char *)tightAfterBuf,
1666 &size, subsamp, quality, flags) == -1) {
1667 rfbLog(
"JPEG Error: %s\n", tjGetErrorStr());
1685 cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
1692 PrepareRowForImg(rfbClientPtr cl,
1698 if (cl->screen->serverFormat.bitsPerPixel == 32) {
1699 if ( cl->screen->serverFormat.redMax == 0xFF &&
1700 cl->screen->serverFormat.greenMax == 0xFF &&
1701 cl->screen->serverFormat.blueMax == 0xFF ) {
1702 PrepareRowForImg24(cl, dst, x, y, count);
1704 PrepareRowForImg32(cl, dst, x, y, count);
1708 PrepareRowForImg16(cl, dst, x, y, count);
1713 PrepareRowForImg24(rfbClientPtr cl,
1722 fbptr = (uint32_t *)
1723 &cl->scaledScreen->frameBuffer[y * cl->scaledScreen->paddedWidthInBytes + x * 4];
1727 *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.redShift);
1728 *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.greenShift);
1729 *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.blueShift);
1733 #define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ 1736 PrepareRowForImg##bpp(rfbClientPtr cl, uint8_t *dst, int x, int y, int count) { \ 1737 uint##bpp##_t *fbptr; \ 1738 uint##bpp##_t pix; \ 1739 int inRed, inGreen, inBlue; \ 1741 fbptr = (uint##bpp##_t *) \ 1742 &cl->scaledScreen->frameBuffer[y * cl->scaledScreen->paddedWidthInBytes + \ 1749 (pix >> cl->screen->serverFormat.redShift & cl->screen->serverFormat.redMax); \ 1751 (pix >> cl->screen->serverFormat.greenShift & cl->screen->serverFormat.greenMax); \ 1753 (pix >> cl->screen->serverFormat.blueShift & cl->screen->serverFormat.blueMax); \ 1755 *dst++ = (uint8_t)((inRed * 255 + cl->screen->serverFormat.redMax / 2) / \ 1756 cl->screen->serverFormat.redMax); \ 1757 *dst++ = (uint8_t)((inGreen * 255 + cl->screen->serverFormat.greenMax / 2) / \ 1758 cl->screen->serverFormat.greenMax); \ 1759 *dst++ = (uint8_t)((inBlue * 255 + cl->screen->serverFormat.blueMax / 2) / \ 1760 cl->screen->serverFormat.blueMax); \ 1771 #ifdef LIBVNCSERVER_HAVE_LIBPNG 1773 static TLS int pngDstDataLen = 0;
1775 static rfbBool CanSendPngRect(rfbClientPtr cl,
int w,
int h) {
1780 if ( cl->screen->serverFormat.bitsPerPixel == 8 ||
1781 cl->format.bitsPerPixel == 8) {
1788 static void pngWriteData(png_structp png_ptr, png_bytep data,
1792 rfbClientPtr cl = png_get_io_ptr(png_ptr);
1794 buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
1795 memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
1797 memcpy(tightAfterBuf + pngDstDataLen, data, length);
1799 pngDstDataLen += length;
1802 static void pngFlushData(png_structp png_ptr)
1807 static void *pngMalloc(png_structp png_ptr, png_size_t size)
1809 return malloc(size);
1812 static void pngFree(png_structp png_ptr, png_voidp ptr)
1817 static rfbBool SendPngRect(rfbClientPtr cl,
int x,
int y,
int w,
int h) {
1820 png_byte color_type;
1821 png_structp png_ptr;
1823 png_colorp png_palette = NULL;
1824 int level = tightPngConf[cl->tightCompressLevel].png_zlib_level;
1825 int filters = tightPngConf[cl->tightCompressLevel].png_filters;
1831 png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
1832 NULL, pngMalloc, pngFree);
1834 if (png_ptr == NULL)
1837 info_ptr = png_create_info_struct(png_ptr);
1839 if (info_ptr == NULL) {
1840 png_destroy_write_struct(&png_ptr, NULL);
1844 png_set_write_fn(png_ptr, (
void *) cl, pngWriteData, pngFlushData);
1845 png_set_compression_level(png_ptr, level);
1846 png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
1851 color_type = PNG_COLOR_TYPE_PALETTE;
1853 color_type = PNG_COLOR_TYPE_RGB;
1856 color_type = PNG_COLOR_TYPE_RGB;
1858 png_set_IHDR(png_ptr, info_ptr, w, h,
1859 8, color_type, PNG_INTERLACE_NONE,
1860 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1863 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1864 struct palette_cb_priv priv;
1866 png_palette = pngMalloc(png_ptr,
sizeof(*png_palette) *
1867 palette_size(palette));
1870 priv.png_palette = png_palette;
1871 palette_iter(palette, write_png_palette, &priv);
1873 png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
1875 offset = vs->tight.tight.offset;
1876 if (vs->clientds.pf.bytes_per_pixel == 4) {
1877 tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
1879 tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
1883 buffer_reserve(&vs->tight.png, 2048);
1886 png_write_info(png_ptr, info_ptr);
1887 buf = malloc(w * 3);
1890 pngFree(png_ptr, png_palette);
1891 png_destroy_write_struct(&png_ptr, &info_ptr);
1895 for (dy = 0; dy < h; dy++)
1898 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1899 memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
1901 PrepareRowForImg(cl, buf, x, y + dy, w);
1904 PrepareRowForImg(cl, buf, x, y + dy, w);
1906 png_write_row(png_ptr, buf);
1910 png_write_end(png_ptr, NULL);
1912 pngFree(png_ptr, png_palette);
1914 png_destroy_write_struct(&png_ptr, &info_ptr);
1923 cl->updateBuf[cl->ublen++] = (char)(rfbTightPng << 4);
rfbBool rfbSendTightHeader(rfbClientPtr cl, int x, int y, int w, int h)
void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount)
int rfbNumCodedRectsTight(rfbClientPtr cl, int x, int y, int w, int h)
#define DEFINE_FILL_PALETTE_FUNCTION(bpp)
#define MAX_SPLIT_TILE_SIZE
rfbBool rfbSendCompressedDataTight(rfbClientPtr cl, char *buf, int compressedLen)
#define DEFINE_MONO_ENCODE_FUNCTION(bpp)
#define UPDATE_BUF_SIZE
UPDATE_BUF_SIZE must be big enough to send at least one whole line of the framebuffer.
#define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp)
rfbBool rfbSendUpdateBuf(rfbClientPtr cl)
#define MIN_SPLIT_RECT_SIZE
#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)
void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
#define DEFINE_IDX_ENCODE_FUNCTION(bpp)
#define TIGHT_MIN_TO_COMPRESS
rfbBool rfbSendRectEncodingTightPng(rfbClientPtr cl, int x, int y, int w, int h)
#define sz_rfbFramebufferUpdateRectHeader
struct COLOR_LIST_s * next
void rfbTightCleanup(rfbScreenInfoPtr screen)
#define DEFINE_CHECK_SOLID_FUNCTION(bpp)
#define rfbEncodingTightPng
rfbBool rfbSendRectEncodingTight(rfbClientPtr cl, int x, int y, int w, int h)
#define MIN_SOLID_SUBRECT_SIZE