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_ */