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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/src/writeavicodec.c')
-rw-r--r--source/blender/src/writeavicodec.c799
1 files changed, 799 insertions, 0 deletions
diff --git a/source/blender/src/writeavicodec.c b/source/blender/src/writeavicodec.c
new file mode 100644
index 00000000000..6c19dfaac4e
--- /dev/null
+++ b/source/blender/src/writeavicodec.c
@@ -0,0 +1,799 @@
+/**
+ * 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 _WIN32
+
+#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 "render_types.h"
+#include "render.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)
+{
+ 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);
+ }
+}
+
+
+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_codec_settings(void)
+{
+ char name[2048];
+ int ret_val = 0;
+ AVICOMPRESSOPTIONS *aopts[1] = {&opts};
+ AviCodecData *acd = G.scene->r.avicodecdata;
+ static PAVISTREAM psdummy;
+
+ acd_to_opts(G.scene->r.avicodecdata);
+
+ psdummy = NewBall();
+
+ if (psdummy == NULL) {
+ ret_val = 1;
+ } else {
+ if (!AVISaveOptions(NULL,
+ ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
+ 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