blob: f0a97c595523761a22fa71152699e973f68f760f [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18#include <stdio.h>
19#include <assert.h>
20#include <rdr/OutStream.h>
21#include <rfb/msgTypes.h>
22#include <rfb/ColourMap.h>
23#include <rfb/ConnParams.h>
24#include <rfb/UpdateTracker.h>
25#include <rfb/SMsgWriter.h>
26#include <rfb/LogWriter.h>
27
28using namespace rfb;
29
30static LogWriter vlog("SMsgWriter");
31
32SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
33 : imageBufIdealSize(0), cp(cp_), os(os_), lenBeforeRect(0),
34 currentEncoding(0), updatesSent(0), rawBytesEquivalent(0),
35 imageBuf(0), imageBufSize(0)
36{
Peter Åstrand98fe98c2010-02-10 07:43:02 +000037 for (int i = 0; i <= encodingMax; i++) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000038 encoders[i] = 0;
39 bytesSent[i] = 0;
40 rectsSent[i] = 0;
41 }
42}
43
44SMsgWriter::~SMsgWriter()
45{
46 vlog.info("framebuffer updates %d",updatesSent);
47 int bytes = 0;
Peter Åstrand98fe98c2010-02-10 07:43:02 +000048 for (int i = 0; i <= encodingMax; i++) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049 delete encoders[i];
50 if (i != encodingCopyRect)
51 bytes += bytesSent[i];
52 if (rectsSent[i])
53 vlog.info(" %s rects %d, bytes %d",
54 encodingName(i), rectsSent[i], bytesSent[i]);
55 }
56 vlog.info(" raw bytes equivalent %d, compression ratio %f",
57 rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
58 delete [] imageBuf;
59}
60
61void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours,
62 ColourMap* cm)
63{
64 startMsg(msgTypeSetColourMapEntries);
65 os->pad(1);
66 os->writeU16(firstColour);
67 os->writeU16(nColours);
68 for (int i = firstColour; i < firstColour+nColours; i++) {
69 int r, g, b;
70 cm->lookup(i, &r, &g, &b);
71 os->writeU16(r);
72 os->writeU16(g);
73 os->writeU16(b);
74 }
75 endMsg();
76}
77
78void SMsgWriter::writeBell()
79{
80 startMsg(msgTypeBell);
81 endMsg();
82}
83
84void SMsgWriter::writeServerCutText(const char* str, int len)
85{
86 startMsg(msgTypeServerCutText);
87 os->pad(3);
88 os->writeU32(len);
89 os->writeBytes(str, len);
90 endMsg();
91}
92
93void SMsgWriter::setupCurrentEncoder()
94{
Peter Åstrand98fe98c2010-02-10 07:43:02 +000095 int encoding = cp->currentEncoding();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000096
97 // FIXME: Code duplication, see writeRect().
98 if (!encoders[encoding]) {
99 encoders[encoding] = Encoder::createEncoder(encoding, this);
100 assert(encoders[encoding]);
101 }
102
103 encoders[encoding]->setCompressLevel(cp->compressLevel);
104 encoders[encoding]->setQualityLevel(cp->qualityLevel);
105}
106
107int SMsgWriter::getNumRects(const Rect &r)
108{
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000109 int encoding = cp->currentEncoding();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000110
111 if (!encoders[encoding])
112 setupCurrentEncoder();
113
114 return encoders[encoding]->getNumRects(r);
115}
116
Pierre Ossmane9962f72009-04-23 12:31:42 +0000117bool SMsgWriter::needFakeUpdate()
118{
119 return false;
120}
121
Constantin Kaplinskyfe6b5692007-08-31 15:44:12 +0000122// FIXME: This functions is not used because it incorrectly computes
123// the number of rectangles if the Tight encoder is used.
124/*
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000125void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
126 Region* updatedRegion)
127{
128 writeFramebufferUpdateStart(ui.numRects());
129 writeRects(ui, ig, updatedRegion);
130 writeFramebufferUpdateEnd();
131}
Constantin Kaplinskyfe6b5692007-08-31 15:44:12 +0000132*/
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000133
Pierre Ossmane9962f72009-04-23 12:31:42 +0000134bool SMsgWriter::needNoDataUpdate()
135{
136 return false;
137}
138
139void SMsgWriter::writeNoDataUpdate()
140{
141 // This class has no pseudo-rectangles so there is nothing to do here
142 vlog.error("writeNoDataUpdate() called");
143}
144
DRCffe09d62011-08-17 02:27:59 +0000145void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig,
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000146 Region* updatedRegion)
147{
148 std::vector<Rect> rects;
149 std::vector<Rect>::const_iterator i;
150 updatedRegion->copyFrom(ui.changed);
151 updatedRegion->assign_union(ui.copied);
152
153 ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0);
154 for (i = rects.begin(); i != rects.end(); i++)
155 writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y);
156
157 ui.changed.get_rects(&rects);
158 for (i = rects.begin(); i != rects.end(); i++) {
159 Rect actual;
160 if (!writeRect(*i, ig, &actual)) {
161 updatedRegion->assign_subtract(*i);
162 updatedRegion->assign_union(actual);
163 }
164 }
165}
166
DRCffe09d62011-08-17 02:27:59 +0000167bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000168{
169 return writeRect(r, cp->currentEncoding(), ig, actual);
170}
171
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000172bool SMsgWriter::writeRect(const Rect& r, int encoding,
DRCffe09d62011-08-17 02:27:59 +0000173 TransImageGetter* ig, Rect* actual)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000174{
175 if (!encoders[encoding]) {
176 encoders[encoding] = Encoder::createEncoder(encoding, this);
177 assert(encoders[encoding]);
178 }
179 return encoders[encoding]->writeRect(r, ig, actual);
180}
181
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000182void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
183{
184 startRect(r,encodingCopyRect);
185 os->writeU16(srcX);
186 os->writeU16(srcY);
187 endRect();
188}
189
190rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels)
191{
192 int requiredBytes = required * (cp->pf().bpp / 8);
193 int requestedBytes = requested * (cp->pf().bpp / 8);
194 int size = requestedBytes;
195 if (size > imageBufIdealSize) size = imageBufIdealSize;
196
197 if (size < requiredBytes)
198 size = requiredBytes;
199
200 if (imageBufSize < size) {
201 imageBufSize = size;
202 delete [] imageBuf;
203 imageBuf = new rdr::U8[imageBufSize];
204 }
205 if (nPixels)
206 *nPixels = imageBufSize / (cp->pf().bpp / 8);
207 return imageBuf;
208}
209
210int SMsgWriter::bpp()
211{
212 return cp->pf().bpp;
213}