blob: f47f3eeb7d05c9c8b884e75bf2e0017d69c97e6d [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
DRCb4a83232011-08-19 04:57:18 +00002 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
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 <stdio.h>
20#include <assert.h>
21#include <rdr/OutStream.h>
22#include <rfb/msgTypes.h>
23#include <rfb/ColourMap.h>
24#include <rfb/ConnParams.h>
25#include <rfb/UpdateTracker.h>
26#include <rfb/SMsgWriter.h>
27#include <rfb/LogWriter.h>
28
29using namespace rfb;
30
31static LogWriter vlog("SMsgWriter");
32
33SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
34 : imageBufIdealSize(0), cp(cp_), os(os_), lenBeforeRect(0),
35 currentEncoding(0), updatesSent(0), rawBytesEquivalent(0),
36 imageBuf(0), imageBufSize(0)
37{
Peter Åstrand98fe98c2010-02-10 07:43:02 +000038 for (int i = 0; i <= encodingMax; i++) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000039 encoders[i] = 0;
40 bytesSent[i] = 0;
41 rectsSent[i] = 0;
42 }
43}
44
45SMsgWriter::~SMsgWriter()
46{
47 vlog.info("framebuffer updates %d",updatesSent);
48 int bytes = 0;
Peter Åstrand98fe98c2010-02-10 07:43:02 +000049 for (int i = 0; i <= encodingMax; i++) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000050 delete encoders[i];
51 if (i != encodingCopyRect)
52 bytes += bytesSent[i];
53 if (rectsSent[i])
54 vlog.info(" %s rects %d, bytes %d",
55 encodingName(i), rectsSent[i], bytesSent[i]);
56 }
DRC887c5fd2011-08-19 03:13:47 +000057 vlog.info(" raw bytes equivalent %llu, compression ratio %f",
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058 rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
59 delete [] imageBuf;
60}
61
62void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours,
63 ColourMap* cm)
64{
65 startMsg(msgTypeSetColourMapEntries);
66 os->pad(1);
67 os->writeU16(firstColour);
68 os->writeU16(nColours);
69 for (int i = firstColour; i < firstColour+nColours; i++) {
70 int r, g, b;
71 cm->lookup(i, &r, &g, &b);
72 os->writeU16(r);
73 os->writeU16(g);
74 os->writeU16(b);
75 }
76 endMsg();
77}
78
79void SMsgWriter::writeBell()
80{
81 startMsg(msgTypeBell);
82 endMsg();
83}
84
85void SMsgWriter::writeServerCutText(const char* str, int len)
86{
87 startMsg(msgTypeServerCutText);
88 os->pad(3);
89 os->writeU32(len);
90 os->writeBytes(str, len);
91 endMsg();
92}
93
94void SMsgWriter::setupCurrentEncoder()
95{
Peter Åstrand98fe98c2010-02-10 07:43:02 +000096 int encoding = cp->currentEncoding();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000097
98 // FIXME: Code duplication, see writeRect().
99 if (!encoders[encoding]) {
100 encoders[encoding] = Encoder::createEncoder(encoding, this);
101 assert(encoders[encoding]);
102 }
103
104 encoders[encoding]->setCompressLevel(cp->compressLevel);
105 encoders[encoding]->setQualityLevel(cp->qualityLevel);
DRCb4a83232011-08-19 04:57:18 +0000106 encoders[encoding]->setFineQualityLevel(cp->fineQualityLevel,
107 cp->subsampling);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000108}
109
110int SMsgWriter::getNumRects(const Rect &r)
111{
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000112 int encoding = cp->currentEncoding();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000113
114 if (!encoders[encoding])
115 setupCurrentEncoder();
116
117 return encoders[encoding]->getNumRects(r);
118}
119
Pierre Ossmane9962f72009-04-23 12:31:42 +0000120bool SMsgWriter::needFakeUpdate()
121{
122 return false;
123}
124
Constantin Kaplinskyfe6b5692007-08-31 15:44:12 +0000125// FIXME: This functions is not used because it incorrectly computes
126// the number of rectangles if the Tight encoder is used.
127/*
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000128void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
129 Region* updatedRegion)
130{
131 writeFramebufferUpdateStart(ui.numRects());
132 writeRects(ui, ig, updatedRegion);
133 writeFramebufferUpdateEnd();
134}
Constantin Kaplinskyfe6b5692007-08-31 15:44:12 +0000135*/
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000136
Pierre Ossmane9962f72009-04-23 12:31:42 +0000137bool SMsgWriter::needNoDataUpdate()
138{
139 return false;
140}
141
142void SMsgWriter::writeNoDataUpdate()
143{
144 // This class has no pseudo-rectangles so there is nothing to do here
145 vlog.error("writeNoDataUpdate() called");
146}
147
DRCffe09d62011-08-17 02:27:59 +0000148void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig,
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000149 Region* updatedRegion)
150{
151 std::vector<Rect> rects;
152 std::vector<Rect>::const_iterator i;
153 updatedRegion->copyFrom(ui.changed);
154 updatedRegion->assign_union(ui.copied);
155
156 ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0);
157 for (i = rects.begin(); i != rects.end(); i++)
158 writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y);
159
160 ui.changed.get_rects(&rects);
161 for (i = rects.begin(); i != rects.end(); i++) {
162 Rect actual;
163 if (!writeRect(*i, ig, &actual)) {
164 updatedRegion->assign_subtract(*i);
165 updatedRegion->assign_union(actual);
166 }
167 }
168}
169
DRCffe09d62011-08-17 02:27:59 +0000170bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000171{
172 return writeRect(r, cp->currentEncoding(), ig, actual);
173}
174
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000175bool SMsgWriter::writeRect(const Rect& r, int encoding,
DRCffe09d62011-08-17 02:27:59 +0000176 TransImageGetter* ig, Rect* actual)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000177{
178 if (!encoders[encoding]) {
179 encoders[encoding] = Encoder::createEncoder(encoding, this);
180 assert(encoders[encoding]);
181 }
182 return encoders[encoding]->writeRect(r, ig, actual);
183}
184
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000185void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
186{
187 startRect(r,encodingCopyRect);
188 os->writeU16(srcX);
189 os->writeU16(srcY);
190 endRect();
191}
192
193rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels)
194{
195 int requiredBytes = required * (cp->pf().bpp / 8);
196 int requestedBytes = requested * (cp->pf().bpp / 8);
197 int size = requestedBytes;
198 if (size > imageBufIdealSize) size = imageBufIdealSize;
199
200 if (size < requiredBytes)
201 size = requiredBytes;
202
203 if (imageBufSize < size) {
204 imageBufSize = size;
205 delete [] imageBuf;
206 imageBuf = new rdr::U8[imageBufSize];
207 }
208 if (nPixels)
209 *nPixels = imageBufSize / (cp->pf().bpp / 8);
210 return imageBuf;
211}
212
213int SMsgWriter::bpp()
214{
215 return cp->pf().bpp;
216}