doorbell
changeset 5:f21ae31ef0e7
craptacular
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 15 Mar 2016 08:35:21 +0200 |
parents | 08ea0abdbb8a |
children | 026156ea8801 |
files | .hgignore doorbell-client/Makefile doorbell-client/src/main.c doorbelld/Makefile doorbelld/src/main.c doorbelld/src/srv.c |
diffstat | 6 files changed, 290 insertions(+), 6 deletions(-) [+] |
line diff
1.1 --- a/.hgignore Mon Mar 14 04:20:59 2016 +0200 1.2 +++ b/.hgignore Tue Mar 15 08:35:21 2016 +0200 1.3 @@ -3,4 +3,5 @@ 1.4 \.swp$ 1.5 spycam$ 1.6 doorbelld$ 1.7 +doorbell$ 1.8 \.ppm$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/doorbell-client/Makefile Tue Mar 15 08:35:21 2016 +0200 2.3 @@ -0,0 +1,20 @@ 2.4 +src = $(wildcard src/*.c) 2.5 +obj = $(src:.c=.o) 2.6 +bin = doorbell 2.7 + 2.8 +CFLAGS = -pedantic -Wall -g 2.9 +LDFLAGS = -lGL -lGLU -lglut 2.10 + 2.11 +.PHONY: all 2.12 +all: .clang_complete $(bin) 2.13 + 2.14 +$(bin): $(obj) 2.15 + $(CC) -o $@ $(obj) $(LDFLAGS) 2.16 + 2.17 +.clang_complete: 2.18 + echo '-x c' >$@ 2.19 + for i in $(CFLAGS); do echo $$i >>$@; done 2.20 + 2.21 +.PHONY: clean 2.22 +clean: 2.23 + rm -f $(obj) $(bin)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/doorbell-client/src/main.c Tue Mar 15 08:35:21 2016 +0200 3.3 @@ -0,0 +1,216 @@ 3.4 +#include <stdio.h> 3.5 +#include <stdlib.h> 3.6 +#include <string.h> 3.7 +#include <errno.h> 3.8 +#include <unistd.h> 3.9 +#include <fcntl.h> 3.10 +#include <sys/select.h> 3.11 +#include <sys/socket.h> 3.12 +#include <arpa/inet.h> 3.13 +#include <netdb.h> 3.14 +#include <GL/glut.h> 3.15 +#include <GL/freeglut_ext.h> 3.16 +#include <GL/glx.h> 3.17 + 3.18 +struct video_block_header { 3.19 + unsigned int magic; 3.20 + int frame; 3.21 + int x, y; 3.22 + int width, height; 3.23 + int frame_width, frame_height; 3.24 +}; 3.25 + 3.26 +int conn(const char *host, int port); 3.27 +void display(void); 3.28 +void reshape(int x, int y); 3.29 +void keyb(unsigned char key, int x, int y); 3.30 +int handle_conn(int s); 3.31 +void post_redisplay(void); 3.32 + 3.33 +int quit; 3.34 +int srvsock; 3.35 +const char *address = "localhost"; 3.36 +int port = 2828; 3.37 +unsigned int tex, tex_width, tex_height; 3.38 +int redraw_pending; 3.39 + 3.40 +int main(int argc, char **argv) 3.41 +{ 3.42 + Display *dpy; 3.43 + int xsock; 3.44 + 3.45 + glutInit(&argc, argv); 3.46 + glutInitWindowSize(800, 600); 3.47 + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 3.48 + glutCreateWindow("doorbell"); 3.49 + 3.50 + glutDisplayFunc(display); 3.51 + glutReshapeFunc(reshape); 3.52 + glutKeyboardFunc(keyb); 3.53 + 3.54 + dpy = glXGetCurrentDisplay(); 3.55 + xsock = ConnectionNumber(dpy); 3.56 + 3.57 + if((srvsock = conn(address, port)) == -1) { 3.58 + return 1; 3.59 + } 3.60 + write(srvsock, "hello", 5); 3.61 + 3.62 + glGenTextures(1, &tex); 3.63 + glBindTexture(GL_TEXTURE_2D, tex); 3.64 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 3.65 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 3.66 + 3.67 + for(;;) { 3.68 + int res; 3.69 + int maxfd = srvsock > xsock ? srvsock : xsock; 3.70 + struct timeval tv0 = {0, 0}; 3.71 + fd_set rdset; 3.72 + 3.73 + FD_ZERO(&rdset); 3.74 + FD_SET(xsock, &rdset); 3.75 + FD_SET(srvsock, &rdset); 3.76 + 3.77 + while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR); 3.78 + if(res == -1) break; 3.79 + 3.80 + if(redraw_pending || FD_ISSET(xsock, &rdset)) { 3.81 + glutMainLoopEvent(); 3.82 + if(quit) { 3.83 + break; 3.84 + } 3.85 + } 3.86 + if(FD_ISSET(srvsock, &rdset)) { 3.87 + if(handle_conn(srvsock) == -1) { 3.88 + break; 3.89 + } 3.90 + } 3.91 + } 3.92 + 3.93 + close(srvsock); 3.94 + return 0; 3.95 +} 3.96 + 3.97 + 3.98 +int conn(const char *hostname, int port) 3.99 +{ 3.100 + int s; 3.101 + struct sockaddr_in addr; 3.102 + struct hostent *host; 3.103 + 3.104 + if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 3.105 + fprintf(stderr, "failed to create socket\n"); 3.106 + return -1; 3.107 + } 3.108 + 3.109 + if(!(host = gethostbyname(hostname))) { 3.110 + fprintf(stderr, "failed to resolve hostname: %s\n", hostname); 3.111 + return -1; 3.112 + } 3.113 + 3.114 + memset(&addr, 0, sizeof addr); 3.115 + addr.sin_family = AF_INET; 3.116 + addr.sin_port = htons(port); 3.117 + addr.sin_addr = *(struct in_addr*)host->h_addr; 3.118 + 3.119 + printf("connecting to %s (%s), port %d\n", hostname, inet_ntoa(addr.sin_addr), port); 3.120 + if(connect(s, (struct sockaddr*)&addr, sizeof addr) == -1) { 3.121 + fprintf(stderr, "failed to connect\n"); 3.122 + return -1; 3.123 + } 3.124 + 3.125 + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); 3.126 + return s; 3.127 +} 3.128 + 3.129 +void display(void) 3.130 +{ 3.131 + redraw_pending = 0; 3.132 + 3.133 + glClear(GL_COLOR_BUFFER_BIT); 3.134 + 3.135 + glMatrixMode(GL_MODELVIEW); 3.136 + glLoadIdentity(); 3.137 + 3.138 + glPushMatrix(); 3.139 + glScalef(0.75, 0.75, 0.75); 3.140 + 3.141 + glBindTexture(GL_TEXTURE_2D, tex); 3.142 + glEnable(GL_TEXTURE_2D); 3.143 + 3.144 + glBegin(GL_QUADS); 3.145 + glTexCoord2f(0, 0); glVertex2f(-1, -1); 3.146 + glTexCoord2f(1, 0); glVertex2f(1, -1); 3.147 + glTexCoord2f(1, 1); glVertex2f(1, 1); 3.148 + glTexCoord2f(0, 1); glVertex2f(-1, 1); 3.149 + glEnd(); 3.150 + 3.151 + glDisable(GL_TEXTURE_2D); 3.152 + glPopMatrix(); 3.153 + 3.154 + glutSwapBuffers(); 3.155 +} 3.156 + 3.157 +void reshape(int x, int y) 3.158 +{ 3.159 + glViewport(0, 0, x, y); 3.160 + glMatrixMode(GL_PROJECTION); 3.161 + glLoadIdentity(); 3.162 +} 3.163 + 3.164 +void keyb(unsigned char key, int x, int y) 3.165 +{ 3.166 + switch(key) { 3.167 + case 27: 3.168 + quit = 1; 3.169 + break; 3.170 + } 3.171 +} 3.172 + 3.173 +int handle_conn(int s) 3.174 +{ 3.175 + static int cur_frame; 3.176 + struct video_block_header hdr; 3.177 + int size; 3.178 + unsigned char *pixels; 3.179 + 3.180 + if(read(s, &hdr, sizeof hdr) != sizeof hdr) { 3.181 + fprintf(stderr, "failed to read video block header\n"); 3.182 + return -1; 3.183 + } 3.184 + if(hdr.frame < cur_frame) { 3.185 + printf("skipping old frame %d\n", hdr.frame); 3.186 + } 3.187 + cur_frame = hdr.frame; 3.188 + printf("updating block %dx%d%+d%+d in frame %d\n", hdr.width, hdr.height, hdr.x, hdr.y, hdr.frame); 3.189 + 3.190 + size = hdr.width * hdr.height * 2; 3.191 + if(!(pixels = malloc(size))) { 3.192 + fprintf(stderr, "failed to allocate pixel block %dx%d\n", hdr.width, hdr.height); 3.193 + return -1; 3.194 + } 3.195 + if(read(s, pixels, size) != size) { 3.196 + fprintf(stderr, "failed to read pixel block\n"); 3.197 + return -1; 3.198 + } 3.199 + 3.200 + glBindTexture(GL_TEXTURE_2D, tex); 3.201 + 3.202 + if(tex_width < hdr.frame_width || tex_height < hdr.frame_height) { 3.203 + tex_width = hdr.frame_width; 3.204 + tex_height = hdr.frame_height; 3.205 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, 3.206 + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); 3.207 + } 3.208 + glTexSubImage2D(GL_TEXTURE_2D, 0, hdr.x, hdr.y, hdr.width, hdr.height, 3.209 + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels); 3.210 + 3.211 + post_redisplay(); 3.212 + return 0; 3.213 +} 3.214 + 3.215 +void post_redisplay(void) 3.216 +{ 3.217 + glutPostRedisplay(); 3.218 + redraw_pending = 1; 3.219 +}
4.1 --- a/doorbelld/Makefile Mon Mar 14 04:20:59 2016 +0200 4.2 +++ b/doorbelld/Makefile Tue Mar 15 08:35:21 2016 +0200 4.3 @@ -5,9 +5,16 @@ 4.4 CFLAGS = -pedantic -Wall -g 4.5 LDFLAGS = -lwcam -lpthread 4.6 4.7 +.PHONY: all 4.8 +all: .clang_complete $(bin) 4.9 + 4.10 $(bin): $(obj) 4.11 $(CC) -o $@ $(obj) $(LDFLAGS) 4.12 4.13 +.clang_complete: 4.14 + echo '-x c' >$@ 4.15 + for i in $(CFLAGS); do echo $$i >>$@; done 4.16 + 4.17 .PHONY: clean 4.18 clean: 4.19 rm -f $(obj) $(bin)
5.1 --- a/doorbelld/src/main.c Mon Mar 14 04:20:59 2016 +0200 5.2 +++ b/doorbelld/src/main.c Tue Mar 15 08:35:21 2016 +0200 5.3 @@ -64,7 +64,6 @@ 5.4 } 5.5 } 5.6 printf("serving test pattern\n"); 5.7 - save_image("output.ppm", frame, width, height); 5.8 } 5.9 5.10 if(pthread_create(&thread, 0, frame_proc, 0) == -1) { 5.11 @@ -112,6 +111,12 @@ 5.12 for(i=0; i<num_sockets; i++) { 5.13 if(FD_ISSET(sock[i], &rdset)) { 5.14 srv_handle(sock[i]); 5.15 + if(fd == -1) { 5.16 + pthread_mutex_lock(&mutex); 5.17 + frame_available = 1; 5.18 + pthread_mutex_unlock(&mutex); 5.19 + pthread_cond_signal(&condvar); 5.20 + } 5.21 } 5.22 } 5.23 } 5.24 @@ -141,8 +146,9 @@ 5.25 5.26 if(fd != -1) { 5.27 wcam_read_frame_rgb(fd, frame); 5.28 - save_image("output.ppm", frame, width, height); 5.29 + /*save_image("output.ppm", frame, width, height);*/ 5.30 } 5.31 + srv_send_frame(frame, width, height); 5.32 } 5.33 return 0; 5.34 }
6.1 --- a/doorbelld/src/srv.c Mon Mar 14 04:20:59 2016 +0200 6.2 +++ b/doorbelld/src/srv.c Tue Mar 15 08:35:21 2016 +0200 6.3 @@ -1,6 +1,8 @@ 6.4 #include <stdio.h> 6.5 #include <stdlib.h> 6.6 #include <string.h> 6.7 +#include <stddef.h> 6.8 +#include <stdint.h> 6.9 #include <errno.h> 6.10 #include <assert.h> 6.11 #include <unistd.h> 6.12 @@ -35,7 +37,7 @@ 6.13 csock[0] = lis_sock; 6.14 max_socket = lis_sock; 6.15 6.16 - fcntl(lis_sock, F_SETFD, fcntl(lis_sock, F_GETFD) | O_NONBLOCK); 6.17 + fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK); 6.18 6.19 memset(&addr, 0, sizeof addr); 6.20 addr.sin_family = AF_INET; 6.21 @@ -99,7 +101,7 @@ 6.22 if(s > max_socket) { 6.23 max_socket = s; 6.24 } 6.25 - fcntl(s, F_SETFD, fcntl(s, F_GETFD) | O_NONBLOCK); 6.26 + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); 6.27 return 0; 6.28 } 6.29 6.30 @@ -129,22 +131,54 @@ 6.31 } 6.32 6.33 struct video_block { 6.34 + unsigned int magic; 6.35 int frame; 6.36 int x, y; 6.37 int width, height; 6.38 + int frame_width, frame_height; 6.39 char pixels[1]; 6.40 }; 6.41 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels)) 6.42 6.43 void srv_send_frame(unsigned char *frame, int xsz, int ysz) 6.44 { 6.45 + static int frame_num; 6.46 static unsigned char *buffer; 6.47 + int i, j, size, num_clients; 6.48 struct video_block *vblock; 6.49 + uint16_t *dest; 6.50 + 6.51 + printf("sending frame\n"); 6.52 6.53 /* for now just send a big block */ 6.54 - if(!buffer && !(buffer = malloc(xsz * ysz * 2) + VBLOCK_HEADER_SIZE)) { 6.55 + size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE; 6.56 + if(!buffer && !(buffer = malloc(size))) { 6.57 fprintf(stderr, "failed to allocate frame send buffer\n"); 6.58 return; 6.59 } 6.60 - vblock = buffer; 6.61 + vblock = (struct video_block*)buffer; 6.62 + 6.63 + vblock->magic = 0x12341234; 6.64 + vblock->frame = frame_num++; 6.65 + vblock->x = vblock->y = 0; 6.66 + vblock->width = vblock->frame_width = xsz; 6.67 + vblock->height = vblock->frame_height = ysz; 6.68 + 6.69 + dest = (uint16_t*)vblock->pixels; 6.70 + 6.71 + for(i=0; i<ysz; i++) { 6.72 + for(j=0; j<xsz; j++) { 6.73 + unsigned int r = frame[0]; 6.74 + unsigned int g = frame[1]; 6.75 + unsigned int b = frame[2]; 6.76 + 6.77 + *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f); 6.78 + frame += 4; 6.79 + } 6.80 + } 6.81 + 6.82 + num_clients = dynarr_size(csock); 6.83 + for(i=1; i<num_clients; i++) { /* first socket is the listening socket */ 6.84 + write(csock[i], buffer, size); 6.85 + } 6.86 }