Question: I need to display a live camera image via VNC. Until now I just grab an image, set the rect to modified and do a 0.1 s sleep to give the system time to transfer the data. This is obviously a solution which doesn't scale very well to different connection speeds/cpu horsepowers, so I wonder if there is a way for the server application to determine if the updates have been sent. This would cause the live image update rate to always be the maximum the connection supports while avoiding excessive loads.
Thanks in advance,
Christian Daschill
Answer: Originally, I thought about using separate threads and using a mutex to determine when the frame buffer was being accessed by any client so we could determine a safe time to take a picture. The probem is, we are lock-stepping everything with framebuffer access. Why not be a single-thread application and in-between rfbProcessEvents perform a camera snapshot. And this is what I do here. It guarantees that the clients have been serviced before taking another picture.
The downside to this approach is that the more clients you have, there is less time available for you to service the camera equating to reduced frame rate. (or, your clients are on really slow links). Increasing your systems ethernet transmit queues may help improve the overall performance as the libvncserver should not stall on transmitting to any single client.
Another solution would be to provide a separate framebuffer for each client and use mutexes to determine if any particular client is ready for a snapshot. This way, your not updating a framebuffer for a slow client while it is being transferred.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef LIBVNCSERVER_HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#if !defined LIBVNCSERVER_HAVE_GETTIMEOFDAY && defined WIN32
#include <fcntl.h>
#include <conio.h>
#include <sys/timeb.h>
static void gettimeofday(struct timeval* tv,char* dummy)
{
SYSTEMTIME t;
GetSystemTime(&t);
tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
tv->tv_usec=t.wMilliseconds*1000;
}
#endif
#define WIDTH 640
#define HEIGHT 480
#define BPP 4
#define PICTURE_TIMEOUT (1.0/15.0)
static struct timeval now={0,0}, then={0,0};
double elapsed, dnow, dthen;
gettimeofday(&now,NULL);
dnow = now.tv_sec + (now.tv_usec /1000000.0);
dthen = then.tv_sec + (then.tv_usec/1000000.0);
elapsed = dnow - dthen;
memcpy((char *)&then, (char *)&now, sizeof(struct timeval));
}
{
static int last_line=0, fps=0, fcount=0;
int line=0;
int i,j;
struct timeval now;
}
}
gettimeofday(&now,NULL);
line = now.tv_usec / (1000000/
HEIGHT);
fcount++;
if (last_line > line) {
fps = fcount;
fcount = 0;
}
last_line = line;
fprintf(stderr,
"%03d/%03d Picture (%03d fps)\r", line,
HEIGHT, fps);
return (1==1);
}
int main(
int argc,
char** argv)
{
long usec;
if(!server)
return 1;
server->desktopName = "Live Video Feed Example";
server->alwaysShared=(1==1);
usec = server->deferUpdateTime*1000;
}
return(0);
}
int TakePicture(unsigned char *buffer)
int main(int argc, char **argv)
void rfbInitServer(rfbScreenInfoPtr rfbScreen)
void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen, int x1, int y1, int x2, int y2)
rfbScreenInfoPtr rfbGetScreen(int *argc, char **argv, int width, int height, int bitsPerSample, int samplesPerPixel, int bytesPerPixel)
rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo)
rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo, long usec)