Bläddra i källkod

Added JpegCompressor abstract class and two implementations -- one cross-platform and another IRIX-specific.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2320 3789f03b-4d11-0410-bbf8-ca57d06f2519
tags/v0.0.90
Constantin Kaplinsky 17 år sedan
förälder
incheckning
71a32f0dc8

+ 54
- 53
common/configure Visa fil

@@ -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

+ 8
- 0
common/configure.in Visa fil

@@ -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])

+ 423
- 0
common/rfb/IrixDMIC_RawToJpeg.cxx Visa fil

@@ -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");
}


+ 54
- 0
common/rfb/IrixDMIC_RawToJpeg.h Visa fil

@@ -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__


+ 153
- 0
common/rfb/IrixDMJpegCompressor.cxx Visa fil

@@ -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;
}


+ 62
- 0
common/rfb/IrixDMJpegCompressor.h Visa fil

@@ -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__


+ 193
- 0
common/rfb/JpegCompressor.cxx Visa fil

@@ -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);
}


+ 82
- 0
common/rfb/JpegCompressor.h Visa fil

@@ -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__


+ 3
- 1
common/rfb/Makefile.in Visa fil

@@ -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)


Laddar…
Avbryt
Spara