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.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. #ifdef HAVE_CONFIG_H
  21. #include <config.h>
  22. #endif
  23. #include <rdr/OutStream.h>
  24. #include <rfb/encodings.h>
  25. #include <rfb/SConnection.h>
  26. #include <rfb/PixelBuffer.h>
  27. #include <rfb/TightJPEGEncoder.h>
  28. #include <rfb/TightConstants.h>
  29. using namespace rfb;
  30. struct TightJPEGConfiguration {
  31. int quality;
  32. int subsampling;
  33. };
  34. // NOTE: The JPEG quality and subsampling levels below were obtained
  35. // experimentally by the VirtualGL Project. They represent the approximate
  36. // average compression ratios listed below, as measured across the set of
  37. // every 10th frame in the SPECviewperf 9 benchmark suite.
  38. //
  39. // 9 = JPEG quality 100, no subsampling (ratio ~= 10:1)
  40. // [this should be lossless, except for round-off error]
  41. // 8 = JPEG quality 92, no subsampling (ratio ~= 20:1)
  42. // [this should be perceptually lossless, based on current research]
  43. // 7 = JPEG quality 86, no subsampling (ratio ~= 25:1)
  44. // 6 = JPEG quality 79, no subsampling (ratio ~= 30:1)
  45. // 5 = JPEG quality 77, 4:2:2 subsampling (ratio ~= 40:1)
  46. // 4 = JPEG quality 62, 4:2:2 subsampling (ratio ~= 50:1)
  47. // 3 = JPEG quality 42, 4:2:2 subsampling (ratio ~= 60:1)
  48. // 2 = JPEG quality 41, 4:2:0 subsampling (ratio ~= 70:1)
  49. // 1 = JPEG quality 29, 4:2:0 subsampling (ratio ~= 80:1)
  50. // 0 = JPEG quality 15, 4:2:0 subsampling (ratio ~= 100:1)
  51. static const struct TightJPEGConfiguration conf[10] = {
  52. { 15, subsample4X }, // 0
  53. { 29, subsample4X }, // 1
  54. { 41, subsample4X }, // 2
  55. { 42, subsample2X }, // 3
  56. { 62, subsample2X }, // 4
  57. { 77, subsample2X }, // 5
  58. { 79, subsampleNone }, // 6
  59. { 86, subsampleNone }, // 7
  60. { 92, subsampleNone }, // 8
  61. { 100, subsampleNone } // 9
  62. };
  63. TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) :
  64. Encoder(conn, encodingTight,
  65. (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1, 9),
  66. qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined)
  67. {
  68. }
  69. TightJPEGEncoder::~TightJPEGEncoder()
  70. {
  71. }
  72. bool TightJPEGEncoder::isSupported()
  73. {
  74. if (!conn->client.supportsEncoding(encodingTight))
  75. return false;
  76. // Any one of these indicates support for JPEG
  77. if (conn->client.qualityLevel != -1)
  78. return true;
  79. if (conn->client.fineQualityLevel != -1)
  80. return true;
  81. if (conn->client.subsampling != -1)
  82. return true;
  83. // Tight support, but not JPEG
  84. return false;
  85. }
  86. void TightJPEGEncoder::setQualityLevel(int level)
  87. {
  88. qualityLevel = level;
  89. }
  90. void TightJPEGEncoder::setFineQualityLevel(int quality, int subsampling)
  91. {
  92. fineQuality = quality;
  93. fineSubsampling = subsampling;
  94. }
  95. int TightJPEGEncoder::getQualityLevel()
  96. {
  97. return qualityLevel;
  98. }
  99. void TightJPEGEncoder::writeRect(const PixelBuffer* pb,
  100. const Palette& /*palette*/)
  101. {
  102. const rdr::U8* buffer;
  103. int stride;
  104. int quality, subsampling;
  105. rdr::OutStream* os;
  106. buffer = pb->getBuffer(pb->getRect(), &stride);
  107. if (qualityLevel >= 0 && qualityLevel <= 9) {
  108. quality = conf[qualityLevel].quality;
  109. subsampling = conf[qualityLevel].subsampling;
  110. } else {
  111. quality = -1;
  112. subsampling = subsampleUndefined;
  113. }
  114. // Fine settings trump level
  115. if (fineQuality != -1)
  116. quality = fineQuality;
  117. if (fineSubsampling != subsampleUndefined)
  118. subsampling = fineSubsampling;
  119. jc.clear();
  120. jc.compress(buffer, stride, pb->getRect(),
  121. pb->getPF(), quality, subsampling);
  122. os = conn->getOutStream();
  123. os->writeU8(tightJpeg << 4);
  124. writeCompact(jc.length(), os);
  125. os->writeBytes(jc.data(), jc.length());
  126. }
  127. void TightJPEGEncoder::writeSolidRect(int width, int height,
  128. const PixelFormat& pf,
  129. const rdr::U8* colour)
  130. {
  131. // FIXME: Add a shortcut in the JPEG compressor to handle this case
  132. // without having to use the default fallback which is very slow.
  133. Encoder::writeSolidRect(width, height, pf, colour);
  134. }
  135. void TightJPEGEncoder::writeCompact(rdr::U32 value, rdr::OutStream* os)
  136. {
  137. // Copied from TightEncoder as it's overkill to inherit just for this
  138. rdr::U8 b;
  139. b = value & 0x7F;
  140. if (value <= 0x7F) {
  141. os->writeU8(b);
  142. } else {
  143. os->writeU8(b | 0x80);
  144. b = value >> 7 & 0x7F;
  145. if (value <= 0x3FFF) {
  146. os->writeU8(b);
  147. } else {
  148. os->writeU8(b | 0x80);
  149. os->writeU8(value >> 14 & 0xFF);
  150. }
  151. }
  152. }