Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * Frameserver 00004 * Makes Blender accessible from TMPGenc directly using VFAPI (you can 00005 * use firefox too ;-) 00006 * 00007 * Copyright (c) 2006 Peter Schlaile 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 */ 00020 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 #ifdef FREE_WINDOWS 00261 int socklen; 00262 #else 00263 unsigned int socklen; 00264 #endif 00265 char buf[4096]; 00266 00267 if (connsock != -1) { 00268 closesocket(connsock); 00269 connsock = -1; 00270 } 00271 00272 tv.tv_sec = 1; 00273 tv.tv_usec = 0; 00274 00275 FD_ZERO(&readfds); 00276 FD_SET(sock, &readfds); 00277 00278 rval = select(sock + 1, &readfds, NULL, NULL, &tv); 00279 if (rval < 0) { 00280 return -1; 00281 } 00282 00283 if (rval == 0) { /* nothing to be done */ 00284 return -1; 00285 } 00286 00287 socklen = sizeof(addr); 00288 00289 if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) { 00290 return -1; 00291 } 00292 00293 FD_ZERO(&readfds); 00294 FD_SET(connsock, &readfds); 00295 00296 for (;;) { 00297 /* give 10 seconds for telnet testing... */ 00298 tv.tv_sec = 10; 00299 tv.tv_usec = 0; 00300 00301 rval = select(connsock + 1, &readfds, NULL, NULL, &tv); 00302 if (rval > 0) { 00303 break; 00304 } else if (rval == 0) { 00305 return -1; 00306 } else if (rval < 0) { 00307 if (!select_was_interrupted_by_signal()) { 00308 return -1; 00309 } 00310 } 00311 } 00312 00313 len = recv(connsock, buf, sizeof(buf) - 1, 0); 00314 00315 if (len < 0) { 00316 return -1; 00317 } 00318 00319 buf[len] = 0; 00320 00321 return handle_request(rd, buf); 00322 } 00323 00324 static void serve_ppm(int *pixels, int rectx, int recty) 00325 { 00326 unsigned char* rendered_frame; 00327 unsigned char* row = (unsigned char*) malloc(render_width * 3); 00328 int y; 00329 char header[1024]; 00330 00331 sprintf(header, 00332 "HTTP/1.1 200 OK\r\n" 00333 "Content-Type: image/ppm\r\n" 00334 "Connection: close\r\n" 00335 "\r\n" 00336 "P6\n" 00337 "# Creator: blender frameserver v0.0.1\n" 00338 "%d %d\n" 00339 "255\n", 00340 rectx, recty); 00341 00342 safe_puts(header); 00343 00344 rendered_frame = (unsigned char *)pixels; 00345 00346 for (y = recty - 1; y >= 0; y--) { 00347 unsigned char* target = row; 00348 unsigned char* src = rendered_frame + rectx * 4 * y; 00349 unsigned char* end = src + rectx * 4; 00350 while (src != end) { 00351 target[2] = src[2]; 00352 target[1] = src[1]; 00353 target[0] = src[0]; 00354 00355 target += 3; 00356 src += 4; 00357 } 00358 safe_write((char*)row, 3 * rectx); 00359 } 00360 free(row); 00361 closesocket(connsock); 00362 connsock = -1; 00363 } 00364 00365 int append_frameserver(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels, 00366 int rectx, int recty, ReportList *UNUSED(reports)) 00367 { 00368 fprintf(stderr, "Serving frame: %d\n", frame); 00369 if (write_ppm) { 00370 serve_ppm(pixels, rectx, recty); 00371 } 00372 if (connsock != -1) { 00373 closesocket(connsock); 00374 connsock = -1; 00375 } 00376 00377 return 0; 00378 } 00379 00380 void end_frameserver(void) 00381 { 00382 if (connsock != -1) { 00383 closesocket(connsock); 00384 connsock = -1; 00385 } 00386 closesocket(sock); 00387 shutdown_socket_system(); 00388 } 00389 00390 #endif /* WITH_FRAMESERVER */