Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

VideoStream.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 *      $RCSfile: OptiXDisplayDevice.h
00013 *      $Author: johns $      $Locker:  $               $State: Exp $
00014 *      $Revision: 1.37 $         $Date: 2020/05/22 03:44:30 $
00015 *
00016 ***************************************************************************
00017 * DESCRIPTION:
00018 *   VMD interface for video streaming
00019 *
00020 ***************************************************************************/
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <errno.h>
00026 
00027 #include "WKFUtils.h"
00028 #include "Inform.h"
00029 #include "VideoStream.h"
00030 #include "vmdsock.h"
00031 #include "VMDApp.h"
00032 #include "DisplayDevice.h"
00033 #include "TextEvent.h"      // event handling callbacks for keypresses
00034 
00035 
00036 // XXX enable simulated codec
00037 #if !defined(VMDNVPIPE)
00038 #define VIDEOSTREAM_SIMENCODER 1
00039 #endif
00040 
00041 #if defined(VIDEOSTREAM_SIMENCODER)
00042 typedef struct {
00043   int width;        
00044   int height;            
00045 } simenc_handle;
00046 
00047 
00048 static void * simenc_initialize(int width, int height, int Mbps, int tfps) {
00049   simenc_handle *sep = (simenc_handle *) calloc(sizeof(simenc_handle), 1);
00050   sep->width = width;
00051   sep->height = height;
00052   return sep;
00053 }
00054 
00055 
00056 static void simenc_destroy(void *voidhandle) {
00057   free(voidhandle);
00058 }
00059 
00060 
00061 static int simenc_reconfig(void *voidhandle, int width, int height, 
00062                            int bitrateMbps, int targetfps) {
00063   simenc_handle *sep = (simenc_handle *) calloc(sizeof(simenc_handle), 1);
00064   sep->width = width;
00065   sep->height = height;
00066   return 0;
00067 }
00068 
00069 
00070 static unsigned long simenc_encode_frame(void *voidhandle, 
00071                                          const unsigned char *rgba,
00072                                          int pitch, int width, int height, 
00073                                          unsigned char * & compbuf, 
00074                                          long compbufsz, bool forceIframe) {
00075   long sz = pitch * height;
00076   if (sz > compbufsz)
00077     return 0;
00078 
00079   memcpy(compbuf, rgba, sz); // no-op passthrough compression  
00080   return sz;
00081 }
00082 
00083 
00084 static unsigned long simenc_decode_frame(void *voidhandle, 
00085                                          unsigned char *compbuf,
00086                                          long compbufsz, unsigned char *rgba,
00087                                          int width, int height) {
00088   long sz = 4 * width * height;
00089   if (sz > compbufsz) {
00090     printf("\nsimenc: sz: %ld  compbufsz: %ld\n", sz, compbufsz);
00091     return 0;
00092   }
00093  
00094   memcpy(rgba, compbuf, sz); // no-op passthrough decompression  
00095   return sz;
00096 }
00097 
00098 
00099 #endif
00100 
00101 
00102 //
00103 // Support for NvPipe+NVEnc hardware video encoding 
00104 //
00105 #if defined(VMDNVPIPE)
00106 #include <NvPipe.h>
00107 #include <cuda_runtime_api.h>
00108 
00109 typedef struct {
00110   NvPipe_Format format;           // BGRA or RGBA format
00111   NvPipe_Codec codec;             // NVPIPE_H264 or NVPIPE_HEVC (*)new GPUs  
00112   NvPipe_Compression compression; // NVPIPE_LOSSY or NVPIPE_LOSSLESS
00113   float bitrateMbps;              // 5-20 MBps is reasonable
00114   uint32_t targetFPS;             // 20 FPS is decent
00115   uint32_t width;        
00116   uint32_t height;            
00117   NvPipe *encoder;
00118   NvPipe *decoder;
00119 } nvpipe_handle;
00120 
00121 
00122 static void * nvpipe_initialize(int width, int height, int Mbps, int tfps) {
00123   nvpipe_handle *nvp = (nvpipe_handle *) calloc(sizeof(nvpipe_handle), 1);
00124 
00125   // XXX NvPipe_Format enumeration is different across platforms, 
00126   //     even in the case that byte ordering is the same
00127 #if defined(ARCH_SUMMIT) || defined(ARCH_OPENPOWER)
00128   nvp->format = NVPIPE_RGBA32; // XXX why do ppc64le and x86 differ?!?!?!?
00129 #else
00130   nvp->format = NVPIPE_BGRA32; // XXX why do ppc64le and x86 differ?!?!?!?
00131 #endif
00132 
00133   nvp->codec = NVPIPE_H264;
00134   nvp->compression = NVPIPE_LOSSY;
00135   nvp->bitrateMbps = Mbps;
00136   nvp->targetFPS = tfps;
00137   nvp->width = width;
00138   nvp->height = height;
00139 
00140   nvp->encoder = NvPipe_CreateEncoder(nvp->format, nvp->codec, 
00141                                       nvp->compression,
00142                                       nvp->bitrateMbps * 1000 * 1000, 
00143                                       nvp->targetFPS);
00144 
00145   nvp->decoder = NvPipe_CreateDecoder(nvp->format, nvp->codec);
00146 
00147   if (nvp->encoder != NULL && nvp->decoder != NULL) {
00148     return nvp;
00149   }
00150 
00151   // if either encoder or decoder don't init, we have to bail entirely
00152   if (nvp->encoder != NULL)
00153     NvPipe_Destroy(nvp->encoder);
00154   if (nvp->decoder != NULL)
00155     NvPipe_Destroy(nvp->decoder);
00156 
00157   return NULL;
00158 }
00159 
00160 
00161 static void nvpipe_destroy(void *voidhandle) {
00162   nvpipe_handle *nvp = (nvpipe_handle *) voidhandle;
00163   if (nvp->encoder != NULL) {
00164     NvPipe_Destroy(nvp->encoder);
00165   }
00166   if (nvp->decoder != NULL) {
00167     NvPipe_Destroy(nvp->decoder);
00168   }
00169   free(nvp);
00170 }
00171 
00172 
00173 static int nvpipe_reconfig(void *voidhandle, int width, int height, 
00174                            int bitrateMbps, int targetfps) {
00175   nvpipe_handle *nvp = (nvpipe_handle *) voidhandle;
00176 
00177   if (width <= 0 || height <= 0) {
00178     printf("nvpipe_reconfig(): invalid resolution: %d x %d\n", width, height);
00179     return -1;
00180   }
00181 
00182   nvp->width = width;
00183   nvp->height = height;
00184   NvPipe_Destroy(nvp->encoder);
00185   nvp->encoder = NvPipe_CreateEncoder(nvp->format, nvp->codec, 
00186                                       nvp->compression,
00187                                       nvp->bitrateMbps * 1000 * 1000, 
00188                                       nvp->targetFPS);
00189   return 0;
00190 }
00191 
00192 
00193 static unsigned long nvpipe_encode_frame(void *voidhandle, 
00194                                          const unsigned char *rgba,
00195                                          int pitch, int width, int height, 
00196                                          unsigned char * & compbuf, 
00197                                          long compbufsz,
00198                                          bool forceIframe) {
00199   nvpipe_handle *nvp = (nvpipe_handle *) voidhandle;
00200 
00201 #if 1
00202   if (unsigned(width) != nvp->width || unsigned(height) != nvp->height) {
00203     printf("nvpipe_encode_frame(): inconsistent resolution: %d x %d\n", width, height);
00204     printf("                         does not match config: %d x %d\n", nvp->width, nvp->height);
00205   }
00206 #endif
00207 
00208   // encode the image...
00209   uint64_t compsz = NvPipe_Encode(nvp->encoder, rgba, pitch, compbuf, 
00210                                   compbufsz, width, height, forceIframe);
00211   if (compsz == 0) {
00212     printf("NVEnc: encode failed!: %s\n", NvPipe_GetError(nvp->encoder));
00213   }
00214 
00215   return compsz;
00216 }
00217 
00218 
00219 static unsigned long nvpipe_decode_frame(void *voidhandle, 
00220                                          unsigned char *compbuf,
00221                                          long compbufsz,
00222                                          unsigned char *rgba,
00223                                          int width, int height) {
00224   nvpipe_handle *nvp = (nvpipe_handle *) voidhandle;
00225   uint64_t r = NvPipe_Decode(nvp->decoder, compbuf, compbufsz, 
00226                              rgba, width, height);
00227 
00228   return (r == 0); // error if we get a zero size back
00229 }
00230 
00231 #endif
00232 
00233 
00234 #define VS_PROTOCOL_VERSION     1
00235 #define VS_HEADER_NUM_DATAUNION 6
00236 
00237 typedef union {
00238     int   ival;
00239     float fval;
00240 } eventdataunion;
00241 
00242 typedef struct VSMsgHeader_t {
00243   int type;
00244   int len;
00245   int width;
00246   int height;
00247 
00248   int framecount;
00249   int eventtype;
00250   eventdataunion eventdata[VS_HEADER_NUM_DATAUNION];
00251 } VSMsgHeader;
00252 
00253 #define VS_HEADERSIZE       sizeof(VSMsgHeader)
00254 
00255 static void swap4(char *data, int ndata) {
00256   int i;
00257   char *dataptr;
00258   char b0, b1;
00259 
00260   dataptr = data;
00261   for (i=0; i<ndata; i+=4) {
00262     b0 = dataptr[0];
00263     b1 = dataptr[1];
00264     dataptr[0] = dataptr[3];
00265     dataptr[1] = dataptr[2];
00266     dataptr[2] = b1;
00267     dataptr[3] = b0;
00268     dataptr += 4;
00269   }
00270 }
00271 
00272 static int vs_htonl(int h) {
00273   int n;
00274   ((char *)&n)[0] = (h >> 24) & 0x0FF;
00275   ((char *)&n)[1] = (h >> 16) & 0x0FF;
00276   ((char *)&n)[2] = (h >> 8) & 0x0FF;
00277   ((char *)&n)[3] = h & 0x0FF;
00278   return n;
00279 }
00280 
00281 typedef union {
00282   int sint;
00283   struct {
00284     unsigned int highest : 8;
00285     unsigned int high    : 8;
00286     unsigned int low     : 8;
00287     unsigned int lowest  : 8;
00288   } bytes;
00289 } netint;
00290 
00291 static int vs_ntohl(int n) {
00292   int h = 0;
00293   netint net;
00294   net.sint = n;
00295   h |= net.bytes.highest << 24 | net.bytes.high << 16 | net.bytes.low << 8 | net.bytes.lowest;
00296   return h;
00297 }
00298 
00299 static void fill_header(VSMsgHeader *header, int type, int length,
00300                         int width = 0, int height = 0, int framecount = 0) {
00301   header->type       = vs_htonl((int)type);
00302   header->len        = vs_htonl(length);
00303   header->width      = vs_htonl(width);
00304   header->height     = vs_htonl(height);
00305 
00306   header->framecount = vs_htonl(framecount);
00307   header->eventtype  = 0;
00308   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00309     header->eventdata[i].ival = 0;
00310   }
00311 }
00312 
00313 
00314 #if 0
00315 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00316                                 int ival0, int ival1) {
00317   header->type       = vs_htonl((int)type);
00318   header->len        = 0;
00319   header->width      = 0;
00320   header->height     = 0;
00321 
00322   header->framecount = 0;
00323   header->eventtype  = vs_htonl(eventtype);
00324   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00325     header->eventdata[i].ival = 0;
00326   }
00327   header->eventdata[0].ival = vs_htonl(ival0);
00328   header->eventdata[1].ival = vs_htonl(ival1);
00329 }
00330 
00331 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00332                                 int ival0) {
00333   header->type       = vs_htonl((int)type);
00334   header->len        = 0;
00335   header->width      = 0;
00336   header->height     = 0;
00337 
00338   header->framecount = 0;
00339   header->eventtype  = vs_htonl(eventtype);
00340   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00341     header->eventdata[i].ival = 0;
00342   }
00343   header->eventdata[0].ival = vs_htonl(ival0);
00344 }
00345 #endif
00346 
00347 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00348                                 int ival0, int ival1, int ival2) {
00349   header->type       = vs_htonl((int)type);
00350   header->len        = 0;
00351   header->width      = 0;
00352   header->height     = 0;
00353 
00354   header->framecount = 0;
00355   header->eventtype  = vs_htonl(eventtype);
00356   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00357     header->eventdata[i].ival = 0;
00358   }
00359   header->eventdata[0].ival = vs_htonl(ival0);
00360   header->eventdata[1].ival = vs_htonl(ival1);
00361   header->eventdata[2].ival = vs_htonl(ival2);
00362 }
00363 
00364 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00365                                 float fval0) {
00366   header->type       = vs_htonl(type);
00367   header->len        = 0;
00368   header->width      = 0;
00369   header->height     = 0;
00370 
00371   header->framecount = 0;
00372   header->eventtype  = vs_htonl(eventtype);
00373   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00374     header->eventdata[i].ival = 0;
00375   }
00376 
00377   // XXX treat the float/int union as a float, then as an int 
00378   //     for vs_htonl() handling, clean up this hack later
00379   header->eventdata[0].fval = fval0;
00380   header->eventdata[0].ival = vs_htonl(header->eventdata[0].ival);
00381 }
00382 
00383 
00384 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00385                                 float fval0, int ival1) {
00386   header->type       = vs_htonl(type);
00387   header->len        = 0;
00388   header->width      = 0;
00389   header->height     = 0;
00390 
00391   header->framecount = 0;
00392   header->eventtype  = vs_htonl(eventtype);
00393   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00394     header->eventdata[i].ival = 0;
00395   }
00396 
00397   // XXX treat the float/int union as a float, then as an int 
00398   //     for vs_htonl() handling, clean up this hack later
00399   header->eventdata[0].fval = fval0;
00400   header->eventdata[0].ival = vs_htonl(header->eventdata[0].ival);
00401   header->eventdata[1].ival = vs_htonl(ival1);
00402 }
00403 
00404 
00405 static void fill_header_uievent(VSMsgHeader *header, int type, int eventtype, 
00406                                 float fval0, float fval1, float fval2) {
00407   header->type       = vs_htonl(type);
00408   header->len        = 0;
00409   header->width      = 0;
00410   header->height     = 0;
00411 
00412   header->framecount = 0;
00413   header->eventtype  = vs_htonl(eventtype);
00414   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00415     header->eventdata[i].ival = 0;
00416   }
00417 
00418   // XXX treat the float/int union as a float, then as an int 
00419   //     for vs_htonl() handling, clean up this hack later
00420   header->eventdata[0].fval = fval0;
00421   header->eventdata[0].ival = vs_htonl(header->eventdata[0].ival);
00422   header->eventdata[1].fval = fval1;
00423   header->eventdata[1].ival = vs_htonl(header->eventdata[1].ival);
00424   header->eventdata[2].fval = fval2;
00425   header->eventdata[2].ival = vs_htonl(header->eventdata[2].ival);
00426 }
00427 
00428 
00429 static void swap_header(VSMsgHeader *header) {
00430   header->type       = vs_ntohl(header->type);
00431   header->len        = vs_ntohl(header->len);
00432   header->width      = vs_ntohl(header->width);
00433   header->height     = vs_ntohl(header->height);
00434 
00435   header->framecount = vs_ntohl(header->framecount);
00436   header->eventtype  = vs_ntohl(header->eventtype);
00437   for (int i=0; i<VS_HEADER_NUM_DATAUNION; i++) {
00438     int tmp = header->eventdata[i].ival;
00439     header->eventdata[i].ival = vs_ntohl(tmp);
00440   }
00441 }
00442 
00443 
00444 
00445 
00446 //
00447 // VideoStream class methods
00448 //
00449 
00450 VideoStream::VideoStream(VMDApp *vmdapp) : UIObject(vmdapp) {
00451   ench = NULL;
00452   cli_socket = NULL;
00453   srv_socket = NULL;
00454 
00455   timer = wkf_timer_create();
00456   wkf_timer_start(timer);
00457 
00458   srv_get_one_ui_event = 0;
00459 
00460   // initialize last_xxx timers to now so we don't get warnings at startup
00461   double now = wkf_timer_timenow(timer);
00462   cli_lastmsgtime = now;
00463   cli_lastframe = now;
00464   srv_lastmsgtime = now;
00465   srv_lastframe = now;
00466 
00467   expave_fps = 0.0;
00468   imagesz_uncomp = 0.0;
00469   imagesz_comp = 0.0;
00470   lastmsgeventloops = 0;
00471   lastconsolemesg = wkf_timer_timenow(timer);
00472 
00473   // get video stream resolution from the active client display size
00474   vs_width = app->display->xSize;
00475   vs_height = app->display->ySize;
00476 
00477   // force window resize to video encoder block-multiple
00478   vs_width = ((vs_width + 15) / 16) * 16;
00479   vs_height = ((vs_height + 15) / 16) * 16;
00480   //  XXX can't call through VMDApp chain because we can rapidly 
00481   //      get into a deeply recursive call chain leading to a segfault.
00482 //  app->display_set_size(vs_width, vs_height);
00483   app->display->resize_window(vs_width, vs_height);
00484 
00485   vs_bitrateMbps = 10;
00486   vs_targetFPS = 20;
00487 
00488 #if defined(VIDEOSTREAM_SIMENCODER)
00489   ench = simenc_initialize(vs_width, vs_height, vs_bitrateMbps, vs_targetFPS);
00490 #elif defined(VMDNVPIPE)
00491   ench = nvpipe_initialize(vs_width, vs_height, vs_bitrateMbps, vs_targetFPS);
00492   msgInfo << "VideoStream: codec initialized @ "
00493           << vs_width << "x" << vs_height << " res, " 
00494           << vs_targetFPS << " FPS @ " << vs_bitrateMbps << "Mbps."
00495           << sendmsg;
00496 #endif
00497 
00498 #if defined(VIDEOSTREAM_STATICBUFS)
00499   vs_imgbufsz = 8192 * 4320 * 4 + VS_HEADERSIZE; // max framebuffer sz
00500   vs_imgbuf = (unsigned char *) malloc(vs_cbufsz);
00501 
00502   vs_cbufsz = 8192 * 4320 * 4 + VS_HEADERSIZE; // max framebuffer sz
00503   vs_cbuf = (unsigned char *) malloc(vs_cbufsz);
00504 #endif
00505 
00506   // clear all "pending" frame state variables
00507   vs_framepending = 0;
00508   vs_rgba_pend = NULL;
00509   vs_rgba_width = 0;
00510   vs_rgba_height = 0;
00511 
00512   // clear pending codec reconfig for now
00513   vs_codec_reconfig_pending = 0;
00514 }
00515 
00516 
00517 VideoStream::~VideoStream(void) {
00518 
00519 #if defined(VIDEOSTREAM_STATICBUFS)
00520   if (vs_imgbuf) {
00521     free(vs_imgbuf); 
00522     vs_imgbuf = NULL;
00523   }
00524 
00525   if (vs_cbuf) {
00526     free(vs_cbuf); 
00527     vs_cbuf = NULL;
00528   }
00529 #endif
00530 
00531   if (ench != NULL) {
00532 #if defined(VIDEOSTREAM_SIMENCODER)
00533     simenc_destroy(ench);
00534 #elif defined(VMDNVPIPE)
00535     nvpipe_destroy(ench);
00536 #endif
00537     ench = NULL;
00538   }
00539 
00540   wkf_timer_destroy(timer);
00541 }
00542 
00543 
00544 //
00545 // client-side APIs
00546 //
00547 int VideoStream::cli_listen(int port) {
00548   vmdsock_init(); // ensure socket interface is ready
00549 
00550   msgInfo << "VideoStream client: setting up incoming socket\n" << sendmsg;
00551   void *listen_socket = vmdsock_create();
00552   vmdsock_bind(listen_socket, port);
00553 
00554   msgInfo << "VideoStream client: Waiting for connection on port: " << port << sendmsg;
00555   vmdsock_listen(listen_socket);
00556   while (!cli_socket) {
00557     if (vmdsock_selread(listen_socket, 0) > 0) {
00558       cli_socket = vmdsock_accept(listen_socket);
00559       if (vs_recv_handshake(cli_socket)) {
00560         cli_socket = NULL;
00561       };
00562     }
00563   }
00564 
00565   vmdsock_destroy(listen_socket); // we are no longer listening...
00566 
00567   return 0;
00568 }
00569 
00570 
00571 int VideoStream::cli_connect(const char *hostname, int port) {
00572   vmdsock_init(); // ensure socket interface is ready
00573  
00574   cli_socket = vmdsock_create();
00575   if (cli_socket == NULL) {
00576     msgErr << "VideoStream client: could not create socket" << sendmsg;
00577     return -1;
00578   }
00579   int rc = vmdsock_connect(cli_socket, hostname, port);
00580   if (rc < 0) {
00581     msgErr << "VideoStream client: error connecting to " << hostname << " on port "<< port <<sendmsg;
00582     vmdsock_destroy(cli_socket);
00583     cli_socket = 0;
00584     return -1;
00585   }
00586   rc = vs_send_handshake(cli_socket);
00587   msgInfo << "VideoStream client: handshake return code: " << rc << sendmsg;  
00588 
00589   // initialize last_xxx timers to now so we don't get warnings at startup
00590   double now = wkf_timer_timenow(timer);
00591   cli_lastmsgtime = now;
00592   cli_lastframe = now;
00593 
00594   expave_fps = 0.0;
00595   imagesz_uncomp = 0.0;
00596  
00597   return rc;
00598 }
00599 
00600 int VideoStream::cli_wait_msg() {
00601   return -1;
00602 }
00603 
00604 int VideoStream::cli_disconnect() {
00605   if (cli_socket != NULL) {
00606     vs_send_disconnect(cli_socket);
00607     vmdsock_destroy(cli_socket);
00608     cli_socket = 0;
00609     return 0;
00610   }
00611   return -1;
00612 }
00613 
00614 
00615 //
00616 // server-side APIs
00617 //
00618 
00619 int VideoStream::vs_encoder_reconfig() {
00620   int rc = -1;
00621 #if defined(VIDEOSTREAM_SIMENCODER)
00622   rc = simenc_reconfig(ench, vs_width, vs_height, vs_bitrateMbps, vs_targetFPS);
00623 #elif defined(VMDNVPIPE)
00624   rc = nvpipe_reconfig(ench, vs_width, vs_height, vs_bitrateMbps, vs_targetFPS);
00625 #endif
00626   return rc;
00627 }
00628 
00629 
00630 int VideoStream::srv_listen(int port) {
00631   vmdsock_init(); // ensure socket interface is ready
00632 
00633   msgInfo << "VideoStream: setting up incoming socket\n" << sendmsg;
00634   void *listen_socket = vmdsock_create();
00635   vmdsock_bind(listen_socket, port);
00636 
00637   msgInfo << "VideoStream server: Waiting for connection on port: " << port << sendmsg;
00638   vmdsock_listen(listen_socket);
00639   while (!srv_socket) {
00640     if (vmdsock_selread(listen_socket, 0) > 0) {
00641       srv_socket = vmdsock_accept(listen_socket);
00642       if (vs_recv_handshake(srv_socket)) {
00643         srv_socket = NULL;
00644       };
00645     }
00646   }
00647 
00648   vmdsock_destroy(listen_socket); // we are no longer listening...
00649 
00650   return 0;
00651 }
00652 
00653 
00654 int VideoStream::srv_connect(const char *hostname, int port) {
00655   vmdsock_init(); // ensure socket interface is ready
00656 
00657   srv_socket = vmdsock_create();
00658   if (srv_socket == NULL) {
00659     msgErr << "VideoStream server: could not create socket" << sendmsg;
00660     return -1;
00661   }
00662   int rc = vmdsock_connect(srv_socket, hostname, port);
00663   if (rc < 0) {
00664     msgErr << "VideoStream server: error connecting to " << hostname << " on port "<< port <<sendmsg;
00665     vmdsock_destroy(srv_socket);
00666     srv_socket = 0;
00667     return -1;
00668   }
00669   rc = vs_send_handshake(srv_socket);
00670   msgInfo << "VideoStream servert: handshake return code: " << rc << sendmsg;
00671 
00672   // initialize last_xxx timers to now so we don't get warnings at startup
00673   double now = wkf_timer_timenow(timer);
00674   srv_lastmsgtime = now;
00675   srv_lastframe = now;
00676 
00677   return rc;
00678 }
00679 
00680 
00681 int VideoStream::srv_send_frame(const unsigned char *rgba, int pitch,   
00682                                 int width, int height, int forceIFrame) {
00683   int rc = -1;
00684   if (ench) {
00685     long imgsz = pitch * height;
00686     long msgallocsz = imgsz + VS_HEADERSIZE; // original uncompressed msg size
00687 #if defined(VIDEOSTREAM_STATICBUFS)
00688     unsigned char *cbuf = vs_cbuf;
00689 #else
00690     unsigned char *cbuf = (unsigned char *) malloc(msgallocsz);
00691 #endif
00692     unsigned char *imgbuf = cbuf + VS_HEADERSIZE; // offset past header
00693 
00694     unsigned long compsz=0;
00695 #if defined(VIDEOSTREAM_SIMENCODER)
00696     compsz = simenc_encode_frame(ench, rgba, width * 4, width, height, 
00697                                  imgbuf, imgsz, false);
00698 #elif defined(VMDNVPIPE)
00699     compsz = nvpipe_encode_frame(ench, rgba, width * 4, width, height, 
00700                                  imgbuf, imgsz, false);
00701 #endif
00702 
00703     // if encoding succeeded, send it!
00704     if (compsz > 0) {
00705       // compute exponential moving average for exp(-1/10)
00706       imagesz_uncomp = (imagesz_uncomp * 0.90) + (imgsz * 0.10);
00707       imagesz_comp   = (imagesz_comp * 0.90)   + (compsz * 0.10);
00708 
00709       fill_header((VSMsgHeader *)cbuf, VS_IMAGE, compsz, width, height);
00710 
00711       long msgsz = compsz + VS_HEADERSIZE; // final actual compressed msg size
00712       rc = (vs_writen(srv_socket, (const char*) cbuf, msgsz) != msgsz);
00713     }
00714  
00715 #if !defined(VIDEOSTREAM_STATICBUFS)
00716     free(cbuf);
00717 #endif
00718   }
00719 
00720 #if 1
00721   printf("NVEnc: %dx%d  raw:%.1fMB  comp:%.1fMB  ratio:%.1f:1  FPS:%.1f   \r",
00722           width, height, 
00723           imagesz_uncomp/(1024.0*1024.0), imagesz_comp/(1024.0*1024.0),
00724           imagesz_uncomp/imagesz_comp, expave_fps);
00725           fflush(stdout);
00726 #endif
00727   
00728   // Throttle video throughput so we don't hammer the network.
00729   // Don't allow our actual FPS to exceed the user-defined setpoint.
00730   // If we arrive too early at this point, we stall the outbound video
00731   // frame by looping on the wall clock and/or making millisecond sleep
00732   // calls as needed.
00733   const double mintimeperframe = 1.0 / ((double) vs_targetFPS); 
00734   double nowtime = wkf_timer_timenow(timer);
00735   double timesincelastframe = fabs(nowtime - srv_lastframe) + 0.0001;
00736   while (timesincelastframe < mintimeperframe) {
00737     nowtime = wkf_timer_timenow(timer);
00738     timesincelastframe = fabs(nowtime - srv_lastframe) + 0.0001;
00739     if ((mintimeperframe - timesincelastframe) > 0.001) 
00740       vmd_msleep(1);  
00741   }
00742 
00743   // compute exponential moving average for exp(-1/10)
00744   double fps = 1.0 / timesincelastframe;
00745   expave_fps = (expave_fps * 0.90) + (fps * 0.10);
00746   
00747   srv_lastframe = nowtime; // update timestamp of last sent image
00748 
00749   return rc;
00750 }
00751 
00752 
00753 int VideoStream::srv_disconnect() {
00754   if (srv_socket != NULL) {
00755     vs_send_disconnect(srv_socket);
00756     vmdsock_destroy(srv_socket);
00757     cli_socket = 0;
00758     return 0;
00759   }
00760   return -1;
00761 }
00762 
00763 
00764 //
00765 // Helper routines
00766 //
00767 int VideoStream::vs_readn(void *s, char *ptr, int n) {
00768   int nleft;
00769   int nread;
00770 
00771   nleft = n;
00772   while (nleft > 0) {
00773     if ((nread = vmdsock_read(s, ptr, nleft)) < 0) {
00774       if (errno == EINTR)
00775         nread = 0;         /* and call read() again */
00776       else
00777         return -1;
00778     } else if (nread == 0)
00779       break;               /* EOF */
00780     nleft -= nread;
00781     ptr += nread;
00782   }
00783   return n-nleft;
00784 }
00785 
00786 
00787 int VideoStream::vs_readn_discard(void *s, int discardsz) {
00788   // read+discard next discardsz bytes 
00789   char buf[1024 * 1024];
00790   const int bufsz = 1024 * 1024;
00791   while (discardsz > 0) {
00792     int readsz = (discardsz > bufsz) ? bufsz : discardsz;
00793     int n = vs_readn(cli_socket, buf, readsz);
00794     if (n < 0) {
00795       printf("VS: vs_readn_discard(): error reading message!\n");
00796       return -1;
00797     }
00798     discardsz -= n;
00799   } 
00800   return 0;
00801 }
00802 
00803 
00804 int VideoStream::vs_writen(void *s, const char *ptr, int n) {
00805   int nleft;
00806   int nwritten;
00807 
00808   nleft = n;
00809   while (nleft > 0) {
00810     if ((nwritten = vmdsock_write(s, ptr, nleft)) <= 0) {
00811       if (errno == EINTR)
00812         nwritten = 0;
00813       else
00814         return -1;
00815     }
00816     nleft -= nwritten;
00817     ptr += nwritten;
00818   }
00819   return n;
00820 }
00821 
00822 
00823 int VideoStream::vs_recv_handshake(void *s) {
00824   int buf;
00825   int type;
00826 
00827   /* Wait up to 5 seconds for the handshake to come */
00828   if (vmdsock_selread(s, 5) != 1) return -1;
00829 
00830   /* Check to see that a valid handshake was received */
00831   type = vs_recv_header_nolengthswap(s, &buf);
00832   if (type != VS_HANDSHAKE) return -1;
00833 
00834   /* Check its endianness, as well as the VS version. */
00835   if (buf == VS_PROTOCOL_VERSION) {
00836     if (!vs_send_go(s)) return 0;
00837     return -1;
00838   }
00839   swap4((char *)&buf, 4);
00840   if (buf == VS_PROTOCOL_VERSION) {
00841     if (!vs_send_go(s)) return 1;
00842   }
00843 
00844   /* We failed to determine endianness. */
00845   return -1;
00846 }
00847 
00848 int VideoStream::vs_send_handshake(void *s) {
00849   VSMsgHeader header;
00850   fill_header(&header, VS_HANDSHAKE, 0, 0, 0);
00851   header.len = VS_PROTOCOL_VERSION;   /* Not byteswapped! */
00852   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00853 }
00854 
00855 int VideoStream::vs_recv_header(void *s, VSMsgHeader &header) {
00856   if (vs_readn(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE)
00857     return VS_IOERROR;
00858   swap_header(&header);
00859   return (VSMsgType) header.type;
00860 }
00861 
00862 int VideoStream::vs_recv_header_nolengthswap(void *s, int *length) {
00863   VSMsgHeader header;
00864   if (vs_readn(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE)
00865     return VS_IOERROR;
00866   *length = header.len;
00867   swap_header(&header);
00868   return (VSMsgType) header.type;
00869 }
00870 
00871 int VideoStream::vs_send_disconnect(void *s) {
00872   VSMsgHeader header;
00873   fill_header(&header, VS_DISCONNECT, 0, 0, 0);
00874   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00875 }
00876 
00877 int VideoStream::vs_send_pause(void *s) {
00878   VSMsgHeader header;
00879   fill_header(&header, VS_PAUSE, 0, 0, 0);
00880   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00881 }
00882 
00883 int VideoStream::vs_send_go(void *s) {
00884   VSMsgHeader header;
00885   fill_header(&header, VS_GO, 0, 0, 0);
00886   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00887 }
00888 
00889 int VideoStream::vs_send_heartbeat(void *s) {
00890   VSMsgHeader header;
00891   fill_header(&header, VS_HEARTBEAT, 0, 0, 0);
00892   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00893 }
00894 
00895 int VideoStream::vs_send_resize(void *s, int width, int height) {
00896   VSMsgHeader header;
00897   fill_header(&header, VS_RESIZE, 0, width, height);
00898   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00899 }
00900 
00901 int VideoStream::vs_send_codec_reconfig(void *s, int bitrateMbps, int tFPS) {
00902   // XXX add a new reconfig-specific fill_header variant
00903   VSMsgHeader header;
00904   fill_header(&header, VS_CODEC_RECONFIG, 0, bitrateMbps, tFPS);
00905   return (vs_writen(s, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00906 }
00907 
00908 
00909 int VideoStream::cli_decode_frame(unsigned char *cbuf, long cbufsz,
00910                                   unsigned char *rgba, int width, int height) {
00911   int rc = -1;
00912 #if defined(VIDEOSTREAM_SIMENCODER)
00913   rc = simenc_decode_frame(ench, cbuf, cbufsz, rgba, width, height);
00914 #elif defined(VMDNVPIPE)
00915   rc = nvpipe_decode_frame(ench, cbuf, cbufsz, rgba, width, height);
00916 #endif
00917   return rc;
00918 }
00919 
00920 
00921 int VideoStream::cli_send_rotate_by(float angle, char axis) {
00922   if (!cli_socket) return -1;
00923 
00924 // printf("\nVS rotateby: %f  %d\n", angle, axis);
00925 
00926   VSMsgHeader header;
00927   fill_header_uievent(&header, VS_UIEVENT, VS_EV_ROTATE_BY, angle, (int)axis);
00928   return (vs_writen(cli_socket, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00929 }
00930 
00931 int VideoStream::cli_send_translate_by(float dx, float dy, float dz) {
00932   if (!cli_socket) return -1;
00933 
00934 // printf("\nVS translateby: %f %f %f\n", dx, dy, dz);
00935 
00936   VSMsgHeader header;
00937   fill_header_uievent(&header, VS_UIEVENT, VS_EV_TRANSLATE_BY, dx, dy, dz);
00938   return (vs_writen(cli_socket, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00939 }
00940 
00941 int VideoStream::cli_send_scale_by(float scalefactor) {
00942   if (!cli_socket) return -1;
00943 
00944 // printf("\nVS scaleby: %f \n", scalefactor);
00945 
00946   VSMsgHeader header;
00947   fill_header_uievent(&header, VS_UIEVENT, VS_EV_SCALE_BY, scalefactor);
00948   return (vs_writen(cli_socket, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00949 }
00950 
00951 int VideoStream::cli_send_keyboard(int dev, char val, int shift_state) {
00952   if (!cli_socket) return -1;
00953 
00954 // printf("\nVS keyboard: %d %d %d\n", dev, val, shift_state);
00955 
00956   VSMsgHeader header;
00957   fill_header_uievent(&header, VS_UIEVENT, VS_EV_KEYBOARD,
00958                       (int) dev, (int) val, (int) shift_state);
00959   return (vs_writen(cli_socket, (char *)&header, VS_HEADERSIZE) != VS_HEADERSIZE);
00960 }
00961 
00962 int VideoStream::srv_check_ui_event() {
00963   srv_get_one_ui_event = 1;
00964   check_event();
00965   if (srv_last_event_type != VS_EV_NONE)
00966     return 1;
00967 
00968   return 0;
00969 }
00970 
00971 //
00972 // UIObject virtual methods
00973 //
00974 int VideoStream::check_event() {
00975   // entry point to check for network events
00976   double curtime = wkf_timer_timenow(timer);
00977 
00978   // give status updates only once per 10 sec or so
00979   if ((curtime - lastconsolemesg) > 10) {
00980     int verbose = (getenv("VMDVIDEOSTREAMVERBOSE") != NULL);
00981     if (verbose) {
00982       printf("VS::check_event(): Cli: %s Srv: %s loops: %d\n",
00983              (cli_socket != NULL) ? "on" : "off",
00984              (srv_socket != NULL) ? "on" : "off",
00985              lastmsgeventloops);
00986     }
00987     lastconsolemesg = curtime;
00988     lastmsgeventloops = 0;
00989   }
00990   lastmsgeventloops++;
00991 
00992   //
00993   // VideoStream client-specific event handling implementation
00994   // 
00995   if (cli_socket) {
00996     // force main VMD event loop to run flat-out with no millisleep calls
00997     app->background_processing_set();
00998 
00999     // 
01000     // Process inbound mesgs from the video stream server
01001     //
01002 
01003     // loop to process all incoming data before continuing...
01004     int selectloops = 0;
01005     while (vmdsock_selread(cli_socket, 0) > 0) {
01006       VSMsgHeader header;
01007       int msgtype = vs_recv_header(cli_socket, header);
01008       int payloadsz = header.len;
01009 
01010       switch (msgtype) {
01011         case VS_HANDSHAKE:
01012           msgInfo << "VideoStream: received out-of-seq message type: " 
01013                   << msgtype << sendmsg;
01014           break;
01015 
01016         case VS_GO:
01017           // just eat the message, nothing specific to do presently
01018           break;
01019 
01020         case VS_HEARTBEAT:
01021 #if 0
01022           printf("VS client received heartbeat message sz: %d\n", header.len);
01023 #endif
01024           break;
01025 
01026         case VS_IMAGE:
01027           {
01028             // compute exponential moving average for exp(-1/10)
01029             double fps = 1.0 / (fabs(curtime - cli_lastframe) + 0.0001);
01030             expave_fps = (expave_fps * 0.90) + (fps * 0.10);
01031             printf("VS client recv image sz: %d, res: %dx%d  FPS:%.1f      \r", 
01032                    header.len, header.width, header.height, expave_fps);
01033             fflush(stdout);
01034 #if defined(VIDEOSTREAM_STATICBUFS)
01035             unsigned char *compbuf = vs_cbuf;
01036 #else
01037             unsigned char *compbuf = (unsigned char *) malloc(payloadsz);
01038 #endif
01039             long imgsz = 4 * header.width * header.height;
01040             vs_readn(cli_socket, (char *) compbuf, payloadsz);
01041 
01042 #if defined(VIDEOSTREAM_STATICBUFS)
01043             unsigned char *imgbuf = vs_imgbuf;
01044 #else
01045             unsigned char *imgbuf = (unsigned char *) malloc(imgsz);
01046 #endif
01047              
01048             unsigned long decodesz = 0;
01049 #if defined(VIDEOSTREAM_SIMENCODER)
01050             decodesz = simenc_decode_frame(ench, compbuf, payloadsz, imgbuf, 
01051                                            header.width, header.height);
01052 #elif defined(VMDNVPIPE)
01053             decodesz = nvpipe_decode_frame(ench, compbuf, payloadsz, imgbuf, 
01054                                            header.width, header.height);
01055 #endif
01056 
01057             app->display->prepare3D(1);
01058             app->display->drawpixels_rgba4u(imgbuf, header.width, header.height);
01059 
01060 #if 0
01061             { int ll, cnt;
01062               long inten=0;
01063               for (ll=0, cnt=0; ll<imgsz; ll++) {
01064                 inten += imgbuf[ll];
01065                 cnt += (imgbuf[ll] > 0);
01066               }
01067               printf("\nDecode: sz: %ld  Pixel stats: totalI: %ld, nonZero: %d \n", decodesz, inten, cnt);
01068             }
01069 #endif
01070 
01071 #if !defined(VIDEOSTREAM_STATICBUFS)
01072             free(imgbuf);
01073             free(compbuf);
01074 #endif
01075 
01076             if (decodesz == 0) {
01077               printf("\nVS_IMAGE decode size 0 error!\n");
01078             }
01079 
01080             payloadsz = 0; // we've used all of the incoming data
01081           }
01082           cli_lastframe = curtime;
01083           break;
01084 
01085         case VS_DISCONNECT:
01086           printf("VS client received disconnect message sz: %d\n", header.len);
01087           vmdsock_destroy(cli_socket);
01088           cli_socket = 0;
01089           return 0; // bail all the way out since we no longer have a socket
01090           break;
01091 
01092         case VS_IOERROR:
01093           printf("VS client: I/O error, disconnecting!\n");
01094           vmdsock_destroy(cli_socket);
01095           cli_socket = 0;
01096           return 0; // bail all the way out since we no longer have a socket
01097           break;
01098 
01099         default:
01100           printf("VS client message type: %d  sz: %d\n", msgtype, header.len);
01101           break;
01102       }
01103       // read+discard next payloadsz bytes if any are left unused...
01104       if (payloadsz > 0) {
01105 #if 0
01106         printf("VS server discarding payload, %d bytes\n", payloadsz);
01107 #endif
01108         vs_readn_discard(cli_socket, payloadsz);
01109       }
01110 
01111       cli_lastmsgtime = curtime; 
01112       selectloops++;
01113     }
01114 #if 0
01115     if (selectloops > 0) {
01116       printf("VideoStream: client select loops %d\n", selectloops);
01117     }
01118 #endif
01119 
01120     // 
01121     // Send outbound mesgs to the video stream server
01122     //
01123 
01124     // check if the local display size has been changed
01125     int framesizechanged = 0;
01126     if (app->display->xSize != vs_width) {
01127       vs_width = app->display->xSize;
01128       framesizechanged = 1;
01129     }
01130     if (app->display->ySize != vs_height) {
01131       vs_height = app->display->ySize;
01132       framesizechanged = 1;
01133     }
01134 
01135     if (framesizechanged) {
01136       printf("\n");
01137       msgInfo << "VideoStream: client window resize: " 
01138               << vs_width << "x" << vs_height << sendmsg;
01139       vs_send_resize(cli_socket, vs_width, vs_height);
01140     } 
01141 
01142     // check whether codec parameters need reconfiguration
01143     if (vs_codec_reconfig_pending) {
01144       vs_send_codec_reconfig(cli_socket, vs_bitrateMbps, vs_targetFPS);
01145       vs_codec_reconfig_pending = 0;
01146     }
01147 
01148     // print warnings if we haven't gotten any messages for 5 sec
01149     if ((curtime - cli_lastmsgtime) > 5) {
01150       printf("VS: no mesgs for 5 seconds...\n");    
01151       cli_lastmsgtime = curtime; 
01152     }
01153   }
01154 
01155 
01156   //
01157   // VideoStream server-specific event handling implementation
01158   // 
01159   if (srv_socket) {
01160     // force main VMD event loop to run flat-out with no millisleep calls
01161     app->background_processing_set();
01162 
01163     // 
01164     // Process inbound mesgs from the video stream client
01165     //
01166 
01167     // loop to process all incoming data before continuing...
01168     int selectloops = 0;
01169     while (vmdsock_selread(srv_socket, 0) > 0) {
01170       VSMsgHeader header;
01171       int msgtype = vs_recv_header(srv_socket, header);
01172       int payloadsz = header.len;
01173 
01174       switch (msgtype) {
01175         case VS_HANDSHAKE:
01176           msgInfo << "VideoStream: received out-of-seq message type: " 
01177                   << msgtype << sendmsg;
01178           break;
01179 
01180         case VS_GO:
01181           // just eat the message, nothing specific to do presently
01182           break;
01183 
01184         case VS_HEARTBEAT:
01185 #if 0
01186           printf("VS server received heartbeat, sz: %d\n", header.len);
01187 #endif
01188           break;
01189 
01190         case VS_RESIZE:
01191           printf("\n");
01192           printf("VS server received resize, sz: %d new size: %dx%d\n", 
01193                  header.len, header.width, header.height);
01194 
01195           // force window resize to video encoder block-multiple
01196 //          vs_width = ((header.width + 15) / 16) * 16;
01197 //          vs_height = ((header.height + 15) / 16) * 16;
01198           vs_width = header.width;
01199           vs_height = header.height;
01200 
01201           //  XXX can't call through VMDApp chain because we can rapidly 
01202           //      get into a deeply recursive call chain leading to a segfault.
01203 //          app->display_set_size(vs_width, vs_height);
01204           app->display->resize_window(vs_width, vs_height);
01205 
01206           vs_encoder_reconfig(); // apply new width/height to encoder
01207           break;
01208 
01209         case VS_CODEC_RECONFIG:
01210           // XXX add a new reconfig-specific fill_header variant
01211           printf("\n");
01212           printf("VS server received reconfig, sz: %d new Mbps: %d, FPS: %d\n", 
01213                  header.len, header.width, header.height);
01214           vs_bitrateMbps = header.width;
01215           vs_targetFPS = header.height;
01216           vs_encoder_reconfig(); // apply new width/height to encoder
01217           break;
01218 
01219         case VS_UIEVENT:
01220           {
01221 #if 0
01222             printf("\nUIEvent: %d  [%d | %f]  [%d | %f]\n", 
01223                    header.eventtype, 
01224                    header.eventdata[0].ival, header.eventdata[0].fval,
01225                    header.eventdata[1].ival, header.eventdata[1].fval);
01226 #endif
01227 
01228             srv_last_event_type = header.eventtype;
01229             switch (header.eventtype) {
01230               case VS_EV_ROTATE_BY:
01231                 app->scene_rotate_by(header.eventdata[0].fval, header.eventdata[1].ival);
01232                 srv_last_rotate_by_angle = header.eventdata[0].fval;
01233                 srv_last_rotate_by_axis = header.eventdata[1].ival;
01234                 break;
01235 
01236               case VS_EV_TRANSLATE_BY:
01237                 app->scene_translate_by(header.eventdata[0].fval, header.eventdata[1].fval, header.eventdata[2].fval);
01238                 srv_last_translate_by_vec[0] = header.eventdata[0].fval;
01239                 srv_last_translate_by_vec[1] = header.eventdata[1].fval;
01240                 srv_last_translate_by_vec[2] = header.eventdata[2].fval;
01241                 break;
01242 
01243               case VS_EV_SCALE_BY:
01244                 app->scene_scale_by(header.eventdata[0].fval);
01245                 srv_last_scale_by_factor = header.eventdata[0].fval;
01246                 break;
01247 
01248               case VS_EV_KEYBOARD:
01249                // forward keyboard events through normal command queues
01250                 runcommand(new UserKeyEvent((DisplayDevice::EventCodes) header.eventdata[0].ival, 
01251                            (char) header.eventdata[1].ival, 
01252                            header.eventdata[2].ival));
01253                 srv_last_key_dev = header.eventdata[0].ival;
01254                 srv_last_key_val = header.eventdata[1].ival;
01255                 srv_last_key_shift_state = header.eventdata[2].ival;
01256                 break;
01257 
01258               default:
01259                 printf("\nUnhandled UIEvent: %d  [%d | %f]\n", 
01260                        header.eventtype,
01261                        header.eventdata[0].ival, header.eventdata[0].fval);
01262                 break;
01263             }
01264 
01265             if (srv_get_one_ui_event) {
01266               return 1; // early-exit so caller can catch events 1-at-a-time
01267             }
01268           }
01269           break;
01270 
01271         case VS_DISCONNECT:
01272           printf("VS server: received disconnect, sz: %d\n", header.len);
01273           vmdsock_destroy(srv_socket);
01274           srv_socket = 0;
01275           return 0; // bail all the way out since we no longer have a socket
01276           break;
01277 
01278         case VS_IOERROR:
01279           printf("VS server: I/O error, disconnecting!\n");
01280           vmdsock_destroy(srv_socket);
01281           srv_socket = 0;
01282           return 0; // bail all the way out since we no longer have a socket
01283           break;
01284 
01285         default:
01286           printf("VS server message type: %d  sz: %d\n", msgtype, header.len);
01287           break;
01288       }
01289       // read+discard next payloadsz bytes if any are left unused...
01290       if (payloadsz > 0) {
01291 #if 0
01292         printf("VS server discarding payload, %d bytes\n", payloadsz);
01293 #endif
01294         vs_readn_discard(srv_socket, payloadsz);
01295       }
01296 
01297       srv_lastmsgtime = curtime; 
01298       selectloops++;
01299     }
01300 #if 0
01301     if (selectloops > 0) {
01302       printf("VideoStream: server select loops %d\n", selectloops);
01303     }
01304 #endif
01305 
01306     // 
01307     // Send outbound mesgs to the video stream client
01308     //
01309 
01310     // check if the local display state has been changed
01311     if (vs_framepending) {
01312       unsigned char *img = NULL;
01313       if (vs_rgba_pend != NULL) {
01314         srv_send_frame(vs_rgba_pend, vs_rgba_width * 4, 
01315                        vs_rgba_width, vs_rgba_height, vs_forceIframe);
01316       } else {
01317         // if no frame was provided, we grab the GL framebuffer
01318         int xs, ys;
01319         img = app->display->readpixels_rgba4u(xs, ys);
01320         if (xs == 0 || ys == 0) {
01321           printf("VS: check_event() zero framebuffer dim!: %d x %d\n", xs, ys);
01322         }
01323 
01324         if (img != NULL) {
01325           srv_send_frame(img, xs * 4, xs, ys, vs_forceIframe);
01326           free(img);
01327         }
01328       }
01329 
01330       // clear any pending frame encoding flags
01331       vs_framepending = 0;
01332       vs_forceIframe = 0;
01333     }
01334 
01335     // send a heartbeat message if no other msg was sent in last second
01336     if ((curtime - srv_lastmsgtime) > 1) {
01337       vs_send_heartbeat(srv_socket);
01338       srv_lastmsgtime = curtime; 
01339     }
01340   } 
01341  
01342   return 0;
01343 }
01344 
01345 int VideoStream::act_on_command(int type, Command *cmd) {
01346   // take any appropriate actions based on incoming commands
01347   return 0;
01348 }
01349 
01350 
01351 

Generated on Thu Apr 25 02:43:44 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002