#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/poll.h> #include <rfb/IrixDMIC_RawToJpeg.h> #include <rfb/LogWriter.h> using namespace rfb; static LogWriter vlog("IrixDMIC"); // // Constructor. Find a converter and create a context. Also, create // DMparams structures for using with dmICSetSrcParams, // dmICSetDstParams and dmICSetConvParams. // IrixDMIC_RawToJpeg::IrixDMIC_RawToJpeg(bool needRealtime) : m_valid_ic(false), m_srcParams(0), m_dstParams(0), m_convParams(0) { if ( dmParamsCreate(&m_srcParams) != DM_SUCCESS || dmParamsCreate(&m_dstParams) != DM_SUCCESS || dmParamsCreate(&m_convParams) != DM_SUCCESS ) { reportError("dmParamsCreate"); return; } DMparams *p; const int JPEG_ID = 0x6A706567; // same as 'jpeg' int id, direction, speed; int n = dmICGetNum(); while (n--) { if (dmParamsCreate(&p) != DM_SUCCESS) { reportError("dmParamsCreate"); return; } if (dmICGetDescription(n, p) != DM_SUCCESS) continue; id = dmParamsGetInt(p, DM_IC_ID); direction = dmParamsGetEnum(p, DM_IC_CODE_DIRECTION); speed = dmParamsGetEnum(p, DM_IC_SPEED); if ( id == JPEG_ID && direction == DM_IC_CODE_DIRECTION_ENCODE && (!needRealtime || speed == DM_IC_SPEED_REALTIME) ) { const char *engine = dmParamsGetString(p, DM_IC_ENGINE); vlog.info("Found JPEG encoder: \"%s\" (%d)", engine, n); dmParamsDestroy(p); break; } dmParamsDestroy(p); } if (n < 0) { vlog.error("Error: No matching JPEG encoder found"); debugListConverters(); return; } if (dmICCreate(n, &m_ic) != DM_SUCCESS) { reportError("dmICCreate"); return; } m_valid_ic = true; } // // Destructor. // IrixDMIC_RawToJpeg::~IrixDMIC_RawToJpeg() { if (m_valid_ic) dmICDestroy(m_ic); if (m_convParams) dmParamsDestroy(m_convParams); if (m_dstParams) dmParamsDestroy(m_dstParams); if (m_srcParams) dmParamsDestroy(m_srcParams); } void IrixDMIC_RawToJpeg::debugListConverters() { int n = dmICGetNum(); vlog.debug("IRIX DMIC converters available (%d):", n); for (int i = 0; i < n; i++) { DMparams *p; if (dmParamsCreate(&p) != DM_SUCCESS) { return; } if (dmICGetDescription(i, p) != DM_SUCCESS) { vlog.debug(" continue"); continue; } union { int id; char label[5]; } id; id.id = dmParamsGetInt(p, DM_IC_ID); id.label[4] = '\0'; int direction = dmParamsGetEnum(p, DM_IC_CODE_DIRECTION); const char *directionLabel = "converter"; if (direction == DM_IC_CODE_DIRECTION_ENCODE) { directionLabel = "encoder"; } else if (direction == DM_IC_CODE_DIRECTION_DECODE) { directionLabel = "decoder"; } int speed = dmParamsGetEnum(p, DM_IC_SPEED); const char *speedLabel = ""; if (speed == DM_IC_SPEED_REALTIME) { speedLabel = "realtime "; } const char *engine = dmParamsGetString(p, DM_IC_ENGINE); vlog.debug(" converter %d: '%s' %s%s (%s)", i, id.label, speedLabel, directionLabel, engine); dmParamsDestroy(p); } } // // Configure the source and destination formats. // // FIXME: Remember image size that was previously set, do not set the // same size again. // bool IrixDMIC_RawToJpeg::setImageParams(int w, int h) { if (!m_valid_ic) { reportErrorNotInited(); return false; } // Set source image parameters. DMpacking packing = DM_IMAGE_PACKING_XBGR; int orient = DM_IMAGE_TOP_TO_BOTTOM; if (dmSetImageDefaults(m_srcParams, w, h, packing) != DM_SUCCESS) { reportError("dmSetImageDefaults"); return false; } DMstatus err = dmParamsSetEnum(m_srcParams, DM_IMAGE_ORIENTATION, orient); if (err != DM_SUCCESS) { reportError("dmParamsSetEnum"); return false; } if (dmICSetSrcParams(m_ic, m_srcParams) != DM_SUCCESS) { reportError("dmICSetSrcParams"); return false; } // Set destination image parameters. packing = DM_IMAGE_PACKING_CbYCrY; const char *compression = DM_IMAGE_JPEG; if (dmSetImageDefaults(m_dstParams, w, h, packing) != DM_SUCCESS) { reportError("dmSetImageDefaults"); return false; } err = dmParamsSetEnum(m_dstParams, DM_IMAGE_ORIENTATION, orient); if (err != DM_SUCCESS) { reportError("dmParamsSetEnum"); return false; } err = dmParamsSetString(m_dstParams, DM_IMAGE_COMPRESSION, compression); if (err != DM_SUCCESS) { reportError("dmParamsSetString"); return false; } if (dmICSetDstParams(m_ic, m_dstParams) != DM_SUCCESS) { reportError("dmICSetDstParams"); return false; } return true; } // // Set JPEG image quality level (an integer in the range 0..99). // // FIXME: Remember image quality that was previously set, do not set // the same quality again. // bool IrixDMIC_RawToJpeg::setImageQuality(int quality) { if (!m_valid_ic) { reportErrorNotInited(); return false; } double qf = (double)quality / 100.0; DMstatus err = dmParamsSetFloat(m_convParams, DM_IMAGE_QUALITY_SPATIAL, qf); if (err != DM_SUCCESS) { reportError("dmParamsSetFloat"); return false; } if (dmICSetConvParams(m_ic, m_convParams) != DM_SUCCESS) { reportError("dmICSetConvParams"); return false; } return true; } // // Set up source buffer pool. // // NOTE: Both setImageParams() and setImageQuality() functions should // be called prior to creating and registering buffer pools. // bool IrixDMIC_RawToJpeg::createSrcBufferPool(DMbufferpool *pool, int bufCount, int bufSize) { if (!m_valid_ic) { reportErrorNotInited(); return false; } DMparams *p; if (dmParamsCreate(&p) != DM_SUCCESS) { reportError("dmParamsCreate"); return false; } if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) != DM_SUCCESS) { reportError("dmBufferSetPoolDefaults"); dmParamsDestroy(p); return false; } if (dmICGetSrcPoolParams(m_ic, p) != DM_SUCCESS) { reportError("dmICGetSrcPoolParams"); dmParamsDestroy(p); return false; } if (dmBufferCreatePool(p, pool) != DM_SUCCESS) { reportError("dmBufferCreatePool"); dmParamsDestroy(p); return false; } dmParamsDestroy(p); return true; } // // Set up and register destination buffer pool. // // NOTE: Both setImageParams() and setImageQuality() functions should // be called prior to creating and registering buffer pools. // bool IrixDMIC_RawToJpeg::registerDstBufferPool(DMbufferpool *pool, int bufCount, int bufSize) { if (!m_valid_ic) { reportErrorNotInited(); return false; } DMparams *p; if (dmParamsCreate(&p) != DM_SUCCESS) { reportError("dmParamsCreate"); return false; } if (dmBufferSetPoolDefaults(p, bufCount, bufSize, DM_FALSE, DM_TRUE) != DM_SUCCESS) { reportError("dmBufferSetPoolDefaults"); dmParamsDestroy(p); return false; } if (dmICGetDstPoolParams(m_ic, p) != DM_SUCCESS) { reportError("dmICGetDstPoolParams"); dmParamsDestroy(p); return false; } if (dmBufferCreatePool(p, pool) != DM_SUCCESS) { reportError("dmBufferCreatePool"); dmParamsDestroy(p); return false; } dmParamsDestroy(p); if (dmICSetDstPool(m_ic, *pool) != DM_SUCCESS) { reportError("dmICSetDstPool"); destroyBufferPool(*pool); return false; } return true; } // // Destroy buffer pool created with either createSrcBufferPool() or // registerDstBufferPool(). // void IrixDMIC_RawToJpeg::destroyBufferPool(DMbufferpool pool) { if (dmBufferDestroyPool(pool) != DM_SUCCESS) reportError("dmBufferDestroyPool"); } // // Allocate a buffer from the specified pool. // bool IrixDMIC_RawToJpeg::allocBuffer(DMbuffer *pbuf, DMbufferpool pool) { if (dmBufferAllocate(pool, pbuf) != DM_SUCCESS) { reportError("dmBufferAllocate"); return false; } return true; } // // Fill in a DMbuffer with data. // // NOTE: The caller must make sure that the buffer size is no less // than dataSize. // bool IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data, int dataSize) { void *bufPtr = dmBufferMapData(buf); memcpy(bufPtr, data, dataSize); if (dmBufferSetSize(buf, dataSize) != DM_SUCCESS) { reportError("dmBufferSetSize"); return false; } return true; } // // Fill in a DMbuffer with data. // // NOTE: The caller must make sure that the buffer size is no less // than (nRows * rowSize). // bool IrixDMIC_RawToJpeg::copyToBuffer(DMbuffer buf, const void *data, int rowSize, int nRows, int stride) { char *dataBytes = (char *)data; char *bufPtr = (char *)dmBufferMapData(buf); for (int i = 0; i < nRows; i++) { memcpy(bufPtr, &dataBytes[i * stride], rowSize); bufPtr += rowSize; } if (dmBufferSetSize(buf, nRows * rowSize) != DM_SUCCESS) { reportError("dmBufferSetSize"); return false; } return true; } // // Map DMbuffer to physical memory. // void * IrixDMIC_RawToJpeg::mapBufferData(DMbuffer buf) { return dmBufferMapData(buf); } // // Get the number of valid bytes in DMbuffer. // int IrixDMIC_RawToJpeg::getBufferSize(DMbuffer buf) { return dmBufferGetSize(buf); } // // Free DMbuffer. // void IrixDMIC_RawToJpeg::freeBuffer(DMbuffer buf) { if (dmBufferFree(buf) != DM_SUCCESS) reportError("dmBufferFree"); } // // Send input data (raw pixels) to the converter. // bool IrixDMIC_RawToJpeg::sendData(DMbuffer buf) { if (dmICSend(m_ic, buf, 0, NULL) != DM_SUCCESS) { reportError("dmICSend"); return false; } return true; } // // Wait until compression is finished (infinite timeout!). // This function should be called after sendData() and before receiveData(). // // FIXME: Report errors. // bool IrixDMIC_RawToJpeg::waitConversion() { struct pollfd ps; ps.fd = dmICGetDstQueueFD(m_ic); ps.events = POLLIN; int result = poll(&ps, 1, -1); if (result != 1) return false; if ((ps.revents & POLLIN) != 0) { return true; } else { return false; } } // // Receive output (JPEG data) from the converter. // Call waitConversion() function first. // bool IrixDMIC_RawToJpeg::receiveData(DMbuffer *pbuf) { if (dmICReceive(m_ic, pbuf) != DM_SUCCESS) { reportError("dmICReceive"); return false; } return true; } // // Report an error when a function returns DM_FAILURE. // void IrixDMIC_RawToJpeg::reportError(const char *funcName) { char errorDetail[DM_MAX_ERROR_DETAIL]; const char *errorCategory = dmGetError(NULL, errorDetail); vlog.error("%s() failed: %s: %s", funcName, errorCategory, errorDetail); } // // Report an error when (m_valid_ic == false). // void IrixDMIC_RawToJpeg::reportErrorNotInited() { vlog.error("Internal error: Image converter not initialized"); }