# HG changeset patch # User John Tsiombikas # Date 1458023721 -7200 # Node ID f21ae31ef0e763a6db6ff829d9be735514b52ab2 # Parent 08ea0abdbb8aadaf4626cfb4f08ed9b2ee515caa craptacular diff -r 08ea0abdbb8a -r f21ae31ef0e7 .hgignore --- a/.hgignore Mon Mar 14 04:20:59 2016 +0200 +++ b/.hgignore Tue Mar 15 08:35:21 2016 +0200 @@ -3,4 +3,5 @@ \.swp$ spycam$ doorbelld$ +doorbell$ \.ppm$ diff -r 08ea0abdbb8a -r f21ae31ef0e7 doorbell-client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doorbell-client/Makefile Tue Mar 15 08:35:21 2016 +0200 @@ -0,0 +1,20 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +bin = doorbell + +CFLAGS = -pedantic -Wall -g +LDFLAGS = -lGL -lGLU -lglut + +.PHONY: all +all: .clang_complete $(bin) + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.clang_complete: + echo '-x c' >$@ + for i in $(CFLAGS); do echo $$i >>$@; done + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 08ea0abdbb8a -r f21ae31ef0e7 doorbell-client/src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doorbell-client/src/main.c Tue Mar 15 08:35:21 2016 +0200 @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct video_block_header { + unsigned int magic; + int frame; + int x, y; + int width, height; + int frame_width, frame_height; +}; + +int conn(const char *host, int port); +void display(void); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); +int handle_conn(int s); +void post_redisplay(void); + +int quit; +int srvsock; +const char *address = "localhost"; +int port = 2828; +unsigned int tex, tex_width, tex_height; +int redraw_pending; + +int main(int argc, char **argv) +{ + Display *dpy; + int xsock; + + glutInit(&argc, argv); + glutInitWindowSize(800, 600); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("doorbell"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + + dpy = glXGetCurrentDisplay(); + xsock = ConnectionNumber(dpy); + + if((srvsock = conn(address, port)) == -1) { + return 1; + } + write(srvsock, "hello", 5); + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + for(;;) { + int res; + int maxfd = srvsock > xsock ? srvsock : xsock; + struct timeval tv0 = {0, 0}; + fd_set rdset; + + FD_ZERO(&rdset); + FD_SET(xsock, &rdset); + FD_SET(srvsock, &rdset); + + while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR); + if(res == -1) break; + + if(redraw_pending || FD_ISSET(xsock, &rdset)) { + glutMainLoopEvent(); + if(quit) { + break; + } + } + if(FD_ISSET(srvsock, &rdset)) { + if(handle_conn(srvsock) == -1) { + break; + } + } + } + + close(srvsock); + return 0; +} + + +int conn(const char *hostname, int port) +{ + int s; + struct sockaddr_in addr; + struct hostent *host; + + if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "failed to create socket\n"); + return -1; + } + + if(!(host = gethostbyname(hostname))) { + fprintf(stderr, "failed to resolve hostname: %s\n", hostname); + return -1; + } + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *(struct in_addr*)host->h_addr; + + printf("connecting to %s (%s), port %d\n", hostname, inet_ntoa(addr.sin_addr), port); + if(connect(s, (struct sockaddr*)&addr, sizeof addr) == -1) { + fprintf(stderr, "failed to connect\n"); + return -1; + } + + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); + return s; +} + +void display(void) +{ + redraw_pending = 0; + + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPushMatrix(); + glScalef(0.75, 0.75, 0.75); + + glBindTexture(GL_TEXTURE_2D, tex); + glEnable(GL_TEXTURE_2D); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(-1, -1); + glTexCoord2f(1, 0); glVertex2f(1, -1); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(-1, 1); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + + glutSwapBuffers(); +} + +void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); +} + +void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 27: + quit = 1; + break; + } +} + +int handle_conn(int s) +{ + static int cur_frame; + struct video_block_header hdr; + int size; + unsigned char *pixels; + + if(read(s, &hdr, sizeof hdr) != sizeof hdr) { + fprintf(stderr, "failed to read video block header\n"); + return -1; + } + if(hdr.frame < cur_frame) { + printf("skipping old frame %d\n", hdr.frame); + } + cur_frame = hdr.frame; + printf("updating block %dx%d%+d%+d in frame %d\n", hdr.width, hdr.height, hdr.x, hdr.y, hdr.frame); + + size = hdr.width * hdr.height * 2; + if(!(pixels = malloc(size))) { + fprintf(stderr, "failed to allocate pixel block %dx%d\n", hdr.width, hdr.height); + return -1; + } + if(read(s, pixels, size) != size) { + fprintf(stderr, "failed to read pixel block\n"); + return -1; + } + + glBindTexture(GL_TEXTURE_2D, tex); + + if(tex_width < hdr.frame_width || tex_height < hdr.frame_height) { + tex_width = hdr.frame_width; + tex_height = hdr.frame_height; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, hdr.x, hdr.y, hdr.width, hdr.height, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels); + + post_redisplay(); + return 0; +} + +void post_redisplay(void) +{ + glutPostRedisplay(); + redraw_pending = 1; +} diff -r 08ea0abdbb8a -r f21ae31ef0e7 doorbelld/Makefile --- a/doorbelld/Makefile Mon Mar 14 04:20:59 2016 +0200 +++ b/doorbelld/Makefile Tue Mar 15 08:35:21 2016 +0200 @@ -5,9 +5,16 @@ CFLAGS = -pedantic -Wall -g LDFLAGS = -lwcam -lpthread +.PHONY: all +all: .clang_complete $(bin) + $(bin): $(obj) $(CC) -o $@ $(obj) $(LDFLAGS) +.clang_complete: + echo '-x c' >$@ + for i in $(CFLAGS); do echo $$i >>$@; done + .PHONY: clean clean: rm -f $(obj) $(bin) diff -r 08ea0abdbb8a -r f21ae31ef0e7 doorbelld/src/main.c --- a/doorbelld/src/main.c Mon Mar 14 04:20:59 2016 +0200 +++ b/doorbelld/src/main.c Tue Mar 15 08:35:21 2016 +0200 @@ -64,7 +64,6 @@ } } printf("serving test pattern\n"); - save_image("output.ppm", frame, width, height); } if(pthread_create(&thread, 0, frame_proc, 0) == -1) { @@ -112,6 +111,12 @@ for(i=0; i #include #include +#include +#include #include #include #include @@ -35,7 +37,7 @@ csock[0] = lis_sock; max_socket = lis_sock; - fcntl(lis_sock, F_SETFD, fcntl(lis_sock, F_GETFD) | O_NONBLOCK); + fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK); memset(&addr, 0, sizeof addr); addr.sin_family = AF_INET; @@ -99,7 +101,7 @@ if(s > max_socket) { max_socket = s; } - fcntl(s, F_SETFD, fcntl(s, F_GETFD) | O_NONBLOCK); + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); return 0; } @@ -129,22 +131,54 @@ } struct video_block { + unsigned int magic; int frame; int x, y; int width, height; + int frame_width, frame_height; char pixels[1]; }; #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels)) void srv_send_frame(unsigned char *frame, int xsz, int ysz) { + static int frame_num; static unsigned char *buffer; + int i, j, size, num_clients; struct video_block *vblock; + uint16_t *dest; + + printf("sending frame\n"); /* for now just send a big block */ - if(!buffer && !(buffer = malloc(xsz * ysz * 2) + VBLOCK_HEADER_SIZE)) { + size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE; + if(!buffer && !(buffer = malloc(size))) { fprintf(stderr, "failed to allocate frame send buffer\n"); return; } - vblock = buffer; + vblock = (struct video_block*)buffer; + + vblock->magic = 0x12341234; + vblock->frame = frame_num++; + vblock->x = vblock->y = 0; + vblock->width = vblock->frame_width = xsz; + vblock->height = vblock->frame_height = ysz; + + dest = (uint16_t*)vblock->pixels; + + for(i=0; i> 3) & 0x1f); + frame += 4; + } + } + + num_clients = dynarr_size(csock); + for(i=1; i