git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4623 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v1.1.90
ZlibOutStream::ZlibOutStream(OutStream* os, int bufSize_, int compressLevel) | ZlibOutStream::ZlibOutStream(OutStream* os, int bufSize_, int compressLevel) | ||||
: underlying(os), compressionLevel(compressLevel), newLevel(compressLevel), | : underlying(os), compressionLevel(compressLevel), newLevel(compressLevel), | ||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) | |||||
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0), | |||||
newBehavior(false) | |||||
{ | { | ||||
zs = new z_stream; | zs = new z_stream; | ||||
zs->zalloc = Z_NULL; | zs->zalloc = Z_NULL; | ||||
} | } | ||||
ptr = start = new U8[bufSize]; | ptr = start = new U8[bufSize]; | ||||
end = start + bufSize; | end = start + bufSize; | ||||
const char *version = zlibVersion(); | |||||
if (strcmp(version, "1.2.3") > 0) newBehavior = true; | |||||
} | } | ||||
ZlibOutStream::~ZlibOutStream() | ZlibOutStream::~ZlibOutStream() | ||||
// fprintf(stderr,"zos flush: avail_in %d\n",zs->avail_in); | // fprintf(stderr,"zos flush: avail_in %d\n",zs->avail_in); | ||||
if (!underlying) | |||||
throw Exception("ZlibOutStream: underlying OutStream has not been set"); | |||||
while (zs->avail_in != 0) { | while (zs->avail_in != 0) { | ||||
do { | do { | ||||
if (itemSize > bufSize) | if (itemSize > bufSize) | ||||
throw Exception("ZlibOutStream overrun: max itemSize exceeded"); | throw Exception("ZlibOutStream overrun: max itemSize exceeded"); | ||||
if (!underlying) | |||||
throw Exception("ZlibOutStream: underlying OutStream has not been set"); | |||||
while (end - ptr < itemSize) { | while (end - ptr < itemSize) { | ||||
zs->next_in = start; | zs->next_in = start; | ||||
zs->avail_in = ptr - start; | zs->avail_in = ptr - start; | ||||
// fprintf(stderr,"zos overrun: calling deflate, avail_in %d, avail_out %d\n", | // fprintf(stderr,"zos overrun: calling deflate, avail_in %d, avail_out %d\n", | ||||
// zs->avail_in,zs->avail_out); | // zs->avail_in,zs->avail_out); | ||||
checkCompressionLevel(); | |||||
if (zs->avail_in != 0) { | |||||
int rc = deflate(zs, 0); | |||||
if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed"); | |||||
} | |||||
checkCompressionLevel(); | |||||
if (zs->avail_in != 0) { | |||||
int rc = deflate(zs, 0); | |||||
if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed"); | |||||
} | |||||
// fprintf(stderr,"zos overrun: after deflate: %d bytes\n", | // fprintf(stderr,"zos overrun: after deflate: %d bytes\n", | ||||
// zs->next_out-underlying->getptr()); | // zs->next_out-underlying->getptr()); | ||||
void ZlibOutStream::checkCompressionLevel() | void ZlibOutStream::checkCompressionLevel() | ||||
{ | { | ||||
if (newLevel != compressionLevel) { | if (newLevel != compressionLevel) { | ||||
// This is a horrible hack, but after many hours of trying, I couldn't find | |||||
// a better way to make this class work properly with both Zlib 1.2.3 and | |||||
// 1.2.5. 1.2.3 does a Z_PARTIAL_FLUSH in the body of deflateParams() if | |||||
// the compression level has changed, and 1.2.5 does a Z_BLOCK flush. | |||||
if (newBehavior) { | |||||
int rc = deflate(zs, Z_SYNC_FLUSH); | |||||
if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed"); | |||||
} | |||||
if (deflateParams (zs, newLevel, Z_DEFAULT_STRATEGY) != Z_OK) { | if (deflateParams (zs, newLevel, Z_DEFAULT_STRATEGY) != Z_OK) { | ||||
throw Exception("ZlibOutStream: deflateParams failed"); | throw Exception("ZlibOutStream: deflateParams failed"); | ||||
} | } |
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | ||||
* Copyright (C) 2011 D. R. Commander. All Rights Reserved. | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
int offset; | int offset; | ||||
z_stream_s* zs; | z_stream_s* zs; | ||||
U8* start; | U8* start; | ||||
bool newBehavior; | |||||
}; | }; | ||||
} // end of namespace rdr | } // end of namespace rdr |
// | // | ||||
static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, | static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, | ||||
const void *buf, unsigned int length, int zlibLevel) | |||||
const void *buf, const PixelFormat& pf, | |||||
unsigned int length, int zlibLevel) | |||||
{ | { | ||||
if (length < TIGHT_MIN_TO_COMPRESS) { | if (length < TIGHT_MIN_TO_COMPRESS) { | ||||
os->writeBytes(buf, length); | os->writeBytes(buf, length); | ||||
} else { | } else { | ||||
// FIXME: Using a temporary MemOutStream may be not efficient. | // FIXME: Using a temporary MemOutStream may be not efficient. | ||||
// Maybe use the same static object used in the JPEG coder? | // Maybe use the same static object used in the JPEG coder? | ||||
int maxBeforeSize = s_pconf->maxRectSize * (BPP / 8); | |||||
int maxBeforeSize = s_pconf->maxRectSize * (pf.bpp / 8); | |||||
int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; | int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; | ||||
rdr::MemOutStream mem_os(maxAfterSize); | rdr::MemOutStream mem_os(maxAfterSize); | ||||
zos->setUnderlying(&mem_os); | zos->setUnderlying(&mem_os); | ||||
zos->setCompressionLevel(zlibLevel); | zos->setCompressionLevel(zlibLevel); | ||||
zos->writeBytes(buf, length); | zos->writeBytes(buf, length); | ||||
zos->flush(); | zos->flush(); | ||||
zos->setUnderlying(NULL); | |||||
os->writeCompactLength(mem_os.length()); | os->writeCompactLength(mem_os.length()); | ||||
os->writeBytes(mem_os.data(), mem_os.length()); | os->writeBytes(mem_os.data(), mem_os.length()); | ||||
} | } | ||||
os->writeU8(streamId << 4); | os->writeU8(streamId << 4); | ||||
int length = PACK_PIXELS(buf, r.area(), pf); | int length = PACK_PIXELS(buf, r.area(), pf); | ||||
compressData(os, &zos[streamId], buf, length, s_pconf->rawZlibLevel); | |||||
compressData(os, &zos[streamId], buf, pf, length, s_pconf->rawZlibLevel); | |||||
} | } | ||||
static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], | static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], | ||||
// Write the data | // Write the data | ||||
int length = (w + 7) / 8; | int length = (w + 7) / 8; | ||||
length *= h; | length *= h; | ||||
compressData(os, &zos[streamId], buf, length, s_pconf->monoZlibLevel); | |||||
compressData(os, &zos[streamId], buf, pf, length, s_pconf->monoZlibLevel); | |||||
} | } | ||||
#if (BPP != 8) | #if (BPP != 8) | ||||
} | } | ||||
// Write the data | // Write the data | ||||
compressData(os, &zos[streamId], buf, r.area(), s_pconf->idxZlibLevel); | |||||
compressData(os, &zos[streamId], buf, pf, r.area(), s_pconf->idxZlibLevel); | |||||
} | } | ||||
#endif // #if (BPP != 8) | #endif // #if (BPP != 8) | ||||