blob: 8917d8ffe7df2b89c672c654202a992490ab1ff0 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossmanc0397262014-03-14 15:59:46 +01002 * Copyright 2014 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19#include <rdr/OutStream.h>
20#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <rfb/encodings.h>
22#include <rfb/ConnParams.h>
Pierre Ossmanc0397262014-03-14 15:59:46 +010023#include <rfb/Palette.h>
Pierre Ossman668468b2014-01-31 12:37:32 +010024#include <rfb/SConnection.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025#include <rfb/ZRLEEncoder.h>
26#include <rfb/Configuration.h>
27
28using namespace rfb;
29
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000030IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1);
31
Pierre Ossman668468b2014-01-31 12:37:32 +010032ZRLEEncoder::ZRLEEncoder(SConnection* conn)
Pierre Ossmanc0397262014-03-14 15:59:46 +010033 : Encoder(conn, encodingZRLE, EncoderPlain, 127),
34 zos(0,0,zlibLevel), mos(129*1024)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000035{
Pierre Ossmanc0397262014-03-14 15:59:46 +010036 zos.setUnderlying(&mos);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000037}
38
39ZRLEEncoder::~ZRLEEncoder()
40{
Pierre Ossmanc0397262014-03-14 15:59:46 +010041 zos.setUnderlying(NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000042}
43
Pierre Ossmanc0397262014-03-14 15:59:46 +010044bool ZRLEEncoder::isSupported()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000045{
Pierre Ossmanc0397262014-03-14 15:59:46 +010046 return conn->cp.supportsEncoding(encodingZRLE);
47}
Pierre Ossman0c9bd4b2014-07-09 16:44:11 +020048
Pierre Ossmanc0397262014-03-14 15:59:46 +010049void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
50{
51 int x, y;
52 Rect tile;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053
Pierre Ossmanc0397262014-03-14 15:59:46 +010054 rdr::OutStream* os;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000055
Pierre Ossmanc0397262014-03-14 15:59:46 +010056 // A bit of a special case
57 if (palette.size() == 1) {
58 Encoder::writeSolidRect(pb, palette);
59 return;
60 }
61
62 for (y = 0;y < pb->height();y += 64) {
63 tile.tl.y = y;
64 tile.br.y = y + 64;
65 if (tile.br.y > pb->height())
66 tile.br.y = pb->height();
67
68 for (x = 0;x < pb->width();x += 64) {
69 tile.tl.x = x;
70 tile.br.x = x + 64;
71 if (tile.br.x > pb->width())
72 tile.br.x = pb->width();
73
74 if (palette.size() == 0)
75 writeRawTile(tile, pb, palette);
76 else if (palette.size() <= 16)
77 writePaletteTile(tile, pb, palette);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078 else
Pierre Ossmanc0397262014-03-14 15:59:46 +010079 writePaletteRLETile(tile, pb, palette);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000080 }
81 }
82
Pierre Ossmanc0397262014-03-14 15:59:46 +010083 zos.flush();
84
85 os = conn->getOutStream();
86
Pierre Ossman4bca9112014-03-13 15:08:36 +010087 os->writeU32(mos.length());
88 os->writeBytes(mos.data(), mos.length());
Pierre Ossmanc0397262014-03-14 15:59:46 +010089
90 mos.clear();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000091}
Pierre Ossmanc0397262014-03-14 15:59:46 +010092
93void ZRLEEncoder::writeSolidRect(int width, int height,
94 const PixelFormat& pf,
95 const rdr::U8* colour)
96{
97 int tiles;
98
99 rdr::OutStream* os;
100
101 tiles = ((width + 63)/64) * ((height + 63)/64);
102
103 while (tiles--) {
104 zos.writeU8(1);
105 writePixels(colour, pf, 1);
106 }
107
108 zos.flush();
109
110 os = conn->getOutStream();
111
112 os->writeU32(mos.length());
113 os->writeBytes(mos.data(), mos.length());
114
115 mos.clear();
116}
117
118void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb,
119 const Palette& palette)
120{
121 const rdr::U8* buffer;
122 int stride;
123
124 buffer = pb->getBuffer(tile, &stride);
125
126 switch (pb->getPF().bpp) {
127 case 32:
128 writePaletteTile(tile.width(), tile.height(),
129 (rdr::U32*)buffer, stride,
130 pb->getPF(), palette);
131 break;
132 case 16:
133 writePaletteTile(tile.width(), tile.height(),
134 (rdr::U16*)buffer, stride,
135 pb->getPF(), palette);
136 break;
137 default:
138 writePaletteTile(tile.width(), tile.height(),
139 (rdr::U8*)buffer, stride,
140 pb->getPF(), palette);
141 }
142}
143
144void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb,
145 const Palette& palette)
146{
147 const rdr::U8* buffer;
148 int stride;
149
150 buffer = pb->getBuffer(tile, &stride);
151
152 switch (pb->getPF().bpp) {
153 case 32:
154 writePaletteRLETile(tile.width(), tile.height(),
155 (rdr::U32*)buffer, stride,
156 pb->getPF(), palette);
157 break;
158 case 16:
159 writePaletteRLETile(tile.width(), tile.height(),
160 (rdr::U16*)buffer, stride,
161 pb->getPF(), palette);
162 break;
163 default:
164 writePaletteRLETile(tile.width(), tile.height(),
165 (rdr::U8*)buffer, stride,
166 pb->getPF(), palette);
167 }
168}
169
170void ZRLEEncoder::writeRawTile(const Rect& tile, const PixelBuffer* pb,
171 const Palette& palette)
172{
173 const rdr::U8* buffer;
174 int stride;
175
176 int w, h, stride_bytes;
177
178 buffer = pb->getBuffer(tile, &stride);
179
180 zos.writeU8(0); // Empty palette (i.e. raw pixels)
181
182 w = tile.width();
183 h = tile.height();
184 stride_bytes = stride * pb->getPF().bpp/8;
185 while (h--) {
186 writePixels(buffer, pb->getPF(), w);
187 buffer += stride_bytes;
188 }
189}
190
191void ZRLEEncoder::writePalette(const PixelFormat& pf, const Palette& palette)
192{
193 rdr::U8 buffer[256*4];
194 int i;
195
196 if (pf.bpp == 32) {
197 rdr::U32* buf;
198 buf = (rdr::U32*)buffer;
199 for (i = 0;i < palette.size();i++)
200 *buf++ = palette.getColour(i);
201 } else if (pf.bpp == 16) {
202 rdr::U16* buf;
203 buf = (rdr::U16*)buffer;
204 for (i = 0;i < palette.size();i++)
205 *buf++ = palette.getColour(i);
206 } else {
207 rdr::U8* buf;
208 buf = (rdr::U8*)buffer;
209 for (i = 0;i < palette.size();i++)
210 *buf++ = palette.getColour(i);
211 }
212
213 writePixels(buffer, pf, palette.size());
214}
215
216void ZRLEEncoder::writePixels(const rdr::U8* buffer, const PixelFormat& pf,
217 unsigned int count)
218{
219 Pixel maxPixel;
220 rdr::U8 pixBuf[4];
221
222 maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
223 pf.bufferFromPixel(pixBuf, maxPixel);
224
225 if ((pf.bpp != 32) || ((pixBuf[0] != 0) && (pixBuf[3] != 0))) {
Pierre Ossmanf81148c2018-07-25 20:44:32 +0200226 zos.writeBytes(buffer, count * (pf.bpp/8));
Pierre Ossmanc0397262014-03-14 15:59:46 +0100227 return;
228 }
229
230 if (pixBuf[0] == 0)
231 buffer++;
232
233 while (count--) {
234 zos.writeBytes(buffer, 3);
235 buffer += 4;
236 }
237}
238
239//
240// Including BPP-dependent implementation of the encoder.
241//
242
243#define BPP 8
244#include <rfb/ZRLEEncoderBPP.cxx>
245#undef BPP
246#define BPP 16
247#include <rfb/ZRLEEncoderBPP.cxx>
248#undef BPP
249#define BPP 32
250#include <rfb/ZRLEEncoderBPP.cxx>
251#undef BPP