blob: 4cdb1ba03ddd9753ae28b482b0843492cf0deeee [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 Kaplinsky9964c782007-10-10 06:22:34 +000011static LogWriter vlog("IrixDMIC");
Constantin Kaplinsky67649492007-10-10 02:03:33 +000012
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 Kaplinsky9964c782007-10-10 06:22:34 +000060 debugListConverters();
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +000061 return;
62 }
63 if (dmICCreate(n, &m_ic) != DM_SUCCESS) {
64 reportError("dmICCreate");
65 return;
66 }
67
68 m_valid_ic = true;
69}
70
71//
72// Destructor.
73//
74
75IrixDMIC_RawToJpeg::~IrixDMIC_RawToJpeg()
76{
77 if (m_valid_ic)
78 dmICDestroy(m_ic);
79
80 if (m_convParams)
81 dmParamsDestroy(m_convParams);
82 if (m_dstParams)
83 dmParamsDestroy(m_dstParams);
84 if (m_srcParams)
85 dmParamsDestroy(m_srcParams);
86}
87
Constantin Kaplinsky9964c782007-10-10 06:22:34 +000088void
89IrixDMIC_RawToJpeg::debugListConverters()
90{
91 int n = dmICGetNum();
92 vlog.debug("IRIX DMIC converters available (%d):", n);
93 for (int i = 0; i < n; i++) {
94 DMparams *p;
95 if (dmParamsCreate(&p) != DM_SUCCESS) {
96 return;
97 }
98 if (dmICGetDescription(i, p) != DM_SUCCESS) {
99 vlog.debug(" continue");
100 continue;
101 }
102 union {
103 int id;
104 char label[5];
105 } id;
106 id.id = dmParamsGetInt(p, DM_IC_ID);
107 id.label[4] = '\0';
108 int direction = dmParamsGetEnum(p, DM_IC_CODE_DIRECTION);
109 const char *directionLabel = "converter";
110 if (direction == DM_IC_CODE_DIRECTION_ENCODE) {
111 directionLabel = "encoder";
112 } else if (direction == DM_IC_CODE_DIRECTION_DECODE) {
113 directionLabel = "decoder";
114 }
115 int speed = dmParamsGetEnum(p, DM_IC_SPEED);
116 const char *speedLabel = "";
117 if (speed == DM_IC_SPEED_REALTIME) {
118 speedLabel = "realtime ";
119 }
120 const char *engine = dmParamsGetString(p, DM_IC_ENGINE);
121 vlog.debug(" converter %d: '%s' %s%s (%s)",
122 i, id.label, speedLabel, directionLabel, engine);
123 dmParamsDestroy(p);
124 }
125}
126
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000127//
128// Configure the source and destination formats.
129//
130// FIXME: Remember image size that was previously set, do not set the
131// same size again.
132//
133
134bool
135IrixDMIC_RawToJpeg::setImageParams(int w, int h)
136{
137 if (!m_valid_ic) {
138 reportErrorNotInited();
139 return false;
140 }
141
142 // Set source image parameters.
143 DMpacking packing = DM_IMAGE_PACKING_XBGR;
144 int orient = DM_IMAGE_TOP_TO_BOTTOM;
145 if (dmSetImageDefaults(m_srcParams, w, h, packing) != DM_SUCCESS) {
146 reportError("dmSetImageDefaults");
147 return false;
148 }
149 DMstatus err = dmParamsSetEnum(m_srcParams, DM_IMAGE_ORIENTATION, orient);
150 if (err != DM_SUCCESS) {
151 reportError("dmParamsSetEnum");
152 return false;
153 }
154 if (dmICSetSrcParams(m_ic, m_srcParams) != DM_SUCCESS) {
155 reportError("dmICSetSrcParams");
156 return false;
157 }
158
159 // Set destination image parameters.
160 packing = DM_IMAGE_PACKING_CbYCrY;
161 const char *compression = DM_IMAGE_JPEG;
162 if (dmSetImageDefaults(m_dstParams, w, h, packing) != DM_SUCCESS) {
163 reportError("dmSetImageDefaults");
164 return false;
165 }
166 err = dmParamsSetEnum(m_dstParams, DM_IMAGE_ORIENTATION, orient);
167 if (err != DM_SUCCESS) {
168 reportError("dmParamsSetEnum");
169 return false;
170 }
171 err = dmParamsSetString(m_dstParams, DM_IMAGE_COMPRESSION, compression);
172 if (err != DM_SUCCESS) {
173 reportError("dmParamsSetString");
174 return false;
175 }
176 if (dmICSetDstParams(m_ic, m_dstParams) != DM_SUCCESS) {
177 reportError("dmICSetDstParams");
178 return false;
179 }
180
181 return true;
182}
183
184//
185// Set JPEG image quality level (an integer in the range 0..99).
186//
187// FIXME: Remember image quality that was previously set, do not set
188// the same quality again.
189//
190
191bool
192IrixDMIC_RawToJpeg::setImageQuality(int quality)
193{
194 if (!m_valid_ic) {
195 reportErrorNotInited();
196 return false;
197 }
198
199 double qf = (double)quality / 100.0;
200
201 DMstatus err = dmParamsSetFloat(m_convParams, DM_IMAGE_QUALITY_SPATIAL, qf);
202 if (err != DM_SUCCESS) {
203 reportError("dmParamsSetFloat");
204 return false;
205 }
Constantin Kaplinskyabcbd002007-12-07 10:28:11 +0000206
207 // For some reason, dmICSetConvParams() does not have effect without
208 // calling dmICSetDstParams() as well. So we call it here.
209 if (m_dstParams && dmParamsGetNumElems(m_dstParams) &&
210 dmICSetDstParams(m_ic, m_dstParams) != DM_SUCCESS) {
211 reportError("dmICSetDstParams");
212 return false;
213 }
214
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000215 if (dmICSetConvParams(m_ic, m_convParams) != DM_SUCCESS) {
216 reportError("dmICSetConvParams");
217 return false;
218 }
219
220 return true;
221}
222
223//
224// Set up source buffer pool.
225//
226// NOTE: Both setImageParams() and setImageQuality() functions should
227// be called prior to creating and registering buffer pools.
228//
229
230bool
231IrixDMIC_RawToJpeg::createSrcBufferPool(DMbufferpool *pool,
232 int bufCount, int bufSize)
233{
234 if (!m_valid_ic) {
235 reportErrorNotInited();
236 return false;
237 }
238
239 DMparams *p;
240 if (dmParamsCreate(&p) != DM_SUCCESS) {
241 reportError("dmParamsCreate");
242 return false;
243 }
244
245 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
246 DM_SUCCESS) {
247 reportError("dmBufferSetPoolDefaults");
248 dmParamsDestroy(p);
249 return false;
250 }
251 if (dmICGetSrcPoolParams(m_ic, p) != DM_SUCCESS) {
252 reportError("dmICGetSrcPoolParams");
253 dmParamsDestroy(p);
254 return false;
255 }
256 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
257 reportError("dmBufferCreatePool");
258 dmParamsDestroy(p);
259 return false;
260 }
261
262 dmParamsDestroy(p);
263 return true;
264}
265
266//
267// Set up and register destination buffer pool.
268//
269// NOTE: Both setImageParams() and setImageQuality() functions should
270// be called prior to creating and registering buffer pools.
271//
272
273bool
274IrixDMIC_RawToJpeg::registerDstBufferPool(DMbufferpool *pool,
275 int bufCount, int bufSize)
276{
277 if (!m_valid_ic) {
278 reportErrorNotInited();
279 return false;
280 }
281
282 DMparams *p;
283 if (dmParamsCreate(&p) != DM_SUCCESS) {
284 reportError("dmParamsCreate");
285 return false;
286 }
287
288 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
289 DM_SUCCESS) {
290 reportError("dmBufferSetPoolDefaults");
291 dmParamsDestroy(p);
292 return false;
293 }
294 if (dmICGetDstPoolParams(m_ic, p) != DM_SUCCESS) {
295 reportError("dmICGetDstPoolParams");
296 dmParamsDestroy(p);
297 return false;
298 }
299 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
300 reportError("dmBufferCreatePool");
301 dmParamsDestroy(p);
302 return false;
303 }
304
305 dmParamsDestroy(p);
306
307 if (dmICSetDstPool(m_ic, *pool) != DM_SUCCESS) {
308 reportError("dmICSetDstPool");
309 destroyBufferPool(*pool);
310 return false;
311 }
312
313 return true;
314}
315
316//
317// Destroy buffer pool created with either createSrcBufferPool() or
318// registerDstBufferPool().
319//
320
321void
322IrixDMIC_RawToJpeg::destroyBufferPool(DMbufferpool pool)
323{
324 if (dmBufferDestroyPool(pool) != DM_SUCCESS)
325 reportError("dmBufferDestroyPool");
326}
327
328//
329// Allocate a buffer from the specified pool.
330//
331
332bool
333IrixDMIC_RawToJpeg::allocBuffer(DMbuffer *pbuf, DMbufferpool pool)
334{
335 if (dmBufferAllocate(pool, pbuf) != DM_SUCCESS) {
336 reportError("dmBufferAllocate");
337 return false;
338 }
339
340 return true;
341}
342
343//
344// Fill in a DMbuffer with data.
345//
346// NOTE: The caller must make sure that the buffer size is no less
347// than dataSize.
348//
349
350bool
351IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data, int dataSize)
352{
353 void *bufPtr = dmBufferMapData(buf);
354 memcpy(bufPtr, data, dataSize);
355
356 if (dmBufferSetSize(buf, dataSize) != DM_SUCCESS) {
357 reportError("dmBufferSetSize");
358 return false;
359 }
360
361 return true;
362}
363
364//
Constantin Kaplinsky52eaa8c2007-09-04 09:12:59 +0000365// Fill in a DMbuffer with data.
366//
367// NOTE: The caller must make sure that the buffer size is no less
368// than (nRows * rowSize).
369//
370
371bool
372IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data,
373 int rowSize, int nRows, int stride)
374{
375 char *dataBytes = (char *)data;
376 char *bufPtr = (char *)dmBufferMapData(buf);
377 for (int i = 0; i < nRows; i++) {
378 memcpy(bufPtr, &dataBytes[i * stride], rowSize);
379 bufPtr += rowSize;
380 }
381
382 if (dmBufferSetSize(buf, nRows * rowSize) != DM_SUCCESS) {
383 reportError("dmBufferSetSize");
384 return false;
385 }
386
387 return true;
388}
389
390//
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000391// Map DMbuffer to physical memory.
392//
393
394void *
395IrixDMIC_RawToJpeg::mapBufferData(DMbuffer buf)
396{
397 return dmBufferMapData(buf);
398}
399
400//
401// Get the number of valid bytes in DMbuffer.
402//
403
404int
405IrixDMIC_RawToJpeg::getBufferSize(DMbuffer buf)
406{
407 return dmBufferGetSize(buf);
408}
409
410//
411// Free DMbuffer.
412//
413
414void
415IrixDMIC_RawToJpeg::freeBuffer(DMbuffer buf)
416{
417 if (dmBufferFree(buf) != DM_SUCCESS)
418 reportError("dmBufferFree");
419}
420
421//
422// Send input data (raw pixels) to the converter.
423//
424
425bool
426IrixDMIC_RawToJpeg::sendData(DMbuffer buf)
427{
428 if (dmICSend(m_ic, buf, 0, NULL) != DM_SUCCESS) {
429 reportError("dmICSend");
430 return false;
431 }
432
433 return true;
434}
435
436//
437// Wait until compression is finished (infinite timeout!).
438// This function should be called after sendData() and before receiveData().
439//
440// FIXME: Report errors.
441//
442
443bool
444IrixDMIC_RawToJpeg::waitConversion()
445{
446 struct pollfd ps;
447 ps.fd = dmICGetDstQueueFD(m_ic);
448 ps.events = POLLIN;
449
450 int result = poll(&ps, 1, -1);
451 if (result != 1)
452 return false;
453
454 if ((ps.revents & POLLIN) != 0) {
455 return true;
456 } else {
457 return false;
458 }
459}
460
461//
462// Receive output (JPEG data) from the converter.
463// Call waitConversion() function first.
464//
465
466bool
467IrixDMIC_RawToJpeg::receiveData(DMbuffer *pbuf)
468{
469 if (dmICReceive(m_ic, pbuf) != DM_SUCCESS) {
470 reportError("dmICReceive");
471 return false;
472 }
473
474 return true;
475}
476
477//
478// Report an error when a function returns DM_FAILURE.
479//
480
481void
482IrixDMIC_RawToJpeg::reportError(const char *funcName)
483{
484 char errorDetail[DM_MAX_ERROR_DETAIL];
485 const char *errorCategory = dmGetError(NULL, errorDetail);
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000486 vlog.error("%s() failed: %s: %s",
487 funcName, errorCategory, errorDetail);
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000488}
489
490//
491// Report an error when (m_valid_ic == false).
492//
493
494void
495IrixDMIC_RawToJpeg::reportErrorNotInited()
496{
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000497 vlog.error("Internal error: Image converter not initialized");
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000498}
499