diff options
Diffstat (limited to 'source/blender/blenkernel/intern/writeframeserver.c')
-rw-r--r-- | source/blender/blenkernel/intern/writeframeserver.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c new file mode 100644 index 00000000000..75bf0750766 --- /dev/null +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -0,0 +1,362 @@ +/* + * Frameserver + * Makes Blender accessible from TMPGenc directly using VFAPI (you can + * use firefox too ;-) + * + * Copyright (c) 2006 Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +#include <string.h> +#include <stdio.h> + +#if defined(_WIN32) +#include <windows.h> +#include <winbase.h> +#include <direct.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netdb.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/un.h> +#include <fcntl.h> +#endif + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "DNA_userdef_types.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_global.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_scene_types.h" +#include "blendef.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* + Big red FIXME: + + You can't simply press escape to stop the frameserver, since somehow + the escape signal handling does not work, when you wait for a connection. + + You have to point your favorite webbrowser to + + blenderserver:port + + and click on "Stop Rendering" + + It does help, if you start blender using "-p 0 0 800 600" e.g... + +*/ + +static int sock; +static int connsock; +static int write_ppm; +static int render_width; +static int render_height; + + +#if !defined(_WIN32) +static inline int closesocket(int fd) { + return close(fd); +} +#endif + +void start_frameserver(RenderData *rd, int rectx, int recty) +{ + struct sockaddr_in addr; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + G.afbreek = 1; /* Abort render */ + error("Can't open socket"); + return; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(U.frameserverport); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + G.afbreek = 1; /* Abort render */ + error("Can't bind to socket"); + return; + } + + if (listen(sock, SOMAXCONN) < 0) { + G.afbreek = 1; /* Abort render */ + error("Can't establish listen backlog"); + return; + } + connsock = -1; + + render_width = rectx; + render_height = recty; +} + +static char index_page[] += +"HTTP/1.1 200 OK\n" +"Content-Type: text/html\n\n" +"<html><head><title>Blender Frameserver</title></head>\n" +"<body><pre>\n" +"<H2>Blender Frameserver</H2>\n" +"<A HREF=info.txt>Render Info</A><br>\n" +"<A HREF=close.txt>Stop Rendering</A><br>\n" +"\n" +"Images can be found here\n" +"\n" +"images/ppm/%d.ppm\n" +"\n" +"</pre></body></html>\n"; + +static char good_bye[] += "HTTP/1.1 200 OK\n" +"Content-Type: text/html\n\n" +"<html><head><title>Blender Frameserver</title></head>\n" +"<body><pre>\n" +"Render stopped. Goodbye</pre></body></html>"; + +static int safe_write(char * s, int tosend) +{ + int total = tosend; + do { + int got = send(connsock, s, tosend, 0); + if (got < 0) { + return got; + } + tosend -= got; + s += got; + } while (tosend > 0); + + return total; +} + +static int safe_puts(char * s) +{ + return safe_write(s, strlen(s)); +} + +static int handle_request(char * req) +{ + char * p; + char * path; + + if (strlen(req) < 20) { + return -1; + } + + if (memcmp(req, "GET ", 4) != 0) { + return -1; + } + + p = req + 4; + path = p; + + while (*p != ' ' && *p) p++; + + *p = 0; + + if (strcmp(path, "/index.html") == 0 + || strcmp(path, "/") == 0) { + safe_puts(index_page); + return -1; + } + + write_ppm = 0; + + if (memcmp(path, "/images/ppm/", 12) == 0) { + write_ppm = 1; + return atoi(path + 12); + } + if (strcmp(path, "/info.txt") == 0) { + char buf[4096]; + + sprintf(buf, + "HTTP/1.1 200 OK\n" + "Content-Type: text/html\n\n" + "start %d\n" + "end %d\n" + "width %d\n" + "height %d\n" + "rate %d\n" + "ratescale %d\n", + G.scene->r.sfra, + G.scene->r.efra, + render_width, + render_height, + G.scene->r.frs_sec, + 1 + ); + + safe_puts(buf); + return -1; + } + if (strcmp(path, "/close.txt") == 0) { + safe_puts(good_bye); + G.afbreek = 1; /* Abort render */ + return -1; + } + return -1; +} + +int frameserver_loop() +{ + fd_set readfds; +#if !defined(_WIN32) + struct timeval tv; +#endif + struct sockaddr_in addr; + int len; + char buf[4096]; + int rval; + + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } + +#if !defined(_WIN32) + /* FIXME: Don't know, how to wait for socket on Windows ... */ + + tv.tv_sec = 1; + tv.tv_usec = 0; + + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + rval = select(sock + 1, &readfds, NULL, NULL, &tv); + if (rval < 0) { + return -1; + } + + if (rval == 0) { /* nothing to be done */ + return -1; + } +#endif + + len = sizeof(addr); + + if ((connsock = accept(sock, (struct sockaddr *)&addr, &len)) < 0) { + return -1; + } + +#if !defined(_WIN32) + /* FIXME: Don't know, how to wait for socket on Windows ... */ + + FD_ZERO(&readfds); + FD_SET(connsock, &readfds); + + for (;;) { + /* give 10 seconds for telnet testing... */ + tv.tv_sec = 10; + tv.tv_usec = 0; + + rval = select(connsock + 1, &readfds, NULL, NULL, &tv); + if (rval > 0) { + break; + } else if (rval == 0) { + return -1; + } else if (rval < 0) { + if (errno != EINTR) { + return -1; + } + } + } +#endif + + len = recv(connsock, buf, 4095, 0); + + if (len < 0) { + return -1; + } + + buf[len] = 0; + + return handle_request(buf); +} + +static void serve_ppm(int *pixels, int rectx, int recty) +{ + unsigned char* rendered_frame; + unsigned char* row = (unsigned char*) malloc(render_width * 3); + int y; + char header[1024]; + + sprintf(header, + "HTTP/1.1 200 OK\n" + "Content-Type: image/ppm\n" + "Connection: close\n\n" + "P6\n" + "# Creator: blender frameserver v0.0.1\n" + "%d %d\n" + "255\n", + rectx, recty); + + safe_puts(header); + + rendered_frame = pixels; + + for (y = recty - 1; y >= 0; y--) { + uint8_t* target = row; + uint8_t* src = rendered_frame + rectx * 4 * y; + uint8_t* end = src + rectx * 4; + while (src != end) { + target[2] = src[2]; + target[1] = src[1]; + target[0] = src[0]; + + target += 3; + src += 4; + } + safe_write(row, 3 * rectx); + } + free(row); + closesocket(connsock); + connsock = -1; +} + +void append_frameserver(int frame, int *pixels, int rectx, int recty) +{ + fprintf(stderr, "Serving frame: %d\n", frame); + if (write_ppm) { + serve_ppm(pixels, rectx, recty); + } + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } +} + +void end_frameserver() +{ + if (connsock != -1) { + closesocket(connsock); + connsock = -1; + } + closesocket(sock); +} + |