Browse Source

Remove the "video" feature and its associated custom JPEG handling.

Having the client specifiy the video region is conceptually wrong
and a problem like this should be handled by better encoding selection.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3635 3789f03b-4d11-0410-bbf8-ca57d06f2519
tags/v0.0.90
Pierre Ossman 15 years ago
parent
commit
02e43d78bf

+ 0
- 8
common/rfb/ComparingUpdateTracker.cxx View File

@@ -39,14 +39,6 @@ ComparingUpdateTracker::~ComparingUpdateTracker()

void ComparingUpdateTracker::compare()
{
// First of all, exclude video area from both changed and copied regions.
// We handle video area separately and do not compare it -- we know it's
// being changed continuously.
if (!video_area.is_empty()) {
changed.assign_subtract(video_area);
copied.assign_subtract(video_area);
}

std::vector<Rect> rects;
std::vector<Rect>::iterator i;


+ 0
- 147
common/rfb/IrixCLJpegCompressor.cxx View File

@@ -1,147 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>

#include <rfb/IrixCLJpegCompressor.h>
#include <rfb/LogWriter.h>

using namespace rfb;

static LogWriter vlog("IrixCLJpeg");

const int IrixCLJpegCompressor::DEFAULT_QUALITY = 75;

//
// Constructor and destructor.
//

IrixCLJpegCompressor::IrixCLJpegCompressor()
: m_quality(DEFAULT_QUALITY),
m_clHandleValid(false),
m_srcBufferSize(0),
m_dstBufferSize(0),
m_sourceData(0),
m_compressedData(0),
m_compressedLength(0)
{
int impactScheme = clQuerySchemeFromName(CL_ALG_VIDEO, "impact");
if (impactScheme < 0) {
vlog.error("Warning: No compression scheme named \"impact\"");
}

vlog.debug("Trying \"impact\" compression scheme (Octane Compression)");
int r = clOpenCompressor(impactScheme, &m_clHandle);
if (r == SUCCESS) {
vlog.debug("Using \"impact\" compression scheme");
m_clHandleValid = true;
return;
}
vlog.debug("Trying Cosmo Compress");
r = clOpenCompressor(CL_JPEG_COSMO, &m_clHandle);
if (r == SUCCESS) {
vlog.debug("Using Cosmo Compress");
m_clHandleValid = true;
return;
}

#ifdef DEBUG_FORCE_CL
vlog.debug("DEBUG: Trying Irix software JPEG compressor");
r = clOpenCompressor(CL_JPEG_SOFTWARE, &m_clHandle);
if (r == SUCCESS) {
vlog.debug("DEBUG: Using Irix software JPEG compressor");
m_clHandleValid = true;
return;
}
#endif

vlog.error("Ho hardware JPEG available via Irix CL library");
}

IrixCLJpegCompressor::~IrixCLJpegCompressor()
{
if (m_clHandleValid)
clCloseCompressor(m_clHandle);

if (m_sourceData)
delete[] m_sourceData;
if (m_compressedData)
delete[] m_compressedData;
}

//
// Set JPEG quality level (1..99)
//

void
IrixCLJpegCompressor::setQuality(int level)
{
if (level < 1) {
level = 1;
} else if (level > 99) {
level = 99;
}
if (level != m_quality) {
m_quality = level;
}
}

//
// Perform JPEG compression.
//
// FIXME: This function assumes that pixel format is 32-bit XBGR
// (depth 24), compatible with IRIX Compression Library.
//

void
IrixCLJpegCompressor::compress(const rdr::U32 *buf,
const PixelFormat *fmt,
int w, int h, int stride)
{
// Discard previous compression results.
m_compressedLength = 0;

// A sanity check.
if (!m_clHandleValid)
return;

// (Re)allocate the source buffer if necessary.
if (w * h > m_srcBufferSize) {
if (m_sourceData)
delete[] m_sourceData;
m_srcBufferSize = w * h;
m_sourceData = new rdr::U32[m_srcBufferSize];
}

// Copy source pixels
for (int y = 0; y < h; y++) {
memcpy(&m_sourceData[y * w], &buf[y * stride], w * sizeof(rdr::U32));
}

// Set image attributes and JPEG quality factor.
clSetParam(m_clHandle, CL_FORMAT, CL_FORMAT_XBGR);
clSetParam(m_clHandle, CL_IMAGE_WIDTH, w);
clSetParam(m_clHandle, CL_IMAGE_HEIGHT, h);
clSetParam(m_clHandle, CL_FRAME_BUFFER_SIZE, w * h * 4);
clSetParam(m_clHandle, CL_JPEG_QUALITY_FACTOR, m_quality);

// Determine buffer size required.
int newBufferSize = clGetParam(m_clHandle, CL_COMPRESSED_BUFFER_SIZE);

// (Re)allocate destination buffer if necessary.
if (newBufferSize > m_dstBufferSize) {
if (m_compressedData)
delete[] m_compressedData;
m_dstBufferSize = newBufferSize;
m_compressedData = new char[m_dstBufferSize];
}

int newCompressedSize = newBufferSize;
int n = clCompress(m_clHandle, 1, m_sourceData,
&newCompressedSize, m_compressedData);
if (n != 1)
return;

m_compressedLength = (size_t)newCompressedSize;
}


+ 0
- 58
common/rfb/IrixCLJpegCompressor.h View File

@@ -1,58 +0,0 @@
#ifndef __IRIXCLJPEGCOMPRESSOR_H__
#define __IRIXCLJPEGCOMPRESSOR_H__

#include <sys/types.h>
#include <dmedia/cl.h>

#include <rdr/types.h>
#include <rfb/PixelFormat.h>

#include <rfb/JpegCompressor.h>

namespace rfb {

//
// A C++ class for performing JPEG compression.
// This implementation uses IRIX Compression Library (CL).
//

class IrixCLJpegCompressor : public JpegCompressor
{
public:
IrixCLJpegCompressor();
virtual ~IrixCLJpegCompressor();

// Check if the object has been created successfully.
bool isValid() const { return m_clHandleValid; }

// 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_compressedLength; }
virtual const char *getDataPtr() { return m_compressedData; }

protected:
static const int DEFAULT_QUALITY;
int m_quality;

CLhandle m_clHandle;
bool m_clHandleValid;

int m_srcBufferSize;
int m_dstBufferSize;

rdr::U32 *m_sourceData;
char *m_compressedData;

size_t m_compressedLength;
};

}

#endif // __IRIXCLJPEGCOMPRESSOR_H__


+ 0
- 499
common/rfb/IrixDMIC_RawToJpeg.cxx View File

@@ -1,499 +0,0 @@
#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");
}


+ 0
- 58
common/rfb/IrixDMIC_RawToJpeg.h View File

@@ -1,58 +0,0 @@
#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();

void debugListConverters();

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 bool copyToBuffer(DMbuffer buf, const void *data,
int rowSize, int nRows, int stride);
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
- 155
common/rfb/IrixDMJpegCompressor.cxx View File

@@ -1,155 +0,0 @@
#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 (1..99)
//

void
IrixDMJpegCompressor::setQuality(int level)
{
if (level < 1) {
level = 1;
} else if (level > 99) {
level = 99;
}
if (level != m_quality) {
m_quality = level;
m_ic.setImageQuality(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;
}
int widthInBytes = w * (fmt->bpp / 8);
int strideInBytes = stride * (fmt->bpp / 8);
if (!m_ic.copyToBuffer(srcBuf, buf, widthInBytes, h, strideInBytes)) {
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
- 62
common/rfb/IrixDMJpegCompressor.h View File

@@ -1,62 +0,0 @@
#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).
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_compressedLength; }
virtual 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
- 193
common/rfb/JpegCompressor.cxx View File

@@ -1,193 +0,0 @@
#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;
} else 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
- 82
common/rfb/JpegCompressor.h View File

@@ -1,82 +0,0 @@
#ifndef __JPEGCOMPRESSOR_H__
#define __JPEGCOMPRESSOR_H__

#include <stdio.h>
#include <sys/types.h>
extern "C" {
#include <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__


+ 0
- 159
common/rfb/JpegEncoder.cxx View File

@@ -1,159 +0,0 @@
/* Copyright (C) 2007 Constantin Kaplinsky. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

#ifdef HAVE_COMMON_CONFIG_H
#include <common-config.h>
#endif

#include <rfb/JpegEncoder.h>
#include <rdr/OutStream.h>
#include <rdr/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ConnParams.h>
#include <rfb/LogWriter.h>

#ifdef HAVE_CL
#include <rfb/IrixCLJpegCompressor.h>
#endif
#ifdef HAVE_DMEDIA
#include <rfb/IrixDMJpegCompressor.h>
#endif

using namespace rfb;

static LogWriter vlog("JpegEncoder");

BoolParameter JpegEncoder::useHardwareJPEG
("UseHardwareJPEG",
"Use hardware-accelerated JPEG compressor for video if available",
true);

const int JpegEncoder::qualityMap[10] = {
2, 10, 15, 25, 37, 50, 60, 70, 80, 90
};

JpegEncoder::JpegEncoder(SMsgWriter* writer_) : writer(writer_), jcomp(0)
{
#ifdef HAVE_DMEDIA
#ifdef DEBUG_FORCE_CL
vlog.debug("DEBUG: skipping IRIX DM JPEG compressor");
#else
if (!jcomp && useHardwareJPEG) {
vlog.debug("trying IRIX DM JPEG compressor");
IrixDMJpegCompressor *dmComp = new IrixDMJpegCompressor;
if (dmComp->isValid()) {
vlog.debug("initialized IRIX DM JPEG compressor successfully");
jcomp = dmComp;
} else {
vlog.error("warning: could not create IRIX DM JPEG compressor");
delete dmComp;
}
}
#endif
#endif

#ifdef HAVE_CL
if (!jcomp && useHardwareJPEG) {
vlog.debug("trying IRIX CL JPEG compressor");
IrixCLJpegCompressor *clComp = new IrixCLJpegCompressor;
if (clComp->isValid()) {
vlog.debug("initialized IRIX CL JPEG compressor successfully");
jcomp = clComp;
} else {
vlog.error("warning: could not create IRIX CL JPEG compressor");
delete clComp;
}
}
#endif

if (!jcomp) {
if (useHardwareJPEG) {
vlog.info("no hardware JPEG compressor available");
}
vlog.debug("using software JPEG compressor");
jcomp = new StandardJpegCompressor;
}
jcomp->setQuality(qualityMap[6]);
}

JpegEncoder::~JpegEncoder()
{
delete jcomp;
}

void JpegEncoder::setQualityLevel(int level)
{
if (level < 0) {
level = 0;
} else if (level > 9) {
level = 9;
}
jcomp->setQuality(qualityMap[level]);
}

bool JpegEncoder::isPixelFormatSupported(PixelBuffer* pb) const
{
const PixelFormat &serverPF = pb->getPF();
const PixelFormat &clientPF = writer->getConnParams()->pf();

// FIXME: Ask encoders if they support given pixel formats.

if ( serverPF.bpp == 32 && clientPF.bpp >= 16 &&
serverPF.depth == 24 && serverPF.redMax == 255 &&
serverPF.greenMax == 255 && serverPF.blueMax == 255 ) {
return true;
}

return false;
}

void JpegEncoder::writeRect(PixelBuffer* pb, const Rect& r)
{
if (!isPixelFormatSupported(pb)) {
vlog.error("pixel format unsupported by JPEG encoder");
throw rdr::Exception("internal error in JpegEncoder");
}

writer->startRect(r, encodingTight);
rdr::OutStream* os = writer->getOutStream();

// Get access to pixel data
int stride;
const rdr::U32* pixels = (const rdr::U32 *)pb->getPixelsR(r, &stride);
const PixelFormat& fmt = pb->getPF();

// Try to encode data
jcomp->compress(pixels, &fmt, r.width(), r.height(), stride);

// If not successful, switch to StandardJpegCompressor
if (jcomp->getDataLength() == 0) {
vlog.info("switching to standard software JPEG compressor");
delete jcomp;
jcomp = new StandardJpegCompressor;
jcomp->setQuality(qualityMap[6]);
jcomp->compress(pixels, &fmt, r.width(), r.height(), stride);
}

// Write Tight-encoded header and JPEG data.
os->writeU8(0x09 << 4);
os->writeCompactLength(jcomp->getDataLength());
os->writeBytes(jcomp->getDataPtr(), jcomp->getDataLength());

writer->endRect();
}


+ 0
- 55
common/rfb/JpegEncoder.h View File

@@ -1,55 +0,0 @@
/* Copyright (C) 2007 Constantin Kaplinsky. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_JPEGENCODER_H__
#define __RFB_JPEGENCODER_H__

#include <rfb/SMsgWriter.h>
#include <rfb/PixelBuffer.h>
#include <rfb/JpegCompressor.h>
#include <rfb/Configuration.h>

//
// JPEG Encoder.
// NOTE: JpegEncoder class is NOT derived from Encoder, because we need
// access to the original server's framebuffer, without extra pixel
// copying and with no pixel format translation.
//

namespace rfb {

class JpegEncoder {
public:
JpegEncoder(SMsgWriter* writer);
virtual ~JpegEncoder();

virtual void setQualityLevel(int level);
virtual bool isPixelFormatSupported(PixelBuffer* pb) const;
virtual void writeRect(PixelBuffer* pb, const Rect& r);

static BoolParameter useHardwareJPEG;

private:
SMsgWriter* writer;
JpegCompressor* jcomp;

static const int qualityMap[10];
};

}

#endif

+ 3
- 13
common/rfb/Makefile.am View File

@@ -9,8 +9,7 @@ HDRS = Blacklist.h CapsContainer.h CapsList.h CConnection.h CFTMsgReader.h \
FileWriter.h fttypes.h hextileConstants.h hextileDecode.h \
HextileDecoder.h hextileEncodeBetter.h hextileEncode.h \
HextileEncoder.h Hostname.h HTTPServer.h ImageGetter.h InputHandler.h \
IrixCLJpegCompressor.h IrixDMIC_RawToJpeg.h IrixDMJpegCompressor.h \
JpegCompressor.h JpegEncoder.h KeyRemapper.h keysymdef.h \
KeyRemapper.h keysymdef.h \
ListConnInfo.h Logger_file.h Logger.h Logger_stdio.h LogWriter.h \
msgTypes.h Password.h PixelBuffer.h PixelFormat.h Pixel.h \
RawDecoder.h RawEncoder.h Rect.h Region.h rreDecode.h RREDecoder.h \
@@ -31,8 +30,8 @@ librfb_la_SOURCES = $(HDRS) Blacklist.cxx CConnection.cxx CFTMsgReader.cxx CFTMs
CSecurityVncAuth.cxx CapsContainer.cxx CapsList.cxx \
ComparingUpdateTracker.cxx Configuration.cxx ConnParams.cxx \
Cursor.cxx Decoder.cxx d3des.c Encoder.cxx FileInfo.cxx \
FileManager.cxx FileReader.cxx FileWriter.cxx JpegCompressor.cxx \
JpegEncoder.cxx HTTPServer.cxx HextileDecoder.cxx HextileEncoder.cxx \
FileManager.cxx FileReader.cxx FileWriter.cxx \
HTTPServer.cxx HextileDecoder.cxx HextileEncoder.cxx \
KeyRemapper.cxx LogWriter.cxx Logger.cxx Logger_file.cxx \
Logger_stdio.cxx Password.cxx PixelBuffer.cxx PixelFormat.cxx \
RREEncoder.cxx RREDecoder.cxx RawDecoder.cxx RawEncoder.cxx \
@@ -49,15 +48,6 @@ librfb_la_SOURCES = $(HDRS) Blacklist.cxx CConnection.cxx CFTMsgReader.cxx CFTMs
librfb_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/../win
librfb_la_LIBADD =

if IRIX_COMPRESS
librfb_la_SOURCES += IrixCLJpegCompressor.cxx
librfb_la_LIBADD += -lcl
endif
if IRIX_MEDIA
librfb_la_SOURCES += IrixDMJpegCompressor.cxx IrixDMIC_RawToJpeg.cxx
librfb_la_LIBADD += -ldmedia
endif

if INCLUDED_JPEG
librfb_la_CPPFLAGS += -I$(top_srcdir)/jpeg
librfb_la_LIBADD += $(top_srcdir)/jpeg/libjpeg.la

+ 1
- 11
common/rfb/SConnection.cxx View File

@@ -46,8 +46,7 @@ SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
: readyForSetColourMapEntries(false),
is(0), os(0), reader_(0), writer_(0),
security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
reverseConnection(reverseConnection_),
m_videoSelectionEnabled(false)
reverseConnection(reverseConnection_)
{
defaultMajorVersion = 3;
defaultMinorVersion = 8;
@@ -77,11 +76,6 @@ void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
os = os_;
}

void SConnection::setProtocolOptions(bool enableVideoSelection)
{
m_videoSelectionEnabled = enableVideoSelection;
}

void SConnection::initialiseProtocol()
{
cp.writeVersion(os);
@@ -465,10 +459,6 @@ void SConnection::sendInteractionCaps()
ccaps.addTightExt(msgTypeFileDeleteRequest, "FTC_RMRQ");
*/

if (m_videoSelectionEnabled) {
ccaps.addTightExt(msgTypeVideoRectangleSelection, "VRECTSEL");
}

//
// Advertise all supported encoding types (except raw encoding).
//

+ 0
- 8
common/rfb/SConnection.h View File

@@ -50,11 +50,6 @@ namespace rfb {
// (i.e. SConnection will not delete them).
void setStreams(rdr::InStream* is, rdr::OutStream* os);

// setProtocolOptions() configures TightVNC-specific protocol options.
// It can be optionally called before calling initialiseProtocol().
// See also: VNCServerST::enableVideoSelection();
void setProtocolOptions(bool enableVideoSelection);

// initialiseProtocol() should be called once the streams and security
// types are set. Subsequently, processMsg() should be called whenever
// there is data to read on the InStream.
@@ -203,9 +198,6 @@ namespace rfb {
SSecurityFactory* securityFactory;
stateEnum state_;
bool reverseConnection;

// TightVNC-specific protocol options.
bool m_videoSelectionEnabled;
};
}
#endif

+ 0
- 3
common/rfb/SMsgHandler.cxx View File

@@ -51,6 +51,3 @@ void SMsgHandler::supportsLocalCursor()
{
}

void SMsgHandler::setVideoRectangle(const Rect& r)
{
}

+ 0
- 2
common/rfb/SMsgHandler.h View File

@@ -47,8 +47,6 @@ namespace rfb {
virtual void setEncodings(int nEncodings, rdr::U32* encodings);
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);

virtual void setVideoRectangle(const Rect& r);

// InputHandler interface
// The InputHandler methods will be called for the corresponding messages.


+ 0
- 22
common/rfb/SMsgReader.cxx View File

@@ -99,25 +99,3 @@ void SMsgReader::readClientCutText()
handler->clientCutText(ca.buf, len);
}

void SMsgReader::readVideoRectangleSelection()
{
(void)is->readU8();
int x = is->readU16();
int y = is->readU16();
int w = is->readU16();
int h = is->readU16();
Rect rect(x, y, x+w, y+h);

if (!rect.is_empty()) {
vlog.debug("Video area selected by client: %dx%d at (%d,%d)",
w, h, x, y);
} else if (x != 0 || y != 0 || w != 0 || h != 0) {
vlog.debug("Empty video area selected by client: %dx%d at (%d,%d)",
w, h, x, y);
rect.clear();
} else {
vlog.debug("Video area discarded by client");
}
handler->setVideoRectangle(rect);
}


+ 0
- 3
common/rfb/SMsgReader.h View File

@@ -47,9 +47,6 @@ namespace rfb {
virtual void readPointerEvent();
virtual void readClientCutText();

// Read TightVNC-specific protocol messages.
virtual void readVideoRectangleSelection();

SMsgReader(SMsgHandler* handler, rdr::InStream* is);

SMsgHandler* handler;

+ 0
- 2
common/rfb/SMsgReaderV3.cxx View File

@@ -63,8 +63,6 @@ void SMsgReaderV3::readMsg()
case msgTypeFileRenameRequest:
case msgTypeFileDeleteRequest: handler->processFTMsg(msgType); break;

case msgTypeVideoRectangleSelection: readVideoRectangleSelection(); break;

default:
fprintf(stderr, "unknown message type %d\n", msgType);
throw Exception("unknown message type");

+ 0
- 15
common/rfb/SMsgWriter.cxx View File

@@ -24,7 +24,6 @@
#include <rfb/UpdateTracker.h>
#include <rfb/SMsgWriter.h>
#include <rfb/LogWriter.h>
#include <rfb/JpegEncoder.h>

using namespace rfb;

@@ -40,7 +39,6 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
bytesSent[i] = 0;
rectsSent[i] = 0;
}
jpegEncoder = new JpegEncoder(this);
}

SMsgWriter::~SMsgWriter()
@@ -58,7 +56,6 @@ SMsgWriter::~SMsgWriter()
vlog.info(" raw bytes equivalent %d, compression ratio %f",
rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
delete [] imageBuf;
delete jpegEncoder;
}

void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours,
@@ -105,8 +102,6 @@ void SMsgWriter::setupCurrentEncoder()

encoders[encoding]->setCompressLevel(cp->compressLevel);
encoders[encoding]->setQualityLevel(cp->qualityLevel);
if (cp->qualityLevel != -1)
jpegEncoder->setQualityLevel(cp->qualityLevel);
}

int SMsgWriter::getNumRects(const Rect &r)
@@ -174,16 +169,6 @@ bool SMsgWriter::writeRect(const Rect& r, unsigned int encoding,
return encoders[encoding]->writeRect(r, ig, actual);
}

bool SMsgWriter::canUseJpegEncoder(PixelBuffer *pb) const
{
return (cp->qualityLevel != -1 && jpegEncoder->isPixelFormatSupported(pb));
}

void SMsgWriter::writeJpegRect(PixelBuffer *pb, const Rect& r)
{
jpegEncoder->writeRect(pb, r);
}

void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
{
startRect(r,encodingCopyRect);

+ 0
- 6
common/rfb/SMsgWriter.h View File

@@ -37,7 +37,6 @@ namespace rfb {
class ColourMap;
class Region;
class UpdateInfo;
class JpegEncoder;

class WriteSetCursorCallback {
public:
@@ -133,9 +132,6 @@ namespace rfb {

virtual void writeCopyRect(const Rect& r, int srcX, int srcY);

virtual bool canUseJpegEncoder(PixelBuffer *pb) const;
virtual void writeJpegRect(PixelBuffer *pb, const Rect& r);

virtual void startRect(const Rect& r, unsigned int enc)=0;
virtual void endRect()=0;

@@ -161,14 +157,12 @@ namespace rfb {
rdr::OutStream* os;

Encoder* encoders[encodingMax+1];
JpegEncoder* jpegEncoder;
int lenBeforeRect;
unsigned int currentEncoding;
int updatesSent;
int bytesSent[encodingMax+1];
int rectsSent[encodingMax+1];
int rawBytesEquivalent;
// FIXME: Gather statistics for JpegEncoder as well.

rdr::U8* imageBuf;
int imageBufSize;

+ 0
- 5
common/rfb/ServerCore.cxx View File

@@ -93,8 +93,3 @@ rfb::BoolParameter rfb::Server::queryConnect
"Prompt the local user to accept or reject incoming connections.",
false);

// TightVNC-specific parameters
rfb::IntParameter rfb::Server::videoPriority
("VideoPriority",
"Priority of sending video updates (0..8)",
2, 0, 8);

+ 0
- 3
common/rfb/ServerCore.h View File

@@ -48,9 +48,6 @@ namespace rfb {
static BoolParameter sendCutText;
static BoolParameter queryConnect;

// TightVNC-specific parameters
static IntParameter videoPriority;

};

};

+ 1
- 23
common/rfb/UpdateTracker.cxx View File

@@ -60,10 +60,6 @@ void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
ut->add_changed(tmp);
}

void ClippingUpdateTracker::set_video_area(const Rect &rect) {
ut->set_video_area(rect.intersect(clipRect));
}

// SimpleUpdateTracker

SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
@@ -139,18 +135,6 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
return;
}

void SimpleUpdateTracker::set_video_area(const Rect &rect)
{
video_area = rect;
}

//
// subtract() is called to mark some region as unchanged. We just remove that
// region from both `copied' and `changed' regions. Note that `video_area' is
// not affected intentionally; we assume that video is continuously changing,
// so it should always be treated as "changed".
//

void SimpleUpdateTracker::subtract(const Region& region) {
copied.assign_subtract(region);
changed.assign_subtract(region);
@@ -158,15 +142,10 @@ void SimpleUpdateTracker::subtract(const Region& region) {

void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
{
changed.assign_subtract(video_area);
copied.assign_subtract(changed.union_(video_area));
copied.assign_subtract(changed);
info->changed = changed.intersect(clip);
info->copied = copied.intersect(clip);
info->copy_delta = copy_delta;
// FIXME: Using get_bounding_rect() is not what should actually be done!
// We should use the biggest inner rectangle of the `clip' instead.
// From the other side, `clip' is usually just a sole rectangle.
info->video_area = video_area.intersect(clip.get_bounding_rect());
}

void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
@@ -174,5 +153,4 @@ void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
to->add_copied(copied, copy_delta);
if (!changed.is_empty())
to->add_changed(changed);
to->set_video_area(video_area);
}

+ 5
- 31
common/rfb/UpdateTracker.h View File

@@ -30,15 +30,14 @@ namespace rfb {
Region changed;
Region copied;
Point copy_delta;
Rect video_area;
bool is_empty() const {
return copied.is_empty() && changed.is_empty() && video_area.is_empty();
return copied.is_empty() && changed.is_empty();
}
// NOTE: We do not ever use UpdateInfo::numRects(), because Tight encoding
// complicates computing the number of rectangles.
/*
int numRects() const {
return copied.numRects() + changed.numRects() + !video_area.is_empty();
return copied.numRects() + changed.numRects();
}
*/
};
@@ -50,7 +49,6 @@ namespace rfb {

virtual void add_changed(const Region &region) = 0;
virtual void add_copied(const Region &dest, const Point &delta) = 0;
virtual void set_video_area(const Rect &rect) = 0;
};

class ClippingUpdateTracker : public UpdateTracker {
@@ -63,7 +61,6 @@ namespace rfb {

virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void set_video_area(const Rect &rect);
protected:
UpdateTracker* ut;
Rect clipRect;
@@ -78,49 +75,26 @@ namespace rfb {

virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void set_video_area(const Rect &rect);
virtual void subtract(const Region& region);

// Fill the supplied UpdateInfo structure with update information
// FIXME: Provide getUpdateInfo() with no clipping, for better efficiency.
virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);

// Get coordinates of the video rectangle
virtual const Rect& getVideoArea() const {
return video_area;
}

// Copy the contained updates to another tracker
virtual void copyTo(UpdateTracker* to) const;

// Move the entire update region by an offset
void translate(const Point& p) {
changed.translate(p);
copied.translate(p);
video_area.translate(p);
}
void translate(const Point& p) {changed.translate(p); copied.translate(p);}

virtual bool is_empty() const {
return changed.is_empty() && copied.is_empty() && video_area.is_empty();
}

// NOTE: We do not clear video_area intentionally.
virtual void clear() {
changed.clear();
copied.clear();
}
virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();}

virtual void clear() {changed.clear(); copied.clear();};
protected:
Region changed;
Region copied;
Point copy_delta;
bool copy_enabled;

// We can track one rectangle on the screen as a "video area". We assume
// it is changing continuously, in whole. Thus, we don't need to detect
// and track individual changes in the video area -- we can assume it's
// always in the changed state.
Rect video_area;
};

}

+ 5
- 44
common/rfb/VNCSConnectionST.cxx View File

@@ -86,7 +86,6 @@ VNCSConnectionST::~VNCSConnectionST()
bool VNCSConnectionST::init()
{
try {
setProtocolOptions(server->isVideoSelectionEnabled());
initialiseProtocol();
} catch (rdr::Exception& e) {
close(e.str());
@@ -128,12 +127,9 @@ void VNCSConnectionST::processMessages()
}

// If there were update requests, try to send a framebuffer update.
// We don't send updates immediately on requests for two reasons:
// (1) If a video area is set, we don't want to send it on every
// update request. We should gobble all the pending update
// requests and send just one update.
// (2) This way, we give higher priority to user actions such as
// keyboard and pointer events.
// We don't send updates immediately on requests as this way, we
// give higher priority to user actions such as keyboard and
// pointer events.
if (!requested.is_empty()) {
writeFramebufferUpdate();
}
@@ -508,11 +504,6 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
}
}

void VNCSConnectionST::setVideoRectangle(const Rect& r)
{
server->setVideoRectangle(r);
}

void VNCSConnectionST::setInitialColourMap()
{
setColourMapEntries(0, 0);
@@ -573,26 +564,11 @@ void VNCSConnectionST::writeFramebufferUpdate()

updates.enable_copyrect(cp.useCopyRect);

static int counter = 1;
if (--counter > 0) {
server->checkVideoUpdate();
} else {
counter = rfb::Server::videoPriority;
server->checkUpdate();
}

// If VideoPriority is 0, convert video updates to normal updates.

if (rfb::Server::videoPriority == 0) {
Region videoRegion(updates.getVideoArea());
updates.add_changed(videoRegion);
Rect nullRect(0, 0, 0, 0);
updates.set_video_area(nullRect);
}
server->checkUpdate();

// Get the lists of updates. Prior to exporting the data to the `ui' object,
// getUpdateInfo() will normalize the `updates' object such way that its
// `changed', `copied' and `video_area' regions would not intersect.
// `changed' and `copied' regions would not intersect.

UpdateInfo ui;
updates.getUpdateInfo(&ui, requested);
@@ -665,13 +641,6 @@ void VNCSConnectionST::writeFramebufferUpdate()
writer()->setupCurrentEncoder();
int nRects = (ui.copied.numRects() +
(drawRenderedCursor ? 1 : 0));
if (!ui.video_area.is_empty()) {
if (writer()->canUseJpegEncoder(server->getPixelBuffer())) {
nRects++;
} else {
nRects += writer()->getNumRects(ui.video_area);
}
}

std::vector<Rect> rects;
std::vector<Rect>::const_iterator i;
@@ -682,14 +651,6 @@ void VNCSConnectionST::writeFramebufferUpdate()
}
writer()->writeFramebufferUpdateStart(nRects);
if (!ui.video_area.is_empty()) {
if (writer()->canUseJpegEncoder(server->getPixelBuffer())) {
writer()->writeJpegRect(server->getPixelBuffer(), ui.video_area);
} else {
Rect actual;
writer()->writeRect(ui.video_area, &image_getter, &actual);
}
}
Region updatedRegion;
writer()->writeRects(ui, &image_getter, &updatedRegion);
updates.subtract(updatedRegion);

+ 0
- 3
common/rfb/VNCSConnectionST.h View File

@@ -94,7 +94,6 @@ namespace rfb {
void add_copied(const Region& dest, const Point& delta) {
updates.add_copied(dest, delta);
}
void set_video_area(const Rect &rect) { updates.set_video_area(rect); }

const char* getPeerEndpoint() const {return peerEndpoint.buf;}

@@ -131,8 +130,6 @@ namespace rfb {
virtual void setInitialColourMap();
virtual void supportsLocalCursor();

virtual void setVideoRectangle(const Rect& r);

// setAccessRights() allows a security package to limit the access rights
// of a VNCSConnectioST to the server. These access rights are applied
// such that the actual rights granted are the minimum of the server's

+ 2
- 69
common/rfb/VNCServerST.cxx View File

@@ -77,8 +77,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_,
securityFactory(sf ? sf : &defaultSecurityFactory),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
useEconomicTranslate(false),
lastConnectionTime(0), disableclients(false),
m_videoSelectionEnabled(false)
lastConnectionTime(0), disableclients(false)
{
lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
@@ -147,7 +146,6 @@ void VNCServerST::removeSocket(network::Socket* sock) {
slog.debug("no authenticated clients - stopping desktop");
desktopStarted = false;
desktop->stop();
setVideoRectangle(Rect(0, 0, 0, 0));
}
return;
}
@@ -260,7 +258,6 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_)

if (pb) {
comparer = new ComparingUpdateTracker(pb);
applyVideoRectangle();
cursor.setPF(pb->getPF());
renderedCursor.setPF(pb->getPF());

@@ -326,13 +323,6 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta)
}
}

void VNCServerST::set_video_area(const Rect &rect)
{
if (comparer != 0) {
comparer->set_video_area(rect);
}
}

bool VNCServerST::clientsReadyForUpdate()
{
std::list<VNCSConnectionST*>::iterator ci;
@@ -478,7 +468,7 @@ void VNCServerST::checkUpdate()
if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
return;

Region toCheck = ui.changed.union_(ui.copied).union_(ui.video_area);
Region toCheck = ui.changed.union_(ui.copied);

if (renderCursor) {
Rect clippedCursorRect
@@ -516,28 +506,11 @@ void VNCServerST::checkUpdate()
ci_next = ci; ci_next++;
(*ci)->add_copied(ui.copied, ui.copy_delta);
(*ci)->add_changed(ui.changed);
(*ci)->set_video_area(ui.video_area);
}

comparer->clear();
}

void VNCServerST::checkVideoUpdate()
{
const Rect &videoRect = comparer->getVideoArea();
Region videoRegion(videoRect);

if (!videoRegion.is_empty()) {
pb->grabRegion(videoRegion);

std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++;
(*ci)->set_video_area(videoRect);
}
}
}

void VNCServerST::getConnInfo(ListConnInfo * listConn)
{
listConn->Clear();
@@ -571,43 +544,3 @@ void VNCServerST::setConnStatus(ListConnInfo* listConn)
}
}

void VNCServerST::enableVideoSelection(bool enable)
{
slog.debug("Enabling video selection");
m_videoSelectionEnabled = enable;
applyVideoRectangle();
}

bool VNCServerST::isVideoSelectionEnabled() const
{
return m_videoSelectionEnabled;
}

void VNCServerST::setVideoRectangle(const Rect& r)
{
m_videoRect = r;
applyVideoRectangle();
}

void VNCServerST::setDefaultVideoRectangle(const Rect& r)
{
m_defaultVideoRect = r;
applyVideoRectangle();
}

void VNCServerST::applyVideoRectangle()
{
if (pb != 0) {
if (isVideoSelectionEnabled() && !m_videoRect.is_empty()) {
slog.debug("Applying video selection");
set_video_area(m_videoRect);
} else {
if (!m_defaultVideoRect.is_empty()) {
slog.debug("Applying default video area");
} else {
slog.debug("Applying empty video area");
}
set_video_area(m_defaultVideoRect);
}
}
}

+ 0
- 21
common/rfb/VNCServerST.h View File

@@ -84,7 +84,6 @@ namespace rfb {
virtual void serverCutText(const char* str, int len);
virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void set_video_area(const Rect &rect);
virtual bool clientsReadyForUpdate();
virtual void tryUpdate();
virtual void setCursor(int width, int height, const Point& hotspot,
@@ -192,19 +191,6 @@ namespace rfb {

void setFTManager(rfb::SFileTransferManager *pFTManager) { m_pFTManager = pFTManager; };

// Enable/disable support for TightVNC-specific VideoRectangleSelection
// client message. This is a protocol option that lets a client select a
// rectangle to be treated by the server as video data. Once selected, this
// part of the framebuffer will be sent using JpegEncoder, on each update
// request, as we expect that video data is changing continuously. By
// default, this option is disabled, as it's rather a specialized feature
// and video selection GUI can confuse users of the TigerVNC client.
void enableVideoSelection(bool enable);
bool isVideoSelectionEnabled() const;

void setVideoRectangle(const Rect& r);
void setDefaultVideoRectangle(const Rect& r);

protected:

friend class VNCSConnectionST;
@@ -241,7 +227,6 @@ namespace rfb {

bool needRenderedCursor();
void checkUpdate();
void checkVideoUpdate();

SSecurityFactory* securityFactory;
QueryConnectionHandler* queryConnectionHandler;
@@ -253,12 +238,6 @@ namespace rfb {
time_t lastConnectionTime;

bool disableclients;

bool m_videoSelectionEnabled;
Rect m_videoRect;
Rect m_defaultVideoRect;

void applyVideoRectangle();
};

};

+ 0
- 1
common/rfb/msgTypes.h View File

@@ -57,6 +57,5 @@ namespace rfb {
const int msgTypeFileDeleteRequest = 139;

const int msgTypeEnableContinuousUpdates = 150;
const int msgTypeVideoRectangleSelection = 151;
}
#endif

+ 0
- 16
common/rfb/rfb.dsp View File

@@ -219,14 +219,6 @@ SOURCE=.\HTTPServer.cxx
# End Source File
# Begin Source File
SOURCE=.\JpegCompressor.cxx
# End Source File
# Begin Source File
SOURCE=.\JpegEncoder.cxx
# End Source File
# Begin Source File
SOURCE=.\KeyRemapper.cxx
# End Source File
# Begin Source File
@@ -553,14 +545,6 @@ SOURCE=.\InputHandler.h
# End Source File
# Begin Source File
SOURCE=.\JpegCompressor.h
# End Source File
# Begin Source File
SOURCE=.\JpegEncoder.h
# End Source File
# Begin Source File
SOURCE=.\KeyRemapper.h
# End Source File
# Begin Source File

+ 0
- 2
unix/x0vncserver/x0vncserver.cxx View File

@@ -188,7 +188,6 @@ public:

server = (VNCServerST *)vs;
server->setPixelBuffer(pb);
server->setDefaultVideoRectangle(geometry->getVideoRect());

running = true;
}
@@ -447,7 +446,6 @@ int main(int argc, char** argv)
VNCServerST server("x0vncserver", &desktop);
QueryConnHandler qcHandler(dpy, &server);
server.setQueryConnectionHandler(&qcHandler);
server.enableVideoSelection(true);

TcpListener listener((int)rfbport);
vlog.info("Listening on port %d", (int)rfbport);

Loading…
Cancel
Save