blob: 92fd13d1cebc75c7a9ebe263258f08891c12b740 [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>
Pierre Ossmanc0397262014-03-14 15:59:46 +010022#include <rfb/Palette.h>
Pierre Ossman668468b2014-01-31 12:37:32 +010023#include <rfb/SConnection.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000024#include <rfb/ZRLEEncoder.h>
25#include <rfb/Configuration.h>
26
27using namespace rfb;
28
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1);
30
Pierre Ossman668468b2014-01-31 12:37:32 +010031ZRLEEncoder::ZRLEEncoder(SConnection* conn)
Pierre Ossmanc0397262014-03-14 15:59:46 +010032 : Encoder(conn, encodingZRLE, EncoderPlain, 127),
33 zos(0,0,zlibLevel), mos(129*1024)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034{
Pierre Ossmanc0397262014-03-14 15:59:46 +010035 zos.setUnderlying(&mos);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000036}
37
38ZRLEEncoder::~ZRLEEncoder()
39{
Pierre Ossmanc0397262014-03-14 15:59:46 +010040 zos.setUnderlying(NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000041}
42
Pierre Ossmanc0397262014-03-14 15:59:46 +010043bool ZRLEEncoder::isSupported()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000044{
Pierre Ossman0d3ce872018-06-18 15:59:00 +020045 return conn->client.supportsEncoding(encodingZRLE);
Pierre Ossmanc0397262014-03-14 15:59:46 +010046}
Pierre Ossman0c9bd4b2014-07-09 16:44:11 +020047
Pierre Ossmanc0397262014-03-14 15:59:46 +010048void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
49{
50 int x, y;
51 Rect tile;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052
Pierre Ossmanc0397262014-03-14 15:59:46 +010053 rdr::OutStream* os;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000054
Pierre Ossmanc0397262014-03-14 15:59:46 +010055 // A bit of a special case
56 if (palette.size() == 1) {
57 Encoder::writeSolidRect(pb, palette);
58 return;
59 }
60
61 for (y = 0;y < pb->height();y += 64) {
62 tile.tl.y = y;
63 tile.br.y = y + 64;
64 if (tile.br.y > pb->height())
65 tile.br.y = pb->height();
66
67 for (x = 0;x < pb->width();x += 64) {
68 tile.tl.x = x;
69 tile.br.x = x + 64;
70 if (tile.br.x > pb->width())
71 tile.br.x = pb->width();
72
73 if (palette.size() == 0)
74 writeRawTile(tile, pb, palette);
75 else if (palette.size() <= 16)
76 writePaletteTile(tile, pb, palette);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000077 else
Pierre Ossmanc0397262014-03-14 15:59:46 +010078 writePaletteRLETile(tile, pb, palette);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000079 }
80 }
81
Pierre Ossmanc0397262014-03-14 15:59:46 +010082 zos.flush();
83
84 os = conn->getOutStream();
85
Pierre Ossman4bca9112014-03-13 15:08:36 +010086 os->writeU32(mos.length());
87 os->writeBytes(mos.data(), mos.length());
Pierre Ossmanc0397262014-03-14 15:59:46 +010088
89 mos.clear();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000090}
Pierre Ossmanc0397262014-03-14 15:59:46 +010091
92void ZRLEEncoder::writeSolidRect(int width, int height,
93 const PixelFormat& pf,
94 const rdr::U8* colour)
95{
96 int tiles;
97
98 rdr::OutStream* os;
99
100 tiles = ((width + 63)/64) * ((height + 63)/64);
101
102 while (tiles--) {
103 zos.writeU8(1);
104 writePixels(colour, pf, 1);
105 }
106
107 zos.flush();
108
109 os = conn->getOutStream();
110
111 os->writeU32(mos.length());
112 os->writeBytes(mos.data(), mos.length());
113
114 mos.clear();
115}
116
117void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb,
118 const Palette& palette)
119{
120 const rdr::U8* buffer;
121 int stride;
122
123 buffer = pb->getBuffer(tile, &stride);
124
125 switch (pb->getPF().bpp) {
126 case 32:
127 writePaletteTile(tile.width(), tile.height(),
128 (rdr::U32*)buffer, stride,
129 pb->getPF(), palette);
130 break;
131 case 16:
132 writePaletteTile(tile.width(), tile.height(),
133 (rdr::U16*)buffer, stride,
134 pb->getPF(), palette);
135 break;
136 default:
137 writePaletteTile(tile.width(), tile.height(),
138 (rdr::U8*)buffer, stride,
139 pb->getPF(), palette);
140 }
141}
142
143void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb,
144 const Palette& palette)
145{
146 const rdr::U8* buffer;
147 int stride;
148
149 buffer = pb->getBuffer(tile, &stride);
150
151 switch (pb->getPF().bpp) {
152 case 32:
153 writePaletteRLETile(tile.width(), tile.height(),
154 (rdr::U32*)buffer, stride,
155 pb->getPF(), palette);
156 break;
157 case 16:
158 writePaletteRLETile(tile.width(), tile.height(),
159 (rdr::U16*)buffer, stride,
160 pb->getPF(), palette);
161 break;
162 default:
163 writePaletteRLETile(tile.width(), tile.height(),
164 (rdr::U8*)buffer, stride,
165 pb->getPF(), palette);
166 }
167}
168
169void ZRLEEncoder::writeRawTile(const Rect& tile, const PixelBuffer* pb,
170 const Palette& palette)
171{
172 const rdr::U8* buffer;
173 int stride;
174
175 int w, h, stride_bytes;
176
177 buffer = pb->getBuffer(tile, &stride);
178
179 zos.writeU8(0); // Empty palette (i.e. raw pixels)
180
181 w = tile.width();
182 h = tile.height();
183 stride_bytes = stride * pb->getPF().bpp/8;
184 while (h--) {
185 writePixels(buffer, pb->getPF(), w);
186 buffer += stride_bytes;
187 }
188}
189
190void ZRLEEncoder::writePalette(const PixelFormat& pf, const Palette& palette)
191{
192 rdr::U8 buffer[256*4];
193 int i;
194
195 if (pf.bpp == 32) {
196 rdr::U32* buf;
197 buf = (rdr::U32*)buffer;
198 for (i = 0;i < palette.size();i++)
199 *buf++ = palette.getColour(i);
200 } else if (pf.bpp == 16) {
201 rdr::U16* buf;
202 buf = (rdr::U16*)buffer;
203 for (i = 0;i < palette.size();i++)
204 *buf++ = palette.getColour(i);
205 } else {
206 rdr::U8* buf;
207 buf = (rdr::U8*)buffer;
208 for (i = 0;i < palette.size();i++)
209 *buf++ = palette.getColour(i);
210 }
211
212 writePixels(buffer, pf, palette.size());
213}
214
215void ZRLEEncoder::writePixels(const rdr::U8* buffer, const PixelFormat& pf,
216 unsigned int count)
217{
218 Pixel maxPixel;
219 rdr::U8 pixBuf[4];
220
221 maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
222 pf.bufferFromPixel(pixBuf, maxPixel);
223
224 if ((pf.bpp != 32) || ((pixBuf[0] != 0) && (pixBuf[3] != 0))) {
Pierre Ossmanf81148c2018-07-25 20:44:32 +0200225 zos.writeBytes(buffer, count * (pf.bpp/8));
Pierre Ossmanc0397262014-03-14 15:59:46 +0100226 return;
227 }
228
229 if (pixBuf[0] == 0)
230 buffer++;
231
232 while (count--) {
233 zos.writeBytes(buffer, 3);
234 buffer += 4;
235 }
236}
237
238//
239// Including BPP-dependent implementation of the encoder.
240//
241
242#define BPP 8
243#include <rfb/ZRLEEncoderBPP.cxx>
244#undef BPP
245#define BPP 16
246#include <rfb/ZRLEEncoderBPP.cxx>
247#undef BPP
248#define BPP 32
249#include <rfb/ZRLEEncoderBPP.cxx>
250#undef BPP