Sculpting on shapekeys
[blender.git] / source / blender / blenkernel / intern / writeframeserver.c
1 /** \file blender/blenkernel/intern/writeframeserver.c
2  *  \ingroup bke
3  */
4 /*
5  * $Id$
6  *
7  * Frameserver
8  * Makes Blender accessible from TMPGenc directly using VFAPI (you can
9  * use firefox too ;-)
10  *
11  * Copyright (c) 2006 Peter Schlaile
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  */
24
25
26 #include <string.h>
27 #include <stdio.h>
28
29 #if defined(_WIN32)
30 #include <winsock2.h>
31 #include <windows.h>
32 #include <winbase.h>
33 #include <direct.h>
34 #else
35 #include <sys/time.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <net/if.h>
41 #include <netdb.h>
42 #include <sys/ioctl.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <sys/un.h>
46 #include <fcntl.h>
47 #endif
48
49 #include <stdlib.h>
50
51 #include "DNA_userdef_types.h"
52
53 #include "BLI_utildefines.h"
54
55 #include "BKE_writeframeserver.h"
56 #include "BKE_global.h"
57 #include "BKE_report.h"
58
59 #include "DNA_scene_types.h"
60
61 static int sock;
62 static int connsock;
63 static int write_ppm;
64 static int render_width;
65 static int render_height;
66
67
68 #if defined(_WIN32)
69 static int startup_socket_system(void)
70 {
71         WSADATA wsa;
72         return (WSAStartup(MAKEWORD(2,0),&wsa) == 0);
73 }
74
75 static void shutdown_socket_system(void)
76 {
77         WSACleanup();
78 }
79 static int select_was_interrupted_by_signal(void)
80 {
81         return (WSAGetLastError() == WSAEINTR);
82 }
83 #else
84 static int startup_socket_system(void)
85 {
86         return 1;
87 }
88
89 static void shutdown_socket_system(void)
90 {
91 }
92
93 static int select_was_interrupted_by_signal(void)
94 {
95         return (errno == EINTR);
96 }
97
98 static int closesocket(int fd)
99 {
100         return close(fd);
101 }
102 #endif
103
104 int start_frameserver(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports)
105 {
106         struct sockaddr_in addr;
107         int arg = 1;
108         
109         (void)scene; /* unused */
110
111         if (!startup_socket_system()) {
112                 BKE_report(reports, RPT_ERROR, "Can't startup socket system");
113                 return 0;
114         }
115
116         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
117                 shutdown_socket_system();
118                 BKE_report(reports, RPT_ERROR, "Can't open socket");
119                 return 0;
120         }
121
122         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg));
123
124         addr.sin_family = AF_INET;
125         addr.sin_port = htons(U.frameserverport);
126         addr.sin_addr.s_addr = INADDR_ANY;
127
128         if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
129                 shutdown_socket_system();
130                 BKE_report(reports, RPT_ERROR, "Can't bind to socket");
131                 return 0;
132         }
133
134         if (listen(sock, SOMAXCONN) < 0) {
135                 shutdown_socket_system();
136                 BKE_report(reports, RPT_ERROR, "Can't establish listen backlog");
137                 return 0;
138         }
139         connsock = -1;
140
141         render_width = rectx;
142         render_height = recty;
143
144         return 1;
145 }
146
147 static char index_page[] =
148 "HTTP/1.1 200 OK\r\n"
149 "Content-Type: text/html\r\n"
150 "\r\n"
151 "<html><head><title>Blender Frameserver</title></head>\n"
152 "<body><pre>\n"
153 "<H2>Blender Frameserver</H2>\n"
154 "<A HREF=info.txt>Render Info</A><br>\n"
155 "<A HREF=close.txt>Stop Rendering</A><br>\n"
156 "\n"
157 "Images can be found here\n"
158 "\n"
159 "images/ppm/%d.ppm\n"
160 "\n"
161 "</pre></body></html>\n";
162
163 static char good_bye[] =
164 "HTTP/1.1 200 OK\r\n"
165 "Content-Type: text/html\r\n"
166 "\r\n"
167 "<html><head><title>Blender Frameserver</title></head>\n"
168 "<body><pre>\n"
169 "Render stopped. Goodbye</pre></body></html>";
170
171 static int safe_write(char * s, int tosend)
172 {
173         int total = tosend;
174         do {
175                 int got = send(connsock, s, tosend, 0);
176                 if (got < 0) {
177                         return got;
178                 }
179                 tosend -= got;
180                 s += got;
181         } while (tosend > 0);
182
183         return total;
184 }
185
186 static int safe_puts(char * s)
187 {
188         return safe_write(s, strlen(s));
189 }
190
191 static int handle_request(RenderData *rd, char * req)
192 {
193         char * p;
194         char * path;
195         int pathlen;
196
197         if (memcmp(req, "GET ", 4) != 0) {
198                 return -1;
199         }
200            
201         p = req + 4;
202         path = p;
203
204         while (*p != ' ' && *p) p++;
205
206         *p = 0;
207
208         if (strcmp(path, "/index.html") == 0
209                 || strcmp(path, "/") == 0) {
210                 safe_puts(index_page);
211                 return -1;
212         }
213
214         write_ppm = 0;
215         pathlen = strlen(path);
216
217         if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
218                 write_ppm = 1;
219                 return atoi(path + 12);
220         }
221         if (strcmp(path, "/info.txt") == 0) {
222                 char buf[4096];
223
224                 sprintf(buf,
225                         "HTTP/1.1 200 OK\r\n"
226                         "Content-Type: text/html\r\n"
227                         "\r\n"
228                         "start %d\n"
229                         "end %d\n"
230                         "width %d\n"
231                         "height %d\n"
232                         "rate %d\n"
233                         "ratescale %d\n",
234                         rd->sfra,
235                         rd->efra,
236                         render_width,
237                         render_height,
238                         rd->frs_sec,
239                         1
240                         );
241
242                 safe_puts(buf);
243                 return -1;
244         }
245         if (strcmp(path, "/close.txt") == 0) {
246                 safe_puts(good_bye);
247                 G.afbreek = 1; /* Abort render */
248                 return -1;
249         }
250         return -1;
251 }
252
253 int frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
254 {
255         fd_set readfds;
256         struct timeval tv;
257         struct sockaddr_in      addr;
258         int len, rval;
259         unsigned int socklen;
260         char buf[4096];
261
262         if (connsock != -1) {
263                 closesocket(connsock);
264                 connsock = -1;
265         }
266
267         tv.tv_sec = 1;
268         tv.tv_usec = 0;
269
270         FD_ZERO(&readfds);
271         FD_SET(sock, &readfds);
272
273         rval = select(sock + 1, &readfds, NULL, NULL, &tv);
274         if (rval < 0) {
275                 return -1;
276         }
277
278         if (rval == 0) { /* nothing to be done */
279                 return -1;
280         }
281
282         socklen = sizeof(addr);
283
284         if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
285                 return -1;
286         }
287
288         FD_ZERO(&readfds);
289         FD_SET(connsock, &readfds);
290
291         for (;;) {
292                 /* give 10 seconds for telnet testing... */
293                 tv.tv_sec = 10;
294                 tv.tv_usec = 0;
295
296                         rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
297                 if (rval > 0) {
298                         break;
299                 } else if (rval == 0) {
300                         return -1;
301                 } else if (rval < 0) {
302                         if (!select_was_interrupted_by_signal()) {
303                                 return -1;
304                         }
305                 }
306         }
307
308         len = recv(connsock, buf, 4095, 0);
309
310         if (len < 0) {
311                 return -1;
312         }
313
314         buf[len] = 0;
315
316         return handle_request(rd, buf);
317 }
318
319 static void serve_ppm(int *pixels, int rectx, int recty)
320 {
321         unsigned char* rendered_frame;
322         unsigned char* row = (unsigned char*) malloc(render_width * 3);
323         int y;
324         char header[1024];
325
326         sprintf(header,
327                 "HTTP/1.1 200 OK\r\n"
328                 "Content-Type: image/ppm\r\n"
329                 "Connection: close\r\n"
330                 "\r\n"
331                 "P6\n"
332                 "# Creator: blender frameserver v0.0.1\n"
333                 "%d %d\n"
334                 "255\n",
335                 rectx, recty);
336
337         safe_puts(header);
338
339         rendered_frame = (unsigned char *)pixels;
340
341         for (y = recty - 1; y >= 0; y--) {
342                 unsigned char* target = row;
343                 unsigned char* src = rendered_frame + rectx * 4 * y;
344                 unsigned char* end = src + rectx * 4;
345                 while (src != end) {
346                         target[2] = src[2];
347                         target[1] = src[1];
348                         target[0] = src[0];
349                         
350                         target += 3;
351                         src += 4;
352                 }
353                 safe_write((char*)row, 3 * rectx);
354         }
355         free(row);
356         closesocket(connsock);
357         connsock = -1;
358 }
359
360 int append_frameserver(RenderData *UNUSED(rd), int frame, int *pixels, int rectx, int recty, ReportList *UNUSED(reports))
361 {
362         fprintf(stderr, "Serving frame: %d\n", frame);
363         if (write_ppm) {
364                 serve_ppm(pixels, rectx, recty);
365         }
366         if (connsock != -1) {
367                 closesocket(connsock);
368                 connsock = -1;
369         }
370
371         return 0;
372 }
373
374 void end_frameserver(void)
375 {
376         if (connsock != -1) {
377                 closesocket(connsock);
378                 connsock = -1;
379         }
380         closesocket(sock);
381         shutdown_socket_system();
382 }
383