This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/src/writeavicodec.c
Ton Roosendaal ec99255c27 Phew, a lot of work, and no new features...
Main target was to make the inner rendering loop using no globals anymore.
This is essential for proper usage while raytracing, it caused a lot of
hacks in the raycode as well, which even didn't work correctly for all
situations (textures especially).

Done this by creating a new local struct RenderInput, which replaces usage
of the global struct Render R. The latter now only is used to denote
image size, viewmatrix, and the like.

Making the inner render loops using no globals caused 1000s of vars to
be changed... but the result definitely is much nicer code, which enables
making 'real' shaders in a next stage.
It also enabled me to remove the hacks from ray.c

Then i went to the task of removing redundant code. Especially the calculus
of texture coords took place (identical) in three locations.
Most obvious is the change in the unified render part, which is much less
code now; it uses the same rendering routines as normal render now.
(Note; not for halos yet!)

I also removed 6 files called 'shadowbuffer' something. This was experimen-
tal stuff from NaN days. And again saved a lot of double used code.

Finally I went over the blenkernel and blender/src calls to render stuff.
Here the same local data is used now, resulting in less dependency.
I also moved render-texture to the render module, this was still in Kernel.
(new file: texture.c)

So! After this commit I will check on the autofiles, to try to fix that.
MSVC people have to do it themselves.
This commit will need quite some testing help, but I'm around!
2003-12-21 21:52:51 +00:00

826 lines
22 KiB
C

/**
* Functions for writing windows avi-format files.
*
* $Id$
*
* ***** 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 *****
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(_WIN32) && !defined(FREE_WINDOWS)
#define INC_OLE2
#include <windows.h>
#include <windowsx.h>
#include <memory.h>
#include <mmsystem.h>
#include <vfw.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "DNA_userdef_types.h"
#include "render_types.h"
#include "BKE_global.h"
#include "BKE_scene.h"
#include "BKE_writeavi.h"
#include "BIF_toolbox.h"
// this defines the compression type for
// the output video stream
AVICOMPRESSOPTIONS opts;
static int sframe;
static PAVIFILE pfile = NULL;
static int avifileinitdone = 0;
static PAVISTREAM psUncompressed = NULL, psCompressed = NULL;
// function definitions
static void init_bmi(BITMAPINFOHEADER *bmi);
static void opts_to_acd(AviCodecData *acd);
static void acd_to_opts(AviCodecData *acd);
static void free_opts_data();
static int open_avi_codec_file(char * name);
///////////////////////////////////////////////////////////////////////////
//
// silly default parameters
//
///////////////////////////////////////////////////////////////////////////
#define DEFAULT_WIDTH 240
#define DEFAULT_HEIGHT 120
#define DEFAULT_LENGTH 100
#define DEFAULT_SIZE 6
#define DEFAULT_COLOR RGB(255,0,0)
#define XSPEED 7
#define YSPEED 5
///////////////////////////////////////////////////////////////////////////
//
// useful macros
//
///////////////////////////////////////////////////////////////////////////
#define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
#define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
#define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
(int)(lpbi)->biSize + \
(int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
///////////////////////////////////////////////////////////////////////////
//
// custom video stream instance structure
//
///////////////////////////////////////////////////////////////////////////
typedef struct {
//
// The Vtbl must come first
//
IAVIStreamVtbl * lpvtbl;
//
// private ball instance data
//
ULONG ulRefCount;
DWORD fccType; // is this audio/video
int width; // size in pixels of each frame
int height;
int length; // length in frames of the pretend AVI movie
int size;
COLORREF color; // ball color
} AVIBALL, * PAVIBALL;
///////////////////////////////////////////////////////////////////////////
//
// custom stream methods
//
///////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj);
HRESULT STDMETHODCALLTYPE AVIBallCreate (PAVISTREAM ps, LONG lParam1, LONG lParam2);
ULONG STDMETHODCALLTYPE AVIBallAddRef (PAVISTREAM ps);
ULONG STDMETHODCALLTYPE AVIBallRelease (PAVISTREAM ps);
HRESULT STDMETHODCALLTYPE AVIBallInfo (PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize);
LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags);
HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG *lpcbFormat);
HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat);
HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG * plBytes,LONG * plSamples);
HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten);
HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples);
HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG *lpcb);
HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG cb);
IAVIStreamVtbl AVIBallHandler = {
AVIBallQueryInterface,
AVIBallAddRef,
AVIBallRelease,
AVIBallCreate,
AVIBallInfo,
AVIBallFindSample,
AVIBallReadFormat,
AVIBallSetFormat,
AVIBallRead,
AVIBallWrite,
AVIBallDelete,
AVIBallReadData,
AVIBallWriteData
};
//
// This is the function an application would call to create a PAVISTREAM to
// reference the ball. Then the standard AVIStream function calls can be
// used to work with this stream.
//
PAVISTREAM WINAPI NewBall(void)
{
static AVIBALL ball;
PAVIBALL pball = &ball;
//
// Fill the function table
//
pball->lpvtbl = &AVIBallHandler;
//
// Call our own create code to create a new instance (calls AVIBallCreate)
// For now, don't use any lParams.
//
pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);
return (PAVISTREAM) pball;
}
///////////////////////////////////////////////////////////////////////////
//
// This function is called to initialize an instance of the bouncing ball.
//
// When called, we look at the information possibly passed in <lParam1>,
// if any, and use it to determine the length of movie they want. (Not
// supported by NewBall right now, but it could be).
//
///////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE AVIBallCreate(PAVISTREAM ps, LONG lParam1, LONG lParam2)
{
PAVIBALL pball = (PAVIBALL) ps;
//
// what type of data are we? (audio/video/other stream)
//
pball->fccType = streamtypeVIDEO;
//
// We define lParam1 as being the length of movie they want us to pretend
// to be.
//
if (lParam1)
pball->length = (int) lParam1;
else
pball->length = DEFAULT_LENGTH;
switch (pball->fccType) {
case streamtypeVIDEO:
pball->color = DEFAULT_COLOR;
pball->width = DEFAULT_WIDTH;
pball->height = DEFAULT_HEIGHT;
pball->size = DEFAULT_SIZE;
pball->ulRefCount = 1; // note that we are opened once
return AVIERR_OK; // success
case streamtypeAUDIO:
return ResultFromScode(AVIERR_UNSUPPORTED); // we don't do audio
default:
return ResultFromScode(AVIERR_UNSUPPORTED); // or anything else
}
}
//
// Increment our reference count
//
ULONG STDMETHODCALLTYPE AVIBallAddRef(PAVISTREAM ps)
{
PAVIBALL pball = (PAVIBALL) ps;
return (++pball->ulRefCount);
}
//
// Decrement our reference count
//
ULONG STDMETHODCALLTYPE AVIBallRelease(PAVISTREAM ps)
{
PAVIBALL pball = (PAVIBALL) ps;
if (--pball->ulRefCount)
return pball->ulRefCount;
// Free any data we're keeping around - like our private structure
GlobalFreePtr(pball);
return 0;
}
//
// Fills an AVISTREAMINFO structure
//
HRESULT STDMETHODCALLTYPE AVIBallInfo(PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize)
{
PAVIBALL pball = (PAVIBALL) ps;
if (lSize < sizeof(AVISTREAMINFO))
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
_fmemset(psi, 0, (int)lSize);
// Fill out a stream header with information about us.
psi->fccType = pball->fccType;
psi->fccHandler = mmioFOURCC('B','a','l','l');
psi->dwScale = 1;
psi->dwRate = 15;
psi->dwLength = pball->length;
psi->dwSuggestedBufferSize = pball->height * ALIGNULONG(pball->width);
psi->rcFrame.right = pball->width;
psi->rcFrame.bottom = pball->height;
CopyMemory((PVOID)psi->szName,
(PVOID)L"Bouncing ball video",
sizeof(L"Bouncing ball video"));
return AVIERR_OK;
}
///////////////////////////////////////////////////////////////////////////
//
// AVIBallReadFormat: needs to return the format of our data.
//
///////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos,LPVOID lpFormat,LONG *lpcbFormat)
{
PAVIBALL pball = (PAVIBALL) ps;
LPBITMAPINFO lpbi = (LPBITMAPINFO) lpFormat;
if (lpFormat == NULL || *lpcbFormat == 0) {
*lpcbFormat = sizeof(BITMAPINFOHEADER);
return AVIERR_OK;
}
if (*lpcbFormat < sizeof(BITMAPINFOHEADER))
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
// This is a relatively silly example: we build up our
// format from scratch every time.
/*
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biCompression = BI_RGB;
lpbi->bmiHeader.biWidth = pball->width;
lpbi->bmiHeader.biHeight = pball->height;
lpbi->bmiHeader.biBitCount = 8;
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biClrUsed = 2;
lpbi->bmiHeader.biSizeImage = pball->height * DIBWIDTHBYTES(lpbi->bmiHeader);
*/
//init_bmi(&lpbi->bmiHeader);
memset(&lpbi->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth = pball->width;
lpbi->bmiHeader.biHeight = pball->height;
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biBitCount = 24;
lpbi->bmiHeader.biSizeImage = pball->width * pball->height * sizeof(RGBTRIPLE);
/*
lpbi->bmiColors[0].rgbRed = 0;
lpbi->bmiColors[0].rgbGreen = 0;
lpbi->bmiColors[0].rgbBlue = 0;
lpbi->bmiColors[1].rgbRed = GetRValue(pball->color);
lpbi->bmiColors[1].rgbGreen = GetGValue(pball->color);
lpbi->bmiColors[1].rgbBlue = GetBValue(pball->color);
*/
*lpcbFormat = sizeof(BITMAPINFOHEADER);
return AVIERR_OK;
}
///////////////////////////////////////////////////////////////////////////
//
// AVIBallRead: needs to return the data for a particular frame.
//
///////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart,LONG lSamples,LPVOID lpBuffer,LONG cbBuffer,LONG * plBytes,LONG * plSamples)
{
PAVIBALL pball = (PAVIBALL) ps;
LONG lSize = pball->height * ALIGNULONG(pball->width); // size of frame
// in bytes
int x, y;
HPSTR hp = lpBuffer;
int xPos, yPos;
// Reject out of range values
if (lStart < 0 || lStart >= pball->length)
return ResultFromScode(AVIERR_BADPARAM);
// Did they just want to know the size of our data?
if (lpBuffer == NULL || cbBuffer == 0)
goto exit;
// Will our frame fit in the buffer passed?
if (lSize > cbBuffer)
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
// Figure out the position of the ball.
// It just bounces back and forth.
xPos = 5 + XSPEED * (int) lStart; // x = x0 + vt
xPos = xPos % ((pball->width - pball->size) * 2); // limit to 2xwidth
if (xPos > (pball->width - pball->size)) // reflect if
xPos = 2 * (pball->width - pball->size) - xPos; // needed
yPos = 5 + YSPEED * (int) lStart;
yPos = yPos % ((pball->height - pball->size) * 2);
if (yPos > (pball->height - pball->size))
yPos = 2 * (pball->height - pball->size) - yPos;
//
// Build a DIB from scratch by writing in 1's where the ball is, 0's
// where it isn't.
//
// Notice that we just build it in the buffer we've been passed.
//
// This is pretty ugly, I have to admit.
//
for (y = 0; y < pball->height; y++)
{
if (y >= yPos && y < yPos + pball->size)
{
for (x = 0; x < pball->width; x++)
{
*hp++ = (BYTE) ((x >= xPos && x < xPos + pball->size) ? 1 : 0);
}
}
else
{
for (x = 0; x < pball->width; x++)
{
*hp++ = 0;
}
}
hp += pball->width - ALIGNULONG(pball->width);
}
exit:
// We always return exactly one frame
if (plSamples)
*plSamples = 1;
// Return the size of our frame
if (plBytes)
*plBytes = lSize;
return AVIERR_OK;
}
HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj)
{
PAVIBALL pball = (PAVIBALL) ps;
// We support the Unknown interface (everybody does) and our Stream
// interface.
if (_fmemcmp(riid, &IID_IUnknown, sizeof(GUID)) == 0)
*ppvObj = (LPVOID)pball;
else if (_fmemcmp(riid, &IID_IAVIStream, sizeof(GUID)) == 0)
*ppvObj = (LPVOID)pball;
else {
*ppvObj = NULL;
return ResultFromScode(E_NOINTERFACE);
}
AVIBallAddRef(ps);
return AVIERR_OK;
}
LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags)
{
// The only format change is frame 0
if ((lFlags & FIND_TYPE) == FIND_FORMAT) {
if ((lFlags & FIND_DIR) == FIND_NEXT && lPos > 0)
return -1; // no more format changes
else
return 0;
// FIND_KEY and FIND_ANY always return the same position because
// every frame is non-empty and a key frame
} else
return lPos;
}
HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG *lpcb)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}
HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}
HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG cb)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}
HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}
HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}
//////////////////////////////////////
static void init_bmi(BITMAPINFOHEADER *bmi)
{
memset(bmi, 0, sizeof(BITMAPINFOHEADER));
bmi->biSize = sizeof(BITMAPINFOHEADER);
bmi->biWidth = R.rectx;
bmi->biHeight = R.recty;
bmi->biPlanes = 1;
bmi->biBitCount = 24;
bmi->biSizeImage = bmi->biWidth * bmi->biHeight * sizeof(RGBTRIPLE);
}
static void opts_to_acd(AviCodecData *acd)
{
HIC hic;
ICINFO icinfo;
acd->fccType = opts.fccType;
acd->fccHandler = opts.fccHandler;
acd->dwKeyFrameEvery = opts.dwKeyFrameEvery;
acd->dwQuality = opts.dwQuality;
acd->dwBytesPerSecond = opts.dwBytesPerSecond;
acd->dwFlags = opts.dwFlags;
acd->dwInterleaveEvery = opts.dwInterleaveEvery;
acd->cbFormat = opts.cbFormat;
acd->cbParms = opts.cbParms;
if (opts.lpFormat && opts.cbFormat) {
acd->lpFormat = MEM_mallocN(opts.cbFormat, "avi.lpFormat");
memcpy(acd->lpFormat, opts.lpFormat, opts.cbFormat);
}
if (opts.lpParms && opts.cbParms) {
acd->lpParms = MEM_mallocN(opts.cbParms, "avi.lpParms");
memcpy(acd->lpParms, opts.lpParms, opts.cbParms);
}
if ((hic=ICOpen(ICTYPE_VIDEO,acd->fccHandler,ICMODE_QUERY))!=NULL) {
icinfo.dwSize=sizeof(ICINFO);
if (ICGetInfo(hic,&icinfo,sizeof(ICINFO))) {
WideCharToMultiByte(CP_ACP,0,icinfo.szDescription,-1,acd->avicodecname,128,NULL,NULL);
} else
sprintf(acd->avicodecname, "undefined");
if (ICClose(hic)!=ICERR_OK)
;// return 0;
} else {
sprintf(acd->avicodecname, "Full Frames (Uncompressed)"); //heh, nasty
}
}
static void acd_to_opts(AviCodecData *acd)
{
memset(&opts, 0, sizeof(opts));
if (acd) {
opts.fccType = acd->fccType;
opts.fccHandler = acd->fccHandler;
opts.dwKeyFrameEvery = acd->dwKeyFrameEvery;
opts.dwQuality = acd->dwQuality;
opts.dwBytesPerSecond = acd->dwBytesPerSecond;
opts.dwFlags = acd->dwFlags;
opts.dwInterleaveEvery = acd->dwInterleaveEvery;
opts.cbFormat = acd->cbFormat;
opts.cbParms = acd->cbParms;
if (acd->lpFormat && acd->cbFormat) {
opts.lpFormat = malloc(opts.cbFormat);
memcpy(opts.lpFormat, acd->lpFormat, opts.cbFormat);
}
if (acd->lpParms && acd->cbParms) {
opts.lpParms = malloc(opts.cbParms);
memcpy(opts.lpParms, acd->lpParms, opts.cbParms);
}
}
}
static void free_opts_data()
{
if (opts.lpFormat) {
free(opts.lpFormat);
opts.lpFormat = NULL;
}
if (opts.lpParms) {
free(opts.lpParms);
opts.lpParms = NULL;
}
}
static int open_avi_codec_file(char * name)
{
HRESULT hr;
WORD wVer;
BITMAPINFOHEADER bmi;
AVISTREAMINFO strhdr;
int ret_val = 0;
wVer = HIWORD(VideoForWindowsVersion());
if (wVer < 0x010a){
// this is probably an obsolete check...
ret_val = 1;
} else {
AVIFileInit();
avifileinitdone++;
hr = AVIFileOpen(&pfile, // returned file pointer
name, // file name
OF_WRITE | OF_CREATE, // mode to open file with
NULL); // use handler determined
if (hr != AVIERR_OK) {
ret_val = 1;
} else {
// initialize the BITMAPINFOHEADER
init_bmi(&bmi);
// and associate a stream with the input images
memset(&strhdr, 0, sizeof(strhdr));
strhdr.fccType = streamtypeVIDEO; // stream type
if (G.scene->r.avicodecdata) {
strhdr.fccHandler = G.scene->r.avicodecdata->fccHandler;
}
strhdr.dwScale = 1;
strhdr.dwRate = R.r.frs_sec;
strhdr.dwSuggestedBufferSize = bmi.biSizeImage;
SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream
(int) bmi.biWidth,
(int) bmi.biHeight);
// And create the stream
hr = AVIFileCreateStream(
pfile, // file pointer
&psUncompressed,// returned stream pointer
&strhdr); // stream header
if (hr != AVIERR_OK) {
ret_val = 1;
} else {
acd_to_opts(G.scene->r.avicodecdata);
}
}
}
return(ret_val);
}
void end_avi_codec(void)
{
free_opts_data();
if (psUncompressed) {
AVIStreamClose(psUncompressed);
psUncompressed = NULL;
}
if (psCompressed) {
AVIStreamClose(psCompressed);
psCompressed = NULL;
}
if (pfile) {
AVIFileClose(pfile);
pfile = NULL;
}
if (avifileinitdone > 0) {
AVIFileExit();
avifileinitdone--;
}
}
void start_avi_codec(void)
{
HRESULT hr;
BITMAPINFOHEADER bmi;
char name[2048];
char bakname[2048];
makeavistring(name);
sframe = (G.scene->r.sfra);
strcpy(bakname, name);
strcat(bakname, ".bak");
if (BLI_exists(name)) {
BLI_move(name, bakname);
}
// initialize the BITMAPINFOHEADER
init_bmi(&bmi);
if (open_avi_codec_file(name)) {
error("Can not open file %s", name);
G.afbreek = 1;
} else {
// now create a compressed stream from the uncompressed
// stream and the compression options
hr = AVIMakeCompressedStream(
&psCompressed, // returned stream pointer
psUncompressed, // uncompressed stream
&opts, // compression options
NULL); // Unknown...
if (hr != AVIERR_OK) {
error("Codec is locked or not supported.");
G.afbreek = 1;
} else {
hr = AVIStreamSetFormat(psCompressed, 0,
&bmi, // stream format
bmi.biSize + // format size
bmi.biClrUsed * sizeof(RGBQUAD)); // plus size of colormap
if (hr != AVIERR_OK) {
error("Codec is locked or not supported.");
G.afbreek = 1;
}
}
}
if (G.afbreek != 1) {
printf("Created win avi: %s\n", name);
if (BLI_exists(bakname)) {
BLI_delete(bakname, 0, 0);
}
} else {
// close the darn thing and remove it.
end_avi_codec();
if (BLI_exists(name)) {
BLI_delete(name, 0, 0);
}
if (BLI_exists(bakname)) {
BLI_move(bakname, name);
}
}
}
void append_avi_codec(int frame)
{
HRESULT hr;
BITMAPINFOHEADER bmi;
RGBTRIPLE *buffer, *to;
int x, y;
unsigned char *from;
if (psCompressed) {
// initialize the BITMAPINFOHEADER
init_bmi(&bmi);
// copy pixels
buffer = MEM_mallocN(bmi.biSizeImage, "append_win_avi");
to = buffer;
from = (unsigned char *) R.rectot;
for (y = R.recty; y > 0 ; y--) {
for (x = R.rectx; x > 0 ; x--) {
to->rgbtRed = from[0];
to->rgbtGreen = from[1];
to->rgbtBlue = from[2];
to++; from += 4;
}
}
hr = AVIStreamWrite(
psCompressed, // stream pointer
frame - sframe, // frame number
1, // number to write
(LPBYTE) buffer,// pointer to data
bmi.biSizeImage,// size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
MEM_freeN(buffer);
if (hr != AVIERR_OK) {
G.afbreek = 1;
} else {
printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe);
}
}
}
int get_avicodec_settings(void)
{
int ret_val = 0;
AVICOMPRESSOPTIONS *aopts[1] = {&opts};
AviCodecData *acd = G.scene->r.avicodecdata;
static PAVISTREAM psdummy;
UINT uiFlags;
acd_to_opts(G.scene->r.avicodecdata);
psdummy = NewBall();
if(U.uiflag & ALLWINCODECS)
uiFlags = ICMF_CHOOSE_ALLCOMPRESSORS;
else
uiFlags = ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE;
if (psdummy == NULL) {
ret_val = 1;
} else {
if (!AVISaveOptions(NULL,
uiFlags,
// ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
// ICMF_CHOOSE_ALLCOMPRESSORS,
1,
&psdummy,
(LPAVICOMPRESSOPTIONS *) &aopts))
{
ret_val = 1;
} else {
if (acd) {
free_avicodecdata(acd);
} else {
acd = G.scene->r.avicodecdata = MEM_callocN(sizeof(AviCodecData), "AviCodecData");
}
opts_to_acd(acd);
AVISaveOptionsFree(1, aopts);
memset(&opts, 0, sizeof(opts));
}
}
return(ret_val);
}
#endif // _WIN32