blender/release/windows/contrib/vfapi/vfapi-plugin.c

419 lines
8.3 KiB
C

/*
* VFAPI-Plugin
*
* 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 <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#define VF_STREAM_VIDEO 0x00000001
#define VF_STREAM_AUDIO 0x00000002
#define VF_OK 0x00000000
#define VF_ERROR 0x80004005
typedef struct {
DWORD dwSize;
DWORD dwAPIVersion;
DWORD dwVersion;
DWORD dwSupportStreamType;
char cPluginInfo[256];
char cFileType[256];
} VF_PluginInfo,*LPVF_PluginInfo;
typedef DWORD VF_FileHandle,*LPVF_FileHandle;
typedef struct {
DWORD dwSize;
DWORD dwHasStreams;
} VF_FileInfo,*LPVF_FileInfo;
typedef struct {
DWORD dwSize;
DWORD dwLengthL;
DWORD dwLengthH;
DWORD dwRate;
DWORD dwScale;
DWORD dwWidth;
DWORD dwHeight;
DWORD dwBitCount;
} VF_StreamInfo_Video,*LPVF_StreamInfo_Video;
typedef struct {
DWORD dwSize;
DWORD dwLengthL;
DWORD dwLengthH;
DWORD dwRate;
DWORD dwScale;
DWORD dwChannels;
DWORD dwBitsPerSample;
DWORD dwBlockAlign;
} VF_StreamInfo_Audio,*LPVF_StreamInfo_Audio;
typedef struct {
DWORD dwSize;
DWORD dwFrameNumberL;
DWORD dwFrameNumberH;
void *lpData;
long lPitch;
} VF_ReadData_Video,*LPVF_ReadData_Video;
typedef struct {
DWORD dwSize;
LONGLONG dwSamplePos;
DWORD dwSampleCount;
DWORD dwReadedSampleCount;
DWORD dwBufSize;
void *lpBuf;
} VF_ReadData_Audio,*LPVF_ReadData_Audio;
typedef struct {
DWORD dwSize;
HRESULT (__stdcall *OpenFile)(
char *lpFileName, LPVF_FileHandle lpFileHandle );
HRESULT (__stdcall *CloseFile)( VF_FileHandle hFileHandle );
HRESULT (__stdcall *GetFileInfo)( VF_FileHandle hFileHandle,
LPVF_FileInfo lpFileInfo );
HRESULT (__stdcall *GetStreamInfo)( VF_FileHandle hFileHandle,
DWORD dwStream,void *lpStreamInfo );
HRESULT (__stdcall *ReadData)( VF_FileHandle hFileHandle,
DWORD dwStream,void *lpData );
} VF_PluginFunc,*LPVF_PluginFunc;
__declspec(dllexport) HRESULT vfGetPluginInfo(
LPVF_PluginInfo lpPluginInfo )
{
if (!lpPluginInfo || lpPluginInfo->dwSize != sizeof(VF_PluginInfo)) {
return VF_ERROR;
}
lpPluginInfo->dwAPIVersion = 1;
lpPluginInfo->dwVersion = 1;
lpPluginInfo->dwSupportStreamType = VF_STREAM_VIDEO;
strcpy(lpPluginInfo->cPluginInfo, "Blender Frameserver");
strcpy(lpPluginInfo->cFileType,
"Blender Frame-URL-File (*.blu)|*.blu");
return VF_OK;
}
static unsigned long getipaddress(const char * ipaddr)
{
struct hostent *host;
unsigned long ip;
if (((ip = inet_addr(ipaddr)) == INADDR_NONE)
&& strcmp(ipaddr, "255.255.255.255") != 0) {
if ((host = gethostbyname(ipaddr)) != NULL) {
memcpy(&ip, host->h_addr, sizeof(ip));
}
}
return (ip);
}
static void my_send(SOCKET sock, char * str)
{
send(sock, str, strlen(str), 0);
}
static int my_recv(SOCKET sock, char * line, int maxlen)
{
int got = 0;
int toget = maxlen;
while (toget > 0) {
got = recv(sock, line, toget, 0);
if (got <= 0) {
return got;
}
toget -= got;
line += got;
}
return maxlen;
}
static int my_gets(SOCKET sock, char * line, int maxlen)
{
int last_rval = 0;
while (((last_rval = my_recv(sock, line, 1)) == 1) && maxlen > 0) {
if (*line == '\n') {
line++;
*line = 0;
break;
} else {
line++;
maxlen--;
}
}
return last_rval;
}
typedef struct conndesc_ {
struct sockaddr_in addr;
int width;
int height;
int start;
int end;
int rate;
int ratescale;
} conndesc;
HRESULT __stdcall VF_OpenFileFunc_Blen(
char *lpFileName, LPVF_FileHandle lpFileHandle )
{
conndesc * rval;
char * host;
char * p;
int port;
SOCKET s_in;
char buf[256];
struct sockaddr_in addr;
FILE* fp;
p = lpFileName;
while (*p && *p != '.') p++;
if (*p) p++;
if (strcmp(p, "blu") != 0) {
return VF_ERROR;
}
fp = fopen(lpFileName, "r");
if (!fp) {
return VF_ERROR;
}
fgets(buf, 256, fp);
fclose(fp);
host = buf;
p = host;
while (*p && *p != ':') p++;
if (*p) p++;
p[-1] = 0;
port = atoi(p);
if (!port) {
port = 8080;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = getipaddress(host);
s_in = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s_in < 0) {
return VF_ERROR;
}
if (connect(s_in, (struct sockaddr*) &addr,
sizeof(addr)) < 0) {
closesocket(s_in);
return VF_ERROR;
}
rval = (conndesc*) malloc(sizeof(conndesc));
rval->addr = addr;
my_send(s_in, "GET /info.txt HTTP/1.0\n\n");
for (;;) {
char * key;
char * val;
if (my_gets(s_in, buf, 250) <= 0) {
break;
}
key = buf;
val = buf;
while (*val && *val != ' ') val++;
if (*val) {
*val = 0;
val++;
if (strcmp(key, "width") == 0) {
rval->width = atoi(val);
} else if (strcmp(key, "height") == 0) {
rval->height = atoi(val);
} else if (strcmp(key, "start") == 0) {
rval->start = atoi(val);
} else if (strcmp(key, "end") == 0) {
rval->end = atoi(val);
} else if (strcmp(key, "rate") == 0) {
rval->rate = atoi(val);
} else if (strcmp(key, "ratescale") == 0) {
rval->ratescale = atoi(val);
}
}
}
closesocket(s_in);
*lpFileHandle = (VF_FileHandle) rval;
return VF_OK;
}
HRESULT __stdcall VF_CloseFileFunc_Blen(
VF_FileHandle hFileHandle )
{
free((conndesc*) hFileHandle);
return VF_OK;
}
HRESULT __stdcall VF_GetFileInfoFunc_Blen(
VF_FileHandle hFileHandle,
LPVF_FileInfo lpFileInfo )
{
conndesc * c = (conndesc*) hFileHandle;
if (c == 0) {
return VF_ERROR;
}
if (lpFileInfo->dwSize != sizeof(VF_FileInfo)) {
return VF_ERROR;
}
lpFileInfo->dwHasStreams = VF_STREAM_VIDEO;
return VF_OK;
}
HRESULT __stdcall VF_GetStreamInfoFunc_Blen(
VF_FileHandle hFileHandle,
DWORD dwStream,void *lpStreamInfo )
{
conndesc * c = (conndesc*) hFileHandle;
LPVF_StreamInfo_Video v = (LPVF_StreamInfo_Video) lpStreamInfo;
if (c == 0 || dwStream != VF_STREAM_VIDEO || v == 0) {
return VF_ERROR;
}
v->dwLengthL = c->end - c->start;
v->dwLengthH = 0;
v->dwScale = c->ratescale;
v->dwRate = c->rate;
v->dwWidth = c->width;
v->dwHeight = c->height;
v->dwBitCount = 24;
return VF_OK;
}
HRESULT __stdcall VF_ReadDataFunc_Blen(
VF_FileHandle hFileHandle,
DWORD dwStream,void *lpData )
{
char req[256];
char buf[256];
SOCKET s_in;
int width;
int height;
int y;
int rval;
unsigned char * framebuf;
conndesc * c = (conndesc*) hFileHandle;
LPVF_ReadData_Video v = (LPVF_ReadData_Video) lpData;
if (c == 0 || dwStream != VF_STREAM_VIDEO || v == 0) {
return VF_ERROR;
}
s_in = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s_in < 0) {
return VF_ERROR;
}
if (connect(s_in, (struct sockaddr*) &c->addr,
sizeof(c->addr)) < 0) {
goto errout;
}
sprintf(req, "GET /images/ppm/%d.ppm HTTP/1.0\n\n",
(int) (v->dwFrameNumberL) + c->start);
my_send(s_in, req);
do {
if (my_gets(s_in, buf, 256) <= 0) {
goto errout;
}
} while (strcmp(buf, "P6\n") != 0);
do {
rval = my_gets(s_in, buf, 256);
} while ( (buf[0] == '#' || buf[0] == '\n') && rval >= 0);
if (sscanf(buf, "%d %d\n", &width, &height) != 2) {
goto errout;
}
if (width != c->width || height != c->height) {
goto errout;
}
my_gets(s_in, buf, 256); /* 255 */
framebuf = (unsigned char*) v->lpData;
for (y = 0; y < height; y++) {
unsigned char * p = framebuf + v->lPitch * y;
unsigned char * e = p + width * 3;
my_recv(s_in, (char*) p, width * 3);
while (p != e) {
unsigned char tmp = p[2];
p[2] = p[0];
p[0] = tmp;
p += 3;
}
}
closesocket(s_in);
return VF_OK;
errout:
closesocket(s_in);
return VF_ERROR;
}
__declspec(dllexport) HRESULT vfGetPluginFunc(
LPVF_PluginFunc lpPluginFunc )
{
if (!lpPluginFunc || lpPluginFunc->dwSize != sizeof(VF_PluginFunc)) {
return VF_ERROR;
}
lpPluginFunc->OpenFile = VF_OpenFileFunc_Blen;
lpPluginFunc->CloseFile = VF_CloseFileFunc_Blen;
lpPluginFunc->GetFileInfo = VF_GetFileInfoFunc_Blen;
lpPluginFunc->GetStreamInfo = VF_GetStreamInfoFunc_Blen;
lpPluginFunc->ReadData = VF_ReadDataFunc_Blen;
return VF_OK;
}