summaryrefslogtreecommitdiffstats
path: root/test/encodingstest.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/encodingstest.c')
-rw-r--r--test/encodingstest.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/test/encodingstest.c b/test/encodingstest.c
new file mode 100644
index 0000000..5c84caf
--- /dev/null
+++ b/test/encodingstest.c
@@ -0,0 +1,345 @@
+#include <time.h>
+#include <stdarg.h>
+#include <rfb/rfb.h>
+#include <rfb/rfbclient.h>
+
+#ifndef LIBVNCSERVER_HAVE_LIBPTHREAD
+#error This test need pthread support (otherwise the client blocks the client)
+#endif
+
+#define ALL_AT_ONCE
+//#define VERY_VERBOSE
+
+MUTEX(frameBufferMutex);
+
+typedef struct { int id; char* str; } encoding_t;
+encoding_t testEncodings[]={
+ { rfbEncodingRaw, "raw" },
+ { rfbEncodingRRE, "rre" },
+ /* TODO: fix corre */
+ /* { rfbEncodingCoRRE, "corre" }, */
+ { rfbEncodingHextile, "hextile" },
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ { rfbEncodingZlib, "zlib" },
+ { rfbEncodingZlibHex, "zlibhex" },
+ /* TODO: implement ZRLE decoding */
+ /* { rfbEncodingZRLE, "zrle" }, */
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ { rfbEncodingTight, "tight" },
+#endif
+#endif
+ { 0, 0 }
+};
+
+#define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
+//#define NUMBER_OF_ENCODINGS_TO_TEST 1
+
+/* Here come the variables/functions to handle the test output */
+
+const int width=400,height=300;
+struct { int x1,y1,x2,y2; } lastUpdateRect;
+unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST];
+unsigned int totalFailed,totalCount;
+unsigned int countGotUpdate;
+MUTEX(statisticsMutex);
+
+void initStatistics() {
+ 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;
+ lastUpdateRect.x1=0;
+ lastUpdateRect.y1=0;
+ lastUpdateRect.x2=width;
+ lastUpdateRect.y2=height;
+ INIT_MUTEX(statisticsMutex);
+}
+
+void updateServerStatistics(int x1,int y1,int x2,int y2) {
+ LOCK(statisticsMutex);
+ countGotUpdate=0;
+ lastUpdateRect.x1=x1;
+ lastUpdateRect.y1=y1;
+ lastUpdateRect.x2=x2;
+ lastUpdateRect.y2=y2;
+ UNLOCK(statisticsMutex);
+}
+
+void updateStatistics(int encodingIndex,rfbBool failed) {
+ LOCK(statisticsMutex);
+ if(failed) {
+ statistics[1][encodingIndex]++;
+ totalFailed++;
+ }
+ statistics[0][encodingIndex]++;
+ totalCount++;
+ 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 */
+rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client,
+ 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++)
+ for(k=0;k<3/*server->serverFormat.bitsPerPixel/8*/;k++) {
+ unsigned char s=server->frameBuffer[k+i*4+j*server->paddedWidthInBytes];
+ unsigned char cl=client->frameBuffer[k+i*4+j*client->width*4];
+
+ 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);
+ cl->frameBuffer=(char*)malloc(cl->width*cl->height*cl->format.bitsPerPixel/8);
+ SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE);
+}
+
+typedef struct clientData {
+ int encodingIndex;
+ rfbScreenInfo* server;
+ char* display;
+} clientData;
+
+static void update(rfbClient* client,int x,int y,int w,int h) {
+ clientData* cd=(clientData*)client->clientData;
+ int maxDelta=0;
+
+#ifndef VERY_VERBOSE
+ static const char* progress="|/-\\";
+ static int counter=0;
+
+ if(++counter>sizeof(progress)) counter=0;
+ fprintf(stderr,"%c\r",progress[counter]);
+#else
+ rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
+ testEncodings[cd->encodingIndex].str,
+ x,y,x+w,y+h);
+#endif
+
+ /* only check if this was the last update */
+ if(x+w!=lastUpdateRect.x2 || y+h!=lastUpdateRect.y2) {
+#ifdef VERY_VERBOSE
+ rfbClientLog("Waiting (%d!=%d or %d!=%d)\n",
+ x+w,lastUpdateRect.x2,y+h,lastUpdateRect.y2);
+#endif
+ return;
+ }
+
+ if(testEncodings[cd->encodingIndex].id==rfbEncodingTight)
+ maxDelta=5;
+
+ updateStatistics(cd->encodingIndex,
+ !doFramebuffersMatch(cd->server,client,maxDelta));
+}
+
+static void* clientLoop(void* data) {
+ rfbClient* client=(rfbClient*)data;
+ clientData* cd=(clientData*)client->clientData;
+ int argc=4;
+ char* argv[4]={"client",
+ "-encodings", testEncodings[cd->encodingIndex].str,
+ cd->display};
+
+
+ sleep(1);
+ rfbClientLog("Starting client (encoding %s, display %s)\n",
+ testEncodings[cd->encodingIndex].str,
+ cd->display);
+ if(!rfbInitClient(client,&argc,argv)) {
+ rfbClientErr("Had problems starting client (encoding %s)\n",
+ testEncodings[cd->encodingIndex].str);
+ updateStatistics(cd->encodingIndex,TRUE);
+ return 0;
+ }
+ while(1) {
+ if(WaitForMessage(client,50)>=0)
+ if(!HandleRFBServerMessage(client))
+ break;
+ }
+ free(((clientData*)client->clientData)->display);
+ free(client->clientData);
+ if(client->frameBuffer)
+ free(client->frameBuffer);
+ rfbClientCleanup(client);
+ return 0;
+}
+
+static void startClient(int encodingIndex,rfbScreenInfo* server) {
+ rfbClient* client=rfbGetClient(8,3,4);
+ clientData* cd;
+ pthread_t clientThread;
+
+ client->clientData=malloc(sizeof(clientData));
+ client->MallocFrameBuffer=resize;
+ client->GotFrameBufferUpdate=update;
+
+ cd=(clientData*)client->clientData;
+ cd->encodingIndex=encodingIndex;
+ cd->server=server;
+ cd->display=(char*)malloc(6);
+ sprintf(cd->display,":%d",server->port-5900);
+
+ lastUpdateRect.x1=lastUpdateRect.y1=0;
+ lastUpdateRect.x2=server->width;
+ lastUpdateRect.y2=server->height;
+
+ pthread_create(&clientThread,NULL,clientLoop,(void*)client);
+}
+
+/* Here begin the server functions */
+
+static void idle(rfbScreenInfo* server)
+{
+ int c;
+ rfbBool goForward;
+
+ LOCK(statisticsMutex);
+#ifdef ALL_AT_ONCE
+ goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
+#else
+ goForward=(countGotUpdate==1);
+#endif
+ /* if(lastUpdateRect.x2==354)
+ rfbLog("server checked: countGotUpdate=%d\n",countGotUpdate); */
+ UNLOCK(statisticsMutex);
+ if(!goForward)
+ return;
+ countGotUpdate=0;
+
+ LOCK(frameBufferMutex);
+ {
+ int i,j;
+ int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
+ y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
+ if(x1>x2) { i=x1; x1=x2; x2=i; }
+ if(y1>y2) { i=y1; y1=y2; y2=i; }
+ 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);
+
+ lastUpdateRect.x1=x1;
+ lastUpdateRect.y1=y1;
+ lastUpdateRect.x2=x2;
+ lastUpdateRect.y2=y2;
+#ifdef VERY_VERBOSE
+ rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
+#endif
+ }
+ UNLOCK(frameBufferMutex);
+}
+
+/* log function (to show what messages are from the client) */
+
+void
+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));
+ fprintf(stderr,buf);
+
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+
+ va_end(args);
+}
+
+/* the main function */
+
+int main(int argc,char** argv)
+{
+ int i,j;
+ time_t t;
+
+ rfbClientLog=rfbTestLog;
+ rfbClientErr=rfbTestLog;
+
+ /* Initialize server */
+ rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,width,height,8,3,4);
+
+ server->frameBuffer=malloc(400*300*4);
+ for(j=0;j<400*300*4;j++)
+ server->frameBuffer[j]=j;
+ rfbInitServer(server);
+ rfbProcessEvents(server,0);
+
+ initStatistics();
+
+#ifndef ALL_AT_ONCE
+ for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
+#else
+ /* Initialize clients */
+ for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
+#endif
+ startClient(i,server);
+
+ t=time(0);
+ /* test 20 seconds */
+ while(time(0)-t<5) {
+
+ idle(server);
+
+ 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);
+ }
+ }
+#endif
+
+ free(server->frameBuffer);
+ rfbScreenCleanup(server);
+
+ 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]);
+ if(totalFailed)
+ return 1;
+ return(0);
+}
+
+