📄 vncencodezlib.cpp
字号:
// Copyright (C) 2002 Ultr@VNC Team Members. All Rights Reserved.
// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of TeamViewer.
//
// TeamViewer 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 program 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 program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
//
// If the source code for TeamViewer is not available from the place
// whence you received this file, check http://www.teamviewer.com
// for information on obtaining it.
// vncEncodeZlib
// This file implements the vncEncoder-derived vncEncodeZlib class.
// This class overrides some vncEncoder functions to produce a bitmap
// to Zlib encoder. Zlib is much more efficient than RAW format on
// most screen data and usually twice as efficient as hextile. Of
// course, zlib compression uses more CPU time on the server.
// However, over slower (64kbps or less) connections, the reduction
// in data transmitted usually outweighs the extra latency added
// while the server CPU performs the compression algorithms.
#include "stdhdrs.h"
#include "vncEncodeZlib.h"
#include "..\..\vncviewer\vncviewer.h"
vncEncodeZlib::vncEncodeZlib()
{
m_buffer = NULL;
m_buffer2 = NULL;
m_Queuebuffer = NULL;
m_QueueCompressedbuffer = NULL;
m_bufflen = 0;
m_Queuelen = 0;
m_Maskbuffer =NULL;
m_MaskbufferSize =0;
compStreamInited = false;
MaxQueuebufflen=128*1024;
m_Queuebuffer = new BYTE [MaxQueuebufflen+1];
if (m_Queuebuffer == NULL)
{
vnclog.Print(LL_INTINFO, VNCLOG("Memory error"));
}
m_QueueCompressedbuffer = new BYTE [MaxQueuebufflen+(MaxQueuebufflen/100)+8];
if (m_Queuebuffer == NULL)
{
vnclog.Print(LL_INTINFO, VNCLOG("Memory error"));
}
}
vncEncodeZlib::~vncEncodeZlib()
{
if (m_buffer != NULL)
{
delete [] m_buffer;
m_buffer = NULL;
}
if (m_buffer2 != NULL)
{
delete [] m_buffer2;
m_buffer2 = NULL;
}
if (m_Queuebuffer != NULL)
{
delete [] m_Queuebuffer;
m_Queuebuffer = NULL;
}
if (m_QueueCompressedbuffer != NULL)
{
delete [] m_QueueCompressedbuffer;
m_QueueCompressedbuffer = NULL;
}
if (m_Maskbuffer !=NULL)
{
delete [] m_Maskbuffer;
m_Maskbuffer = NULL;
}
if ( compStreamInited == true )
{
deflateEnd( &compStream );
}
compStreamInited = false;
vnclog.Print(LL_INTINFO, VNCLOG("Zlib Xor encoder stats: rawdata=%d protocol=%d compressed=%d transmitted=%d"),dataSize, rectangleOverhead, encodedSize,transmittedSize);
if (dataSize != 0) {
vnclog.Print(LL_INTINFO, VNCLOG("Zlib Xor encoder efficiency: %.3f%%"),(double)((double)((dataSize - transmittedSize) * 100) / dataSize));
}
}
void
vncEncodeZlib::Init()
{
totalraw=0;
encodedSize=0;
rectangleOverhead=0;
transmittedSize=0;
dataSize=0;
vncEncoder::Init();
m_nNbRects=0;
}
UINT
vncEncodeZlib::RequiredBuffSize(UINT width, UINT height)
{
int result;
// The zlib library specifies a maximum compressed size of
// the raw size plus one percent plus 8 bytes. We also need
// to cover the zlib header space.
result = vncEncoder::RequiredBuffSize(width, height);
Firstrun=result*2;//Needed to exclude xor when cachebuffer is empty
result += ((result / 100) + 8) + sz_rfbZlibHeader;
return result;
}
UINT
vncEncodeZlib::NumCodedRects(const rfb::Rect &rect)
{
const int rectW = rect.br.x - rect.tl.x;
const int rectH = rect.br.y - rect.tl.y;
int aantal=(( rectH - 1 ) / ( ZLIB_MAX_SIZE( rectW ) / rectW ) + 1 );
m_queueEnable=false;
if (m_use_lastrect && aantal>1) {
m_queueEnable=true;
return 0;
}
/******************************************************************
return 1;
******************************************************************/
// Return the number of rectangles needed to encode the given
// update. ( ZLIB_MAX_SIZE(rectW) / rectW ) is the number of lines in
// each maximum size rectangle.
// When solid is enabled, most of the pixels are removed
return (( rectH - 1 ) / ( ZLIB_MAX_SIZE( rectW ) / rectW ) + 1 );
}
/*****************************************************************************
*
* Routines to implement zlib Encoding (LZ+Huffman compression) by calling
* the included zlib library.
*/
// Encode the rectangle using zlib compression
inline UINT
vncEncodeZlib::EncodeRect(BYTE *source,BYTE *source2, VSocket *outConn, BYTE *dest, const rfb::Rect &rect)
{
int totalSize = 0;
int partialSize = 0;
int maxLines;
int linesRemaining;
RECT partialRect;
const int rectW = rect.br.x - rect.tl.x;
const int rectH = rect.br.y - rect.tl.y;
partialRect.right = rect.br.x;
partialRect.left = rect.tl.x;
partialRect.top = rect.tl.y;
partialRect.bottom = rect.br.y;
/* WBB: For testing purposes only! */
// vnclog.Print(LL_INTINFO, VNCLOG("rect.right=%d rect.left=%d rect.top=%d rect.bottom=%d"), rect.right, rect.left, rect.top, rect.bottom);
maxLines = ( ZLIB_MAX_SIZE(rectW) / rectW );
linesRemaining = rectH;
while ( linesRemaining > 0 ) {
int linesToComp;
if ( maxLines < linesRemaining )
linesToComp = maxLines;
else
linesToComp = linesRemaining;
partialRect.bottom = partialRect.top + linesToComp;
/* WBB: For testing purposes only! */
// vnclog.Print(LL_INTINFO, VNCLOG("partialRect.right=%d partialRect.left=%d partialRect.top=%d partialRect.bottom=%d"), partialRect.right, partialRect.left, partialRect.top, partialRect.bottom);
partialSize = EncodeOneRect( source,source2, dest, partialRect,outConn );
totalSize += partialSize;
linesRemaining -= linesToComp;
partialRect.top += linesToComp;
if (( linesRemaining > 0 ) &&
( partialSize > 0 ))
{
// Send the encoded data
outConn->SendExactQueue( (char *)dest, partialSize );
transmittedSize += partialSize;
}
}
transmittedSize += partialSize;
return partialSize;
}
// Encode the rectangle using zlib compression
inline UINT
vncEncodeZlib::EncodeOneRect(BYTE *source,BYTE *source2, BYTE *dest, const RECT &rect,VSocket *outConn)
{
int totalCompDataLen = 0;
int previousTotalOut;
int deflateResult;
const int rectW = rect.right - rect.left;
const int rectH = rect.bottom - rect.top;
const int rawDataSize = (rectW*rectH*m_remoteformat.bitsPerPixel / 8);
const int maxCompSize = (rawDataSize + (rawDataSize/100) + 8);
// Create the rectangle header
rfbFramebufferUpdateRectHeader *surh=(rfbFramebufferUpdateRectHeader *)dest;
// Modif rdv@2002 - v1.1.x - Application Resize
surh->r.x = (CARD16) rect.left-m_SWOffsetx;
surh->r.y = (CARD16) rect.top-m_SWOffsety;
surh->r.w = (CARD16) (rectW);
surh->r.h = (CARD16) (rectH);
surh->r.x = Swap16IfLE(surh->r.x);
surh->r.y = Swap16IfLE(surh->r.y);
surh->r.w = Swap16IfLE(surh->r.w);
surh->r.h = Swap16IfLE(surh->r.h);
surh->encoding = Swap32IfLE(rfbEncodingZlib);
dataSize += ( rectW * rectH * m_remoteformat.bitsPerPixel) / 8;
rectangleOverhead += sz_rfbFramebufferUpdateRectHeader;
// create a space big enough for the Zlib encoded pixels
if (m_bufflen < rawDataSize)
{
if (m_buffer != NULL)
{
delete [] m_buffer;
m_buffer = NULL;
}
m_buffer = new BYTE [rawDataSize+1];
if (m_buffer == NULL)
return vncEncoder::EncodeRect(source, dest, rect);
m_bufflen = rawDataSize;
if (m_buffer2 != NULL)
{
delete [] m_buffer2;
m_buffer2 = NULL;
}
m_buffer2 = new BYTE [rawDataSize+1];
}
bool full_solid=false;
// Translate the data into our new buffer
compStream.avail_in = rawDataSize;
Translate(source, m_buffer, rect);
// Perhaps we can queue the small updates and compress them combined
if (rawDataSize < VNC_ENCODE_ZLIB_MIN_COMP_SIZE)
{
if (m_queueEnable && source2 && dataSize>Firstrun)
{
surh->encoding = Swap32IfLE(rfbEncodingRaw);
memcpy(dest+sz_rfbFramebufferUpdateRectHeader,m_buffer,rawDataSize);
AddToQueu(dest,sz_rfbFramebufferUpdateRectHeader +rawDataSize,outConn,0);
return 0;
}
else return vncEncoder::EncodeRect(source, dest, rect);
}
UINT newsize;
SoMoMu=PURE_ZLIB;
if (m_buffer2 && source2 && dataSize>Firstrun)
{
Translate(source2,m_buffer2, rect);
newsize=PrepareXOR(m_buffer,m_buffer2,rect);
}
switch (SoMoMu)
{
case SOLID_COLOR:
{
surh->encoding = Swap32IfLE(rfbEncodingSolidColor);
memcpy(dest+sz_rfbFramebufferUpdateRectHeader,m_buffer,compStream.avail_in);
//vnclog.Print(LL_INTINFO, VNCLOG("Solid "));
if (m_queueEnable)
{
AddToQueu(dest,sz_rfbFramebufferUpdateRectHeader +newsize,outConn,0);
return 0;
}
return sz_rfbFramebufferUpdateRectHeader +newsize;
}
case MONO_COLOR:
{
compStream.avail_in = newsize;
surh->encoding = Swap32IfLE(rfbEncodingXORMonoColor_Zlib);
//vnclog.Print(LL_INTINFO, VNCLOG("Mono "));
if (m_queueEnable)
{
memcpy(dest+sz_rfbFramebufferUpdateRectHeader,m_buffer,newsize);
AddToQueu(dest,sz_rfbFramebufferUpdateRectHeader +newsize,outConn,1);
return 0;
}
break;
}
case MULTI_COLOR:
{
compStream.avail_in = newsize;
surh->encoding = Swap32IfLE(rfbEncodingXORMultiColor_Zlib);
///vnclog.Print(LL_INTINFO, VNCLOG("MultiColor "));
break;
}
case XOR_SEQUENCE:
{
compStream.avail_in = newsize;
surh->encoding = Swap32IfLE(rfbEncodingXOR_Zlib);
memcpy(dest+sz_rfbFramebufferUpdateRectHeader,m_buffer,newsize);
if (newsize<1000 && m_queueEnable)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -