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