encodingstest.c revision a430b2b5ca4f0967836f5820e8f03adc17fc0a24
1#ifdef __STRICT_ANSI__ 2#define _BSD_SOURCE 3#endif 4#include <time.h> 5#include <stdarg.h> 6#include <rfb/rfb.h> 7#include <rfb/rfbclient.h> 8 9#ifndef LIBVNCSERVER_HAVE_LIBPTHREAD 10#error This test need pthread support (otherwise the client blocks the client) 11#endif 12 13#define ALL_AT_ONCE 14/*#define VERY_VERBOSE*/ 15 16static MUTEX(frameBufferMutex); 17 18typedef struct { int id; char* str; } encoding_t; 19static encoding_t testEncodings[]={ 20 { rfbEncodingRaw, "raw" }, 21 { rfbEncodingRRE, "rre" }, 22 { rfbEncodingCoRRE, "corre" }, 23 { rfbEncodingHextile, "hextile" }, 24 { rfbEncodingUltra, "ultra" }, 25#ifdef LIBVNCSERVER_HAVE_LIBZ 26 { rfbEncodingZlib, "zlib" }, 27 { rfbEncodingZlibHex, "zlibhex" }, 28 { rfbEncodingZRLE, "zrle" }, 29 { rfbEncodingZYWRLE, "zywrle" }, 30#ifdef LIBVNCSERVER_HAVE_LIBJPEG 31 { rfbEncodingTight, "tight" }, 32#endif 33#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/* Here come the variables/functions to handle the test output */ 41 42static const int width=400,height=300; 43static unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST]; 44static unsigned int totalFailed,totalCount; 45static unsigned int countGotUpdate; 46static MUTEX(statisticsMutex); 47 48static void initStatistics(void) { 49 memset(statistics[0],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST); 50 memset(statistics[1],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST); 51 totalFailed=totalCount=0; 52 INIT_MUTEX(statisticsMutex); 53} 54 55 56static void updateStatistics(int encodingIndex,rfbBool failed) { 57 LOCK(statisticsMutex); 58 if(failed) { 59 statistics[1][encodingIndex]++; 60 totalFailed++; 61 } 62 statistics[0][encodingIndex]++; 63 totalCount++; 64 countGotUpdate++; 65 UNLOCK(statisticsMutex); 66} 67 68/* Here begin the functions for the client. They will be called in a 69 * pthread. */ 70 71/* maxDelta=0 means they are expected to match exactly; 72 * maxDelta>0 means that the average difference must be lower than maxDelta */ 73static rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client, 74 int maxDelta) 75{ 76 int i,j,k; 77 unsigned int total=0,diff=0; 78 if(server->width!=client->width || server->height!=client->height) 79 return FALSE; 80 LOCK(frameBufferMutex); 81 /* TODO: write unit test for colour transformation, use here, too */ 82 for(i=0;i<server->width;i++) 83 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 if(maxDelta==0 && s!=cl) { 89 UNLOCK(frameBufferMutex); 90 return FALSE; 91 } else { 92 total++; 93 diff+=(s>cl?s-cl:cl-s); 94 } 95 } 96 UNLOCK(frameBufferMutex); 97 if(maxDelta>0 && diff/total>=maxDelta) 98 return FALSE; 99 return TRUE; 100} 101 102static rfbBool resize(rfbClient* cl) { 103 if(cl->frameBuffer) 104 free(cl->frameBuffer); 105 cl->frameBuffer=malloc(cl->width*cl->height*cl->format.bitsPerPixel/8); 106 if(!cl->frameBuffer) 107 return FALSE; 108 SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE); 109 return TRUE; 110} 111 112typedef struct clientData { 113 int encodingIndex; 114 rfbScreenInfo* server; 115 char* display; 116} clientData; 117 118static void update(rfbClient* client,int x,int y,int w,int h) { 119#ifndef VERY_VERBOSE 120 121 static const char* progress="|/-\\"; 122 static int counter=0; 123 124 if(++counter>sizeof(progress)) counter=0; 125 fprintf(stderr,"%c\r",progress[counter]); 126#else 127 clientData* cd=(clientData*)client->clientData; 128 rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n", 129 testEncodings[cd->encodingIndex].str, 130 x,y,x+w,y+h); 131#endif 132} 133 134static void update_finished(rfbClient* client) { 135 clientData* cd=(clientData*)client->clientData; 136 int maxDelta=0; 137 138#ifdef LIBVNCSERVER_HAVE_LIBZ 139 if(testEncodings[cd->encodingIndex].id==rfbEncodingZYWRLE) 140 maxDelta=5; 141#ifdef LIBVNCSERVER_HAVE_LIBJPEG 142 if(testEncodings[cd->encodingIndex].id==rfbEncodingTight) 143 maxDelta=5; 144#endif 145#endif 146 updateStatistics(cd->encodingIndex, 147 !doFramebuffersMatch(cd->server,client,maxDelta)); 148} 149 150 151static void* clientLoop(void* data) { 152 rfbClient* client=(rfbClient*)data; 153 clientData* cd=(clientData*)client->clientData; 154 155 client->appData.encodingsString=strdup(testEncodings[cd->encodingIndex].str); 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 testEncodings[cd->encodingIndex].str, 161 cd->display); 162 if(!rfbInitClient(client,NULL,NULL)) { 163 rfbClientErr("Had problems starting client (encoding %s)\n", 164 testEncodings[cd->encodingIndex].str); 165 updateStatistics(cd->encodingIndex,TRUE); 166 return NULL; 167 } 168 while(1) { 169 if(WaitForMessage(client,50)>=0) 170 if(!HandleRFBServerMessage(client)) 171 break; 172 } 173 free(((clientData*)client->clientData)->display); 174 free(client->clientData); 175 if(client->frameBuffer) 176 free(client->frameBuffer); 177 rfbClientCleanup(client); 178 return NULL; 179} 180 181static pthread_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST]; 182static int thread_counter; 183 184static void startClient(int encodingIndex,rfbScreenInfo* server) { 185 rfbClient* client=rfbGetClient(8,3,4); 186 clientData* cd; 187 188 client->clientData=malloc(sizeof(clientData)); 189 client->MallocFrameBuffer=resize; 190 client->GotFrameBufferUpdate=update; 191 client->FinishedFrameBufferUpdate=update_finished; 192 193 cd=(clientData*)client->clientData; 194 cd->encodingIndex=encodingIndex; 195 cd->server=server; 196 cd->display=(char*)malloc(6); 197 sprintf(cd->display,":%d",server->port-5900); 198 199 pthread_create(&all_threads[thread_counter++],NULL,clientLoop,(void*)client); 200} 201 202/* Here begin the server functions */ 203 204static void idle(rfbScreenInfo* server) 205{ 206 int c; 207 rfbBool goForward; 208 209 LOCK(statisticsMutex); 210#ifdef ALL_AT_ONCE 211 goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST); 212#else 213 goForward=(countGotUpdate==1); 214#endif 215 216 UNLOCK(statisticsMutex); 217 if(!goForward) 218 return; 219 countGotUpdate=0; 220 221 LOCK(frameBufferMutex); 222 { 223 int i,j; 224 int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)), 225 y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1)); 226 if(x1>x2) { i=x1; x1=x2; x2=i; } 227 if(y1>y2) { i=y1; y1=y2; y2=i; } 228 x2++; y2++; 229 for(c=0;c<3;c++) { 230 for(i=x1;i<x2;i++) 231 for(j=y1;j<y2;j++) 232 server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1); 233 } 234 rfbMarkRectAsModified(server,x1,y1,x2,y2); 235 236#ifdef VERY_VERBOSE 237 rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2); 238#endif 239 } 240 UNLOCK(frameBufferMutex); 241} 242 243/* log function (to show what messages are from the client) */ 244 245static void 246rfbTestLog(const char *format, ...) 247{ 248 va_list args; 249 char buf[256]; 250 time_t log_clock; 251 252 if(!rfbEnableClientLogging) 253 return; 254 255 va_start(args, format); 256 257 time(&log_clock); 258 strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock)); 259 fprintf(stderr,buf); 260 261 vfprintf(stderr, format, args); 262 fflush(stderr); 263 264 va_end(args); 265} 266 267/* the main function */ 268 269int main(int argc,char** argv) 270{ 271 int i,j; 272 time_t t; 273 rfbScreenInfoPtr server; 274 275 rfbClientLog=rfbTestLog; 276 rfbClientErr=rfbTestLog; 277 278 /* Initialize server */ 279 server=rfbGetScreen(&argc,argv,width,height,8,3,4); 280 if(!server) 281 return 0; 282 283 server->frameBuffer=malloc(400*300*4); 284 server->cursor=NULL; 285 for(j=0;j<400*300*4;j++) 286 server->frameBuffer[j]=j; 287 rfbInitServer(server); 288 rfbProcessEvents(server,0); 289 290 initStatistics(); 291 292#ifndef ALL_AT_ONCE 293 for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) { 294#else 295 /* Initialize clients */ 296 for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) 297#endif 298 startClient(i,server); 299 300 t=time(NULL); 301 /* test 20 seconds */ 302 while(time(NULL)-t<20) { 303 304 idle(server); 305 306 rfbProcessEvents(server,1); 307 } 308 rfbLog("%d failed, %d received\n",totalFailed,totalCount); 309#ifndef ALL_AT_ONCE 310 { 311 rfbClientPtr cl; 312 rfbClientIteratorPtr iter=rfbGetClientIterator(server); 313 while((cl=rfbClientIteratorNext(iter))) 314 rfbCloseClient(cl); 315 rfbReleaseClientIterator(iter); 316 } 317 } 318#endif 319 320 /* shut down server, disconnecting all clients */ 321 rfbShutdownServer(server, TRUE); 322 323 for(i=0;i<thread_counter;i++) 324 pthread_join(all_threads[i], NULL); 325 326 free(server->frameBuffer); 327 rfbScreenCleanup(server); 328 329 rfbLog("Statistics:\n"); 330 for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) 331 rfbLog("%s encoding: %d failed, %d received\n", 332 testEncodings[i].str,statistics[1][i],statistics[0][i]); 333 if(totalFailed) 334 return 1; 335 return(0); 336} 337 338 339