git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2320 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v0.0.90
@@ -896,61 +896,10 @@ else | |||
fi | |||
fi | |||
for ac_declaration in \ | |||
''\ | |||
'#include <stdlib.h>' \ | |||
'extern "C" void std::exit (int) throw (); using std::exit;' \ | |||
'extern "C" void std::exit (int); using std::exit;' \ | |||
'extern "C" void exit (int) throw ();' \ | |||
'extern "C" void exit (int);' \ | |||
'void exit (int);' | |||
do | |||
cat > conftest.$ac_ext <<EOF | |||
#line 910 "configure" | |||
#include "confdefs.h" | |||
#include <stdlib.h> | |||
$ac_declaration | |||
int main() { | |||
exit (42); | |||
; return 0; } | |||
EOF | |||
if { (eval echo configure:918: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then | |||
: | |||
else | |||
echo "configure: failed program was:" >&5 | |||
cat conftest.$ac_ext >&5 | |||
rm -rf conftest* | |||
continue | |||
fi | |||
rm -f conftest* | |||
cat > conftest.$ac_ext <<EOF | |||
#line 928 "configure" | |||
#include "confdefs.h" | |||
$ac_declaration | |||
int main() { | |||
exit (42); | |||
; return 0; } | |||
EOF | |||
if { (eval echo configure:935: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then | |||
rm -rf conftest* | |||
break | |||
else | |||
echo "configure: failed program was:" >&5 | |||
cat conftest.$ac_ext >&5 | |||
fi | |||
rm -f conftest* | |||
done | |||
if test -n "$ac_declaration"; then | |||
echo '#ifdef __cplusplus' >>confdefs.h | |||
echo $ac_declaration >>confdefs.h | |||
echo '#endif' >>confdefs.h | |||
fi | |||
# Extract the first word of "ranlib", so it can be a program name with args. | |||
set dummy ranlib; ac_word=$2 | |||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 | |||
echo "configure:954: checking for $ac_word" >&5 | |||
echo "configure:903: checking for $ac_word" >&5 | |||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then | |||
echo $ac_n "(cached) $ac_c" 1>&6 | |||
else | |||
@@ -978,7 +927,7 @@ else | |||
fi | |||
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 | |||
echo "configure:982: checking whether ${MAKE-make} sets \${MAKE}" >&5 | |||
echo "configure:931: checking whether ${MAKE-make} sets \${MAKE}" >&5 | |||
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` | |||
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then | |||
echo $ac_n "(cached) $ac_c" 1>&6 | |||
@@ -1043,6 +992,57 @@ if test "$GXX" = yes; then | |||
fi | |||
fi | |||
echo $ac_n "checking for dmICCreate in -ldmedia""... $ac_c" 1>&6 | |||
echo "configure:997: checking for dmICCreate in -ldmedia" >&5 | |||
ac_lib_var=`echo dmedia'_'dmICCreate | sed 'y%./+-%__p_%'` | |||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then | |||
echo $ac_n "(cached) $ac_c" 1>&6 | |||
else | |||
ac_save_LIBS="$LIBS" | |||
LIBS="-ldmedia $LIBS" | |||
cat > conftest.$ac_ext <<EOF | |||
#line 1005 "configure" | |||
#include "confdefs.h" | |||
/* Override any gcc2 internal prototype to avoid an error. */ | |||
#ifdef __cplusplus | |||
extern "C" | |||
#endif | |||
/* We use char because int might match the return type of a gcc2 | |||
builtin and then its argument prototype would still apply. */ | |||
char dmICCreate(); | |||
int main() { | |||
dmICCreate() | |||
; return 0; } | |||
EOF | |||
if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then | |||
rm -rf conftest* | |||
eval "ac_cv_lib_$ac_lib_var=yes" | |||
else | |||
echo "configure: failed program was:" >&5 | |||
cat conftest.$ac_ext >&5 | |||
rm -rf conftest* | |||
eval "ac_cv_lib_$ac_lib_var=no" | |||
fi | |||
rm -f conftest* | |||
LIBS="$ac_save_LIBS" | |||
fi | |||
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then | |||
echo "$ac_t""yes" 1>&6 | |||
cat >> confdefs.h <<\EOF | |||
#define HAVE_DMEDIA 1 | |||
EOF | |||
PLATFORM_CXXSRCS="$PLATFORM_CXXSRCS IrixDMJpegCompressor.cxx" | |||
PLATFORM_CXXSRCS="$PLATFORM_CXXSRCS IrixDMIC_RawToJpeg.cxx" | |||
LIBS="$LIBS -ldmedia" | |||
else | |||
echo "$ac_t""no" 1>&6 | |||
fi | |||
# Check whether --with-installed-zlib or --without-installed-zlib was given. | |||
if test "${with_installed_zlib+set}" = set; then | |||
withval="$with_installed_zlib" | |||
@@ -1438,6 +1438,7 @@ s%@CC@%$CC%g | |||
s%@CXX@%$CXX%g | |||
s%@RANLIB@%$RANLIB%g | |||
s%@SET_MAKE@%$SET_MAKE%g | |||
s%@PLATFORM_CXXSRCS@%$PLATFORM_CXXSRCS%g | |||
s%@ZLIB_DIR@%$ZLIB_DIR%g | |||
s%@ZLIB_INCLUDE@%$ZLIB_INCLUDE%g | |||
s%@ZLIB_LIB@%$ZLIB_LIB%g |
@@ -44,6 +44,14 @@ if test "$GXX" = yes; then | |||
fi | |||
fi | |||
dnl Checks for IRIX-specific Digital Media libraries. | |||
AC_CHECK_LIB(dmedia, dmICCreate, | |||
[AC_DEFINE(HAVE_DMEDIA) | |||
PLATFORM_CXXSRCS="$PLATFORM_CXXSRCS IrixDMJpegCompressor.cxx" | |||
PLATFORM_CXXSRCS="$PLATFORM_CXXSRCS IrixDMIC_RawToJpeg.cxx" | |||
LIBS="$LIBS -ldmedia"]) | |||
AC_SUBST(PLATFORM_CXXSRCS) | |||
AC_ARG_WITH(installed-zlib, | |||
[ --with-installed-zlib use the version of zlib which is installed on the | |||
system instead of the one distributed with VNC]) |
@@ -0,0 +1,423 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/poll.h> | |||
#include <rfb/IrixDMIC_RawToJpeg.h> | |||
using namespace rfb; | |||
// | |||
// 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) ) { | |||
// FIXME: Just save the engine name and make x0vncserver print it. | |||
const char *engine = dmParamsGetString(p, DM_IC_ENGINE); | |||
printf("Found JPEG encoder: \"%s\" (%d)\n", engine, n); | |||
dmParamsDestroy(p); | |||
break; | |||
} | |||
dmParamsDestroy(p); | |||
} | |||
if (n < 0) { | |||
// FIXME: Unify error handling. | |||
fprintf (stderr, "Error: No matching JPEG encoder found\n"); | |||
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); | |||
} | |||
// | |||
// 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; | |||
} | |||
// | |||
// 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); | |||
fprintf(stderr, "%s() failed: %s: %s\n", | |||
funcName, errorCategory, errorDetail); | |||
} | |||
// | |||
// Report an error when (m_valid_ic == false). | |||
// | |||
void | |||
IrixDMIC_RawToJpeg::reportErrorNotInited() | |||
{ | |||
fprintf(stderr, "Internal error: Image converter not initialized\n"); | |||
} | |||
@@ -0,0 +1,54 @@ | |||
#ifndef __IRIXDMIC_RAWTOJPEG_H__ | |||
#define __IRIXDMIC_RAWTOJPEG_H__ | |||
#include <dmedia/dmedia.h> | |||
#include <dmedia/dm_imageconvert.h> | |||
namespace rfb { | |||
// | |||
// A C++ wrapper for IRIX-specific Digital Media Image Conversion | |||
// library used for JPEG compression. | |||
// | |||
class IrixDMIC_RawToJpeg | |||
{ | |||
public: | |||
IrixDMIC_RawToJpeg(bool needRealtime = true); | |||
virtual ~IrixDMIC_RawToJpeg(); | |||
bool isValid() const { return m_valid_ic; } | |||
bool setImageParams(int w, int h); | |||
bool setImageQuality(int quality); | |||
bool createSrcBufferPool(DMbufferpool *pool, int bufCount, int bufSize); | |||
bool registerDstBufferPool(DMbufferpool *pool, int bufCount, int bufSize); | |||
static void destroyBufferPool(DMbufferpool pool); | |||
static bool allocBuffer(DMbuffer *pbuf, DMbufferpool pool); | |||
static bool copyToBuffer(DMbuffer buf, const void *data, int dataSize); | |||
static int getBufferSize(DMbuffer buf); | |||
static void * mapBufferData(DMbuffer buf); | |||
static void freeBuffer(DMbuffer buf); | |||
bool sendData(DMbuffer buf); | |||
bool waitConversion(); | |||
bool receiveData(DMbuffer *pbuf); | |||
static void reportError(const char *funcName); | |||
static void reportErrorNotInited(); | |||
protected: | |||
DMimageconverter m_ic; | |||
bool m_valid_ic; | |||
DMparams *m_srcParams; | |||
DMparams *m_dstParams; | |||
DMparams *m_convParams; | |||
}; | |||
} | |||
#endif // __IRIXDMIC_RAWTOJPEG_H__ | |||
@@ -0,0 +1,153 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/poll.h> | |||
#include <rfb/IrixDMJpegCompressor.h> | |||
using namespace rfb; | |||
const int IrixDMJpegCompressor::DEFAULT_QUALITY = 75; | |||
// | |||
// Constructor and destructor. | |||
// | |||
IrixDMJpegCompressor::IrixDMJpegCompressor() | |||
: m_quality(DEFAULT_QUALITY), | |||
m_width(0), | |||
m_height(0), | |||
m_bufferSize(0), | |||
m_compressedData(0), | |||
m_compressedLength(0) | |||
{ | |||
} | |||
IrixDMJpegCompressor::~IrixDMJpegCompressor() | |||
{ | |||
if (m_bufferSize > 0) { | |||
m_ic.destroyBufferPool(m_srcPool); | |||
m_ic.destroyBufferPool(m_dstPool); | |||
} | |||
if (m_compressedData) | |||
delete[] m_compressedData; | |||
} | |||
// | |||
// Set JPEG quality level (0..100) | |||
// | |||
// FIXME: Call m_ic.setImageQuality() when necessary. | |||
// | |||
void | |||
IrixDMJpegCompressor::setQuality(int level) | |||
{ | |||
if (level < 0) | |||
level = 0; | |||
if (level > 100) | |||
level = 100; | |||
m_quality = level; | |||
} | |||
// | |||
// Perform JPEG compression. | |||
// | |||
// FIXME: This function assumes that pixel format is 32-bit XBGR | |||
// (depth 24), compatible with IRIX Digital Media libraries. | |||
// | |||
void | |||
IrixDMJpegCompressor::compress(const rdr::U32 *buf, | |||
const PixelFormat *fmt, | |||
int w, int h, int stride) | |||
{ | |||
// Discard previous compression results. | |||
if (m_compressedData) { | |||
delete[] m_compressedData; | |||
m_compressedData = 0; | |||
} | |||
m_compressedLength = 0; | |||
// Setup the compressor. | |||
if (!updateImageSize(w, h)) | |||
return; | |||
// Prepare source image data. | |||
DMbuffer srcBuf; | |||
if (!m_ic.allocBuffer(&srcBuf, m_srcPool)) { | |||
return; | |||
} | |||
// FIXME: Currently, copyToBuffer() copies parts of the image incorrectly. | |||
if (!m_ic.copyToBuffer(srcBuf, buf, w * h * (fmt->bpp / 8))) { | |||
m_ic.freeBuffer(srcBuf); | |||
return; | |||
} | |||
// Initiate compression. | |||
if (!m_ic.sendData(srcBuf)) { | |||
m_ic.freeBuffer(srcBuf); | |||
return; | |||
} | |||
m_ic.freeBuffer(srcBuf); | |||
// Wait for results. | |||
if (!m_ic.waitConversion()) { | |||
perror("poll"); // FIXME: Unify error handling. | |||
return; | |||
} | |||
// Save the results. | |||
DMbuffer dstBuf; | |||
if (!m_ic.receiveData(&dstBuf)) { | |||
return; | |||
} | |||
m_compressedLength = m_ic.getBufferSize(dstBuf); | |||
m_compressedData = new char[m_compressedLength]; | |||
void *bufPtr = m_ic.mapBufferData(dstBuf); | |||
memcpy(m_compressedData, bufPtr, m_compressedLength); | |||
m_ic.freeBuffer(dstBuf); | |||
} | |||
// | |||
// Update image size and make sure that our buffer pools will allocate | |||
// properly-sized buffers. | |||
// | |||
// FIXME: Handle image quality separately. | |||
// | |||
bool | |||
IrixDMJpegCompressor::updateImageSize(int w, int h) | |||
{ | |||
// Configure image formats and parameters, set JPEG image quality level. | |||
if (w != m_width || h != m_height) { | |||
if (!m_ic.setImageParams(w, h) || !m_ic.setImageQuality(m_quality)) { | |||
return false; | |||
} | |||
m_width = w; | |||
m_height = h; | |||
} | |||
// Set up source and destination buffer pools. | |||
int dataLen = w * h * 4; | |||
if (dataLen > m_bufferSize) { | |||
if (m_bufferSize > 0) { | |||
m_ic.destroyBufferPool(m_srcPool); | |||
m_ic.destroyBufferPool(m_dstPool); | |||
m_bufferSize = 0; | |||
} | |||
if (!m_ic.createSrcBufferPool(&m_srcPool, 1, dataLen)) { | |||
return false; | |||
} | |||
if (!m_ic.registerDstBufferPool(&m_dstPool, 1, dataLen)) { | |||
m_ic.destroyBufferPool(m_srcPool); | |||
return false; | |||
} | |||
m_bufferSize = dataLen; | |||
} | |||
return true; | |||
} | |||
@@ -0,0 +1,62 @@ | |||
#ifndef __IRIXDMJPEGCOMPRESSOR_H__ | |||
#define __IRIXDMJPEGCOMPRESSOR_H__ | |||
#include <sys/types.h> | |||
#include <rdr/types.h> | |||
#include <rfb/PixelFormat.h> | |||
#include <rfb/JpegCompressor.h> | |||
#include <rfb/IrixDMIC_RawToJpeg.h> | |||
namespace rfb { | |||
// | |||
// A C++ class for performing JPEG compression. | |||
// This implementation uses IRIX Digital Media libraries. | |||
// | |||
class IrixDMJpegCompressor : public JpegCompressor | |||
{ | |||
public: | |||
IrixDMJpegCompressor(); | |||
virtual ~IrixDMJpegCompressor(); | |||
// Check if the object has been created successfully. | |||
bool isValid() const { return m_ic.isValid(); } | |||
// Set JPEG quality level (0..100). | |||
void setQuality(int level); | |||
// Actually compress the image. | |||
void compress(const rdr::U32 *buf, const PixelFormat *fmt, | |||
int w, int h, int stride); | |||
// Access results of the compression. | |||
size_t getDataLength() { return m_compressedLength; } | |||
const char *getDataPtr() { return m_compressedData; } | |||
protected: | |||
// Update image size and make sure that our buffer pools will | |||
// allocate properly-sized buffers. | |||
bool updateImageSize(int w, int h); | |||
protected: | |||
static const int DEFAULT_QUALITY; | |||
int m_quality; | |||
IrixDMIC_RawToJpeg m_ic; | |||
int m_width; | |||
int m_height; | |||
DMbufferpool m_srcPool; | |||
DMbufferpool m_dstPool; | |||
int m_bufferSize; | |||
char *m_compressedData; | |||
size_t m_compressedLength; | |||
}; | |||
} | |||
#endif // __IRIXDMJPEGCOMPRESSOR_H__ | |||
@@ -0,0 +1,193 @@ | |||
#include <stdlib.h> | |||
#include <rfb/JpegCompressor.h> | |||
using namespace rfb; | |||
const int StandardJpegCompressor::ALLOC_CHUNK_SIZE = 65536; | |||
const int StandardJpegCompressor::DEFAULT_QUALITY = 75; | |||
// | |||
// Extend jpeg_destination_mgr struct with a pointer to our object. | |||
// | |||
typedef struct { | |||
struct jpeg_destination_mgr pub; | |||
StandardJpegCompressor *_this; | |||
} my_destination_mgr; | |||
// | |||
// C-compatible interface to our destination manager. It just obtains | |||
// a pointer to the right object and calls a corresponding C++ member | |||
// function on that object. | |||
// | |||
static void | |||
init_destination(j_compress_ptr cinfo) | |||
{ | |||
my_destination_mgr *dest_ptr = (my_destination_mgr *)cinfo->dest; | |||
dest_ptr->_this->initDestination(); | |||
} | |||
static boolean | |||
empty_output_buffer (j_compress_ptr cinfo) | |||
{ | |||
my_destination_mgr *dest_ptr = (my_destination_mgr *)cinfo->dest; | |||
return (boolean)dest_ptr->_this->emptyOutputBuffer(); | |||
} | |||
static void | |||
term_destination (j_compress_ptr cinfo) | |||
{ | |||
my_destination_mgr *dest_ptr = (my_destination_mgr *)cinfo->dest; | |||
dest_ptr->_this->termDestination(); | |||
} | |||
// | |||
// Constructor and destructor. | |||
// | |||
StandardJpegCompressor::StandardJpegCompressor() | |||
: m_cdata(0), | |||
m_cdata_allocated(0), | |||
m_cdata_ready(0) | |||
{ | |||
// Initialize JPEG compression structure. | |||
m_cinfo.err = jpeg_std_error(&m_jerr); | |||
jpeg_create_compress(&m_cinfo); | |||
// Set up a destination manager. | |||
my_destination_mgr *dest = new my_destination_mgr; | |||
dest->pub.init_destination = init_destination; | |||
dest->pub.empty_output_buffer = empty_output_buffer; | |||
dest->pub.term_destination = term_destination; | |||
dest->_this = this; | |||
m_cinfo.dest = (jpeg_destination_mgr *)dest; | |||
// Set up a destination manager. | |||
m_cinfo.input_components = 3; | |||
m_cinfo.in_color_space = JCS_RGB; | |||
jpeg_set_defaults(&m_cinfo); | |||
jpeg_set_quality(&m_cinfo, DEFAULT_QUALITY, true); | |||
// We prefer speed over quality. | |||
m_cinfo.dct_method = JDCT_FASTEST; | |||
} | |||
StandardJpegCompressor::~StandardJpegCompressor() | |||
{ | |||
// Free compressed data buffer. | |||
if (m_cdata) | |||
free(m_cdata); | |||
// Clean up the destination manager. | |||
delete m_cinfo.dest; | |||
m_cinfo.dest = NULL; | |||
// Release the JPEG compression structure. | |||
jpeg_destroy_compress(&m_cinfo); | |||
} | |||
// | |||
// Our implementation of destination manager. | |||
// | |||
void | |||
StandardJpegCompressor::initDestination() | |||
{ | |||
if (!m_cdata) { | |||
size_t new_size = ALLOC_CHUNK_SIZE; | |||
m_cdata = (unsigned char *)malloc(new_size); | |||
m_cdata_allocated = new_size; | |||
} | |||
m_cdata_ready = 0; | |||
m_cinfo.dest->next_output_byte = m_cdata; | |||
m_cinfo.dest->free_in_buffer = m_cdata_allocated; | |||
} | |||
bool | |||
StandardJpegCompressor::emptyOutputBuffer() | |||
{ | |||
size_t old_size = m_cdata_allocated; | |||
size_t new_size = old_size + ALLOC_CHUNK_SIZE; | |||
m_cdata = (unsigned char *)realloc(m_cdata, new_size); | |||
m_cdata_allocated = new_size; | |||
m_cinfo.dest->next_output_byte = &m_cdata[old_size]; | |||
m_cinfo.dest->free_in_buffer = new_size - old_size; | |||
return true; | |||
} | |||
void | |||
StandardJpegCompressor::termDestination() | |||
{ | |||
m_cdata_ready = m_cdata_allocated - m_cinfo.dest->free_in_buffer; | |||
} | |||
// | |||
// Set JPEG quality level (0..100) | |||
// | |||
void | |||
StandardJpegCompressor::setQuality(int level) | |||
{ | |||
if (level < 0) | |||
level = 0; | |||
if (level > 100) | |||
level = 100; | |||
jpeg_set_quality(&m_cinfo, level, true); | |||
} | |||
// | |||
// Perform JPEG compression. | |||
// | |||
// FIXME: This function assumes that (fmt->bpp == 32 && | |||
// fmt->depth == 24 && fmt->redMax == 255 && | |||
// fmt->greenMax == 255 && fmt->blueMax == 255). | |||
// | |||
void | |||
StandardJpegCompressor::compress(const rdr::U32 *buf, | |||
const PixelFormat *fmt, | |||
int w, int h, int stride) | |||
{ | |||
m_cinfo.image_width = w; | |||
m_cinfo.image_height = h; | |||
jpeg_start_compress(&m_cinfo, TRUE); | |||
const rdr::U32 *src = buf; | |||
// We'll pass up to 8 rows to jpeg_write_scanlines(). | |||
JSAMPLE *rgb = new JSAMPLE[w * 3 * 8]; | |||
JSAMPROW row_pointer[8]; | |||
for (int i = 0; i < 8; i++) | |||
row_pointer[i] = &rgb[w * 3 * i]; | |||
// Feed the pixels to the JPEG library. | |||
while (m_cinfo.next_scanline < m_cinfo.image_height) { | |||
int max_rows = m_cinfo.image_height - m_cinfo.next_scanline; | |||
if (max_rows > 8) { | |||
max_rows = 8; | |||
} | |||
for (int dy = 0; dy < max_rows; dy++) { | |||
JSAMPLE *dst = row_pointer[dy]; | |||
for (int x = 0; x < w; x++) { | |||
dst[x*3] = (JSAMPLE)(src[x] >> fmt->redShift); | |||
dst[x*3+1] = (JSAMPLE)(src[x] >> fmt->greenShift); | |||
dst[x*3+2] = (JSAMPLE)(src[x] >> fmt->blueShift); | |||
} | |||
src += stride; | |||
} | |||
jpeg_write_scanlines(&m_cinfo, row_pointer, max_rows); | |||
} | |||
delete[] rgb; | |||
jpeg_finish_compress(&m_cinfo); | |||
} | |||
@@ -0,0 +1,82 @@ | |||
#ifndef __JPEGCOMPRESSOR_H__ | |||
#define __JPEGCOMPRESSOR_H__ | |||
#include <stdio.h> | |||
#include <sys/types.h> | |||
extern "C" { | |||
#include <jpeg/jpeglib.h> | |||
} | |||
#include <rdr/types.h> | |||
#include <rfb/PixelFormat.h> | |||
namespace rfb { | |||
// | |||
// An abstract interface for performing JPEG compression. | |||
// | |||
class JpegCompressor | |||
{ | |||
public: | |||
virtual ~JpegCompressor() {} | |||
// Set JPEG quality level (0..100) | |||
virtual void setQuality(int level) = 0; | |||
// Actually compress an image. | |||
virtual void compress(const rdr::U32 *buf, const PixelFormat *fmt, | |||
int w, int h, int stride) = 0; | |||
// Access results of the compression. | |||
virtual size_t getDataLength() = 0; | |||
virtual const char *getDataPtr() = 0; | |||
}; | |||
// | |||
// A C++ class for performing JPEG compression via the | |||
// Independent JPEG Group's software (free JPEG library). | |||
// | |||
class StandardJpegCompressor : public JpegCompressor | |||
{ | |||
public: | |||
StandardJpegCompressor(); | |||
virtual ~StandardJpegCompressor(); | |||
// Set JPEG quality level (0..100) | |||
virtual void setQuality(int level); | |||
// Actually compress the image. | |||
virtual void compress(const rdr::U32 *buf, const PixelFormat *fmt, | |||
int w, int h, int stride); | |||
// Access results of the compression. | |||
virtual size_t getDataLength() { return m_cdata_ready; } | |||
virtual const char *getDataPtr() { return (const char *)m_cdata; } | |||
public: | |||
// Our implementation of JPEG destination manager. These three | |||
// functions should never be called directly. They are made public | |||
// because they should be accessible from C-compatible functions | |||
// called by the JPEG library. | |||
void initDestination(); | |||
bool emptyOutputBuffer(); | |||
void termDestination(); | |||
protected: | |||
static const int ALLOC_CHUNK_SIZE; | |||
static const int DEFAULT_QUALITY; | |||
struct jpeg_compress_struct m_cinfo; | |||
struct jpeg_error_mgr m_jerr; | |||
unsigned char *m_cdata; | |||
size_t m_cdata_allocated; | |||
size_t m_cdata_ready; | |||
}; | |||
} | |||
#endif // __JPEGCOMPRESSOR_H__ | |||
@@ -20,6 +20,7 @@ CXXSRCS = \ | |||
FileManager.cxx \ | |||
FileReader.cxx \ | |||
FileWriter.cxx \ | |||
JpegCompressor.cxx \ | |||
HTTPServer.cxx \ | |||
HextileDecoder.cxx \ | |||
HextileEncoder.cxx \ | |||
@@ -64,7 +65,8 @@ CXXSRCS = \ | |||
ZRLEDecoder.cxx \ | |||
encodings.cxx \ | |||
secTypes.cxx \ | |||
util.cxx | |||
util.cxx \ | |||
@PLATFORM_CXXSRCS@ | |||
SRCS = d3des.c $(CXXSRCS) | |||