選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

TightJPEGEncoder.cxx 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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, (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1),
  62. qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined)
  63. {
  64. }
  65. TightJPEGEncoder::~TightJPEGEncoder()
  66. {
  67. }
  68. bool TightJPEGEncoder::isSupported()
  69. {
  70. if (!conn->cp.supportsEncoding(encodingTight))
  71. return false;
  72. // Any one of these indicates support for JPEG
  73. if (conn->cp.qualityLevel != -1)
  74. return true;
  75. if (conn->cp.fineQualityLevel != -1)
  76. return true;
  77. if (conn->cp.subsampling != -1)
  78. return true;
  79. // Tight support, but not JPEG
  80. return false;
  81. }
  82. void TightJPEGEncoder::setQualityLevel(int level)
  83. {
  84. qualityLevel = level;
  85. }
  86. void TightJPEGEncoder::setFineQualityLevel(int quality, int subsampling)
  87. {
  88. fineQuality = quality;
  89. fineSubsampling = subsampling;
  90. }
  91. void TightJPEGEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
  92. {
  93. const rdr::U8* buffer;
  94. int stride;
  95. int quality, subsampling;
  96. rdr::OutStream* os;
  97. buffer = pb->getBuffer(pb->getRect(), &stride);
  98. if (qualityLevel >= 0 && qualityLevel <= 9) {
  99. quality = conf[qualityLevel].quality;
  100. subsampling = conf[qualityLevel].subsampling;
  101. } else {
  102. quality = -1;
  103. subsampling = subsampleUndefined;
  104. }
  105. // Fine settings trump level
  106. if (fineQuality != -1)
  107. quality = fineQuality;
  108. if (fineSubsampling != subsampleUndefined)
  109. subsampling = fineSubsampling;
  110. jc.clear();
  111. jc.compress(buffer, stride, pb->getRect(),
  112. pb->getPF(), quality, subsampling);
  113. os = conn->getOutStream();
  114. os->writeU8(tightJpeg << 4);
  115. writeCompact(jc.length(), os);
  116. os->writeBytes(jc.data(), jc.length());
  117. }
  118. void TightJPEGEncoder::writeSolidRect(int width, int height,
  119. const PixelFormat& pf,
  120. const rdr::U8* colour)
  121. {
  122. // FIXME: Add a shortcut in the JPEG compressor to handle this case
  123. // without having to use the default fallback which is very slow.
  124. Encoder::writeSolidRect(width, height, pf, colour);
  125. }
  126. void TightJPEGEncoder::writeCompact(rdr::U32 value, rdr::OutStream* os)
  127. {
  128. // Copied from TightEncoder as it's overkill to inherit just for this
  129. rdr::U8 b;
  130. b = value & 0x7F;
  131. if (value <= 0x7F) {
  132. os->writeU8(b);
  133. } else {
  134. os->writeU8(b | 0x80);
  135. b = value >> 7 & 0x7F;
  136. if (value <= 0x3FFF) {
  137. os->writeU8(b);
  138. } else {
  139. os->writeU8(b | 0x80);
  140. os->writeU8(value >> 14 & 0xFF);
  141. }
  142. }
  143. }