00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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"
00034
00035
00036
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);
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);
00095 return sz;
00096 }
00097
00098
00099 #endif
00100
00101
00102
00103
00104
00105 #if defined(VMDNVPIPE)
00106 #include <NvPipe.h>
00107 #include <cuda_runtime_api.h>
00108
00109 typedef struct {
00110 NvPipe_Format format;
00111 NvPipe_Codec codec;
00112 NvPipe_Compression compression;
00113 float bitrateMbps;
00114 uint32_t targetFPS;
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
00126
00127 #if defined(ARCH_SUMMIT) || defined(ARCH_OPENPOWER)
00128 nvp->format = NVPIPE_RGBA32;
00129 #else
00130 nvp->format = NVPIPE_BGRA32;
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
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
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);
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
00378
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
00398
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
00419
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
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
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
00474 vs_width = app->display->xSize;
00475 vs_height = app->display->ySize;
00476
00477
00478 vs_width = ((vs_width + 15) / 16) * 16;
00479 vs_height = ((vs_height + 15) / 16) * 16;
00480
00481
00482
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;
00500 vs_imgbuf = (unsigned char *) malloc(vs_cbufsz);
00501
00502 vs_cbufsz = 8192 * 4320 * 4 + VS_HEADERSIZE;
00503 vs_cbuf = (unsigned char *) malloc(vs_cbufsz);
00504 #endif
00505
00506
00507 vs_framepending = 0;
00508 vs_rgba_pend = NULL;
00509 vs_rgba_width = 0;
00510 vs_rgba_height = 0;
00511
00512
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
00546
00547 int VideoStream::cli_listen(int port) {
00548 vmdsock_init();
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);
00566
00567 return 0;
00568 }
00569
00570
00571 int VideoStream::cli_connect(const char *hostname, int port) {
00572 vmdsock_init();
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
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
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();
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);
00649
00650 return 0;
00651 }
00652
00653
00654 int VideoStream::srv_connect(const char *hostname, int port) {
00655 vmdsock_init();
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
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;
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;
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
00704 if (compsz > 0) {
00705
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;
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
00729
00730
00731
00732
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
00744 double fps = 1.0 / timesincelastframe;
00745 expave_fps = (expave_fps * 0.90) + (fps * 0.10);
00746
00747 srv_lastframe = nowtime;
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
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;
00776 else
00777 return -1;
00778 } else if (nread == 0)
00779 break;
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
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
00828 if (vmdsock_selread(s, 5) != 1) return -1;
00829
00830
00831 type = vs_recv_header_nolengthswap(s, &buf);
00832 if (type != VS_HANDSHAKE) return -1;
00833
00834
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
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;
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
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
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
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
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
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
00973
00974 int VideoStream::check_event() {
00975
00976 double curtime = wkf_timer_timenow(timer);
00977
00978
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
00994
00995 if (cli_socket) {
00996
00997 app->background_processing_set();
00998
00999
01000
01001
01002
01003
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
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
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;
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;
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;
01097 break;
01098
01099 default:
01100 printf("VS client message type: %d sz: %d\n", msgtype, header.len);
01101 break;
01102 }
01103
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
01122
01123
01124
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
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
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
01158
01159 if (srv_socket) {
01160
01161 app->background_processing_set();
01162
01163
01164
01165
01166
01167
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
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
01196
01197
01198 vs_width = header.width;
01199 vs_height = header.height;
01200
01201
01202
01203
01204 app->display->resize_window(vs_width, vs_height);
01205
01206 vs_encoder_reconfig();
01207 break;
01208
01209 case VS_CODEC_RECONFIG:
01210
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();
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
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;
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;
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;
01283 break;
01284
01285 default:
01286 printf("VS server message type: %d sz: %d\n", msgtype, header.len);
01287 break;
01288 }
01289
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
01308
01309
01310
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
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
01331 vs_framepending = 0;
01332 vs_forceIframe = 0;
01333 }
01334
01335
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
01347 return 0;
01348 }
01349
01350
01351