Added JpegCompressor abstract class and two implementations -- one cross-platform and another IRIX-specific.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2320 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/IrixDMJpegCompressor.cxx b/common/rfb/IrixDMJpegCompressor.cxx
new file mode 100644
index 0000000..57e8aa8
--- /dev/null
+++ b/common/rfb/IrixDMJpegCompressor.cxx
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+
+#include <rfb/IrixDMJpegCompressor.h>
+
+using namespace rfb;
+
+const int IrixDMJpegCompressor::DEFAULT_QUALITY = 75;
+
+//
+// Constructor and destructor.
+//
+
+IrixDMJpegCompressor::IrixDMJpegCompressor()
+  : m_quality(DEFAULT_QUALITY),
+    m_width(0),
+    m_height(0),
+    m_bufferSize(0),
+    m_compressedData(0),
+    m_compressedLength(0)
+{
+}
+
+IrixDMJpegCompressor::~IrixDMJpegCompressor()
+{
+  if (m_bufferSize > 0) {
+    m_ic.destroyBufferPool(m_srcPool);
+    m_ic.destroyBufferPool(m_dstPool);
+  }
+
+  if (m_compressedData)
+    delete[] m_compressedData;
+}
+
+//
+// Set JPEG quality level (0..100)
+//
+// FIXME: Call m_ic.setImageQuality() when necessary.
+//
+
+void
+IrixDMJpegCompressor::setQuality(int level)
+{
+  if (level < 0)
+    level = 0;
+  if (level > 100)
+    level = 100;
+
+  m_quality = level;
+}
+
+//
+// Perform JPEG compression.
+//
+// FIXME: This function assumes that pixel format is 32-bit XBGR
+//        (depth 24), compatible with IRIX Digital Media libraries.
+//
+
+void
+IrixDMJpegCompressor::compress(const rdr::U32 *buf,
+                               const PixelFormat *fmt,
+                               int w, int h, int stride)
+{
+  // Discard previous compression results.
+  if (m_compressedData) {
+    delete[] m_compressedData;
+    m_compressedData = 0;
+  }
+  m_compressedLength = 0;
+
+  // Setup the compressor.
+  if (!updateImageSize(w, h))
+    return;
+
+  // Prepare source image data.
+  DMbuffer srcBuf;
+  if (!m_ic.allocBuffer(&srcBuf, m_srcPool)) {
+    return;
+  }
+  // FIXME: Currently, copyToBuffer() copies parts of the image incorrectly.
+  if (!m_ic.copyToBuffer(srcBuf, buf, w * h * (fmt->bpp / 8))) {
+    m_ic.freeBuffer(srcBuf);
+    return;
+  }
+
+  // Initiate compression.
+  if (!m_ic.sendData(srcBuf)) {
+    m_ic.freeBuffer(srcBuf);
+    return;
+  }
+  m_ic.freeBuffer(srcBuf);
+
+  // Wait for results.
+  if (!m_ic.waitConversion()) {
+    perror("poll");		// FIXME: Unify error handling.
+    return;
+  }
+
+  // Save the results.
+  DMbuffer dstBuf;
+  if (!m_ic.receiveData(&dstBuf)) {
+    return;
+  }
+  m_compressedLength = m_ic.getBufferSize(dstBuf);
+  m_compressedData = new char[m_compressedLength];
+  void *bufPtr = m_ic.mapBufferData(dstBuf);
+  memcpy(m_compressedData, bufPtr, m_compressedLength);
+
+  m_ic.freeBuffer(dstBuf);
+}
+
+//
+// Update image size and make sure that our buffer pools will allocate
+// properly-sized buffers.
+//
+// FIXME: Handle image quality separately.
+//
+
+bool
+IrixDMJpegCompressor::updateImageSize(int w, int h)
+{
+  // Configure image formats and parameters, set JPEG image quality level.
+  if (w != m_width || h != m_height) {
+    if (!m_ic.setImageParams(w, h) || !m_ic.setImageQuality(m_quality)) {
+      return false;
+    }
+    m_width = w;
+    m_height = h;
+  }
+
+  // Set up source and destination buffer pools.
+  int dataLen = w * h * 4;
+  if (dataLen > m_bufferSize) {
+    if (m_bufferSize > 0) {
+      m_ic.destroyBufferPool(m_srcPool);
+      m_ic.destroyBufferPool(m_dstPool);
+      m_bufferSize = 0;
+    }
+    if (!m_ic.createSrcBufferPool(&m_srcPool, 1, dataLen)) {
+      return false;
+    }
+    if (!m_ic.registerDstBufferPool(&m_dstPool, 1, dataLen)) {
+      m_ic.destroyBufferPool(m_srcPool);
+      return false;
+    }
+    m_bufferSize = dataLen;
+  }
+
+  return true;
+}
+