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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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/ConnParams.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 ConnParams& cp, 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 (cp.pf().is888())
  58. os->copyBytes(is, 3);
  59. else
  60. os->copyBytes(is, cp.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 (cp.pf().is888())
  88. os->copyBytes(is, palSize * 3);
  89. else
  90. os->copyBytes(is, palSize * cp.pf().bpp/8);
  91. break;
  92. case tightFilterGradient:
  93. if (cp.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 (cp.pf().is888()) {
  109. rowSize = r.width() * 3;
  110. } else {
  111. rowSize = r.width() * cp.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 ConnParams& cp)
  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 ConnParams& cp,
  147. ModifiablePixelBuffer* pb)
  148. {
  149. const rdr::U8* bufptr;
  150. const PixelFormat& pf = cp.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. rdr::U8 tightPalette[palSize * 3];
  213. assert(buflen >= sizeof(tightPalette));
  214. memcpy(tightPalette, bufptr, sizeof(tightPalette));
  215. bufptr += sizeof(tightPalette);
  216. buflen -= sizeof(tightPalette);
  217. pf.bufferFromRGB(palette, tightPalette, palSize);
  218. } else {
  219. size_t len;
  220. len = palSize * pf.bpp/8;
  221. assert(buflen >= len);
  222. memcpy(palette, bufptr, len);
  223. bufptr += len;
  224. buflen -= len;
  225. }
  226. break;
  227. case tightFilterGradient:
  228. useGradient = true;
  229. break;
  230. case tightFilterCopy:
  231. break;
  232. default:
  233. assert(false);
  234. }
  235. }
  236. // Determine if the data should be decompressed or just copied.
  237. size_t rowSize, dataSize;
  238. rdr::U8* netbuf;
  239. netbuf = NULL;
  240. if (palSize != 0) {
  241. if (palSize <= 2)
  242. rowSize = (r.width() + 7) / 8;
  243. else
  244. rowSize = r.width();
  245. } else if (pf.is888()) {
  246. rowSize = r.width() * 3;
  247. } else {
  248. rowSize = r.width() * pf.bpp/8;
  249. }
  250. dataSize = r.height() * rowSize;
  251. if (dataSize < TIGHT_MIN_TO_COMPRESS)
  252. assert(buflen >= dataSize);
  253. else {
  254. rdr::U32 len;
  255. int streamId;
  256. rdr::MemInStream* ms;
  257. assert(buflen >= 4);
  258. memcpy(&len, bufptr, 4);
  259. bufptr += 4;
  260. buflen -= 4;
  261. assert(buflen >= len);
  262. streamId = comp_ctl & 0x03;
  263. ms = new rdr::MemInStream(bufptr, len);
  264. zis[streamId].setUnderlying(ms, len);
  265. // Allocate buffer and decompress the data
  266. netbuf = new rdr::U8[dataSize];
  267. zis[streamId].readBytes(netbuf, dataSize);
  268. zis[streamId].removeUnderlying();
  269. delete ms;
  270. bufptr = netbuf;
  271. buflen = dataSize;
  272. }
  273. // Time to decode the actual data
  274. bool directDecode;
  275. rdr::U8* outbuf;
  276. int stride;
  277. if (pb->getPF().equal(pf)) {
  278. // Decode directly into the framebuffer (fast path)
  279. directDecode = true;
  280. } else {
  281. // Decode into an intermediate buffer and use pixel translation
  282. directDecode = false;
  283. }
  284. if (directDecode)
  285. outbuf = pb->getBufferRW(r, &stride);
  286. else {
  287. outbuf = new rdr::U8[r.area() * pf.bpp/8];
  288. stride = r.width();
  289. }
  290. if (palSize == 0) {
  291. // Truecolor data
  292. if (useGradient) {
  293. if (pf.is888())
  294. FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  295. else {
  296. switch (pf.bpp) {
  297. case 8:
  298. assert(false);
  299. break;
  300. case 16:
  301. FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
  302. break;
  303. case 32:
  304. FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  305. break;
  306. }
  307. }
  308. } else {
  309. // Copy
  310. rdr::U8* ptr = outbuf;
  311. const rdr::U8* srcPtr = bufptr;
  312. int w = r.width();
  313. int h = r.height();
  314. if (pf.is888()) {
  315. while (h > 0) {
  316. pf.bufferFromRGB(ptr, srcPtr, w);
  317. ptr += stride * pf.bpp/8;
  318. srcPtr += w * 3;
  319. h--;
  320. }
  321. } else {
  322. while (h > 0) {
  323. memcpy(ptr, srcPtr, w * pf.bpp/8);
  324. ptr += stride * pf.bpp/8;
  325. srcPtr += w * pf.bpp/8;
  326. h--;
  327. }
  328. }
  329. }
  330. } else {
  331. // Indexed color
  332. switch (pf.bpp) {
  333. case 8:
  334. FilterPalette((const rdr::U8*)palette, palSize,
  335. bufptr, (rdr::U8*)outbuf, stride, r);
  336. break;
  337. case 16:
  338. FilterPalette((const rdr::U16*)palette, palSize,
  339. bufptr, (rdr::U16*)outbuf, stride, r);
  340. break;
  341. case 32:
  342. FilterPalette((const rdr::U32*)palette, palSize,
  343. bufptr, (rdr::U32*)outbuf, stride, r);
  344. break;
  345. }
  346. }
  347. if (directDecode)
  348. pb->commitBufferRW(r);
  349. else {
  350. pb->imageRect(pf, r, outbuf);
  351. delete [] outbuf;
  352. }
  353. delete [] netbuf;
  354. }
  355. rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
  356. {
  357. rdr::U8 b;
  358. rdr::U32 result;
  359. b = is->readU8();
  360. result = (int)b & 0x7F;
  361. if (b & 0x80) {
  362. b = is->readU8();
  363. result |= ((int)b & 0x7F) << 7;
  364. if (b & 0x80) {
  365. b = is->readU8();
  366. result |= ((int)b & 0xFF) << 14;
  367. }
  368. }
  369. return result;
  370. }