# HG changeset patch # User John Tsiombikas # Date 1458089430 -7200 # Node ID dc4018af3a4047d32d19a8afd9c3f7bb2e9a5544 # Parent 026156ea880167a764c0b43fa8e5fa66b6656084 video broadcast with UDP. retarded amount of data, unusable. diff -r 026156ea8801 -r dc4018af3a40 doorbell-client/src/main.c --- a/doorbell-client/src/main.c Wed Mar 16 00:00:06 2016 +0200 +++ b/doorbell-client/src/main.c Wed Mar 16 02:50:30 2016 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -12,12 +13,12 @@ #include #include -struct video_block_header { - unsigned int magic; +struct video_block { int frame; - int x, y; - int width, height; - int frame_width, frame_height; + uint16_t x, y; + uint16_t width, height; + uint16_t frame_width, frame_height; + uint16_t pixels[1]; }; int conn(const char *host, int port); @@ -25,15 +26,18 @@ void reshape(int x, int y); void keyb(unsigned char key, int x, int y); int handle_conn(int s); +int handle_video(int s); void post_redisplay(void); int quit; -int srvsock; +int ctlsock, vidsock; const char *address = "localhost"; int port = 2828; unsigned int tex, tex_width, tex_height; int redraw_pending; +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + int main(int argc, char **argv) { Display *dpy; @@ -51,10 +55,10 @@ dpy = glXGetCurrentDisplay(); xsock = ConnectionNumber(dpy); - if((srvsock = conn(address, port)) == -1) { + if(conn(address, port) == -1) { return 1; } - write(srvsock, "hello", 5); + write(ctlsock, "hello", 5); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); @@ -62,15 +66,16 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); for(;;) { - int res; - int maxfd = srvsock > xsock ? srvsock : xsock; + int res, maxfd; struct timeval tv0 = {0, 0}; fd_set rdset; FD_ZERO(&rdset); FD_SET(xsock, &rdset); - FD_SET(srvsock, &rdset); + FD_SET(ctlsock, &rdset); + FD_SET(vidsock, &rdset); + maxfd = MAX(MAX(xsock, ctlsock), vidsock); while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR); if(res == -1) break; @@ -80,25 +85,29 @@ break; } } - if(FD_ISSET(srvsock, &rdset)) { - if(handle_conn(srvsock) == -1) { + if(FD_ISSET(ctlsock, &rdset)) { + if(handle_conn(ctlsock) == -1) { + break; + } + } + if(FD_ISSET(vidsock, &rdset)) { + if(handle_video(vidsock) == -1) { break; } } } - close(srvsock); + close(ctlsock); 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) { + if((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "failed to create socket\n"); return -1; } @@ -114,13 +123,28 @@ 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) { + if(connect(ctlsock, (struct sockaddr*)&addr, sizeof addr) == -1) { fprintf(stderr, "failed to connect\n"); return -1; } + fcntl(ctlsock, F_SETFL, fcntl(ctlsock, F_GETFL) | O_NONBLOCK); - fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); - return s; + /* prepare the video socket */ + if((vidsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + fprintf(stderr, "failed to create video socket\n"); + return 1; + } + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(port + 1); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if(bind(vidsock, (struct sockaddr*)&addr, sizeof addr) == -1) { + fprintf(stderr, "failed to bind video socket to port %d\n", port + 1); + return 1; + } + + return 0; } void display(void) @@ -139,10 +163,10 @@ 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); + glTexCoord2f(0, 1); glVertex2f(-1, -1); + glTexCoord2f(1, 1); glVertex2f(1, -1); + glTexCoord2f(1, 0); glVertex2f(1, 1); + glTexCoord2f(0, 0); glVertex2f(-1, 1); glEnd(); glDisable(GL_TEXTURE_2D); @@ -169,41 +193,44 @@ int handle_conn(int s) { + fprintf(stderr, "whaaaa!\n"); + return -1; +} + +int handle_video(int s) +{ static int cur_frame; - struct video_block_header hdr; - int size; - unsigned char *pixels; + static char buffer[2048]; + struct video_block *vblock; + struct sockaddr_in addr; + socklen_t addr_size; - 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"); + addr_size = sizeof addr; + if(recvfrom(vidsock, buffer, sizeof buffer, 0, (struct sockaddr*)&addr, &addr_size) == -1) { + perror("failed to receive video block"); return -1; } + vblock = (struct video_block*)buffer; + + if(vblock->frame < cur_frame) { + printf("skipping old frame %d\n", vblock->frame); + return 0; + } + cur_frame = vblock->frame; + printf("updating block %dx%d%+d%+d in frame %d\n", vblock->width, vblock->height, + vblock->x, vblock->y, vblock->frame); + 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; + if(tex_width < vblock->frame_width || tex_height < vblock->frame_height) { + tex_width = vblock->frame_width; + tex_height = vblock->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); + glTexSubImage2D(GL_TEXTURE_2D, 0, vblock->x, vblock->y, vblock->width, vblock->height, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, vblock->pixels); post_redisplay(); return 0; diff -r 026156ea8801 -r dc4018af3a40 doorbelld/src/main.c --- a/doorbelld/src/main.c Wed Mar 16 00:00:06 2016 +0200 +++ b/doorbelld/src/main.c Wed Mar 16 02:50:30 2016 +0200 @@ -15,9 +15,9 @@ const char *devfile = "/dev/video0"; int fd = -1; int port = 2828; -int width = 640; -int height = 480; -int framerate = 30; +int width = 320; +int height = 240; +int framerate = 15; unsigned char *frame; int done; int frame_available; @@ -83,12 +83,10 @@ if(fd != -1) { if(fd > maxfd) maxfd = fd; FD_SET(fd, &rdset); - printf("select on socket: %d (video)\n", fd); } for(i=0; i 0) { printf("%s: got data: %s\n", __func__, buf); } - if(sz <= 0 && errno != EAGAIN) { + if((sz < 0 && errno != EAGAIN) || sz == 0) { /* client closed connection probably */ int i, num_clients = dynarr_size(csock); printf("%s: removing client\n", __func__); @@ -158,54 +160,84 @@ } struct video_block { - unsigned int magic; int frame; - int x, y; - int width, height; - int frame_width, frame_height; - char pixels[1]; + uint16_t x, y; + uint16_t width, height; + uint16_t frame_width, frame_height; + uint16_t pixels[1]; }; #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels)) -void srv_send_frame(unsigned char *frame, int xsz, int ysz) +/* ideally we would want each block to stay under the MTU (1500) */ +#define BLKSZ 24 + +int srv_send_frame(unsigned char *frame, int xsz, int ysz) { static int frame_num; - static unsigned char *buffer; - int i, j, size, num_clients; + int i, j; struct video_block *vblock; - uint16_t *dest; + int blksz; - printf("sending frame\n"); + printf("sending frame: %d\n", frame_num); - /* for now just send a big block */ - size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE; - if(!buffer && !(buffer = malloc(size))) { - fprintf(stderr, "failed to allocate frame send buffer\n"); - return; + blksz = BLKSZ * BLKSZ * 2 + VBLOCK_HEADER_SIZE; + if(!(vblock = malloc(blksz))) { + fprintf(stderr, "failed to allocate %dx%d block buffer\n", BLKSZ, BLKSZ); + return -1; } - 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; + vblock->frame_width = xsz; + vblock->frame_height = ysz; - dest = (uint16_t*)vblock->pixels; + vblock->y = 0; + while(vblock->y < ysz) { + if(vblock->y + BLKSZ <= ysz) { + vblock->height = BLKSZ; + } else { + vblock->height = ysz - vblock->y; + } - for(i=0; ix = 0; + while(vblock->x < xsz) { + if(vblock->x + BLKSZ <= xsz) { + vblock->width = BLKSZ; + } else { + vblock->width = xsz - vblock->x; + } - *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f); - frame += 4; + unsigned char *src = frame + (vblock->y * xsz + vblock->x) * 4; + uint16_t *dest = vblock->pixels; + + /* convert block to 565 */ + for(i=0; iheight; i++) { + for(j=0; jwidth; j++) { + unsigned int r = src[0]; + unsigned int g = src[1]; + unsigned int b = src[2]; + + *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f); + src += 4; + } + src += (xsz - vblock->width) * 4; + } + + /* and broadcast it */ + printf("f(%d) b(%d,%d)\n", frame_num - 1, vblock->x, vblock->y); + if(sendto(bsock, vblock, blksz, 0, (struct sockaddr*)&baddr, sizeof baddr) == -1) { + perror("failed to send block"); + if(errno == EMSGSIZE) { + abort(); + } + return -1; + } + + vblock->x += BLKSZ; } + vblock->y += BLKSZ; } - num_clients = dynarr_size(csock); - for(i=1; i