Created
April 24, 2014 03:55
-
-
Save linnaea/11240923 to your computer and use it in GitHub Desktop.
VNC Server exporting framebuffer device content, I wrote it for use with fbterm. It doesn't handle input. Updates at 5fps, very CPU hungry. Code released into the public domain.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <linux/fb.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <rfb/rfb.h> | |
#include <semaphore.h> | |
#include <stdint.h> | |
#include <inttypes.h> | |
#include <time.h> | |
//pthread_mutex_t *fb_lock = 0; | |
sem_t *trigger_update = 0; | |
void(* fb_convert)(char *buffer, int pixels) = NULL; | |
void fatal(char *str, int line, uintmax_t p1, uintmax_t p2, uintmax_t p3, uintmax_t p4) { | |
fprintf(stderr, "fatal(0x%016"PRIXMAX", 0x%016"PRIXMAX", 0x%016"PRIXMAX", 0x%016"PRIXMAX")@%d: %s, errno=%d: %s\n", p1, p2, p3, p4, line, str, errno, strerror(errno)); | |
exit(EXIT_FAILURE); | |
} | |
void convert_bgrx_rgbx(char *buffer, int pixels) { | |
int i = 0; | |
char t; | |
for(i = 0; i < pixels; i++, buffer+=4) { | |
t = *(buffer+2); | |
*(buffer+2) = *buffer; | |
*buffer = t; | |
} | |
} | |
void keyproc(rfbBool down, rfbKeySym keySym, struct _rfbClientRec *cl) { | |
printf("%"PRIX8" %08"PRIX32"\n", down, keySym); | |
//sem_post(trigger_update); | |
} | |
void fb_proc_update(rfbScreenInfoPtr server, char *fb_prev, int resx, int resy/*, struct timespec* time_round*/) { | |
int blkx, blky, bx_s, by_s, bx_e, by_e, bresx, bresy, bx, by, gbx, gby, bdiff; | |
uint32_t *pfb, *pfb_prev; | |
pfb = (uint32_t*)server->frameBuffer; | |
pfb_prev = (uint32_t*)fb_prev; | |
bresx = resx / 8; | |
bresy = resy / 8; | |
for(blky = 0; blky < 8; blky++) { | |
gby = blky * bresy; | |
for(blkx = 0; blkx < 8; blkx++) { | |
gbx = blkx * bresx; | |
bx_s = bresx; bx_e = 0; | |
by_s = bresy; by_e = 0; | |
bdiff = 0; | |
for(by = 0; by < bresy; by++) { | |
if(!(memcmp(pfb + (gby+by)*resx + gbx, pfb_prev + (gby+by)*resx + gbx, bresx*4))) continue; | |
bdiff = 1; | |
for(bx = 0; bx < bx_s; bx++) { | |
if((*(pfb + (gby+by)*resx + gbx+bx)) != (*(pfb_prev + (gby+by)*resx + gbx+bx))) { | |
bx_s = bx; | |
if(bx_e < bx_s) bx_e = bx_s; | |
break; | |
} | |
} | |
for(bx = bx_e; bx < bresx; bx++) { | |
if((*(pfb + (gby+by)*resx + gbx+bx)) != (*(pfb_prev + (gby+by)*resx + gbx+bx))) { | |
bx_e = bx; | |
} | |
} | |
if(by < by_s) by_s = by; | |
if(by > by_e) by_e = by; | |
} | |
if(bdiff) { | |
//printf("[%3ld]blksearch[%d, %d]: [%4d, %-4d] -> [%4d, %-4d]\n", time_round->tv_nsec/1000000, blkx, blky, gbx+bx_s,gby+by_s,gbx+bx_e+1,gby+by_e+1); | |
rfbMarkRectAsModified(server,gbx+bx_s,gby+by_s,gbx+bx_e+1,gby+by_e+1); | |
} | |
} | |
} | |
} | |
int main(int argc, char **argv) { | |
char *fbdev = "/dev/fb0"; | |
struct fb_fix_screeninfo fb_fixinfo; | |
struct fb_var_screeninfo fb_varinfo; | |
struct timespec sem_timeout; | |
//struct timespec ts_action; | |
rfbScreenInfoPtr server; | |
//pthread_mutexattr_t lock_attr; | |
int ret, fbsize; | |
int fd = -1; | |
char *fb_prev = NULL; | |
char cursor[] = " "; | |
trigger_update = (sem_t*) malloc(sizeof(sem_t)); | |
if(!trigger_update) | |
fatal("malloc", __LINE__, sizeof(sem_t), 0, 0, 0); | |
/*fb_lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); | |
if(!fb_lock) | |
fatal("malloc", __LINE__, sizeof(pthread_mutex_t), 0, 0, 0);*/ | |
if((ret = sem_init(trigger_update, 0, 0)) != 0) | |
fatal("sem_init", __LINE__, ret, (uintmax_t)trigger_update, 0, 0); | |
/*if((ret = pthread_mutexattr_init(&lock_attr)) != 0) | |
fatal("pthread_mutexattr_init", __LINE__, ret, (uintmax_t)&lock_attr, 0, 0); | |
if((ret = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) | |
fatal("pthread_mutexattr_settype", __LINE__, ret, (uintmax_t)&lock_attr, PTHREAD_MUTEX_ERRORCHECK, 0); | |
if((ret = pthread_mutex_init(fb_lock, &lock_attr)) != 0) | |
fatal("pthread_mutex_init", __LINE__, ret, (uintmax_t)fb_lock, (uintmax_t)&lock_attr, 0);*/ | |
fd = open(fbdev, O_RDONLY); | |
if(fd == -1) fatal("Open device", __LINE__, fd, 0, 0, 0); | |
if(ioctl(fd, FBIOGET_VSCREENINFO, &fb_varinfo) != 0) | |
fatal("FBIOGET_VSCREENINFO", __LINE__, fd, 0, 0, 0); | |
if(ioctl(fd, FBIOGET_FSCREENINFO, &fb_fixinfo) != 0) | |
fatal("FBIOGET_FSCREENINFO", __LINE__, fd, 0, 0, 0); | |
close(fd); fd = -1; | |
printf("DEV=%-16.16s ID=%-16.16s res=%5dx%-5d\n", fbdev, fb_fixinfo.id, fb_varinfo.xres, fb_varinfo.yres); | |
printf("bpp=%2d grayscale=%08X nonstd=%d\n", fb_varinfo.bits_per_pixel, fb_varinfo.grayscale, fb_varinfo.nonstd); | |
printf("r.offset=%2d r.length=%2d r.msb_right=%d\n", fb_varinfo.red.offset, fb_varinfo.red.length, fb_varinfo.red.msb_right); | |
printf("g.offset=%2d g.length=%2d g.msb_right=%d\n", fb_varinfo.green.offset, fb_varinfo.green.length, fb_varinfo.green.msb_right); | |
printf("b.offset=%2d b.length=%2d b.msb_right=%d\n", fb_varinfo.blue.offset, fb_varinfo.blue.length, fb_varinfo.blue.msb_right); | |
printf("a.offset=%2d a.length=%2d a.msb_right=%d\n", fb_varinfo.transp.offset, fb_varinfo.transp.length, fb_varinfo.transp.msb_right); | |
if( | |
fb_varinfo.nonstd == 0 && fb_varinfo.grayscale == 0 && fb_varinfo.bits_per_pixel == 32 | |
&& fb_varinfo.transp.msb_right == 0 && fb_varinfo.blue.msb_right == 0 && fb_varinfo.green.msb_right == 0 && fb_varinfo.red.msb_right == 0 | |
&& fb_varinfo.red.offset == 16 && fb_varinfo.green.offset == 8 && fb_varinfo.blue.offset == 0 | |
&& fb_varinfo.red.length == 8 && fb_varinfo.green.length == 8 && fb_varinfo.blue.length == 8 | |
) { | |
fb_convert = convert_bgrx_rgbx; | |
} | |
if(fb_convert == NULL) | |
fatal("fb_convert", __LINE__, 0, 0, 0, 0); | |
server = rfbGetScreen(&argc, argv, fb_varinfo.xres, fb_varinfo.yres, 8, 3, 4); | |
if(server == 0) | |
fatal("rfbGetScreen", __LINE__, fb_varinfo.xres, fb_varinfo.yres, 0, 0); | |
fbsize = fb_varinfo.xres*fb_varinfo.yres*4; | |
server->desktopName = fbdev; | |
server->frameBuffer = (char*) malloc(fb_varinfo.xres*fb_varinfo.yres*4); | |
if(!server->frameBuffer) | |
fatal("malloc", __LINE__, fbsize, 0, 0, 0); | |
fb_prev = (char*) malloc(fb_varinfo.xres*fb_varinfo.yres*4); | |
if(!fb_prev) | |
fatal("malloc", __LINE__, fbsize, 0, 0, 0); | |
server->kbdAddEvent = keyproc; | |
server->cursor = rfbMakeXCursor(1, 1, cursor, cursor); | |
rfbInitServer(server); | |
rfbRunEventLoop(server,-1,TRUE); | |
clock_gettime(CLOCK_REALTIME, &sem_timeout); | |
while(1) { | |
sem_timeout.tv_nsec += 200000000; //minimum 5fps | |
if(sem_timeout.tv_nsec > 999999999) { | |
sem_timeout.tv_nsec -= 1000000000; | |
sem_timeout.tv_sec++; | |
} | |
ret = sem_timedwait(trigger_update, &sem_timeout); | |
if((ret != 0) && (errno != ETIMEDOUT)) | |
fatal("sem_timedwait", __LINE__, (uintmax_t)trigger_update, sem_timeout.tv_sec, sem_timeout.tv_nsec, 0); | |
memcpy(fb_prev, server->frameBuffer, fbsize); | |
fd = open(fbdev, O_RDONLY); | |
if(fd == -1) fatal("open", __LINE__, (uintmax_t)fbdev, O_RDONLY, 0, 0); | |
if((ret = read(fd, server->frameBuffer, fbsize)) != fbsize) | |
fatal("read", __LINE__, fd, (uintmax_t)server->frameBuffer, fbsize, ret); | |
close(fd); fd = -1; | |
//printf("SEM TS=%11"PRId64".%09"PRId32"\n", (int64_t)sem_timeout.tv_sec, (int32_t)sem_timeout.tv_nsec); | |
//clock_gettime(CLOCK_REALTIME, &ts_action); | |
//printf("READ TS=%11"PRId64".%09"PRId32"\n", (int64_t)ts_action.tv_sec, (int32_t)ts_action.tv_nsec); | |
fb_convert(server->frameBuffer, fbsize/4); | |
//clock_gettime(CLOCK_REALTIME, &ts_action); | |
//printf("CONV TS=%11"PRId64".%09"PRId32"\n", (int64_t)ts_action.tv_sec, (int32_t)ts_action.tv_nsec); | |
fb_proc_update(server, fb_prev, fb_varinfo.xres, fb_varinfo.yres/*, &ts_action*/); | |
//clock_gettime(CLOCK_REALTIME, &ts_action); | |
//printf("PROC TS=%11"PRId64".%09"PRId32"\n\n", (int64_t)ts_action.tv_sec, (int32_t)ts_action.tv_nsec); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment