blob: afa0d18b4282b0481919fc58545e8b6401c43756 [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 }
206 if (dmICSetConvParams(m_ic, m_convParams) != DM_SUCCESS) {
207 reportError("dmICSetConvParams");
208 return false;
209 }
210
211 return true;
212}
213
214//
215// Set up source buffer pool.
216//
217// NOTE: Both setImageParams() and setImageQuality() functions should
218// be called prior to creating and registering buffer pools.
219//
220
221bool
222IrixDMIC_RawToJpeg::createSrcBufferPool(DMbufferpool *pool,
223 int bufCount, int bufSize)
224{
225 if (!m_valid_ic) {
226 reportErrorNotInited();
227 return false;
228 }
229
230 DMparams *p;
231 if (dmParamsCreate(&p) != DM_SUCCESS) {
232 reportError("dmParamsCreate");
233 return false;
234 }
235
236 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
237 DM_SUCCESS) {
238 reportError("dmBufferSetPoolDefaults");
239 dmParamsDestroy(p);
240 return false;
241 }
242 if (dmICGetSrcPoolParams(m_ic, p) != DM_SUCCESS) {
243 reportError("dmICGetSrcPoolParams");
244 dmParamsDestroy(p);
245 return false;
246 }
247 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
248 reportError("dmBufferCreatePool");
249 dmParamsDestroy(p);
250 return false;
251 }
252
253 dmParamsDestroy(p);
254 return true;
255}
256
257//
258// Set up and register destination buffer pool.
259//
260// NOTE: Both setImageParams() and setImageQuality() functions should
261// be called prior to creating and registering buffer pools.
262//
263
264bool
265IrixDMIC_RawToJpeg::registerDstBufferPool(DMbufferpool *pool,
266 int bufCount, int bufSize)
267{
268 if (!m_valid_ic) {
269 reportErrorNotInited();
270 return false;
271 }
272
273 DMparams *p;
274 if (dmParamsCreate(&p) != DM_SUCCESS) {
275 reportError("dmParamsCreate");
276 return false;
277 }
278
279 if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) !=
280 DM_SUCCESS) {
281 reportError("dmBufferSetPoolDefaults");
282 dmParamsDestroy(p);
283 return false;
284 }
285 if (dmICGetDstPoolParams(m_ic, p) != DM_SUCCESS) {
286 reportError("dmICGetDstPoolParams");
287 dmParamsDestroy(p);
288 return false;
289 }
290 if (dmBufferCreatePool(p, pool) != DM_SUCCESS) {
291 reportError("dmBufferCreatePool");
292 dmParamsDestroy(p);
293 return false;
294 }
295
296 dmParamsDestroy(p);
297
298 if (dmICSetDstPool(m_ic, *pool) != DM_SUCCESS) {
299 reportError("dmICSetDstPool");
300 destroyBufferPool(*pool);
301 return false;
302 }
303
304 return true;
305}
306
307//
308// Destroy buffer pool created with either createSrcBufferPool() or
309// registerDstBufferPool().
310//
311
312void
313IrixDMIC_RawToJpeg::destroyBufferPool(DMbufferpool pool)
314{
315 if (dmBufferDestroyPool(pool) != DM_SUCCESS)
316 reportError("dmBufferDestroyPool");
317}
318
319//
320// Allocate a buffer from the specified pool.
321//
322
323bool
324IrixDMIC_RawToJpeg::allocBuffer(DMbuffer *pbuf, DMbufferpool pool)
325{
326 if (dmBufferAllocate(pool, pbuf) != DM_SUCCESS) {
327 reportError("dmBufferAllocate");
328 return false;
329 }
330
331 return true;
332}
333
334//
335// Fill in a DMbuffer with data.
336//
337// NOTE: The caller must make sure that the buffer size is no less
338// than dataSize.
339//
340
341bool
342IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data, int dataSize)
343{
344 void *bufPtr = dmBufferMapData(buf);
345 memcpy(bufPtr, data, dataSize);
346
347 if (dmBufferSetSize(buf, dataSize) != DM_SUCCESS) {
348 reportError("dmBufferSetSize");
349 return false;
350 }
351
352 return true;
353}
354
355//
Constantin Kaplinsky52eaa8c2007-09-04 09:12:59 +0000356// Fill in a DMbuffer with data.
357//
358// NOTE: The caller must make sure that the buffer size is no less
359// than (nRows * rowSize).
360//
361
362bool
363IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data,
364 int rowSize, int nRows, int stride)
365{
366 char *dataBytes = (char *)data;
367 char *bufPtr = (char *)dmBufferMapData(buf);
368 for (int i = 0; i < nRows; i++) {
369 memcpy(bufPtr, &dataBytes[i * stride], rowSize);
370 bufPtr += rowSize;
371 }
372
373 if (dmBufferSetSize(buf, nRows * rowSize) != DM_SUCCESS) {
374 reportError("dmBufferSetSize");
375 return false;
376 }
377
378 return true;
379}
380
381//
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000382// Map DMbuffer to physical memory.
383//
384
385void *
386IrixDMIC_RawToJpeg::mapBufferData(DMbuffer buf)
387{
388 return dmBufferMapData(buf);
389}
390
391//
392// Get the number of valid bytes in DMbuffer.
393//
394
395int
396IrixDMIC_RawToJpeg::getBufferSize(DMbuffer buf)
397{
398 return dmBufferGetSize(buf);
399}
400
401//
402// Free DMbuffer.
403//
404
405void
406IrixDMIC_RawToJpeg::freeBuffer(DMbuffer buf)
407{
408 if (dmBufferFree(buf) != DM_SUCCESS)
409 reportError("dmBufferFree");
410}
411
412//
413// Send input data (raw pixels) to the converter.
414//
415
416bool
417IrixDMIC_RawToJpeg::sendData(DMbuffer buf)
418{
419 if (dmICSend(m_ic, buf, 0, NULL) != DM_SUCCESS) {
420 reportError("dmICSend");
421 return false;
422 }
423
424 return true;
425}
426
427//
428// Wait until compression is finished (infinite timeout!).
429// This function should be called after sendData() and before receiveData().
430//
431// FIXME: Report errors.
432//
433
434bool
435IrixDMIC_RawToJpeg::waitConversion()
436{
437 struct pollfd ps;
438 ps.fd = dmICGetDstQueueFD(m_ic);
439 ps.events = POLLIN;
440
441 int result = poll(&ps, 1, -1);
442 if (result != 1)
443 return false;
444
445 if ((ps.revents & POLLIN) != 0) {
446 return true;
447 } else {
448 return false;
449 }
450}
451
452//
453// Receive output (JPEG data) from the converter.
454// Call waitConversion() function first.
455//
456
457bool
458IrixDMIC_RawToJpeg::receiveData(DMbuffer *pbuf)
459{
460 if (dmICReceive(m_ic, pbuf) != DM_SUCCESS) {
461 reportError("dmICReceive");
462 return false;
463 }
464
465 return true;
466}
467
468//
469// Report an error when a function returns DM_FAILURE.
470//
471
472void
473IrixDMIC_RawToJpeg::reportError(const char *funcName)
474{
475 char errorDetail[DM_MAX_ERROR_DETAIL];
476 const char *errorCategory = dmGetError(NULL, errorDetail);
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000477 vlog.error("%s() failed: %s: %s",
478 funcName, errorCategory, errorDetail);
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000479}
480
481//
482// Report an error when (m_valid_ic == false).
483//
484
485void
486IrixDMIC_RawToJpeg::reportErrorNotInited()
487{
Constantin Kaplinsky67649492007-10-10 02:03:33 +0000488 vlog.error("Internal error: Image converter not initialized");
Constantin Kaplinsky71a32f02007-07-24 12:10:16 +0000489}
490