You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TightDecoder.cxx 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright 2004-2005 Cendio AB.
  3. * Copyright 2009-2015 Pierre Ossman for Cendio AB
  4. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
  5. *
  6. * This is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This software is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this software; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  19. * USA.
  20. */
  21. #include <assert.h>
  22. #include <rdr/InStream.h>
  23. #include <rdr/MemInStream.h>
  24. #include <rdr/OutStream.h>
  25. #include <rfb/ServerParams.h>
  26. #include <rfb/Exception.h>
  27. #include <rfb/PixelBuffer.h>
  28. #include <rfb/TightConstants.h>
  29. #include <rfb/TightDecoder.h>
  30. using namespace rfb;
  31. static const int TIGHT_MAX_WIDTH = 2048;
  32. static const int TIGHT_MIN_TO_COMPRESS = 12;
  33. #define BPP 8
  34. #include <rfb/tightDecode.h>
  35. #undef BPP
  36. #define BPP 16
  37. #include <rfb/tightDecode.h>
  38. #undef BPP
  39. #define BPP 32
  40. #include <rfb/tightDecode.h>
  41. #undef BPP
  42. TightDecoder::TightDecoder() : Decoder(DecoderPartiallyOrdered)
  43. {
  44. }
  45. TightDecoder::~TightDecoder()
  46. {
  47. }
  48. void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
  49. const ServerParams& server, rdr::OutStream* os)
  50. {
  51. rdr::U8 comp_ctl;
  52. comp_ctl = is->readU8();
  53. os->writeU8(comp_ctl);
  54. comp_ctl >>= 4;
  55. // "Fill" compression type.
  56. if (comp_ctl == tightFill) {
  57. if (server.pf().is888())
  58. os->copyBytes(is, 3);
  59. else
  60. os->copyBytes(is, server.pf().bpp/8);
  61. return;
  62. }
  63. // "JPEG" compression type.
  64. if (comp_ctl == tightJpeg) {
  65. rdr::U32 len;
  66. len = readCompact(is);
  67. os->writeOpaque32(len);
  68. os->copyBytes(is, len);
  69. return;
  70. }
  71. // Quit on unsupported compression type.
  72. if (comp_ctl > tightMaxSubencoding)
  73. throw Exception("TightDecoder: bad subencoding value received");
  74. // "Basic" compression type.
  75. int palSize = 0;
  76. if (r.width() > TIGHT_MAX_WIDTH)
  77. throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width());
  78. // Possible palette
  79. if ((comp_ctl & tightExplicitFilter) != 0) {
  80. rdr::U8 filterId;
  81. filterId = is->readU8();
  82. os->writeU8(filterId);
  83. switch (filterId) {
  84. case tightFilterPalette:
  85. palSize = is->readU8() + 1;
  86. os->writeU8(palSize - 1);
  87. if (server.pf().is888())
  88. os->copyBytes(is, palSize * 3);
  89. else
  90. os->copyBytes(is, palSize * server.pf().bpp/8);
  91. break;
  92. case tightFilterGradient:
  93. if (server.pf().bpp == 8)
  94. throw Exception("TightDecoder: invalid BPP for gradient filter");
  95. break;
  96. case tightFilterCopy:
  97. break;
  98. default:
  99. throw Exception("TightDecoder: unknown filter code received");
  100. }
  101. }
  102. size_t rowSize, dataSize;
  103. if (palSize != 0) {
  104. if (palSize <= 2)
  105. rowSize = (r.width() + 7) / 8;
  106. else
  107. rowSize = r.width();
  108. } else if (server.pf().is888()) {
  109. rowSize = r.width() * 3;
  110. } else {
  111. rowSize = r.width() * server.pf().bpp/8;
  112. }
  113. dataSize = r.height() * rowSize;
  114. if (dataSize < TIGHT_MIN_TO_COMPRESS)
  115. os->copyBytes(is, dataSize);
  116. else {
  117. rdr::U32 len;
  118. len = readCompact(is);
  119. os->writeOpaque32(len);
  120. os->copyBytes(is, len);
  121. }
  122. }
  123. bool TightDecoder::doRectsConflict(const Rect& rectA,
  124. const void* bufferA,
  125. size_t buflenA,
  126. const Rect& rectB,
  127. const void* bufferB,
  128. size_t buflenB,
  129. const ServerParams& server)
  130. {
  131. rdr::U8 comp_ctl_a, comp_ctl_b;
  132. assert(buflenA >= 1);
  133. assert(buflenB >= 1);
  134. comp_ctl_a = *(const rdr::U8*)bufferA;
  135. comp_ctl_b = *(const rdr::U8*)bufferB;
  136. // Resets or use of zlib pose the same problem, so merge them
  137. if ((comp_ctl_a & 0x80) == 0x00)
  138. comp_ctl_a |= 1 << ((comp_ctl_a >> 4) & 0x03);
  139. if ((comp_ctl_b & 0x80) == 0x00)
  140. comp_ctl_b |= 1 << ((comp_ctl_b >> 4) & 0x03);
  141. if (((comp_ctl_a & 0x0f) & (comp_ctl_b & 0x0f)) != 0)
  142. return true;
  143. return false;
  144. }
  145. void TightDecoder::decodeRect(const Rect& r, const void* buffer,
  146. size_t buflen, const ServerParams& server,
  147. ModifiablePixelBuffer* pb)
  148. {
  149. const rdr::U8* bufptr;
  150. const PixelFormat& pf = server.pf();
  151. rdr::U8 comp_ctl;
  152. bufptr = (const rdr::U8*)buffer;
  153. assert(buflen >= 1);
  154. comp_ctl = *bufptr;
  155. bufptr += 1;
  156. buflen -= 1;
  157. // Reset zlib streams if we are told by the server to do so.
  158. for (int i = 0; i < 4; i++) {
  159. if (comp_ctl & 1) {
  160. zis[i].reset();
  161. }
  162. comp_ctl >>= 1;
  163. }
  164. // "Fill" compression type.
  165. if (comp_ctl == tightFill) {
  166. if (pf.is888()) {
  167. rdr::U8 pix[4];
  168. assert(buflen >= 3);
  169. pf.bufferFromRGB(pix, bufptr, 1);
  170. pb->fillRect(pf, r, pix);
  171. } else {
  172. assert(buflen >= (size_t)pf.bpp/8);
  173. pb->fillRect(pf, r, bufptr);
  174. }
  175. return;
  176. }
  177. // "JPEG" compression type.
  178. if (comp_ctl == tightJpeg) {
  179. rdr::U32 len;
  180. int stride;
  181. rdr::U8 *buf;
  182. JpegDecompressor jd;
  183. assert(buflen >= 4);
  184. memcpy(&len, bufptr, 4);
  185. bufptr += 4;
  186. buflen -= 4;
  187. // We always use direct decoding with JPEG images
  188. buf = pb->getBufferRW(r, &stride);
  189. jd.decompress(bufptr, len, buf, stride, r, pb->getPF());
  190. pb->commitBufferRW(r);
  191. return;
  192. }
  193. // Quit on unsupported compression type.
  194. assert(comp_ctl <= tightMaxSubencoding);
  195. // "Basic" compression type.
  196. int palSize = 0;
  197. rdr::U8 palette[256 * 4];
  198. bool useGradient = false;
  199. if ((comp_ctl & tightExplicitFilter) != 0) {
  200. rdr::U8 filterId;
  201. assert(buflen >= 1);
  202. filterId = *bufptr;
  203. bufptr += 1;
  204. buflen -= 1;
  205. switch (filterId) {
  206. case tightFilterPalette:
  207. assert(buflen >= 1);
  208. palSize = *bufptr + 1;
  209. bufptr += 1;
  210. buflen -= 1;
  211. if (pf.is888()) {
  212. size_t len = palSize * 3;
  213. rdr::U8Array tightPalette(len);
  214. assert(buflen >= len);
  215. memcpy(tightPalette.buf, bufptr, len);
  216. bufptr += len;
  217. buflen -= len;
  218. pf.bufferFromRGB(palette, tightPalette.buf, palSize);
  219. } else {
  220. size_t len;
  221. len = palSize * pf.bpp/8;
  222. assert(buflen >= len);
  223. memcpy(palette, bufptr, len);
  224. bufptr += len;
  225. buflen -= len;
  226. }
  227. break;
  228. case tightFilterGradient:
  229. useGradient = true;
  230. break;
  231. case tightFilterCopy:
  232. break;
  233. default:
  234. assert(false);
  235. }
  236. }
  237. // Determine if the data should be decompressed or just copied.
  238. size_t rowSize, dataSize;
  239. rdr::U8* netbuf;
  240. netbuf = NULL;
  241. if (palSize != 0) {
  242. if (palSize <= 2)
  243. rowSize = (r.width() + 7) / 8;
  244. else
  245. rowSize = r.width();
  246. } else if (pf.is888()) {
  247. rowSize = r.width() * 3;
  248. } else {
  249. rowSize = r.width() * pf.bpp/8;
  250. }
  251. dataSize = r.height() * rowSize;
  252. if (dataSize < TIGHT_MIN_TO_COMPRESS)
  253. assert(buflen >= dataSize);
  254. else {
  255. rdr::U32 len;
  256. int streamId;
  257. rdr::MemInStream* ms;
  258. assert(buflen >= 4);
  259. memcpy(&len, bufptr, 4);
  260. bufptr += 4;
  261. buflen -= 4;
  262. assert(buflen >= len);
  263. streamId = comp_ctl & 0x03;
  264. ms = new rdr::MemInStream(bufptr, len);
  265. zis[streamId].setUnderlying(ms, len);
  266. // Allocate buffer and decompress the data
  267. netbuf = new rdr::U8[dataSize];
  268. zis[streamId].readBytes(netbuf, dataSize);
  269. zis[streamId].removeUnderlying();
  270. delete ms;
  271. bufptr = netbuf;
  272. buflen = dataSize;
  273. }
  274. // Time to decode the actual data
  275. bool directDecode;
  276. rdr::U8* outbuf;
  277. int stride;
  278. if (pb->getPF().equal(pf)) {
  279. // Decode directly into the framebuffer (fast path)
  280. directDecode = true;
  281. } else {
  282. // Decode into an intermediate buffer and use pixel translation
  283. directDecode = false;
  284. }
  285. if (directDecode)
  286. outbuf = pb->getBufferRW(r, &stride);
  287. else {
  288. outbuf = new rdr::U8[r.area() * (pf.bpp/8)];
  289. stride = r.width();
  290. }
  291. if (palSize == 0) {
  292. // Truecolor data
  293. if (useGradient) {
  294. if (pf.is888())
  295. FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  296. else {
  297. switch (pf.bpp) {
  298. case 8:
  299. assert(false);
  300. break;
  301. case 16:
  302. FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
  303. break;
  304. case 32:
  305. FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  306. break;
  307. }
  308. }
  309. } else {
  310. // Copy
  311. rdr::U8* ptr = outbuf;
  312. const rdr::U8* srcPtr = bufptr;
  313. int w = r.width();
  314. int h = r.height();
  315. if (pf.is888()) {
  316. while (h > 0) {
  317. pf.bufferFromRGB(ptr, srcPtr, w);
  318. ptr += stride * pf.bpp/8;
  319. srcPtr += w * 3;
  320. h--;
  321. }
  322. } else {
  323. while (h > 0) {
  324. memcpy(ptr, srcPtr, w * pf.bpp/8);
  325. ptr += stride * pf.bpp/8;
  326. srcPtr += w * pf.bpp/8;
  327. h--;
  328. }
  329. }
  330. }
  331. } else {
  332. // Indexed color
  333. switch (pf.bpp) {
  334. case 8:
  335. FilterPalette((const rdr::U8*)palette, palSize,
  336. bufptr, (rdr::U8*)outbuf, stride, r);
  337. break;
  338. case 16:
  339. FilterPalette((const rdr::U16*)palette, palSize,
  340. bufptr, (rdr::U16*)outbuf, stride, r);
  341. break;
  342. case 32:
  343. FilterPalette((const rdr::U32*)palette, palSize,
  344. bufptr, (rdr::U32*)outbuf, stride, r);
  345. break;
  346. }
  347. }
  348. if (directDecode)
  349. pb->commitBufferRW(r);
  350. else {
  351. pb->imageRect(pf, r, outbuf);
  352. delete [] outbuf;
  353. }
  354. delete [] netbuf;
  355. }
  356. rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
  357. {
  358. rdr::U8 b;
  359. rdr::U32 result;
  360. b = is->readU8();
  361. result = (int)b & 0x7F;
  362. if (b & 0x80) {
  363. b = is->readU8();
  364. result |= ((int)b & 0x7F) << 7;
  365. if (b & 0x80) {
  366. b = is->readU8();
  367. result |= ((int)b & 0xFF) << 14;
  368. }
  369. }
  370. return result;
  371. }