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