summaryrefslogtreecommitdiffstats
path: root/common/rfb/IrixDMJpegCompressor.cxx
blob: 33397f634618f44188e6b7b7c0e384ca660b1a17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#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 (1..99)
//

void
IrixDMJpegCompressor::setQuality(int level)
{
  if (level < 1) {
    level = 1;
  } else if (level > 99) {
    level = 99;
  }
  if (level != m_quality) {
    m_quality = level;
    m_ic.setImageQuality(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;
  }
  int widthInBytes = w * (fmt->bpp / 8);
  int strideInBytes = stride * (fmt->bpp / 8);
  if (!m_ic.copyToBuffer(srcBuf, buf, widthInBytes, h, strideInBytes)) {
    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;
}