1a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/** 3a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * @example camera.c 4a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Question: I need to display a live camera image via VNC. Until now I just 5a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * grab an image, set the rect to modified and do a 0.1 s sleep to give the 6a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * system time to transfer the data. 7a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * This is obviously a solution which doesn't scale very well to different 8a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * connection speeds/cpu horsepowers, so I wonder if there is a way for the 9a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * server application to determine if the updates have been sent. This would 10a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * cause the live image update rate to always be the maximum the connection 11a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * supports while avoiding excessive loads. 12a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 13a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Thanks in advance, 14a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 15a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 16a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Christian Daschill 17a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 18a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 19a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Answer: Originally, I thought about using seperate threads and using a 20a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * mutex to determine when the frame buffer was being accessed by any client 21a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * so we could determine a safe time to take a picture. The probem is, we 22a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * are lock-stepping everything with framebuffer access. Why not be a 23a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * single-thread application and in-between rfbProcessEvents perform a 24a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * camera snapshot. And this is what I do here. It guarantees that the 25a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * clients have been serviced before taking another picture. 26a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 27a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * The downside to this approach is that the more clients you have, there is 28a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * less time available for you to service the camera equating to reduced 29a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * frame rate. (or, your clients are on really slow links). Increasing your 30a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * systems ethernet transmit queues may help improve the overall performance 31a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * as the libvncserver should not stall on transmitting to any single 32a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * client. 33a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 34a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Another solution would be to provide a seperate framebuffer for each 35a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * client and use mutexes to determine if any particular client is ready for 36a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * a snapshot. This way, your not updating a framebuffer for a slow client 37a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * while it is being transferred. 38a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 39a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 40a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include <stdio.h> 41a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include <stdlib.h> 42a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include <string.h> 43a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include <rfb/rfb.h> 44a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 45a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 46a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define WIDTH 640 47a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define HEIGHT 480 48a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define BPP 4 49a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 50a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 15 frames per second (if we can) */ 51a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define PICTURE_TIMEOUT (1.0/15.0) 52a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 53a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 54a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 55a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * throttle camera updates 56a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat*/ 57a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint TimeToTakePicture() { 58a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat static struct timeval now={0,0}, then={0,0}; 59a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat double elapsed, dnow, dthen; 60a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 61a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat gettimeofday(&now,NULL); 62a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 63a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat dnow = now.tv_sec + (now.tv_usec /1000000.0); 64a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat dthen = then.tv_sec + (then.tv_usec/1000000.0); 65a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat elapsed = dnow - dthen; 66a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 67a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (elapsed > PICTURE_TIMEOUT) 68a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&then, (char *)&now, sizeof(struct timeval)); 69a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return elapsed > PICTURE_TIMEOUT; 70a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} 71a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 72a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 73a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 74a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 75a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * simulate grabbing a picture from some device 76a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 77a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint TakePicture(unsigned char *buffer) 78a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat{ 79a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat static int last_line=0, fps=0, fcount=0; 80a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int line=0; 81a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int i,j; 82a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat struct timeval now; 83a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 84a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* 85a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * simulate grabbing data from a device by updating the entire framebuffer 86a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 87a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 88a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat for(j=0;j<HEIGHT;++j) { 89a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat for(i=0;i<WIDTH;++i) { 90a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[(j*WIDTH+i)*BPP+0]=(i+j)*128/(WIDTH+HEIGHT); /* red */ 91a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[(j*WIDTH+i)*BPP+1]=i*128/WIDTH; /* green */ 92a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[(j*WIDTH+i)*BPP+2]=j*256/HEIGHT; /* blue */ 93a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 94a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[j*WIDTH*BPP+0]=0xff; 95a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[j*WIDTH*BPP+1]=0xff; 96a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat buffer[j*WIDTH*BPP+2]=0xff; 97a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 98a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 99a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* 100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * simulate the passage of time 101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * draw a simple black line that moves down the screen. The faster the 103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * client, the more updates it will get, the smoother it will look! 104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat gettimeofday(&now,NULL); 106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat line = now.tv_usec / (1000000/HEIGHT); 107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (line>HEIGHT) line=HEIGHT-1; 108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memset(&buffer[(WIDTH * BPP) * line], 0, (WIDTH * BPP)); 109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* frames per second (informational only) */ 111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat fcount++; 112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (last_line > line) { 113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat fps = fcount; 114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat fcount = 0; 115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat last_line = line; 117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat fprintf(stderr,"%03d/%03d Picture (%03d fps)\r", line, HEIGHT, fps); 118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* success! We have a new picture! */ 120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return (1==1); 121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} 122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Single-threaded application that interleaves client servicing with taking 128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * pictures from the camera. This way, we do not update the framebuffer 129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * while an encoding is working on it too (banding, and image artifacts). 130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint main(int argc,char** argv) 132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat{ 133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat long usec; 134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,WIDTH,HEIGHT,8,3,BPP); 136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if(!server) 137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return 0; 138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat server->desktopName = "Live Video Feed Example"; 139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat server->frameBuffer=(char*)malloc(WIDTH*HEIGHT*BPP); 140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat server->alwaysShared=(1==1); 141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Initialize the server */ 143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbInitServer(server); 144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Loop, processing clients and taking pictures */ 146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat while (rfbIsActive(server)) { 147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (TimeToTakePicture()) 148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (TakePicture((unsigned char *)server->frameBuffer)) 149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbMarkRectAsModified(server,0,0,WIDTH,HEIGHT); 150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat usec = server->deferUpdateTime*1000; 152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbProcessEvents(server,usec); 153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return(0); 155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} 156