Blender  V2.59
writeframeserver.c
Go to the documentation of this file.
00001 
00004 /*
00005  * $Id: writeframeserver.c 38594 2011-07-21 23:06:51Z campbellbarton $
00006  *
00007  * Frameserver
00008  * Makes Blender accessible from TMPGenc directly using VFAPI (you can
00009  * use firefox too ;-)
00010  *
00011  * Copyright (c) 2006 Peter Schlaile
00012  *
00013  * This program is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  */
00024 
00025 #ifdef WITH_FRAMESERVER
00026 
00027 #include <string.h>
00028 #include <stdio.h>
00029 
00030 #if defined(_WIN32)
00031 #include <winsock2.h>
00032 #include <windows.h>
00033 #include <winbase.h>
00034 #include <direct.h>
00035 #else
00036 #include <sys/time.h>
00037 #include <sys/socket.h>
00038 #include <sys/types.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 #include <net/if.h>
00042 #include <netdb.h>
00043 #include <sys/ioctl.h>
00044 #include <errno.h>
00045 #include <unistd.h>
00046 #include <sys/un.h>
00047 #include <fcntl.h>
00048 #endif
00049 
00050 #include <stdlib.h>
00051 
00052 #include "DNA_userdef_types.h"
00053 
00054 #include "BLI_utildefines.h"
00055 
00056 #include "BKE_writeframeserver.h"
00057 #include "BKE_global.h"
00058 #include "BKE_report.h"
00059 
00060 #include "DNA_scene_types.h"
00061 
00062 static int sock;
00063 static int connsock;
00064 static int write_ppm;
00065 static int render_width;
00066 static int render_height;
00067 
00068 
00069 #if defined(_WIN32)
00070 static int startup_socket_system(void)
00071 {
00072         WSADATA wsa;
00073         return (WSAStartup(MAKEWORD(2,0),&wsa) == 0);
00074 }
00075 
00076 static void shutdown_socket_system(void)
00077 {
00078         WSACleanup();
00079 }
00080 static int select_was_interrupted_by_signal(void)
00081 {
00082         return (WSAGetLastError() == WSAEINTR);
00083 }
00084 #else
00085 static int startup_socket_system(void)
00086 {
00087         return 1;
00088 }
00089 
00090 static void shutdown_socket_system(void)
00091 {
00092 }
00093 
00094 static int select_was_interrupted_by_signal(void)
00095 {
00096         return (errno == EINTR);
00097 }
00098 
00099 static int closesocket(int fd)
00100 {
00101         return close(fd);
00102 }
00103 #endif
00104 
00105 int start_frameserver(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports)
00106 {
00107         struct sockaddr_in addr;
00108         int arg = 1;
00109         
00110         (void)scene; /* unused */
00111 
00112         if (!startup_socket_system()) {
00113                 BKE_report(reports, RPT_ERROR, "Can't startup socket system");
00114                 return 0;
00115         }
00116 
00117         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00118                 shutdown_socket_system();
00119                 BKE_report(reports, RPT_ERROR, "Can't open socket");
00120                 return 0;
00121         }
00122 
00123         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg));
00124 
00125         addr.sin_family = AF_INET;
00126         addr.sin_port = htons(U.frameserverport);
00127         addr.sin_addr.s_addr = INADDR_ANY;
00128 
00129         if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00130                 shutdown_socket_system();
00131                 BKE_report(reports, RPT_ERROR, "Can't bind to socket");
00132                 return 0;
00133         }
00134 
00135         if (listen(sock, SOMAXCONN) < 0) {
00136                 shutdown_socket_system();
00137                 BKE_report(reports, RPT_ERROR, "Can't establish listen backlog");
00138                 return 0;
00139         }
00140         connsock = -1;
00141 
00142         render_width = rectx;
00143         render_height = recty;
00144 
00145         return 1;
00146 }
00147 
00148 static char index_page[] =
00149 "HTTP/1.1 200 OK\r\n"
00150 "Content-Type: text/html\r\n"
00151 "\r\n"
00152 "<html><head><title>Blender Frameserver</title></head>\n"
00153 "<body><pre>\n"
00154 "<H2>Blender Frameserver</H2>\n"
00155 "<A HREF=info.txt>Render Info</A><br>\n"
00156 "<A HREF=close.txt>Stop Rendering</A><br>\n"
00157 "\n"
00158 "Images can be found here\n"
00159 "\n"
00160 "images/ppm/%d.ppm\n"
00161 "\n"
00162 "</pre></body></html>\n";
00163 
00164 static char good_bye[] =
00165 "HTTP/1.1 200 OK\r\n"
00166 "Content-Type: text/html\r\n"
00167 "\r\n"
00168 "<html><head><title>Blender Frameserver</title></head>\n"
00169 "<body><pre>\n"
00170 "Render stopped. Goodbye</pre></body></html>";
00171 
00172 static int safe_write(char * s, int tosend)
00173 {
00174         int total = tosend;
00175         do {
00176                 int got = send(connsock, s, tosend, 0);
00177                 if (got < 0) {
00178                         return got;
00179                 }
00180                 tosend -= got;
00181                 s += got;
00182         } while (tosend > 0);
00183 
00184         return total;
00185 }
00186 
00187 static int safe_puts(char * s)
00188 {
00189         return safe_write(s, strlen(s));
00190 }
00191 
00192 static int handle_request(RenderData *rd, char * req)
00193 {
00194         char * p;
00195         char * path;
00196         int pathlen;
00197 
00198         if (memcmp(req, "GET ", 4) != 0) {
00199                 return -1;
00200         }
00201            
00202         p = req + 4;
00203         path = p;
00204 
00205         while (*p != ' ' && *p) p++;
00206 
00207         *p = 0;
00208 
00209         if (strcmp(path, "/index.html") == 0
00210                 || strcmp(path, "/") == 0) {
00211                 safe_puts(index_page);
00212                 return -1;
00213         }
00214 
00215         write_ppm = 0;
00216         pathlen = strlen(path);
00217 
00218         if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
00219                 write_ppm = 1;
00220                 return atoi(path + 12);
00221         }
00222         if (strcmp(path, "/info.txt") == 0) {
00223                 char buf[4096];
00224 
00225                 sprintf(buf,
00226                         "HTTP/1.1 200 OK\r\n"
00227                         "Content-Type: text/html\r\n"
00228                         "\r\n"
00229                         "start %d\n"
00230                         "end %d\n"
00231                         "width %d\n"
00232                         "height %d\n"
00233                         "rate %d\n"
00234                         "ratescale %d\n",
00235                         rd->sfra,
00236                         rd->efra,
00237                         render_width,
00238                         render_height,
00239                         rd->frs_sec,
00240                         1
00241                         );
00242 
00243                 safe_puts(buf);
00244                 return -1;
00245         }
00246         if (strcmp(path, "/close.txt") == 0) {
00247                 safe_puts(good_bye);
00248                 G.afbreek = 1; /* Abort render */
00249                 return -1;
00250         }
00251         return -1;
00252 }
00253 
00254 int frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
00255 {
00256         fd_set readfds;
00257         struct timeval tv;
00258         struct sockaddr_in      addr;
00259         int len, rval;
00260         unsigned int socklen;
00261         char buf[4096];
00262 
00263         if (connsock != -1) {
00264                 closesocket(connsock);
00265                 connsock = -1;
00266         }
00267 
00268         tv.tv_sec = 1;
00269         tv.tv_usec = 0;
00270 
00271         FD_ZERO(&readfds);
00272         FD_SET(sock, &readfds);
00273 
00274         rval = select(sock + 1, &readfds, NULL, NULL, &tv);
00275         if (rval < 0) {
00276                 return -1;
00277         }
00278 
00279         if (rval == 0) { /* nothing to be done */
00280                 return -1;
00281         }
00282 
00283         socklen = sizeof(addr);
00284 
00285         if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
00286                 return -1;
00287         }
00288 
00289         FD_ZERO(&readfds);
00290         FD_SET(connsock, &readfds);
00291 
00292         for (;;) {
00293                 /* give 10 seconds for telnet testing... */
00294                 tv.tv_sec = 10;
00295                 tv.tv_usec = 0;
00296 
00297                         rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
00298                 if (rval > 0) {
00299                         break;
00300                 } else if (rval == 0) {
00301                         return -1;
00302                 } else if (rval < 0) {
00303                         if (!select_was_interrupted_by_signal()) {
00304                                 return -1;
00305                         }
00306                 }
00307         }
00308 
00309         len = recv(connsock, buf, 4095, 0);
00310 
00311         if (len < 0) {
00312                 return -1;
00313         }
00314 
00315         buf[len] = 0;
00316 
00317         return handle_request(rd, buf);
00318 }
00319 
00320 static void serve_ppm(int *pixels, int rectx, int recty)
00321 {
00322         unsigned char* rendered_frame;
00323         unsigned char* row = (unsigned char*) malloc(render_width * 3);
00324         int y;
00325         char header[1024];
00326 
00327         sprintf(header,
00328                 "HTTP/1.1 200 OK\r\n"
00329                 "Content-Type: image/ppm\r\n"
00330                 "Connection: close\r\n"
00331                 "\r\n"
00332                 "P6\n"
00333                 "# Creator: blender frameserver v0.0.1\n"
00334                 "%d %d\n"
00335                 "255\n",
00336                 rectx, recty);
00337 
00338         safe_puts(header);
00339 
00340         rendered_frame = (unsigned char *)pixels;
00341 
00342         for (y = recty - 1; y >= 0; y--) {
00343                 unsigned char* target = row;
00344                 unsigned char* src = rendered_frame + rectx * 4 * y;
00345                 unsigned char* end = src + rectx * 4;
00346                 while (src != end) {
00347                         target[2] = src[2];
00348                         target[1] = src[1];
00349                         target[0] = src[0];
00350                         
00351                         target += 3;
00352                         src += 4;
00353                 }
00354                 safe_write((char*)row, 3 * rectx);
00355         }
00356         free(row);
00357         closesocket(connsock);
00358         connsock = -1;
00359 }
00360 
00361 int append_frameserver(RenderData *UNUSED(rd), int frame, int *pixels, int rectx, int recty, ReportList *UNUSED(reports))
00362 {
00363         fprintf(stderr, "Serving frame: %d\n", frame);
00364         if (write_ppm) {
00365                 serve_ppm(pixels, rectx, recty);
00366         }
00367         if (connsock != -1) {
00368                 closesocket(connsock);
00369                 connsock = -1;
00370         }
00371 
00372         return 0;
00373 }
00374 
00375 void end_frameserver(void)
00376 {
00377         if (connsock != -1) {
00378                 closesocket(connsock);
00379                 connsock = -1;
00380         }
00381         closesocket(sock);
00382         shutdown_socket_system();
00383 }
00384 
00385 #endif /* WITH_FRAMESERVER */