Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorPeter Schlaile <peter@schlaile.de>2006-02-05 22:12:25 +0300
committerPeter Schlaile <peter@schlaile.de>2006-02-05 22:12:25 +0300
commit1ce9e196f7c4b76da9a5cf3c789fe6ff2cada2e2 (patch)
tree9faa8ce7ac2cc377b28dd609d84b1120782cd731 /source
parent4f59db9ca17630a0289a953574303b77fccb46ff (diff)
Adds support for frameserver rendering to blender. This is done by
integrating a mini-webserver (around 300 lines of code) into blender. Using the VFAPI-plugin in contrib/windows it enables blender to directly feed its output into TMPGEnc, a commercial high quality MPEG-Encoder. Since it is a mini-webserver, you can probably easily use it for other interfacing purposes.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h1
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h50
-rw-r--r--source/blender/blenkernel/SConscript3
-rw-r--r--source/blender/blenkernel/intern/Makefile5
-rw-r--r--source/blender/blenkernel/intern/image.c12
-rw-r--r--source/blender/blenkernel/intern/writeavi.c20
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c362
7 files changed, 448 insertions, 5 deletions
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 43036612339..6faa5f44878 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -49,6 +49,7 @@ typedef struct bMovieHandle {
void (*start_movie)(struct RenderData *rd, int rectx, int recty);
void (*append_movie)(int frame, int *pixels, int rectx, int recty);
void (*end_movie)(void);
+ int (*get_next_frame)(void); /* can be null */
} bMovieHandle;
bMovieHandle *BKE_get_movie_handle(int imtype);
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
new file mode 100644
index 00000000000..d8414e51f43
--- /dev/null
+++ b/source/blender/blenkernel/BKE_writeframeserver.h
@@ -0,0 +1,50 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_WRITEFRAMESERVER_H
+#define BKE_WRITEFRAMESERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RenderData;
+
+extern void start_frameserver(struct RenderData *rd, int rectx, int recty);
+extern void end_frameserver(void);
+extern void append_frameserver(int frame, int *pixels, int rectx, int recty);
+extern int frameserver_loop();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index aaee2409d89..a5128a33c3e 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -20,6 +20,9 @@ if env['WITH_BF_INTERNATIONAL'] == 1:
if env['WITH_BF_OPENEXR'] == 1:
defs += ' WITH_OPENEXR'
+if env['WITH_BF_FFMPEG'] == 1:
+ defs += ' WITH_FFMPEG'
+
if env['WITH_BF_QUICKTIME'] == 1:
defs += ' WITH_QUICKTIME'
incs += ' ' + env['BF_QUICKTIME_INC']
diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile
index c173051e862..2605541b942 100644
--- a/source/blender/blenkernel/intern/Makefile
+++ b/source/blender/blenkernel/intern/Makefile
@@ -66,6 +66,7 @@ CPPFLAGS += -I../../render/extern/include
# for sound
#CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += $(NAN_SDLCFLAGS)
CPPFLAGS += -I$(NAN_IKSOLVER)/include
CPPFLAGS += -I$(NAN_DECIMATION)/include
@@ -83,6 +84,10 @@ ifeq ($(WITH_FREETYPE2), true)
CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2
endif
+ifeq ($(WITH_FFMPEG),true)
+ CPPFLAGS += -DWITH_FFMPEG
+endif
+
ifeq ($(WITH_OPENEXR), true)
CPPFLAGS += -DWITH_OPENEXR
endif
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index addb4378ce9..4a2f87cf820 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -279,11 +279,13 @@ void free_unused_animimages()
int BKE_imtype_is_movie(int imtype)
{
switch(imtype) {
- case R_MOVIE:
- case R_AVIRAW:
- case R_AVIJPEG:
- case R_AVICODEC:
- case R_QUICKTIME:
+ case R_MOVIE:
+ case R_AVIRAW:
+ case R_AVIJPEG:
+ case R_AVICODEC:
+ case R_QUICKTIME:
+ case R_FFMPEG:
+ case R_FRAMESERVER:
return 1;
}
return 0;
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index eb559df89e7..8c39e5f46c9 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -57,6 +57,12 @@
#include "BIF_writeavicodec.h"
#endif
+#ifdef WITH_FFMPEG
+#include "BKE_writeffmpeg.h"
+#endif
+
+#include "BKE_writeframeserver.h"
+
bMovieHandle *BKE_get_movie_handle(int imtype)
{
static bMovieHandle mh;
@@ -65,6 +71,7 @@ bMovieHandle *BKE_get_movie_handle(int imtype)
mh.start_movie= start_avi;
mh.append_movie= append_avi;
mh.end_movie= end_avi;
+ mh.get_next_frame = 0;
/* do the platform specific handles */
#ifdef __sgi
@@ -86,6 +93,19 @@ bMovieHandle *BKE_get_movie_handle(int imtype)
mh.end_movie= end_qt;
}
#endif
+#ifdef WITH_FFMPEG
+ if (imtype == R_FFMPEG) {
+ mh.start_movie = start_ffmpeg;
+ mh.append_movie = append_ffmpeg;
+ mh.end_movie = end_ffmpeg;
+ }
+#endif
+ if (imtype == R_FRAMESERVER) {
+ mh.start_movie = start_frameserver;
+ mh.append_movie = append_frameserver;
+ mh.end_movie = end_frameserver;
+ mh.get_next_frame = frameserver_loop;
+ }
return &mh;
}
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);
+}
+