encodingstest.c 8.19 KB
Newer Older
1
#ifdef __STRICT_ANSI__
2
#define _BSD_SOURCE
3
#endif
4
#include <time.h>
5
#include <stdarg.h>
6 7 8
#include <rfb/rfb.h>
#include <rfb/rfbclient.h>

9 10
#ifndef LIBVNCSERVER_HAVE_LIBPTHREAD
#error This test need pthread support (otherwise the client blocks the client)
11 12
#endif

13
#define ALL_AT_ONCE
14
/*#define VERY_VERBOSE*/
15

16
static MUTEX(frameBufferMutex);
17

18
typedef struct { int id; char* str; } encoding_t;
19
static encoding_t testEncodings[]={
Christian Beier's avatar
Christian Beier committed
20
        { rfbEncodingRaw, "raw" },
21
	{ rfbEncodingRRE, "rre" },
Christian Beier's avatar
Christian Beier committed
22
	{ rfbEncodingCoRRE, "corre" },
23
	{ rfbEncodingHextile, "hextile" },
Christian Beier's avatar
Christian Beier committed
24
	{ rfbEncodingUltra, "ultra" },
25
#ifdef LIBVNCSERVER_HAVE_LIBZ
26 27
	{ rfbEncodingZlib, "zlib" },
	{ rfbEncodingZlibHex, "zlibhex" },
dscho's avatar
dscho committed
28
	{ rfbEncodingZRLE, "zrle" },
Christian Beier's avatar
Christian Beier committed
29
	{ rfbEncodingZYWRLE, "zywrle" },
30
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
31
	{ rfbEncodingTight, "tight" },
32 33
#endif
#endif
34
	{ 0, NULL }
35 36
};

37
#define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
38
/*#define NUMBER_OF_ENCODINGS_TO_TEST 1*/
39 40 41

/* Here come the variables/functions to handle the test output */

42 43 44 45 46
static const int width=400,height=300;
static unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST];
static unsigned int totalFailed,totalCount;
static unsigned int countGotUpdate;
static MUTEX(statisticsMutex);
47

48
static void initStatistics(void) {
49 50 51
	memset(statistics[0],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
	memset(statistics[1],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
	totalFailed=totalCount=0;
52 53 54 55
	INIT_MUTEX(statisticsMutex);
}


56
static void updateStatistics(int encodingIndex,rfbBool failed) {
57 58
	LOCK(statisticsMutex);
	if(failed) {
59
		statistics[1][encodingIndex]++;
60 61
		totalFailed++;
	}
62 63
	statistics[0][encodingIndex]++;
	totalCount++;
64 65 66 67 68 69 70 71 72
	countGotUpdate++;
	UNLOCK(statisticsMutex);
}

/* Here begin the functions for the client. They will be called in a
 * pthread. */

/* maxDelta=0 means they are expected to match exactly;
 * maxDelta>0 means that the average difference must be lower than maxDelta */
73
static rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client,
74 75 76 77 78 79 80 81 82 83
		int maxDelta)
{
	int i,j,k;
	unsigned int total=0,diff=0;
	if(server->width!=client->width || server->height!=client->height)
		return FALSE;
	LOCK(frameBufferMutex);
	/* TODO: write unit test for colour transformation, use here, too */
	for(i=0;i<server->width;i++)
		for(j=0;j<server->height;j++)
84
			for(k=0;k<3/*server->serverFormat.bitsPerPixel/8*/;k++) {
85
				unsigned char s=server->frameBuffer[k+i*4+j*server->paddedWidthInBytes];
86
				unsigned char cl=client->frameBuffer[k+i*4+j*client->width*4];
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
				if(maxDelta==0 && s!=cl) {
					UNLOCK(frameBufferMutex);
					return FALSE;
				} else {
					total++;
					diff+=(s>cl?s-cl:cl-s);
				}
			}
	UNLOCK(frameBufferMutex);
	if(maxDelta>0 && diff/total>=maxDelta)
		return FALSE;
	return TRUE;
}

static rfbBool resize(rfbClient* cl) {
	if(cl->frameBuffer)
		free(cl->frameBuffer);
Christian Beier's avatar
Christian Beier committed
105
	cl->frameBuffer=malloc(cl->width*cl->height*cl->format.bitsPerPixel/8);
106 107
	if(!cl->frameBuffer)
		return FALSE;
108
	SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE);
109
	return TRUE;
110 111 112 113 114
}

typedef struct clientData {
	int encodingIndex;
	rfbScreenInfo* server;
115
	char* display;
116 117 118
} clientData;

static void update(rfbClient* client,int x,int y,int w,int h) {
119
#ifndef VERY_VERBOSE
Christian Beier's avatar
Christian Beier committed
120

121 122
	static const char* progress="|/-\\";
	static int counter=0;
123

124 125 126
	if(++counter>sizeof(progress)) counter=0;
	fprintf(stderr,"%c\r",progress[counter]);
#else
Christian Beier's avatar
Christian Beier committed
127
	clientData* cd=(clientData*)client->clientData;
128
	rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
129 130 131
			testEncodings[cd->encodingIndex].str,
			x,y,x+w,y+h);
#endif
Christian Beier's avatar
Christian Beier committed
132
}
133

Christian Beier's avatar
Christian Beier committed
134 135 136
static void update_finished(rfbClient* client) {
	clientData* cd=(clientData*)client->clientData;
        int maxDelta=0;
137

138
#ifdef LIBVNCSERVER_HAVE_LIBZ
Christian Beier's avatar
Christian Beier committed
139 140 141
	if(testEncodings[cd->encodingIndex].id==rfbEncodingZYWRLE)
		maxDelta=5;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
142 143
	if(testEncodings[cd->encodingIndex].id==rfbEncodingTight)
		maxDelta=5;
144
#endif
Christian Beier's avatar
Christian Beier committed
145
#endif
146 147 148 149
	updateStatistics(cd->encodingIndex,
			!doFramebuffersMatch(cd->server,client,maxDelta));
}

Christian Beier's avatar
Christian Beier committed
150

151 152
static void* clientLoop(void* data) {
	rfbClient* client=(rfbClient*)data;
153
	clientData* cd=(clientData*)client->clientData;
154 155

	client->appData.encodingsString=strdup(testEncodings[cd->encodingIndex].str);
Christian Beier's avatar
Christian Beier committed
156
	client->appData.qualityLevel = 7; /* ZYWRLE fails the test with standard settings */
157

158
	sleep(1);
159
	rfbClientLog("Starting client (encoding %s, display %s)\n",
160 161
			testEncodings[cd->encodingIndex].str,
			cd->display);
162
	if(!rfbInitClient(client,NULL,NULL)) {
163
		rfbClientErr("Had problems starting client (encoding %s)\n",
164 165
				testEncodings[cd->encodingIndex].str);
		updateStatistics(cd->encodingIndex,TRUE);
166
		return NULL;
167
	}
168 169 170 171 172
	while(1) {
		if(WaitForMessage(client,50)>=0)
			if(!HandleRFBServerMessage(client))
				break;
	}
173 174
	free(((clientData*)client->clientData)->display);
	free(client->clientData);
175
	client->clientData = NULL;
176 177 178
	if(client->frameBuffer)
		free(client->frameBuffer);
	rfbClientCleanup(client);
179
	return NULL;
180 181
}

182 183 184
static pthread_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST];
static int thread_counter;

185 186 187
static void startClient(int encodingIndex,rfbScreenInfo* server) {
	rfbClient* client=rfbGetClient(8,3,4);
	clientData* cd;
188

189 190 191
	client->clientData=malloc(sizeof(clientData));
	client->MallocFrameBuffer=resize;
	client->GotFrameBufferUpdate=update;
Christian Beier's avatar
Christian Beier committed
192
	client->FinishedFrameBufferUpdate=update_finished;
193 194 195 196

	cd=(clientData*)client->clientData;
	cd->encodingIndex=encodingIndex;
	cd->server=server;
197 198
	cd->display=(char*)malloc(6);
	sprintf(cd->display,":%d",server->port-5900);
199

200
	pthread_create(&all_threads[thread_counter++],NULL,clientLoop,(void*)client);
201 202 203 204 205 206 207 208 209 210
}

/* Here begin the server functions */

static void idle(rfbScreenInfo* server)
{
	int c;
	rfbBool goForward;

	LOCK(statisticsMutex);
211
#ifdef ALL_AT_ONCE
212
	goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
213 214 215
#else
	goForward=(countGotUpdate==1);
#endif
Christian Beier's avatar
Christian Beier committed
216

217 218
	UNLOCK(statisticsMutex);
	if(!goForward)
Christian Beier's avatar
Christian Beier committed
219
	  return;
220
	countGotUpdate=0;
221 222

	LOCK(frameBufferMutex);
223
	{
224
		int i,j;
225 226
		int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
		y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
227 228
		if(x1>x2) { i=x1; x1=x2; x2=i; }
		if(y1>y2) { i=y1; y1=y2; y2=i; }
229 230 231 232 233 234 235 236 237 238 239
		x2++; y2++;
		for(c=0;c<3;c++) {
			for(i=x1;i<x2;i++)
				for(j=y1;j<y2;j++)
					server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1);
		}
		rfbMarkRectAsModified(server,x1,y1,x2,y2);

#ifdef VERY_VERBOSE
		rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
#endif
240 241 242 243
	}
	UNLOCK(frameBufferMutex);
}

244 245
/* log function (to show what messages are from the client) */

246
static void
247 248 249 250 251 252 253 254 255 256 257 258 259
rfbTestLog(const char *format, ...)
{
	va_list args;
	char buf[256];
	time_t log_clock;

	if(!rfbEnableClientLogging)
		return;

	va_start(args, format);

	time(&log_clock);
	strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock));
260
	fprintf(stderr,"%s",buf);
261 262 263 264 265 266 267 268 269

	vfprintf(stderr, format, args);
	fflush(stderr);

	va_end(args);
}

/* the main function */

270
int main(int argc,char** argv)
271
{
272 273
	int i,j;
	time_t t;
274
	rfbScreenInfoPtr server;
275

276 277 278
	rfbClientLog=rfbTestLog;
	rfbClientErr=rfbTestLog;

279
	/* Initialize server */
280
	server=rfbGetScreen(&argc,argv,width,height,8,3,4);
281 282
        if(!server)
          return 0;
283

284
	server->frameBuffer=malloc(400*300*4);
285
	server->cursor=NULL;
286 287 288
	for(j=0;j<400*300*4;j++)
		server->frameBuffer[j]=j;
	rfbInitServer(server);
289 290 291
	rfbProcessEvents(server,0);

	initStatistics();
292

293 294 295
#ifndef ALL_AT_ONCE
	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
#else
296 297
	/* Initialize clients */
	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
298
#endif
299
		startClient(i,server);
300

301
	t=time(NULL);
302
	/* test 20 seconds */
303
	while(time(NULL)-t<20) {
304

305
		idle(server);
306

307 308 309 310 311 312 313 314 315 316
		rfbProcessEvents(server,1);
	}
	rfbLog("%d failed, %d received\n",totalFailed,totalCount);
#ifndef ALL_AT_ONCE
	{
		rfbClientPtr cl;
		rfbClientIteratorPtr iter=rfbGetClientIterator(server);
		while((cl=rfbClientIteratorNext(iter)))
			rfbCloseClient(cl);
		rfbReleaseClientIterator(iter);
317
	}
318 319
	}
#endif
320

Christian Beier's avatar
Christian Beier committed
321 322 323
	/* shut down server, disconnecting all clients */
	rfbShutdownServer(server, TRUE);

324 325
	for(i=0;i<thread_counter;i++)
		pthread_join(all_threads[i], NULL);
Christian Beier's avatar
Christian Beier committed
326

327
	free(server->frameBuffer);
Christian Beier's avatar
Christian Beier committed
328
	rfbScreenCleanup(server);
329

330 331 332 333
	rfbLog("Statistics:\n");
	for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
		rfbLog("%s encoding: %d failed, %d received\n",
				testEncodings[i].str,statistics[1][i],statistics[0][i]);
334 335 336
	if(totalFailed)
		return 1;
	return(0);
337
}
338

339