[4] | 1 | /***************************************************************************************** |
---|
| 2 | * VNCViewer for SAGE |
---|
| 3 | * Copyright (C) 2004 Electronic Visualization Laboratory, |
---|
| 4 | * University of Illinois at Chicago |
---|
| 5 | * |
---|
| 6 | * All rights reserved. |
---|
| 7 | * |
---|
| 8 | * Redistribution and use in source and binary forms, with or without |
---|
| 9 | * modification, are permitted provided that the following conditions are met: |
---|
| 10 | * |
---|
| 11 | * * Redistributions of source code must retain the above copyright |
---|
| 12 | * notice, this list of conditions and the following disclaimer. |
---|
| 13 | * * Redistributions in binary form must reproduce the above |
---|
| 14 | * copyright notice, this list of conditions and the following disclaimer |
---|
| 15 | * in the documentation and/or other materials provided with the distribution. |
---|
| 16 | * * Neither the name of the University of Illinois at Chicago nor |
---|
| 17 | * the names of its contributors may be used to endorse or promote |
---|
| 18 | * products derived from this software without specific prior written permission. |
---|
| 19 | * |
---|
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
| 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
---|
| 24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
---|
| 25 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
| 26 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
| 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
| 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
| 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
| 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
| 31 | * |
---|
| 32 | * Direct questions, comments etc about VNCViewer for SAGE to www.evl.uic.edu/cavern/forum |
---|
| 33 | *****************************************************************************************/ |
---|
| 34 | |
---|
| 35 | #if defined(USE_LIBVNC) |
---|
| 36 | #include <rfb/rfbclient.h> |
---|
| 37 | #else |
---|
| 38 | #include "sgVNCViewer.h" |
---|
| 39 | #include <sys/fcntl.h> |
---|
| 40 | #endif |
---|
| 41 | |
---|
| 42 | // headers for SAGE |
---|
| 43 | #include "sail.h" |
---|
| 44 | #include "misc.h" |
---|
| 45 | #include <time.h> |
---|
| 46 | #include <unistd.h> |
---|
| 47 | |
---|
| 48 | // Global variables |
---|
| 49 | char *passwd, *server; |
---|
| 50 | |
---|
| 51 | |
---|
| 52 | // Configuration for SAGE, example: |
---|
| 53 | // nodeNum 1 |
---|
| 54 | // Init 200 200 1480 1224 |
---|
| 55 | // exec 10.0.8.120 VNCViewer 1 |
---|
| 56 | // nwProtocol tvTcpModule.so |
---|
| 57 | |
---|
| 58 | #if defined(WIN32) |
---|
| 59 | LARGE_INTEGER perf_freq; |
---|
| 60 | LARGE_INTEGER perf_start; |
---|
| 61 | #elif defined(__APPLE__) |
---|
| 62 | #include <mach/mach_time.h> |
---|
| 63 | static double perf_conversion = 0.0; |
---|
| 64 | static uint64_t perf_start; |
---|
| 65 | #else |
---|
| 66 | struct timeval tv_start; |
---|
| 67 | #endif |
---|
| 68 | |
---|
| 69 | void aInitialize() |
---|
| 70 | { |
---|
| 71 | #if defined(WIN32) |
---|
| 72 | QueryPerformanceCounter(&perf_start); |
---|
| 73 | QueryPerformanceFrequency(&perf_freq); |
---|
| 74 | #elif defined(__APPLE__) |
---|
| 75 | if( perf_conversion == 0.0 ) |
---|
| 76 | { |
---|
| 77 | mach_timebase_info_data_t info; |
---|
| 78 | kern_return_t err = mach_timebase_info( &info ); |
---|
| 79 | |
---|
| 80 | //Convert the timebase into seconds |
---|
| 81 | if( err == 0 ) |
---|
| 82 | perf_conversion = 1e-9 * (double) info.numer / (double) info.denom; |
---|
| 83 | } |
---|
| 84 | // Start of time |
---|
| 85 | perf_start = mach_absolute_time(); |
---|
| 86 | |
---|
| 87 | // Initialize the random generator |
---|
| 88 | srand(getpid()); |
---|
| 89 | #else |
---|
| 90 | // Start of time |
---|
| 91 | gettimeofday(&tv_start,0); |
---|
| 92 | // Initialize the random generator |
---|
| 93 | srand(getpid()); |
---|
| 94 | #endif |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | double aTime() |
---|
| 98 | // return time since start of process in seconds |
---|
| 99 | { |
---|
| 100 | #if defined(WIN32) |
---|
| 101 | LARGE_INTEGER perf_counter; |
---|
| 102 | #else |
---|
| 103 | struct timeval tv; |
---|
| 104 | #endif |
---|
| 105 | |
---|
| 106 | #if defined(WIN32) |
---|
| 107 | // Windows: get performance counter and subtract starting mark |
---|
| 108 | QueryPerformanceCounter(&perf_counter); |
---|
| 109 | return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart; |
---|
| 110 | #elif defined(__APPLE__) |
---|
| 111 | uint64_t difference = mach_absolute_time(); - perf_start; |
---|
| 112 | return perf_conversion * (double) difference; |
---|
| 113 | #else |
---|
| 114 | // UNIX: gettimeofday |
---|
| 115 | gettimeofday(&tv,0); |
---|
| 116 | return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0; |
---|
| 117 | #endif |
---|
| 118 | } |
---|
| 119 | |
---|
| 120 | // Comment/uncomment to use 24bit or 32bit SAGE application stream |
---|
| 121 | #define VNC_SAGE_USE_24bit 1 |
---|
| 122 | |
---|
| 123 | #if defined(USE_LIBVNC) |
---|
| 124 | rfbClient* vnc; |
---|
| 125 | #else |
---|
| 126 | sgVNCViewer* vnc; |
---|
| 127 | #endif |
---|
| 128 | |
---|
| 129 | #if defined(USE_LIBVNC) |
---|
| 130 | |
---|
| 131 | static rfbBool got_data = FALSE; |
---|
| 132 | static void signal_handler(int signal) |
---|
| 133 | { |
---|
| 134 | rfbClientLog("Cleaning up.\n"); |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | static rfbBool resize_func(rfbClient* client) |
---|
| 138 | { |
---|
| 139 | static rfbBool first=TRUE; |
---|
| 140 | if(!first) { |
---|
| 141 | rfbClientLog("I don't know yet how to change resolutions!\n"); |
---|
| 142 | exit(1); |
---|
| 143 | } |
---|
| 144 | signal(SIGINT,signal_handler); |
---|
| 145 | |
---|
| 146 | int width=client->width; |
---|
| 147 | int height=client->height; |
---|
| 148 | int depth=client->format.bitsPerPixel; |
---|
| 149 | client->updateRect.x = client->updateRect.y = 0; |
---|
| 150 | client->updateRect.w = width; client->updateRect.h = height; |
---|
| 151 | |
---|
| 152 | client->frameBuffer = (uint8_t*)malloc(width*height*depth); |
---|
| 153 | memset(client->frameBuffer, 0, width*height*depth); |
---|
| 154 | |
---|
| 155 | rfbClientLog("Allocate %d bytes: %d x %d x %d\n", width*height*depth, width,height,depth); |
---|
| 156 | return TRUE; |
---|
| 157 | } |
---|
| 158 | |
---|
| 159 | static void frame_func(rfbClient* client) |
---|
| 160 | { |
---|
| 161 | rfbClientLog("Received a frame\n"); |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | static rfbBool position_func(rfbClient* client, int x, int y) |
---|
| 165 | { |
---|
| 166 | //rfbClientLog("Received a position for %d,%d\n",x,y); |
---|
| 167 | return TRUE; |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | static char *password_func(rfbClient* client) |
---|
| 171 | { |
---|
| 172 | char *str = (char*)malloc(64); |
---|
| 173 | memset(str, 0, 64); |
---|
| 174 | strncpy(str, passwd, 64); |
---|
| 175 | return str; |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | static void update_func(rfbClient* client,int x,int y,int w,int h) |
---|
| 179 | { |
---|
| 180 | rfbPixelFormat* pf=&client->format; |
---|
| 181 | int bpp=pf->bitsPerPixel/8; |
---|
| 182 | int row_stride=client->width*bpp; |
---|
| 183 | |
---|
| 184 | got_data = TRUE; |
---|
| 185 | |
---|
| 186 | //rfbClientLog("Received an update for %d,%d,%d,%d.\n",x,y,w,h); |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | |
---|
| 190 | #endif |
---|
| 191 | |
---|
| 192 | int |
---|
| 193 | main(int argc, char **argv) |
---|
| 194 | { |
---|
| 195 | int winWidth, winHeight, display; |
---|
| 196 | sail sageInf; // sail object |
---|
| 197 | double rate = 10; //by default stream at 1fps |
---|
| 198 | |
---|
| 199 | aInitialize(); |
---|
| 200 | |
---|
| 201 | if (argc < 6) |
---|
| 202 | { |
---|
| 203 | fprintf(stderr, "\nUsage> VNCviewer <hostname> <display#> <width> <height> <password> [fps]\n\n"); |
---|
| 204 | exit(0); |
---|
| 205 | } |
---|
| 206 | |
---|
| 207 | // VNC Init |
---|
| 208 | server = strdup(argv[1]); |
---|
| 209 | display = atoi(argv[2]); |
---|
| 210 | winWidth = atoi(argv[3]); |
---|
| 211 | winHeight = atoi(argv[4]); |
---|
| 212 | passwd = argv[5]; |
---|
| 213 | if (argc > 6) |
---|
| 214 | rate = atoi(argv[6]); |
---|
| 215 | |
---|
| 216 | |
---|
| 217 | #if defined(USE_LIBVNC) |
---|
| 218 | // get a vnc client structure (don't connect yet). |
---|
| 219 | // bits, channels, bytes |
---|
| 220 | vnc = rfbGetClient(8,3,4); |
---|
| 221 | vnc->canHandleNewFBSize = FALSE; |
---|
| 222 | // to get position update callbacks |
---|
| 223 | vnc->appData.useRemoteCursor=TRUE; |
---|
| 224 | //vnc->appData.compressLevel=3; |
---|
| 225 | //vnc->appData.qualityLevel=5; |
---|
| 226 | |
---|
| 227 | /* open VNC connection */ |
---|
| 228 | vnc->MallocFrameBuffer=resize_func; |
---|
| 229 | vnc->GotFrameBufferUpdate=update_func; |
---|
| 230 | vnc->HandleCursorPos=position_func; |
---|
| 231 | vnc->GetPassword=password_func; |
---|
| 232 | //client->FinishedFrameBufferUpdate=frame_func; |
---|
| 233 | |
---|
| 234 | |
---|
| 235 | int margc = 2; |
---|
| 236 | char *margv[2]; |
---|
| 237 | margv[0] = strdup("vnc"); |
---|
| 238 | margv[1] = (char*)malloc(256); |
---|
| 239 | memset(margv[1], 0, 256); |
---|
| 240 | sprintf(margv[1], "%s:%d", server, display); |
---|
| 241 | if(!rfbInitClient(vnc,&margc,margv)) { |
---|
| 242 | printf("usage: %s server:port password\n" |
---|
| 243 | "VNC client.\n", argv[0]); |
---|
| 244 | exit(1); |
---|
| 245 | } |
---|
| 246 | if (vnc->serverPort==-1) |
---|
| 247 | vnc->vncRec->doNotSleep = TRUE; /* vncrec playback */ |
---|
| 248 | |
---|
| 249 | winWidth = vnc->width; |
---|
| 250 | winHeight = vnc->height; |
---|
| 251 | |
---|
| 252 | #else |
---|
| 253 | |
---|
| 254 | // Connection to VNC server: |
---|
| 255 | // host, display number, x offset, y offset, width, height, passwd |
---|
| 256 | // passwd is by default 'evl123' but a different one can be specified so that one will be used |
---|
| 257 | vnc = new sgVNCViewer(server, display, 0,0,winWidth,winHeight, passwd); |
---|
| 258 | #endif |
---|
| 259 | |
---|
| 260 | // Sage Init |
---|
| 261 | sailConfig scfg; |
---|
| 262 | scfg.init("VNCViewer.conf"); |
---|
| 263 | scfg.setAppName("VNCViewer"); |
---|
| 264 | scfg.rank = 0; |
---|
| 265 | |
---|
| 266 | scfg.resX = winWidth; |
---|
| 267 | scfg.resY = winHeight; |
---|
| 268 | |
---|
| 269 | sageRect renderImageMap; |
---|
| 270 | renderImageMap.left = 0.0; |
---|
| 271 | renderImageMap.right = 1.0; |
---|
| 272 | renderImageMap.bottom = 0.0; |
---|
| 273 | renderImageMap.top = 1.0; |
---|
| 274 | |
---|
| 275 | scfg.imageMap = renderImageMap; |
---|
| 276 | #if defined(VNC_SAGE_USE_24bit) |
---|
| 277 | scfg.pixFmt = PIXFMT_888; |
---|
| 278 | #else |
---|
| 279 | scfg.pixFmt = PIXFMT_8888; |
---|
| 280 | #endif |
---|
| 281 | scfg.rowOrd = TOP_TO_BOTTOM; |
---|
| 282 | scfg.master = true; |
---|
| 283 | |
---|
| 284 | sageInf.init(scfg); |
---|
| 285 | |
---|
| 286 | |
---|
| 287 | // data pointer |
---|
| 288 | unsigned char *buffer = 0; |
---|
| 289 | unsigned char *vncpixels; |
---|
| 290 | |
---|
| 291 | double t1, t2; |
---|
| 292 | t1 = aTime(); |
---|
| 293 | |
---|
| 294 | // Main lopp |
---|
| 295 | while (1) |
---|
| 296 | { |
---|
| 297 | #if defined(USE_LIBVNC) |
---|
| 298 | double now = sage::getTime(); |
---|
| 299 | while ( (sage::getTime() - now) < (1000000/rate)) { |
---|
| 300 | int i=WaitForMessage(vnc,100000); |
---|
| 301 | if(i<0) { |
---|
| 302 | rfbClientLog("VNC error, quit\n"); |
---|
| 303 | sageInf.shutdown(); |
---|
| 304 | exit(0); |
---|
| 305 | } |
---|
| 306 | if(i) { |
---|
| 307 | if(!HandleRFBServerMessage(vnc)) { |
---|
| 308 | rfbClientLog("HandleRFBServerMessage quit\n"); |
---|
| 309 | sageInf.shutdown(); |
---|
| 310 | exit(0); |
---|
| 311 | } |
---|
| 312 | } |
---|
| 313 | } |
---|
| 314 | |
---|
| 315 | // Copy VNC buffer into SAGE buffer |
---|
| 316 | buffer = (unsigned char *) sageInf.getBuffer(); |
---|
| 317 | vncpixels = (unsigned char *) vnc->frameBuffer; |
---|
| 318 | |
---|
| 319 | for (int k =0 ; k<winWidth*winHeight; k++) { |
---|
| 320 | buffer[3*k + 0] = vncpixels[ 4*k + 0]; |
---|
| 321 | buffer[3*k + 1] = vncpixels[ 4*k + 1]; |
---|
| 322 | buffer[3*k + 2] = vncpixels[ 4*k + 2]; |
---|
| 323 | } |
---|
| 324 | |
---|
| 325 | |
---|
| 326 | // SAGE Swap |
---|
| 327 | sageInf.swapBuffer( ); |
---|
| 328 | |
---|
| 329 | // Process SAGE messages |
---|
| 330 | sageMessage msg; |
---|
| 331 | if (sageInf.checkMsg(msg, false) > 0) { |
---|
| 332 | switch (msg.getCode()) { |
---|
| 333 | case APP_QUIT: |
---|
| 334 | sageInf.shutdown(); |
---|
| 335 | exit(0); |
---|
| 336 | break; |
---|
| 337 | } |
---|
| 338 | } |
---|
| 339 | #else |
---|
| 340 | |
---|
| 341 | if (!vnc->Step()) |
---|
| 342 | { |
---|
| 343 | sageInf.shutdown(); |
---|
| 344 | exit(0); |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | // if it's been (roughly) xxx second since the last |
---|
| 348 | // sent frame, send another one |
---|
| 349 | t2 = aTime(); |
---|
| 350 | if ( (t2-t1) > (1.0/rate) ) |
---|
| 351 | { |
---|
| 352 | |
---|
| 353 | //fprintf(stderr, "Rate: %.2f\n", 1.0/(t2-t1) ); |
---|
| 354 | buffer = (unsigned char *) sageInf.getBuffer(); |
---|
| 355 | vncpixels = (unsigned char *) vnc->Data(); |
---|
| 356 | #if defined(VNC_SAGE_USE_24bit) |
---|
| 357 | for (int k =0 ; k<winWidth*winHeight; k++) { |
---|
| 358 | buffer[3*k + 0] = vncpixels[ 4*k + 0]; |
---|
| 359 | buffer[3*k + 1] = vncpixels[ 4*k + 1]; |
---|
| 360 | buffer[3*k + 2] = vncpixels[ 4*k + 2]; |
---|
| 361 | } |
---|
| 362 | #else |
---|
| 363 | memcpy(buffer, (unsigned char *) vnc->Data(), winWidth*winHeight*4); |
---|
| 364 | #endif |
---|
| 365 | sageInf.swapBuffer( ); |
---|
| 366 | t1 = aTime(); |
---|
| 367 | } |
---|
| 368 | |
---|
| 369 | sageMessage msg; |
---|
| 370 | if (sageInf.checkMsg(msg, false) > 0) { |
---|
| 371 | switch (msg.getCode()) { |
---|
| 372 | case APP_QUIT: |
---|
| 373 | exit(0); |
---|
| 374 | break; |
---|
| 375 | } |
---|
| 376 | } |
---|
| 377 | #endif |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | return 1; |
---|
| 381 | } |
---|
| 382 | |
---|
| 383 | |
---|