blob: 4cdb1ba03ddd9753ae28b482b0843492cf0deeee [file] [log] [blame]
#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;
}
// For some reason, dmICSetConvParams() does not have effect without
// calling dmICSetDstParams() as well. So we call it here.
if (m_dstParams && dmParamsGetNumElems(m_dstParams) &&
dmICSetDstParams(m_ic, m_dstParams) != DM_SUCCESS) {
reportError("dmICSetDstParams");
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");
}