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  }