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.

TightJPEGEncoder.cxx 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
  3. * Copyright 2014 Pierre Ossman for Cendio AB
  4. *
  5. * This is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This software is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this software; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  18. * USA.
  19. */
  20. #include <rdr/OutStream.h>
  21. #include <rfb/encodings.h>
  22. #include <rfb/SConnection.h>
  23. #include <rfb/PixelBuffer.h>
  24. #include <rfb/TightJPEGEncoder.h>
  25. #include <rfb/TightConstants.h>
  26. using namespace rfb;
  27. struct TightJPEGConfiguration {
  28. int quality;
  29. int subsampling;
  30. };
  31. // NOTE: The JPEG quality and subsampling levels below were obtained
  32. // experimentally by the VirtualGL Project. They represent the approximate
  33. // average compression ratios listed below, as measured across the set of
  34. // every 10th frame in the SPECviewperf 9 benchmark suite.
  35. //
  36. // 9 = JPEG quality 100, no subsampling (ratio ~= 10:1)
  37. // [this should be lossless, except for round-off error]
  38. // 8 = JPEG quality 92, no subsampling (ratio ~= 20:1)
  39. // [this should be perceptually lossless, based on current research]
  40. // 7 = JPEG quality 86, no subsampling (ratio ~= 25:1)
  41. // 6 = JPEG quality 79, no subsampling (ratio ~= 30:1)
  42. // 5 = JPEG quality 77, 4:2:2 subsampling (ratio ~= 40:1)
  43. // 4 = JPEG quality 62, 4:2:2 subsampling (ratio ~= 50:1)
  44. // 3 = JPEG quality 42, 4:2:2 subsampling (ratio ~= 60:1)
  45. // 2 = JPEG quality 41, 4:2:0 subsampling (ratio ~= 70:1)
  46. // 1 = JPEG quality 29, 4:2:0 subsampling (ratio ~= 80:1)
  47. // 0 = JPEG quality 15, 4:2:0 subsampling (ratio ~= 100:1)
  48. static const struct TightJPEGConfiguration conf[10] = {
  49. { 15, subsample4X }, // 0
  50. { 29, subsample4X }, // 1
  51. { 41, subsample4X }, // 2
  52. { 42, subsample2X }, // 3
  53. { 62, subsample2X }, // 4
  54. { 77, subsample2X }, // 5
  55. { 79, subsampleNone }, // 6
  56. { 86, subsampleNone }, // 7
  57. { 92, subsampleNone }, // 8
  58. { 100, subsampleNone } // 9
  59. };
  60. TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) :
  61. Encoder(conn, encodingTight,
  62. (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1, 9),
  63. qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined)
  64. {
  65. }
  66. TightJPEGEncoder::~TightJPEGEncoder()
  67. {
  68. }
  69. bool TightJPEGEncoder::isSupported()
  70. {
  71. if (!conn->client.supportsEncoding(encodingTight))
  72. return false;
  73. // Any one of these indicates support for JPEG
  74. if (conn->client.qualityLevel != -1)
  75. return true;
  76. if (conn->client.fineQualityLevel != -1)
  77. return true;
  78. if (conn->client.subsampling != -1)
  79. return true;
  80. // Tight support, but not JPEG
  81. return false;
  82. }
  83. void TightJPEGEncoder::setQualityLevel(int level)
  84. {
  85. qualityLevel = level;
  86. }
  87. void TightJPEGEncoder::setFineQualityLevel(int quality, int subsampling)
  88. {
  89. fineQuality = quality;
  90. fineSubsampling = subsampling;
  91. }
  92. int TightJPEGEncoder::getQualityLevel()
  93. {
  94. return qualityLevel;
  95. }
  96. void TightJPEGEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
  97. {
  98. const rdr::U8* buffer;
  99. int stride;
  100. int quality, subsampling;
  101. rdr::OutStream* os;
  102. buffer = pb->getBuffer(pb->getRect(), &stride);
  103. if (qualityLevel >= 0 && qualityLevel <= 9) {
  104. quality = conf[qualityLevel].quality;
  105. subsampling = conf[qualityLevel].subsampling;
  106. } else {
  107. quality = -1;
  108. subsampling = subsampleUndefined;
  109. }
  110. // Fine settings trump level
  111. if (fineQuality != -1)
  112. quality = fineQuality;
  113. if (fineSubsampling != subsampleUndefined)
  114. subsampling = fineSubsampling;
  115. jc.clear();
  116. jc.compress(buffer, stride, pb->getRect(),
  117. pb->getPF(), quality, subsampling);
  118. os = conn->getOutStream();
  119. os->writeU8(tightJpeg << 4);
  120. writeCompact(jc.length(), os);
  121. os->writeBytes(jc.data(), jc.length());
  122. }
  123. void TightJPEGEncoder::writeSolidRect(int width, int height,
  124. const PixelFormat& pf,
  125. const rdr::U8* colour)
  126. {
  127. // FIXME: Add a shortcut in the JPEG compressor to handle this case
  128. // without having to use the default fallback which is very slow.
  129. Encoder::writeSolidRect(width, height, pf, colour);
  130. }
  131. void TightJPEGEncoder::writeCompact(rdr::U32 value, rdr::OutStream* os)
  132. {
  133. // Copied from TightEncoder as it's overkill to inherit just for this
  134. rdr::U8 b;
  135. b = value & 0x7F;
  136. if (value <= 0x7F) {
  137. os->writeU8(b);
  138. } else {
  139. os->writeU8(b | 0x80);
  140. b = value >> 7 & 0x7F;
  141. if (value <= 0x3FFF) {
  142. os->writeU8(b);
  143. } else {
  144. os->writeU8(b | 0x80);
  145. os->writeU8(value >> 14 & 0xFF);
  146. }
  147. }
  148. }