2
* Functions for writing windows avi-format files.
4
* $Id: writeavicodec.c 14444 2008-04-16 22:40:48Z hos $
6
* ***** BEGIN GPL LICENSE BLOCK *****
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License
10
* as published by the Free Software Foundation; either version 2
11
* of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software Foundation,
20
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23
* All rights reserved.
25
* The Original Code is: all of this file.
27
* Contributor(s): none yet.
29
* ***** END GPL LICENSE BLOCK *****
37
#if defined(_WIN32) && !defined(FREE_WINDOWS)
51
#include "MEM_guardedalloc.h"
52
#include "BLI_blenlib.h"
53
#include "DNA_userdef_types.h"
54
#include "DNA_scene_types.h"
56
#include "BKE_global.h"
57
#include "BKE_scene.h"
58
#include "BKE_writeavi.h"
60
#include "BIF_toolbox.h"
62
// this defines the compression type for
63
// the output video stream
65
AVICOMPRESSOPTIONS opts;
68
static PAVIFILE pfile = NULL;
69
static int avifileinitdone = 0;
70
static PAVISTREAM psUncompressed = NULL, psCompressed = NULL;
72
// function definitions
73
static void init_bmi(BITMAPINFOHEADER *bmi,int rectx, int recty );
74
static void opts_to_acd(AviCodecData *acd);
75
static void acd_to_opts(AviCodecData *acd);
76
static void free_opts_data();
77
static int open_avi_codec_file(char * name,RenderData *rd,int rectx, int recty );
79
///////////////////////////////////////////////////////////////////////////
81
// silly default parameters
83
///////////////////////////////////////////////////////////////////////////
85
#define DEFAULT_WIDTH 240
86
#define DEFAULT_HEIGHT 120
87
#define DEFAULT_LENGTH 100
88
#define DEFAULT_SIZE 6
89
#define DEFAULT_COLOR RGB(255,0,0)
93
///////////////////////////////////////////////////////////////////////////
97
///////////////////////////////////////////////////////////////////////////
99
#define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
100
#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
101
#define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
102
#define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
103
(int)(lpbi)->biSize + \
104
(int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
106
///////////////////////////////////////////////////////////////////////////
108
// custom video stream instance structure
110
///////////////////////////////////////////////////////////////////////////
115
// The Vtbl must come first
117
IAVIStreamVtbl * lpvtbl;
120
// private ball instance data
124
DWORD fccType; // is this audio/video
126
int width; // size in pixels of each frame
128
int length; // length in frames of the pretend AVI movie
130
COLORREF color; // ball color
132
} AVIBALL, * PAVIBALL;
134
///////////////////////////////////////////////////////////////////////////
136
// custom stream methods
138
///////////////////////////////////////////////////////////////////////////
140
HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj);
141
HRESULT STDMETHODCALLTYPE AVIBallCreate (PAVISTREAM ps, LONG lParam1, LONG lParam2);
142
ULONG STDMETHODCALLTYPE AVIBallAddRef (PAVISTREAM ps);
143
ULONG STDMETHODCALLTYPE AVIBallRelease (PAVISTREAM ps);
144
HRESULT STDMETHODCALLTYPE AVIBallInfo (PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize);
145
LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags);
146
HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG *lpcbFormat);
147
HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat);
148
HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG * plBytes,LONG * plSamples);
149
HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten);
150
HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples);
151
HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG *lpcb);
152
HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG cb);
154
IAVIStreamVtbl AVIBallHandler = {
155
AVIBallQueryInterface,
172
// This is the function an application would call to create a PAVISTREAM to
173
// reference the ball. Then the standard AVIStream function calls can be
174
// used to work with this stream.
176
PAVISTREAM WINAPI NewBall(void)
179
PAVIBALL pball = &ball;
182
// Fill the function table
184
pball->lpvtbl = &AVIBallHandler;
187
// Call our own create code to create a new instance (calls AVIBallCreate)
188
// For now, don't use any lParams.
190
pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);
192
return (PAVISTREAM) pball;
195
///////////////////////////////////////////////////////////////////////////
197
// This function is called to initialize an instance of the bouncing ball.
199
// When called, we look at the information possibly passed in <lParam1>,
200
// if any, and use it to determine the length of movie they want. (Not
201
// supported by NewBall right now, but it could be).
203
///////////////////////////////////////////////////////////////////////////
204
HRESULT STDMETHODCALLTYPE AVIBallCreate(PAVISTREAM ps, LONG lParam1, LONG lParam2)
206
PAVIBALL pball = (PAVIBALL) ps;
209
// what type of data are we? (audio/video/other stream)
211
pball->fccType = streamtypeVIDEO;
214
// We define lParam1 as being the length of movie they want us to pretend
218
pball->length = (int) lParam1;
220
pball->length = DEFAULT_LENGTH;
222
switch (pball->fccType) {
224
case streamtypeVIDEO:
225
pball->color = DEFAULT_COLOR;
226
pball->width = DEFAULT_WIDTH;
227
pball->height = DEFAULT_HEIGHT;
228
pball->size = DEFAULT_SIZE;
229
pball->ulRefCount = 1; // note that we are opened once
230
return AVIERR_OK; // success
232
case streamtypeAUDIO:
233
return ResultFromScode(AVIERR_UNSUPPORTED); // we don't do audio
236
return ResultFromScode(AVIERR_UNSUPPORTED); // or anything else
242
// Increment our reference count
244
ULONG STDMETHODCALLTYPE AVIBallAddRef(PAVISTREAM ps)
246
PAVIBALL pball = (PAVIBALL) ps;
247
return (++pball->ulRefCount);
252
// Decrement our reference count
254
ULONG STDMETHODCALLTYPE AVIBallRelease(PAVISTREAM ps)
256
PAVIBALL pball = (PAVIBALL) ps;
257
if (--pball->ulRefCount)
258
return pball->ulRefCount;
260
// Free any data we're keeping around - like our private structure
261
GlobalFreePtr(pball);
268
// Fills an AVISTREAMINFO structure
270
HRESULT STDMETHODCALLTYPE AVIBallInfo(PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize)
272
PAVIBALL pball = (PAVIBALL) ps;
274
if (lSize < sizeof(AVISTREAMINFO))
275
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
277
_fmemset(psi, 0, (int)lSize);
279
// Fill out a stream header with information about us.
280
psi->fccType = pball->fccType;
281
psi->fccHandler = mmioFOURCC('B','a','l','l');
284
psi->dwLength = pball->length;
285
psi->dwSuggestedBufferSize = pball->height * ALIGNULONG(pball->width);
286
psi->rcFrame.right = pball->width;
287
psi->rcFrame.bottom = pball->height;
288
CopyMemory((PVOID)psi->szName,
289
(PVOID)L"Bouncing ball video",
290
sizeof(L"Bouncing ball video"));
295
///////////////////////////////////////////////////////////////////////////
297
// AVIBallReadFormat: needs to return the format of our data.
299
///////////////////////////////////////////////////////////////////////////
300
HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos,LPVOID lpFormat,LONG *lpcbFormat)
302
PAVIBALL pball = (PAVIBALL) ps;
303
LPBITMAPINFO lpbi = (LPBITMAPINFO) lpFormat;
305
if (lpFormat == NULL || *lpcbFormat == 0) {
306
*lpcbFormat = sizeof(BITMAPINFOHEADER);
310
if (*lpcbFormat < sizeof(BITMAPINFOHEADER))
311
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
313
// This is a relatively silly example: we build up our
314
// format from scratch every time.
317
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
318
lpbi->bmiHeader.biCompression = BI_RGB;
319
lpbi->bmiHeader.biWidth = pball->width;
320
lpbi->bmiHeader.biHeight = pball->height;
321
lpbi->bmiHeader.biBitCount = 8;
322
lpbi->bmiHeader.biPlanes = 1;
323
lpbi->bmiHeader.biClrUsed = 2;
324
lpbi->bmiHeader.biSizeImage = pball->height * DIBWIDTHBYTES(lpbi->bmiHeader);
327
//init_bmi(&lpbi->bmiHeader);
329
memset(&lpbi->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
330
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
331
lpbi->bmiHeader.biWidth = pball->width;
332
lpbi->bmiHeader.biHeight = pball->height;
333
lpbi->bmiHeader.biPlanes = 1;
334
lpbi->bmiHeader.biBitCount = 24;
335
lpbi->bmiHeader.biSizeImage = pball->width * pball->height * sizeof(RGBTRIPLE);
338
lpbi->bmiColors[0].rgbRed = 0;
339
lpbi->bmiColors[0].rgbGreen = 0;
340
lpbi->bmiColors[0].rgbBlue = 0;
341
lpbi->bmiColors[1].rgbRed = GetRValue(pball->color);
342
lpbi->bmiColors[1].rgbGreen = GetGValue(pball->color);
343
lpbi->bmiColors[1].rgbBlue = GetBValue(pball->color);
346
*lpcbFormat = sizeof(BITMAPINFOHEADER);
351
///////////////////////////////////////////////////////////////////////////
353
// AVIBallRead: needs to return the data for a particular frame.
355
///////////////////////////////////////////////////////////////////////////
356
HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart,LONG lSamples,LPVOID lpBuffer,LONG cbBuffer,LONG * plBytes,LONG * plSamples)
358
PAVIBALL pball = (PAVIBALL) ps;
359
LONG lSize = pball->height * ALIGNULONG(pball->width); // size of frame
365
// Reject out of range values
366
if (lStart < 0 || lStart >= pball->length)
367
return ResultFromScode(AVIERR_BADPARAM);
369
// Did they just want to know the size of our data?
370
if (lpBuffer == NULL || cbBuffer == 0)
373
// Will our frame fit in the buffer passed?
374
if (lSize > cbBuffer)
375
return ResultFromScode(AVIERR_BUFFERTOOSMALL);
377
// Figure out the position of the ball.
378
// It just bounces back and forth.
380
xPos = 5 + XSPEED * (int) lStart; // x = x0 + vt
381
xPos = xPos % ((pball->width - pball->size) * 2); // limit to 2xwidth
382
if (xPos > (pball->width - pball->size)) // reflect if
383
xPos = 2 * (pball->width - pball->size) - xPos; // needed
385
yPos = 5 + YSPEED * (int) lStart;
386
yPos = yPos % ((pball->height - pball->size) * 2);
387
if (yPos > (pball->height - pball->size))
388
yPos = 2 * (pball->height - pball->size) - yPos;
391
// Build a DIB from scratch by writing in 1's where the ball is, 0's
394
// Notice that we just build it in the buffer we've been passed.
396
// This is pretty ugly, I have to admit.
398
for (y = 0; y < pball->height; y++)
400
if (y >= yPos && y < yPos + pball->size)
402
for (x = 0; x < pball->width; x++)
404
*hp++ = (BYTE) ((x >= xPos && x < xPos + pball->size) ? 1 : 0);
409
for (x = 0; x < pball->width; x++)
415
hp += pball->width - ALIGNULONG(pball->width);
419
// We always return exactly one frame
423
// Return the size of our frame
431
HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj)
433
PAVIBALL pball = (PAVIBALL) ps;
435
// We support the Unknown interface (everybody does) and our Stream
438
if (_fmemcmp(riid, &IID_IUnknown, sizeof(GUID)) == 0)
439
*ppvObj = (LPVOID)pball;
441
else if (_fmemcmp(riid, &IID_IAVIStream, sizeof(GUID)) == 0)
442
*ppvObj = (LPVOID)pball;
446
return ResultFromScode(E_NOINTERFACE);
454
LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags)
456
// The only format change is frame 0
457
if ((lFlags & FIND_TYPE) == FIND_FORMAT) {
458
if ((lFlags & FIND_DIR) == FIND_NEXT && lPos > 0)
459
return -1; // no more format changes
463
// FIND_KEY and FIND_ANY always return the same position because
464
// every frame is non-empty and a key frame
469
HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG *lpcb)
471
return ResultFromScode(AVIERR_UNSUPPORTED);
474
HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat)
476
return ResultFromScode(AVIERR_UNSUPPORTED);
479
HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG cb)
481
return ResultFromScode(AVIERR_UNSUPPORTED);
484
HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten)
486
return ResultFromScode(AVIERR_UNSUPPORTED);
489
HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples)
491
return ResultFromScode(AVIERR_UNSUPPORTED);
495
//////////////////////////////////////
496
static void init_bmi(BITMAPINFOHEADER *bmi,int rectx, int recty )
498
memset(bmi, 0, sizeof(BITMAPINFOHEADER));
499
bmi->biSize = sizeof(BITMAPINFOHEADER);
500
bmi->biWidth = rectx;
501
bmi->biHeight = recty;
503
bmi->biBitCount = 24;
504
bmi->biSizeImage = bmi->biWidth * bmi->biHeight * sizeof(RGBTRIPLE);
508
static void opts_to_acd(AviCodecData *acd)
513
acd->fccType = opts.fccType;
514
acd->fccHandler = opts.fccHandler;
515
acd->dwKeyFrameEvery = opts.dwKeyFrameEvery;
516
acd->dwQuality = opts.dwQuality;
517
acd->dwBytesPerSecond = opts.dwBytesPerSecond;
518
acd->dwFlags = opts.dwFlags;
519
acd->dwInterleaveEvery = opts.dwInterleaveEvery;
520
acd->cbFormat = opts.cbFormat;
521
acd->cbParms = opts.cbParms;
523
if (opts.lpFormat && opts.cbFormat) {
524
acd->lpFormat = MEM_mallocN(opts.cbFormat, "avi.lpFormat");
525
memcpy(acd->lpFormat, opts.lpFormat, opts.cbFormat);
528
if (opts.lpParms && opts.cbParms) {
529
acd->lpParms = MEM_mallocN(opts.cbParms, "avi.lpParms");
530
memcpy(acd->lpParms, opts.lpParms, opts.cbParms);
533
if ((hic=ICOpen(ICTYPE_VIDEO,acd->fccHandler,ICMODE_QUERY))!=NULL) {
534
icinfo.dwSize=sizeof(ICINFO);
535
if (ICGetInfo(hic,&icinfo,sizeof(ICINFO))) {
536
WideCharToMultiByte(CP_ACP,0,icinfo.szDescription,-1,acd->avicodecname,128,NULL,NULL);
538
sprintf(acd->avicodecname, "undefined");
539
if (ICClose(hic)!=ICERR_OK)
542
sprintf(acd->avicodecname, "Full Frames (Uncompressed)"); //heh, nasty
547
static void acd_to_opts(AviCodecData *acd)
549
memset(&opts, 0, sizeof(opts));
551
opts.fccType = acd->fccType;
552
opts.fccHandler = acd->fccHandler;
553
opts.dwKeyFrameEvery = acd->dwKeyFrameEvery;
554
opts.dwQuality = acd->dwQuality;
555
opts.dwBytesPerSecond = acd->dwBytesPerSecond;
556
opts.dwFlags = acd->dwFlags;
557
opts.dwInterleaveEvery = acd->dwInterleaveEvery;
558
opts.cbFormat = acd->cbFormat;
559
opts.cbParms = acd->cbParms;
561
if (acd->lpFormat && acd->cbFormat) {
562
opts.lpFormat = MEM_mallocN(opts.cbFormat, "opts lpFormat");
563
memcpy(opts.lpFormat, acd->lpFormat, opts.cbFormat);
566
if (acd->lpParms && acd->cbParms) {
567
opts.lpParms = MEM_mallocN(opts.cbParms, "opts.cbParms");
568
memcpy(opts.lpParms, acd->lpParms, opts.cbParms);
573
static void free_opts_data()
576
MEM_freeN(opts.lpFormat);
577
opts.lpFormat = NULL;
580
MEM_freeN(opts.lpParms);
585
static int open_avi_codec_file(char * name,RenderData *rd,int rectx, int recty )
589
BITMAPINFOHEADER bmi;
590
AVISTREAMINFO strhdr;
593
wVer = HIWORD(VideoForWindowsVersion());
595
// this is probably an obsolete check...
601
hr = AVIFileOpen(&pfile, // returned file pointer
603
OF_WRITE | OF_CREATE, // mode to open file with
604
NULL); // use handler determined
606
if (hr != AVIERR_OK) {
609
// initialize the BITMAPINFOHEADER
610
init_bmi(&bmi,rectx,recty);
611
// and associate a stream with the input images
612
memset(&strhdr, 0, sizeof(strhdr));
613
strhdr.fccType = streamtypeVIDEO; // stream type
614
if (G.scene->r.avicodecdata) {
615
strhdr.fccHandler = G.scene->r.avicodecdata->fccHandler;
618
strhdr.dwRate = rd->frs_sec;
619
strhdr.dwSuggestedBufferSize = bmi.biSizeImage;
620
SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream
624
// And create the stream
625
hr = AVIFileCreateStream(
626
pfile, // file pointer
627
&psUncompressed,// returned stream pointer
628
&strhdr); // stream header
630
if (hr != AVIERR_OK) {
633
acd_to_opts(G.scene->r.avicodecdata);
642
void end_avi_codec(void)
646
if (psUncompressed) {
647
AVIStreamClose(psUncompressed);
648
psUncompressed = NULL;
652
AVIStreamClose(psCompressed);
661
if (avifileinitdone > 0) {
668
void start_avi_codec(RenderData *rd,int rectx, int recty )
671
BITMAPINFOHEADER bmi;
675
makeavistring(rd,name);
676
sframe = (G.scene->r.sfra);
678
strcpy(bakname, name);
679
strcat(bakname, ".bak");
681
if (BLI_exists(name)) {
682
BLI_move(name, bakname);
685
// initialize the BITMAPINFOHEADER
686
init_bmi(&bmi,rectx,recty);
688
if (open_avi_codec_file(name,rd,rectx,recty)) {
689
error("Can not open file %s", name);
692
// now create a compressed stream from the uncompressed
693
// stream and the compression options
694
hr = AVIMakeCompressedStream(
695
&psCompressed, // returned stream pointer
696
psUncompressed, // uncompressed stream
697
&opts, // compression options
699
if (hr != AVIERR_OK) {
700
error("Codec is locked or not supported.");
703
hr = AVIStreamSetFormat(psCompressed, 0,
704
&bmi, // stream format
705
bmi.biSize + // format size
706
bmi.biClrUsed * sizeof(RGBQUAD)); // plus size of colormap
707
if (hr != AVIERR_OK) {
708
printf("AVIStreamSetFormat() failed .. may be bad image dimensions? \n");
709
error("Codec refuses format.");
715
if (G.afbreek != 1) {
716
printf("Created win avi: %s\n", name);
717
if (BLI_exists(bakname)) {
718
BLI_delete(bakname, 0, 0);
721
// close the darn thing and remove it.
723
if (BLI_exists(name)) {
724
BLI_delete(name, 0, 0);
726
if (BLI_exists(bakname)) {
727
BLI_move(bakname, name);
733
void append_avi_codec(int frame,int *pixels,int rectx, int recty)
736
BITMAPINFOHEADER bmi;
737
RGBTRIPLE *buffer, *to;
738
int x, y ,pad, align =2;
742
// initialize the BITMAPINFOHEADER
743
init_bmi(&bmi, rectx, recty);
745
//windows wants bitmap rows aligned
746
pad = (rectx*3) - align*((rectx*3)/align);
752
buffer = MEM_mallocN(bmi.biSizeImage + pad * recty, "append_win_avi");
754
from = (unsigned char *) pixels;
755
for (y = recty; y > 0 ; y--) {
756
for (x = rectx; x > 0 ; x--) {
757
to->rgbtRed = from[0];
758
to->rgbtGreen = from[1];
759
to->rgbtBlue = from[2];
762
(unsigned char *)to += pad;
766
psCompressed, // stream pointer
767
frame - sframe, // frame number
768
1, // number to write
769
(LPBYTE) buffer,// pointer to data
770
bmi.biSizeImage + pad * recty, // size of this frame
771
AVIIF_KEYFRAME, // flags....
777
if (hr != AVIERR_OK) {
780
printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe);
786
int get_avicodec_settings(void)
789
AVICOMPRESSOPTIONS *aopts[1] = {&opts};
790
AviCodecData *acd = G.scene->r.avicodecdata;
791
static PAVISTREAM psdummy;
794
acd_to_opts(G.scene->r.avicodecdata);
798
if(U.uiflag & USER_ALLWINCODECS)
799
uiFlags = ICMF_CHOOSE_ALLCOMPRESSORS;
801
uiFlags = ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE;
803
if (psdummy == NULL) {
806
if (!AVISaveOptions(NULL,
808
// ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
809
// ICMF_CHOOSE_ALLCOMPRESSORS,
812
(LPAVICOMPRESSOPTIONS *) &aopts))
817
free_avicodecdata(acd);
819
acd = G.scene->r.avicodecdata = MEM_callocN(sizeof(AviCodecData), "AviCodecData");
824
AVISaveOptionsFree(1, aopts);
825
memset(&opts, 0, sizeof(opts));