blob: 0c0a596cf03165cdd9135476352d236dcb075131 [file] [log] [blame]
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +00001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/poll.h>
5
6#include <rfb/IrixDMIC_RawToJpeg.h>
Constantin Kaplinsky67649492007-10-10 02:03:33 +00007#include <rfb/LogWriter.h>
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +00008
9using namespace rfb;
10
Constantin Kaplinsky67649492007-10-10 02:03:33 +000011static LogWriter vlog("IrixDMIC_RawToJpeg");
12
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +000013//
14// Constructor. Find a converter and create a context. Also, create
15// DMparams structures for using with dmICSetSrcParams,
16// dmICSetDstParams and dmICSetConvParams.
17//
18
19IrixDMIC_RawToJpeg::IrixDMIC_RawToJpeg(bool needRealtime)
20 : m_valid_ic(false),
21 m_srcParams(0),
22 m_dstParams(0),
23 m_convParams(0)
24{
25 if ( dmParamsCreate(&m_srcParams) != DM_SUCCESS ||
26 dmParamsCreate(&m_dstParams) != DM_SUCCESS ||
27 dmParamsCreate(&m_convParams) != DM_SUCCESS ) {
28 reportError("dmParamsCreate");
29 return;
30 }
31
32 DMparams *p;
33 const int JPEG_ID = 0x6A706567; // same as 'jpeg'
34 int id, direction, speed;
35
36 int n = dmICGetNum();
37 while (n--) {
38 if (dmParamsCreate(&p) != DM_SUCCESS) {
39 reportError("dmParamsCreate");
40 return;
41 }
42 if (dmICGetDescription(n, p) != DM_SUCCESS)
43 continue;
44 id = dmParamsGetInt(p, DM_IC_ID);
45 direction = dmParamsGetEnum(p, DM_IC_CODE_DIRECTION);
46 speed = dmParamsGetEnum(p, DM_IC_SPEED);
47 if ( id == JPEG_ID && direction == DM_IC_CODE_DIRECTION_ENCODE &&
48 (!needRealtime || speed == DM_IC_SPEED_REALTIME) ) {
49
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +000050 const char *engine = dmParamsGetString(p, DM_IC_ENGINE);
Constantin Kaplinsky67649492007-10-10 02:03:33 +000051 vlog.info("Found JPEG encoder: \"%s\" (%d)", engine, n);
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +000052
53 dmParamsDestroy(p);
54 break;
55 }
56 dmParamsDestroy(p);
57 }
58 if (n < 0) {
Constantin Kaplinsky67649492007-10-10 02:03:33 +000059 vlog.error("Error: No matching JPEG encoder found");
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +000060 return;
61 }
62 if (dmICCreate(n, &m_ic) != DM_SUCCESS) {
63 reportError("dmICCreate");
64 return;
65 }
66
67 m_valid_ic = true;
68}
69
70//
71// Destructor.
72//
73
74IrixDMIC_RawToJpeg::~IrixDMIC_RawToJpeg()
75{
76 if (m_valid_ic)
77 dmICDestroy(m_ic);
78
79 if (m_convParams)
80 dmParamsDestroy(m_convParams);
81 if (m_dstParams)
82 dmParamsDestroy(m_dstParams);
83 if (m_srcParams)
84 dmParamsDestroy(m_srcParams);
85}
86
87//
88// Configure the source and destination formats.
89//
90// FIXME: Remember image size that was previously set, do not set the
91// same size again.
92//
93
94bool
95IrixDMIC_RawToJpeg::setImageParams(int w, int h)
96{
97 if (!m_valid_ic) {
98 reportErrorNotInited();
99 return false;
100 }
101
102 // Set source image parameters.
103 DMpacking packing = DM_IMAGE_PACKING_XBGR;
104 int orient = DM_IMAGE_TOP_TO_BOTTOM;
105 if (dmSetImageDefaults(m_srcParams, w, h, packing) != DM_SUCCESS) {
106 reportError("dmSetImageDefaults");
107 return false;
108 }
109 DMstatus err = dmParamsSetEnum(m_srcParams, DM_IMAGE_ORIENTATION, orient);
110 if (err != DM_SUCCESS) {
111 reportError("dmParamsSetEnum");
112 return false;
113 }
114 if (dmICSetSrcParams(m_ic, m_srcParams) != DM_SUCCESS) {
115 reportError("dmICSetSrcParams");
116 return false;
117 }
118
119 // Set destination image parameters.
120 packing = DM_IMAGE_PACKING_CbYCrY;
121 const char *compression = DM_IMAGE_JPEG;
122 if (dmSetImageDefaults(m_dstParams, w, h, packing) != DM_SUCCESS) {
123 reportError("dmSetImageDefaults");
124 return false;
125 }
126 err = dmParamsSetEnum(m_dstParams, DM_IMAGE_ORIENTATION, orient);
127 if (err != DM_SUCCESS) {
128 reportError("dmParamsSetEnum");
129 return false;
130 }
131 err = dmParamsSetString(m_dstParams, DM_IMAGE_COMPRESSION, compression);
132 if (err != DM_SUCCESS) {
133 reportError("dmParamsSetString");
134 return false;
135 }
136 if (dmICSetDstParams(m_ic, m_dstParams) != DM_SUCCESS) {
137 reportError("dmICSetDstParams");
138 return false;
139 }
140
141 return true;
142}
143
144//
145// Set JPEG image quality level (an integer in the range 0..99).
146//
147// FIXME: Remember image quality that was previously set, do not set
148// the same quality again.
149//
150
151bool
152IrixDMIC_RawToJpeg::setImageQuality(int quality)
153{
154 if (!m_valid_ic) {
155 reportErrorNotInited();
156 return false;
157 }
158
159 double qf = (double)quality / 100.0;
160
161 DMstatus err = dmParamsSetFloat(m_convParams, DM_IMAGE_QUALITY_SPATIAL, qf);
162 if (err != DM_SUCCESS) {
163 reportError("dmParamsSetFloat");
164 return false;
165 }
166 if (dmICSetConvParams(m_ic, m_convParams) != DM_SUCCESS) {
167 reportError("dmICSetConvParams");
168 return false;
169 }
170
171 return true;
172}
173
174//
175// Set up source buffer pool.
176//
177// NOTE: Both setImageParams() and setImageQuality() functions should
178// be called prior to creating and registering buffer pools.
179//
180
181bool
182IrixDMIC_RawToJpeg::createSrcBufferPool(DMbufferpool *pool,
183 int bufCount, int bufSize)
184{
185 if (!m_valid_ic) {
186 reportErrorNotInited();
187 return false;
188 }
189
190 DMparams *p;
191 if (dmParamsCreate(&p) != DM_SUCCESS) {
192 reportError("dmParamsCreate");
193 return false;
194 }
195
196 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
197 DM_SUCCESS) {
198 reportError("dmBufferSetPoolDefaults");
199 dmParamsDestroy(p);
200 return false;
201 }
202 if (dmICGetSrcPoolParams(m_ic, p) != DM_SUCCESS) {
203 reportError("dmICGetSrcPoolParams");
204 dmParamsDestroy(p);
205 return false;
206 }
207 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
208 reportError("dmBufferCreatePool");
209 dmParamsDestroy(p);
210 return false;
211 }
212
213 dmParamsDestroy(p);
214 return true;
215}
216
217//
218// Set up and register destination buffer pool.
219//
220// NOTE: Both setImageParams() and setImageQuality() functions should
221// be called prior to creating and registering buffer pools.
222//
223
224bool
225IrixDMIC_RawToJpeg::registerDstBufferPool(DMbufferpool *pool,
226 int bufCount, int bufSize)
227{
228 if (!m_valid_ic) {
229 reportErrorNotInited();
230 return false;
231 }
232
233 DMparams *p;
234 if (dmParamsCreate(&p) != DM_SUCCESS) {
235 reportError("dmParamsCreate");
236 return false;
237 }
238
239 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
240 DM_SUCCESS) {
241 reportError("dmBufferSetPoolDefaults");
242 dmParamsDestroy(p);
243 return false;
244 }
245 if (dmICGetDstPoolParams(m_ic, p) != DM_SUCCESS) {
246 reportError("dmICGetDstPoolParams");
247 dmParamsDestroy(p);
248 return false;
249 }
250 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
251 reportError("dmBufferCreatePool");
252 dmParamsDestroy(p);
253 return false;
254 }
255
256 dmParamsDestroy(p);
257
258 if (dmICSetDstPool(m_ic, *pool) != DM_SUCCESS) {
259 reportError("dmICSetDstPool");
260 destroyBufferPool(*pool);
261 return false;
262 }
263
264 return true;
265}
266
267//
268// Destroy buffer pool created with either createSrcBufferPool() or
269// registerDstBufferPool().
270//
271
272void
273IrixDMIC_RawToJpeg::destroyBufferPool(DMbufferpool pool)
274{
275 if (dmBufferDestroyPool(pool) != DM_SUCCESS)
276 reportError("dmBufferDestroyPool");
277}
278
279//
280// Allocate a buffer from the specified pool.
281//
282
283bool
284IrixDMIC_RawToJpeg::allocBuffer(DMbuffer *pbuf, DMbufferpool pool)
285{
286 if (dmBufferAllocate(pool, pbuf) != DM_SUCCESS) {
287 reportError("dmBufferAllocate");
288 return false;
289 }
290
291 return true;
292}
293
294//
295// Fill in a DMbuffer with data.
296//
297// NOTE: The caller must make sure that the buffer size is no less
298// than dataSize.
299//
300
301bool
302IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data, int dataSize)
303{
304 void *bufPtr = dmBufferMapData(buf);
305 memcpy(bufPtr, data, dataSize);
306
307 if (dmBufferSetSize(buf, dataSize) != DM_SUCCESS) {
308 reportError("dmBufferSetSize");
309 return false;
310 }
311
312 return true;
313}
314
315//
Constantin Kaplinsky52eaa8c2007-09-04 09:12:59 +0000316// Fill in a DMbuffer with data.
317//
318// NOTE: The caller must make sure that the buffer size is no less
319// than (nRows * rowSize).
320//
321
322bool
323IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data,
324 int rowSize, int nRows, int stride)
325{
326 char *dataBytes = (char *)data;
327 char *bufPtr = (char *)dmBufferMapData(buf);
328 for (int i = 0; i < nRows; i++) {
329 memcpy(bufPtr, &dataBytes[i * stride], rowSize);
330 bufPtr += rowSize;
331 }
332
333 if (dmBufferSetSize(buf, nRows * rowSize) != DM_SUCCESS) {
334 reportError("dmBufferSetSize");
335 return false;
336 }
337
338 return true;
339}
340
341//
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000342// Map DMbuffer to physical memory.
343//
344
345void *
346IrixDMIC_RawToJpeg::mapBufferData(DMbuffer buf)
347{
348 return dmBufferMapData(buf);
349}
350
351//
352// Get the number of valid bytes in DMbuffer.
353//
354
355int
356IrixDMIC_RawToJpeg::getBufferSize(DMbuffer buf)
357{
358 return dmBufferGetSize(buf);
359}
360
361//
362// Free DMbuffer.
363//
364
365void
366IrixDMIC_RawToJpeg::freeBuffer(DMbuffer buf)
367{
368 if (dmBufferFree(buf) != DM_SUCCESS)
369 reportError("dmBufferFree");
370}
371
372//
373// Send input data (raw pixels) to the converter.
374//
375
376bool
377IrixDMIC_RawToJpeg::sendData(DMbuffer buf)
378{
379 if (dmICSend(m_ic, buf, 0, NULL) != DM_SUCCESS) {
380 reportError("dmICSend");
381 return false;
382 }
383
384 return true;
385}
386
387//
388// Wait until compression is finished (infinite timeout!).
389// This function should be called after sendData() and before receiveData().
390//
391// FIXME: Report errors.
392//
393
394bool
395IrixDMIC_RawToJpeg::waitConversion()
396{
397 struct pollfd ps;
398 ps.fd = dmICGetDstQueueFD(m_ic);
399 ps.events = POLLIN;
400
401 int result = poll(&ps, 1, -1);
402 if (result != 1)
403 return false;
404
405 if ((ps.revents & POLLIN) != 0) {
406 return true;
407 } else {
408 return false;
409 }
410}
411
412//
413// Receive output (JPEG data) from the converter.
414// Call waitConversion() function first.
415//
416
417bool
418IrixDMIC_RawToJpeg::receiveData(DMbuffer *pbuf)
419{
420 if (dmICReceive(m_ic, pbuf) != DM_SUCCESS) {
421 reportError("dmICReceive");
422 return false;
423 }
424
425 return true;
426}
427
428//
429// Report an error when a function returns DM_FAILURE.
430//
431
432void
433IrixDMIC_RawToJpeg::reportError(const char *funcName)
434{
435 char errorDetail[DM_MAX_ERROR_DETAIL];
436 const char *errorCategory = dmGetError(NULL, errorDetail);
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000437 vlog.error("%s() failed: %s: %s",
438 funcName, errorCategory, errorDetail);
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000439}
440
441//
442// Report an error when (m_valid_ic == false).
443//
444
445void
446IrixDMIC_RawToJpeg::reportErrorNotInited()
447{
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000448 vlog.error("Internal error: Image converter not initialized");
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000449}
450