doorbell

changeset 7:dc4018af3a40 tip

video broadcast with UDP. retarded amount of data, unusable.
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 16 Mar 2016 02:50:30 +0200
parents 026156ea8801
children
files doorbell-client/src/main.c doorbelld/src/main.c doorbelld/src/srv.c doorbelld/src/srv.h
diffstat 4 files changed, 143 insertions(+), 87 deletions(-) [+]
line diff
     1.1 --- a/doorbell-client/src/main.c	Wed Mar 16 00:00:06 2016 +0200
     1.2 +++ b/doorbell-client/src/main.c	Wed Mar 16 02:50:30 2016 +0200
     1.3 @@ -1,6 +1,7 @@
     1.4  #include <stdio.h>
     1.5  #include <stdlib.h>
     1.6  #include <string.h>
     1.7 +#include <stdint.h>
     1.8  #include <errno.h>
     1.9  #include <unistd.h>
    1.10  #include <fcntl.h>
    1.11 @@ -12,12 +13,12 @@
    1.12  #include <GL/freeglut_ext.h>
    1.13  #include <GL/glx.h>
    1.14  
    1.15 -struct video_block_header {
    1.16 -	unsigned int magic;
    1.17 +struct video_block {
    1.18  	int frame;
    1.19 -	int x, y;
    1.20 -	int width, height;
    1.21 -	int frame_width, frame_height;
    1.22 +	uint16_t x, y;
    1.23 +	uint16_t width, height;
    1.24 +	uint16_t frame_width, frame_height;
    1.25 +	uint16_t pixels[1];
    1.26  };
    1.27  
    1.28  int conn(const char *host, int port);
    1.29 @@ -25,15 +26,18 @@
    1.30  void reshape(int x, int y);
    1.31  void keyb(unsigned char key, int x, int y);
    1.32  int handle_conn(int s);
    1.33 +int handle_video(int s);
    1.34  void post_redisplay(void);
    1.35  
    1.36  int quit;
    1.37 -int srvsock;
    1.38 +int ctlsock, vidsock;
    1.39  const char *address = "localhost";
    1.40  int port = 2828;
    1.41  unsigned int tex, tex_width, tex_height;
    1.42  int redraw_pending;
    1.43  
    1.44 +#define MAX(a, b)	((a) > (b) ? (a) : (b))
    1.45 +
    1.46  int main(int argc, char **argv)
    1.47  {
    1.48  	Display *dpy;
    1.49 @@ -51,10 +55,10 @@
    1.50  	dpy = glXGetCurrentDisplay();
    1.51  	xsock = ConnectionNumber(dpy);
    1.52  
    1.53 -	if((srvsock = conn(address, port)) == -1) {
    1.54 +	if(conn(address, port) == -1) {
    1.55  		return 1;
    1.56  	}
    1.57 -	write(srvsock, "hello", 5);
    1.58 +	write(ctlsock, "hello", 5);
    1.59  
    1.60  	glGenTextures(1, &tex);
    1.61  	glBindTexture(GL_TEXTURE_2D, tex);
    1.62 @@ -62,15 +66,16 @@
    1.63  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    1.64  
    1.65  	for(;;) {
    1.66 -		int res;
    1.67 -		int maxfd = srvsock > xsock ? srvsock : xsock;
    1.68 +		int res, maxfd;
    1.69  		struct timeval tv0 = {0, 0};
    1.70  		fd_set rdset;
    1.71  
    1.72  		FD_ZERO(&rdset);
    1.73  		FD_SET(xsock, &rdset);
    1.74 -		FD_SET(srvsock, &rdset);
    1.75 +		FD_SET(ctlsock, &rdset);
    1.76 +		FD_SET(vidsock, &rdset);
    1.77  
    1.78 +		maxfd = MAX(MAX(xsock, ctlsock), vidsock);
    1.79  		while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR);
    1.80  		if(res == -1) break;
    1.81  
    1.82 @@ -80,25 +85,29 @@
    1.83  				break;
    1.84  			}
    1.85  		}
    1.86 -		if(FD_ISSET(srvsock, &rdset)) {
    1.87 -			if(handle_conn(srvsock) == -1) {
    1.88 +		if(FD_ISSET(ctlsock, &rdset)) {
    1.89 +			if(handle_conn(ctlsock) == -1) {
    1.90 +				break;
    1.91 +			}
    1.92 +		}
    1.93 +		if(FD_ISSET(vidsock, &rdset)) {
    1.94 +			if(handle_video(vidsock) == -1) {
    1.95  				break;
    1.96  			}
    1.97  		}
    1.98  	}
    1.99  
   1.100 -	close(srvsock);
   1.101 +	close(ctlsock);
   1.102  	return 0;
   1.103  }
   1.104  
   1.105  
   1.106  int conn(const char *hostname, int port)
   1.107  {
   1.108 -	int s;
   1.109  	struct sockaddr_in addr;
   1.110  	struct hostent *host;
   1.111  
   1.112 -	if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
   1.113 +	if((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
   1.114  		fprintf(stderr, "failed to create socket\n");
   1.115  		return -1;
   1.116  	}
   1.117 @@ -114,13 +123,28 @@
   1.118  	addr.sin_addr = *(struct in_addr*)host->h_addr;
   1.119  
   1.120  	printf("connecting to %s (%s), port %d\n", hostname, inet_ntoa(addr.sin_addr), port);
   1.121 -	if(connect(s, (struct sockaddr*)&addr, sizeof addr) == -1) {
   1.122 +	if(connect(ctlsock, (struct sockaddr*)&addr, sizeof addr) == -1) {
   1.123  		fprintf(stderr, "failed to connect\n");
   1.124  		return -1;
   1.125  	}
   1.126 +	fcntl(ctlsock, F_SETFL, fcntl(ctlsock, F_GETFL) | O_NONBLOCK);
   1.127  
   1.128 -	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
   1.129 -	return s;
   1.130 +	/* prepare the video socket */
   1.131 +	if((vidsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
   1.132 +		fprintf(stderr, "failed to create video socket\n");
   1.133 +		return 1;
   1.134 +	}
   1.135 +
   1.136 +	memset(&addr, 0, sizeof addr);
   1.137 +	addr.sin_family = AF_INET;
   1.138 +	addr.sin_port = htons(port + 1);
   1.139 +	addr.sin_addr.s_addr = htonl(INADDR_ANY);
   1.140 +	if(bind(vidsock, (struct sockaddr*)&addr, sizeof addr) == -1) {
   1.141 +		fprintf(stderr, "failed to bind video socket to port %d\n", port + 1);
   1.142 +		return 1;
   1.143 +	}
   1.144 +
   1.145 +	return 0;
   1.146  }
   1.147  
   1.148  void display(void)
   1.149 @@ -139,10 +163,10 @@
   1.150  	glEnable(GL_TEXTURE_2D);
   1.151  
   1.152  	glBegin(GL_QUADS);
   1.153 -	glTexCoord2f(0, 0); glVertex2f(-1, -1);
   1.154 -	glTexCoord2f(1, 0); glVertex2f(1, -1);
   1.155 -	glTexCoord2f(1, 1); glVertex2f(1, 1);
   1.156 -	glTexCoord2f(0, 1); glVertex2f(-1, 1);
   1.157 +	glTexCoord2f(0, 1); glVertex2f(-1, -1);
   1.158 +	glTexCoord2f(1, 1); glVertex2f(1, -1);
   1.159 +	glTexCoord2f(1, 0); glVertex2f(1, 1);
   1.160 +	glTexCoord2f(0, 0); glVertex2f(-1, 1);
   1.161  	glEnd();
   1.162  
   1.163  	glDisable(GL_TEXTURE_2D);
   1.164 @@ -169,41 +193,44 @@
   1.165  
   1.166  int handle_conn(int s)
   1.167  {
   1.168 +	fprintf(stderr, "whaaaa!\n");
   1.169 +	return -1;
   1.170 +}
   1.171 +
   1.172 +int handle_video(int s)
   1.173 +{
   1.174  	static int cur_frame;
   1.175 -	struct video_block_header hdr;
   1.176 -	int size;
   1.177 -	unsigned char *pixels;
   1.178 +	static char buffer[2048];
   1.179 +	struct video_block *vblock;
   1.180 +	struct sockaddr_in addr;
   1.181 +	socklen_t addr_size;
   1.182  
   1.183 -	if(read(s, &hdr, sizeof hdr) != sizeof hdr) {
   1.184 -		fprintf(stderr, "failed to read video block header\n");
   1.185 -		return -1;
   1.186 -	}
   1.187 -	if(hdr.frame < cur_frame) {
   1.188 -		printf("skipping old frame %d\n", hdr.frame);
   1.189 -	}
   1.190 -	cur_frame = hdr.frame;
   1.191 -	printf("updating block %dx%d%+d%+d in frame %d\n", hdr.width, hdr.height, hdr.x, hdr.y, hdr.frame);
   1.192 -
   1.193 -	size = hdr.width * hdr.height * 2;
   1.194 -	if(!(pixels = malloc(size))) {
   1.195 -		fprintf(stderr, "failed to allocate pixel block %dx%d\n", hdr.width, hdr.height);
   1.196 -		return -1;
   1.197 -	}
   1.198 -	if(read(s, pixels, size) != size) {
   1.199 -		fprintf(stderr, "failed to read pixel block\n");
   1.200 +	addr_size = sizeof addr;
   1.201 +	if(recvfrom(vidsock, buffer, sizeof buffer, 0, (struct sockaddr*)&addr, &addr_size) == -1) {
   1.202 +		perror("failed to receive video block");
   1.203  		return -1;
   1.204  	}
   1.205  
   1.206 +	vblock = (struct video_block*)buffer;
   1.207 +
   1.208 +	if(vblock->frame < cur_frame) {
   1.209 +		printf("skipping old frame %d\n", vblock->frame);
   1.210 +		return 0;
   1.211 +	}
   1.212 +	cur_frame = vblock->frame;
   1.213 +	printf("updating block %dx%d%+d%+d in frame %d\n", vblock->width, vblock->height,
   1.214 +			vblock->x, vblock->y, vblock->frame);
   1.215 +
   1.216  	glBindTexture(GL_TEXTURE_2D, tex);
   1.217  
   1.218 -	if(tex_width < hdr.frame_width || tex_height < hdr.frame_height) {
   1.219 -		tex_width = hdr.frame_width;
   1.220 -		tex_height = hdr.frame_height;
   1.221 +	if(tex_width < vblock->frame_width || tex_height < vblock->frame_height) {
   1.222 +		tex_width = vblock->frame_width;
   1.223 +		tex_height = vblock->frame_height;
   1.224  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0,
   1.225  				GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
   1.226  	}
   1.227 -	glTexSubImage2D(GL_TEXTURE_2D, 0, hdr.x, hdr.y, hdr.width, hdr.height,
   1.228 -			GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
   1.229 +	glTexSubImage2D(GL_TEXTURE_2D, 0, vblock->x, vblock->y, vblock->width, vblock->height,
   1.230 +			GL_RGB, GL_UNSIGNED_SHORT_5_6_5, vblock->pixels);
   1.231  
   1.232  	post_redisplay();
   1.233  	return 0;
     2.1 --- a/doorbelld/src/main.c	Wed Mar 16 00:00:06 2016 +0200
     2.2 +++ b/doorbelld/src/main.c	Wed Mar 16 02:50:30 2016 +0200
     2.3 @@ -15,9 +15,9 @@
     2.4  const char *devfile = "/dev/video0";
     2.5  int fd = -1;
     2.6  int port = 2828;
     2.7 -int width = 640;
     2.8 -int height = 480;
     2.9 -int framerate = 30;
    2.10 +int width = 320;
    2.11 +int height = 240;
    2.12 +int framerate = 15;
    2.13  unsigned char *frame;
    2.14  int done;
    2.15  int frame_available;
    2.16 @@ -83,12 +83,10 @@
    2.17  		if(fd != -1) {
    2.18  			if(fd > maxfd) maxfd = fd;
    2.19  			FD_SET(fd, &rdset);
    2.20 -			printf("select on socket: %d (video)\n", fd);
    2.21  		}
    2.22  
    2.23  		for(i=0; i<num_sockets; i++) {
    2.24  			FD_SET(sock[i], &rdset);
    2.25 -			printf("select on socket: %d\n", sock[i]);
    2.26  		}
    2.27  
    2.28  		while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 &&
    2.29 @@ -98,7 +96,6 @@
    2.30  			fprintf(stderr, "unexpected failure while waiting for I/O\n");
    2.31  			break;
    2.32  		}
    2.33 -		printf("res: %d\n", res);
    2.34  
    2.35  		if(fd != -1 && FD_ISSET(fd, &rdset)) {
    2.36  			wcam_wait(fd);
     3.1 --- a/doorbelld/src/srv.c	Wed Mar 16 00:00:06 2016 +0200
     3.2 +++ b/doorbelld/src/srv.c	Wed Mar 16 02:50:30 2016 +0200
     3.3 @@ -59,9 +59,11 @@
     3.4  		fprintf(stderr, "%s: failed to create video broadcast socket\n", __func__);
     3.5  		return -1;
     3.6  	}
     3.7 +	/*fcntl(bsock, F_SETFL, fcntl(bsock, F_GETFL) | O_NONBLOCK);*/
     3.8  	val = 1;
     3.9  	setsockopt(bsock, SOL_SOCKET, SO_BROADCAST, &val, sizeof val);
    3.10  
    3.11 +	/* prepare the broadcast address struct */
    3.12  	memset(&baddr, 0, sizeof baddr);
    3.13  	baddr.sin_family = AF_INET;
    3.14  	baddr.sin_port = htons(port + 1);
    3.15 @@ -127,7 +129,7 @@
    3.16  	while((sz = read(s, buf, sizeof buf - 1)) > 0) {
    3.17  		printf("%s: got data: %s\n", __func__, buf);
    3.18  	}
    3.19 -	if(sz <= 0 && errno != EAGAIN) {
    3.20 +	if((sz < 0 && errno != EAGAIN) || sz == 0) {
    3.21  		/* client closed connection probably */
    3.22  		int i, num_clients = dynarr_size(csock);
    3.23  		printf("%s: removing client\n", __func__);
    3.24 @@ -158,54 +160,84 @@
    3.25  }
    3.26  
    3.27  struct video_block {
    3.28 -	unsigned int magic;
    3.29  	int frame;
    3.30 -	int x, y;
    3.31 -	int width, height;
    3.32 -	int frame_width, frame_height;
    3.33 -	char pixels[1];
    3.34 +	uint16_t x, y;
    3.35 +	uint16_t width, height;
    3.36 +	uint16_t frame_width, frame_height;
    3.37 +	uint16_t pixels[1];
    3.38  };
    3.39  #define VBLOCK_HEADER_SIZE	(offsetof(struct video_block, pixels))
    3.40  
    3.41 -void srv_send_frame(unsigned char *frame, int xsz, int ysz)
    3.42 +/* ideally we would want each block to stay under the MTU (1500) */
    3.43 +#define BLKSZ	24
    3.44 +
    3.45 +int srv_send_frame(unsigned char *frame, int xsz, int ysz)
    3.46  {
    3.47  	static int frame_num;
    3.48 -	static unsigned char *buffer;
    3.49 -	int i, j, size, num_clients;
    3.50 +	int i, j;
    3.51  	struct video_block *vblock;
    3.52 -	uint16_t *dest;
    3.53 +	int blksz;
    3.54  
    3.55 -	printf("sending frame\n");
    3.56 +	printf("sending frame: %d\n", frame_num);
    3.57  
    3.58 -	/* for now just send a big block */
    3.59 -	size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE;
    3.60 -	if(!buffer && !(buffer = malloc(size))) {
    3.61 -		fprintf(stderr, "failed to allocate frame send buffer\n");
    3.62 -		return;
    3.63 +	blksz = BLKSZ * BLKSZ * 2 + VBLOCK_HEADER_SIZE;
    3.64 +	if(!(vblock = malloc(blksz))) {
    3.65 +		fprintf(stderr, "failed to allocate %dx%d block buffer\n", BLKSZ, BLKSZ);
    3.66 +		return -1;
    3.67  	}
    3.68 -	vblock = (struct video_block*)buffer;
    3.69  
    3.70 -	vblock->magic = 0x12341234;
    3.71  	vblock->frame = frame_num++;
    3.72  	vblock->x = vblock->y = 0;
    3.73 -	vblock->width = vblock->frame_width = xsz;
    3.74 -	vblock->height = vblock->frame_height = ysz;
    3.75 +	vblock->frame_width = xsz;
    3.76 +	vblock->frame_height = ysz;
    3.77  
    3.78 -	dest = (uint16_t*)vblock->pixels;
    3.79 +	vblock->y = 0;
    3.80 +	while(vblock->y < ysz) {
    3.81 +		if(vblock->y + BLKSZ <= ysz) {
    3.82 +			vblock->height = BLKSZ;
    3.83 +		} else {
    3.84 +			vblock->height = ysz - vblock->y;
    3.85 +		}
    3.86  
    3.87 -	for(i=0; i<ysz; i++) {
    3.88 -		for(j=0; j<xsz; j++) {
    3.89 -			unsigned int r = frame[0];
    3.90 -			unsigned int g = frame[1];
    3.91 -			unsigned int b = frame[2];
    3.92 +		vblock->x = 0;
    3.93 +		while(vblock->x < xsz) {
    3.94 +			if(vblock->x + BLKSZ <= xsz) {
    3.95 +				vblock->width = BLKSZ;
    3.96 +			} else {
    3.97 +				vblock->width = xsz - vblock->x;
    3.98 +			}
    3.99  
   3.100 -			*dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
   3.101 -			frame += 4;
   3.102 +			unsigned char *src = frame + (vblock->y * xsz + vblock->x) * 4;
   3.103 +			uint16_t *dest = vblock->pixels;
   3.104 +
   3.105 +			/* convert block to 565 */
   3.106 +			for(i=0; i<vblock->height; i++) {
   3.107 +				for(j=0; j<vblock->width; j++) {
   3.108 +					unsigned int r = src[0];
   3.109 +					unsigned int g = src[1];
   3.110 +					unsigned int b = src[2];
   3.111 +
   3.112 +					*dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
   3.113 +					src += 4;
   3.114 +				}
   3.115 +				src += (xsz - vblock->width) * 4;
   3.116 +			}
   3.117 +
   3.118 +			/* and broadcast it */
   3.119 +			printf("f(%d) b(%d,%d)\n", frame_num - 1, vblock->x, vblock->y);
   3.120 +			if(sendto(bsock, vblock, blksz, 0, (struct sockaddr*)&baddr, sizeof baddr) == -1) {
   3.121 +				perror("failed to send block");
   3.122 +				if(errno == EMSGSIZE) {
   3.123 +					abort();
   3.124 +				}
   3.125 +				return -1;
   3.126 +			}
   3.127 +
   3.128 +			vblock->x += BLKSZ;
   3.129  		}
   3.130 +		vblock->y += BLKSZ;
   3.131  	}
   3.132  
   3.133 -	num_clients = dynarr_size(csock);
   3.134 -	for(i=1; i<num_clients; i++) {	/* first socket is the listening socket */
   3.135 -		write(csock[i], buffer, size);
   3.136 -	}
   3.137 +	free(vblock);
   3.138 +	return 0;
   3.139  }
     4.1 --- a/doorbelld/src/srv.h	Wed Mar 16 00:00:06 2016 +0200
     4.2 +++ b/doorbelld/src/srv.h	Wed Mar 16 02:50:30 2016 +0200
     4.3 @@ -10,6 +10,6 @@
     4.4  
     4.5  int srv_handle(int s);
     4.6  
     4.7 -void srv_send_frame(unsigned char *frame, int xsz, int ysz);
     4.8 +int srv_send_frame(unsigned char *frame, int xsz, int ysz);
     4.9  
    4.10  #endif	/* SRV_H_ */