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-ca57d06f2519tags/v0.0.90
@@ -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; | |||
@@ -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; | |||
} | |||
@@ -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__ | |||
@@ -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"); | |||
} | |||
@@ -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__ | |||
@@ -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; | |||
} | |||
@@ -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__ | |||
@@ -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); | |||
} | |||
@@ -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__ | |||
@@ -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(); | |||
} | |||
@@ -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 |
@@ -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 |
@@ -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). | |||
// |
@@ -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 |
@@ -51,6 +51,3 @@ void SMsgHandler::supportsLocalCursor() | |||
{ | |||
} | |||
void SMsgHandler::setVideoRectangle(const Rect& r) | |||
{ | |||
} |
@@ -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. | |||
@@ -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); | |||
} | |||
@@ -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; |
@@ -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"); |
@@ -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); |
@@ -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; |
@@ -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); |
@@ -48,9 +48,6 @@ namespace rfb { | |||
static BoolParameter sendCutText; | |||
static BoolParameter queryConnect; | |||
// TightVNC-specific parameters | |||
static IntParameter videoPriority; | |||
}; | |||
}; |
@@ -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); | |||
} |
@@ -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 ®ion) = 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 ®ion); | |||
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 ®ion); | |||
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; | |||
}; | |||
} |
@@ -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); |
@@ -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 |
@@ -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); | |||
} | |||
} | |||
} |
@@ -84,7 +84,6 @@ namespace rfb { | |||
virtual void serverCutText(const char* str, int len); | |||
virtual void add_changed(const Region ®ion); | |||
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(); | |||
}; | |||
}; |
@@ -57,6 +57,5 @@ namespace rfb { | |||
const int msgTypeFileDeleteRequest = 139; | |||
const int msgTypeEnableContinuousUpdates = 150; | |||
const int msgTypeVideoRectangleSelection = 151; | |||
} | |||
#endif |
@@ -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 |
@@ -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); |