blob: 6b7630470ee8467cd1a85d33483f3969243603cb [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//
315// Map DMbuffer to physical memory.
316//
317
318void *
319IrixDMIC_RawToJpeg::mapBufferData(DMbuffer buf)
320{
321 return dmBufferMapData(buf);
322}
323
324//
325// Get the number of valid bytes in DMbuffer.
326//
327
328int
329IrixDMIC_RawToJpeg::getBufferSize(DMbuffer buf)
330{
331 return dmBufferGetSize(buf);
332}
333
334//
335// Free DMbuffer.
336//
337
338void
339IrixDMIC_RawToJpeg::freeBuffer(DMbuffer buf)
340{
341 if (dmBufferFree(buf) != DM_SUCCESS)
342 reportError("dmBufferFree");
343}
344
345//
346// Send input data (raw pixels) to the converter.
347//
348
349bool
350IrixDMIC_RawToJpeg::sendData(DMbuffer buf)
351{
352 if (dmICSend(m_ic, buf, 0, NULL) != DM_SUCCESS) {
353 reportError("dmICSend");
354 return false;
355 }
356
357 return true;
358}
359
360//
361// Wait until compression is finished (infinite timeout!).
362// This function should be called after sendData() and before receiveData().
363//
364// FIXME: Report errors.
365//
366
367bool
368IrixDMIC_RawToJpeg::waitConversion()
369{
370 struct pollfd ps;
371 ps.fd = dmICGetDstQueueFD(m_ic);
372 ps.events = POLLIN;
373
374 int result = poll(&ps, 1, -1);
375 if (result != 1)
376 return false;
377
378 if ((ps.revents & POLLIN) != 0) {
379 return true;
380 } else {
381 return false;
382 }
383}
384
385//
386// Receive output (JPEG data) from the converter.
387// Call waitConversion() function first.
388//
389
390bool
391IrixDMIC_RawToJpeg::receiveData(DMbuffer *pbuf)
392{
393 if (dmICReceive(m_ic, pbuf) != DM_SUCCESS) {
394 reportError("dmICReceive");
395 return false;
396 }
397
398 return true;
399}
400
401//
402// Report an error when a function returns DM_FAILURE.
403//
404
405void
406IrixDMIC_RawToJpeg::reportError(const char *funcName)
407{
408 char errorDetail[DM_MAX_ERROR_DETAIL];
409 const char *errorCategory = dmGetError(NULL, errorDetail);
410 fprintf(stderr, "%s() failed: %s: %s\n",
411 funcName, errorCategory, errorDetail);
412}
413
414//
415// Report an error when (m_valid_ic == false).
416//
417
418void
419IrixDMIC_RawToJpeg::reportErrorNotInited()
420{
421 fprintf(stderr, "Internal error: Image converter not initialized\n");
422}
423