~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to source/blender/src/writeavicodec.c

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Functions for writing windows avi-format files.
 
3
 *
 
4
 * $Id: writeavicodec.c 14444 2008-04-16 22:40:48Z hos $
 
5
 *
 
6
 * ***** BEGIN GPL LICENSE BLOCK *****
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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.
 
21
 *
 
22
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 
23
 * All rights reserved.
 
24
 *
 
25
 * The Original Code is: all of this file.
 
26
 *
 
27
 * Contributor(s): none yet.
 
28
 *
 
29
 * ***** END GPL LICENSE BLOCK *****
 
30
 * 
 
31
 */
 
32
 
 
33
#ifdef HAVE_CONFIG_H
 
34
#include <config.h>
 
35
#endif
 
36
 
 
37
#if defined(_WIN32) && !defined(FREE_WINDOWS)
 
38
 
 
39
#define  INC_OLE2
 
40
#include <windows.h>
 
41
#undef rad1
 
42
#undef rad2
 
43
 
 
44
#include <windowsx.h>
 
45
#include <memory.h>
 
46
#include <mmsystem.h>
 
47
#include <vfw.h>
 
48
 
 
49
#include <string.h>
 
50
 
 
51
#include "MEM_guardedalloc.h"
 
52
#include "BLI_blenlib.h"
 
53
#include "DNA_userdef_types.h"
 
54
#include "DNA_scene_types.h"
 
55
 
 
56
#include "BKE_global.h"
 
57
#include "BKE_scene.h"
 
58
#include "BKE_writeavi.h"
 
59
 
 
60
#include "BIF_toolbox.h"
 
61
 
 
62
// this defines the compression type for
 
63
// the output video stream
 
64
 
 
65
AVICOMPRESSOPTIONS opts;
 
66
 
 
67
static int sframe;
 
68
static PAVIFILE pfile = NULL;
 
69
static int avifileinitdone = 0;
 
70
static PAVISTREAM psUncompressed = NULL, psCompressed = NULL;
 
71
 
 
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 );
 
78
 
 
79
///////////////////////////////////////////////////////////////////////////
 
80
//
 
81
// silly default parameters
 
82
//
 
83
///////////////////////////////////////////////////////////////////////////
 
84
 
 
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)
 
90
#define XSPEED          7
 
91
#define YSPEED          5
 
92
 
 
93
///////////////////////////////////////////////////////////////////////////
 
94
//
 
95
// useful macros
 
96
//
 
97
///////////////////////////////////////////////////////////////////////////
 
98
 
 
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) )
 
105
 
 
106
///////////////////////////////////////////////////////////////////////////
 
107
//
 
108
// custom video stream instance structure
 
109
//
 
110
///////////////////////////////////////////////////////////////////////////
 
111
 
 
112
typedef struct {
 
113
 
 
114
    //
 
115
    // The Vtbl must come first
 
116
    //
 
117
    IAVIStreamVtbl * lpvtbl;
 
118
 
 
119
    //
 
120
    //  private ball instance data
 
121
    //
 
122
    ULONG       ulRefCount;
 
123
 
 
124
    DWORD       fccType;        // is this audio/video
 
125
 
 
126
    int         width;          // size in pixels of each frame
 
127
    int         height;
 
128
    int         length;         // length in frames of the pretend AVI movie
 
129
    int         size;
 
130
    COLORREF    color;          // ball color
 
131
 
 
132
} AVIBALL, * PAVIBALL;
 
133
 
 
134
///////////////////////////////////////////////////////////////////////////
 
135
//
 
136
// custom stream methods
 
137
//
 
138
///////////////////////////////////////////////////////////////////////////
 
139
 
 
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);
 
153
 
 
154
IAVIStreamVtbl AVIBallHandler = {
 
155
    AVIBallQueryInterface,
 
156
    AVIBallAddRef,
 
157
    AVIBallRelease,
 
158
    AVIBallCreate,
 
159
    AVIBallInfo,
 
160
    AVIBallFindSample,
 
161
    AVIBallReadFormat,
 
162
    AVIBallSetFormat,
 
163
    AVIBallRead,
 
164
    AVIBallWrite,
 
165
    AVIBallDelete,
 
166
    AVIBallReadData,
 
167
    AVIBallWriteData
 
168
};
 
169
 
 
170
 
 
171
//
 
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.
 
175
//
 
176
PAVISTREAM WINAPI NewBall(void)
 
177
{
 
178
        static AVIBALL ball;
 
179
    PAVIBALL pball = &ball;
 
180
 
 
181
    //
 
182
    // Fill the function table
 
183
    //
 
184
    pball->lpvtbl = &AVIBallHandler;
 
185
 
 
186
    //
 
187
    // Call our own create code to create a new instance (calls AVIBallCreate)
 
188
    // For now, don't use any lParams.
 
189
    //
 
190
    pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);
 
191
 
 
192
    return (PAVISTREAM) pball;
 
193
}
 
194
 
 
195
///////////////////////////////////////////////////////////////////////////
 
196
//
 
197
// This function is called to initialize an instance of the bouncing ball.
 
198
//
 
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).
 
202
//
 
203
///////////////////////////////////////////////////////////////////////////
 
204
HRESULT STDMETHODCALLTYPE AVIBallCreate(PAVISTREAM ps, LONG lParam1, LONG lParam2)
 
205
{
 
206
    PAVIBALL pball = (PAVIBALL) ps;
 
207
 
 
208
    //
 
209
    // what type of data are we? (audio/video/other stream)
 
210
    //
 
211
    pball->fccType = streamtypeVIDEO;
 
212
 
 
213
    //
 
214
    // We define lParam1 as being the length of movie they want us to pretend
 
215
    // to be.
 
216
    //
 
217
    if (lParam1)
 
218
        pball->length = (int) lParam1;
 
219
    else
 
220
        pball->length = DEFAULT_LENGTH;
 
221
 
 
222
    switch (pball->fccType) {
 
223
 
 
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
 
231
 
 
232
        case streamtypeAUDIO:
 
233
            return ResultFromScode(AVIERR_UNSUPPORTED); // we don't do audio
 
234
 
 
235
        default:
 
236
            return ResultFromScode(AVIERR_UNSUPPORTED); // or anything else
 
237
    }
 
238
}
 
239
 
 
240
 
 
241
//
 
242
// Increment our reference count
 
243
//
 
244
ULONG STDMETHODCALLTYPE AVIBallAddRef(PAVISTREAM ps)
 
245
{
 
246
    PAVIBALL pball = (PAVIBALL) ps;
 
247
    return (++pball->ulRefCount);
 
248
}
 
249
 
 
250
 
 
251
//
 
252
// Decrement our reference count
 
253
//
 
254
ULONG STDMETHODCALLTYPE AVIBallRelease(PAVISTREAM ps)
 
255
{
 
256
    PAVIBALL pball = (PAVIBALL) ps;
 
257
    if (--pball->ulRefCount)
 
258
        return pball->ulRefCount;
 
259
 
 
260
    // Free any data we're keeping around - like our private structure
 
261
    GlobalFreePtr(pball);
 
262
 
 
263
    return 0;
 
264
}
 
265
 
 
266
 
 
267
//
 
268
// Fills an AVISTREAMINFO structure
 
269
//
 
270
HRESULT STDMETHODCALLTYPE AVIBallInfo(PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize)
 
271
{
 
272
    PAVIBALL pball = (PAVIBALL) ps;
 
273
 
 
274
    if (lSize < sizeof(AVISTREAMINFO))
 
275
        return ResultFromScode(AVIERR_BUFFERTOOSMALL);
 
276
 
 
277
    _fmemset(psi, 0, (int)lSize);
 
278
 
 
279
    // Fill out a stream header with information about us.
 
280
    psi->fccType                = pball->fccType;
 
281
    psi->fccHandler             = mmioFOURCC('B','a','l','l');
 
282
    psi->dwScale                = 1;
 
283
    psi->dwRate                 = 15;
 
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"));
 
291
 
 
292
    return AVIERR_OK;
 
293
}
 
294
 
 
295
///////////////////////////////////////////////////////////////////////////
 
296
//
 
297
// AVIBallReadFormat: needs to return the format of our data.
 
298
//
 
299
///////////////////////////////////////////////////////////////////////////
 
300
HRESULT STDMETHODCALLTYPE AVIBallReadFormat   (PAVISTREAM ps, LONG lPos,LPVOID lpFormat,LONG *lpcbFormat)
 
301
{
 
302
    PAVIBALL pball = (PAVIBALL) ps;
 
303
    LPBITMAPINFO    lpbi = (LPBITMAPINFO) lpFormat;
 
304
        
 
305
    if (lpFormat == NULL || *lpcbFormat == 0) {
 
306
                *lpcbFormat = sizeof(BITMAPINFOHEADER);
 
307
                return AVIERR_OK;
 
308
    }
 
309
        
 
310
    if (*lpcbFormat < sizeof(BITMAPINFOHEADER))
 
311
                return ResultFromScode(AVIERR_BUFFERTOOSMALL);
 
312
        
 
313
    // This is a relatively silly example: we build up our
 
314
    // format from scratch every time.
 
315
        
 
316
        /*
 
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);
 
325
        */
 
326
        
 
327
        //init_bmi(&lpbi->bmiHeader);
 
328
 
 
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);
 
336
 
 
337
        /*
 
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);
 
344
        */
 
345
        
 
346
    *lpcbFormat = sizeof(BITMAPINFOHEADER);
 
347
 
 
348
    return AVIERR_OK;
 
349
}
 
350
 
 
351
///////////////////////////////////////////////////////////////////////////
 
352
//
 
353
// AVIBallRead: needs to return the data for a particular frame.
 
354
//
 
355
///////////////////////////////////////////////////////////////////////////
 
356
HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart,LONG lSamples,LPVOID lpBuffer,LONG cbBuffer,LONG * plBytes,LONG * plSamples)
 
357
{
 
358
    PAVIBALL pball = (PAVIBALL) ps;
 
359
    LONG   lSize = pball->height * ALIGNULONG(pball->width); // size of frame
 
360
        // in bytes
 
361
    int x, y;
 
362
    HPSTR hp = lpBuffer;
 
363
    int xPos, yPos;
 
364
        
 
365
    // Reject out of range values
 
366
    if (lStart < 0 || lStart >= pball->length)
 
367
                return ResultFromScode(AVIERR_BADPARAM);
 
368
        
 
369
    // Did they just want to know the size of our data?
 
370
    if (lpBuffer == NULL || cbBuffer == 0)
 
371
                goto exit;
 
372
        
 
373
    // Will our frame fit in the buffer passed?
 
374
    if (lSize > cbBuffer)
 
375
                return ResultFromScode(AVIERR_BUFFERTOOSMALL);
 
376
        
 
377
    // Figure out the position of the ball.
 
378
    // It just bounces back and forth.
 
379
        
 
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
 
384
        
 
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;
 
389
        
 
390
    //
 
391
    // Build a DIB from scratch by writing in 1's where the ball is, 0's
 
392
    // where it isn't.
 
393
    //
 
394
    // Notice that we just build it in the buffer we've been passed.
 
395
    //
 
396
    // This is pretty ugly, I have to admit.
 
397
    //
 
398
    for (y = 0; y < pball->height; y++)
 
399
        {
 
400
                if (y >= yPos && y < yPos + pball->size)
 
401
                {
 
402
                        for (x = 0; x < pball->width; x++)
 
403
                        {
 
404
                                *hp++ = (BYTE) ((x >= xPos && x < xPos + pball->size) ? 1 : 0);
 
405
                        }
 
406
                }
 
407
                else
 
408
                {
 
409
                        for (x = 0; x < pball->width; x++)
 
410
                        {
 
411
                                *hp++ = 0;
 
412
                        }
 
413
                }
 
414
                
 
415
                hp += pball->width - ALIGNULONG(pball->width);
 
416
    }
 
417
        
 
418
exit:
 
419
    // We always return exactly one frame
 
420
    if (plSamples)
 
421
                *plSamples = 1;
 
422
        
 
423
    // Return the size of our frame
 
424
    if (plBytes)
 
425
                *plBytes = lSize;
 
426
        
 
427
    return AVIERR_OK;
 
428
}
 
429
 
 
430
 
 
431
HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj)
 
432
{
 
433
    PAVIBALL pball = (PAVIBALL) ps;
 
434
 
 
435
    // We support the Unknown interface (everybody does) and our Stream
 
436
    // interface.
 
437
 
 
438
    if (_fmemcmp(riid, &IID_IUnknown, sizeof(GUID)) == 0)
 
439
        *ppvObj = (LPVOID)pball;
 
440
 
 
441
    else if (_fmemcmp(riid, &IID_IAVIStream, sizeof(GUID)) == 0)
 
442
        *ppvObj = (LPVOID)pball;
 
443
 
 
444
    else {
 
445
        *ppvObj = NULL;
 
446
        return ResultFromScode(E_NOINTERFACE);
 
447
    }
 
448
 
 
449
    AVIBallAddRef(ps);
 
450
 
 
451
    return AVIERR_OK;
 
452
}
 
453
 
 
454
LONG    STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags)
 
455
{
 
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
 
460
        else
 
461
            return 0;
 
462
 
 
463
    // FIND_KEY and FIND_ANY always return the same position because
 
464
    // every frame is non-empty and a key frame
 
465
    } else
 
466
        return lPos;
 
467
}
 
468
 
 
469
HRESULT STDMETHODCALLTYPE AVIBallReadData     (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG *lpcb)
 
470
{
 
471
    return ResultFromScode(AVIERR_UNSUPPORTED);
 
472
}
 
473
 
 
474
HRESULT STDMETHODCALLTYPE AVIBallSetFormat    (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat)
 
475
{
 
476
    return ResultFromScode(AVIERR_UNSUPPORTED);
 
477
}
 
478
 
 
479
HRESULT STDMETHODCALLTYPE AVIBallWriteData    (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG cb)
 
480
{
 
481
    return ResultFromScode(AVIERR_UNSUPPORTED);
 
482
}
 
483
 
 
484
HRESULT STDMETHODCALLTYPE AVIBallWrite        (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten)
 
485
{
 
486
    return ResultFromScode(AVIERR_UNSUPPORTED);
 
487
}
 
488
 
 
489
HRESULT STDMETHODCALLTYPE AVIBallDelete       (PAVISTREAM ps, LONG lStart, LONG lSamples)
 
490
{
 
491
    return ResultFromScode(AVIERR_UNSUPPORTED);
 
492
}
 
493
 
 
494
 
 
495
//////////////////////////////////////
 
496
static void init_bmi(BITMAPINFOHEADER *bmi,int rectx, int recty )
 
497
{
 
498
        memset(bmi, 0, sizeof(BITMAPINFOHEADER));
 
499
        bmi->biSize = sizeof(BITMAPINFOHEADER);
 
500
        bmi->biWidth = rectx;
 
501
        bmi->biHeight = recty;
 
502
        bmi->biPlanes = 1;
 
503
        bmi->biBitCount = 24;
 
504
        bmi->biSizeImage = bmi->biWidth * bmi->biHeight * sizeof(RGBTRIPLE);
 
505
}
 
506
 
 
507
 
 
508
static void opts_to_acd(AviCodecData *acd)
 
509
{
 
510
        HIC hic;
 
511
        ICINFO icinfo;
 
512
 
 
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;
 
522
 
 
523
        if (opts.lpFormat && opts.cbFormat) {
 
524
                acd->lpFormat = MEM_mallocN(opts.cbFormat, "avi.lpFormat");
 
525
                memcpy(acd->lpFormat, opts.lpFormat, opts.cbFormat);
 
526
        }
 
527
 
 
528
        if (opts.lpParms && opts.cbParms) {
 
529
                acd->lpParms = MEM_mallocN(opts.cbParms, "avi.lpParms");
 
530
                memcpy(acd->lpParms, opts.lpParms, opts.cbParms);
 
531
        }
 
532
 
 
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);
 
537
                } else
 
538
                        sprintf(acd->avicodecname, "undefined");
 
539
                if (ICClose(hic)!=ICERR_OK)
 
540
;//                     return 0;
 
541
        } else {
 
542
                sprintf(acd->avicodecname, "Full Frames (Uncompressed)");       //heh, nasty
 
543
        }
 
544
}
 
545
 
 
546
 
 
547
static void acd_to_opts(AviCodecData *acd)
 
548
{
 
549
        memset(&opts, 0, sizeof(opts));
 
550
        if (acd) {
 
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;
 
560
                
 
561
                if (acd->lpFormat && acd->cbFormat) {
 
562
                        opts.lpFormat = MEM_mallocN(opts.cbFormat, "opts lpFormat");
 
563
                        memcpy(opts.lpFormat, acd->lpFormat, opts.cbFormat);
 
564
                }
 
565
 
 
566
                if (acd->lpParms && acd->cbParms) {
 
567
                        opts.lpParms = MEM_mallocN(opts.cbParms, "opts.cbParms");
 
568
                        memcpy(opts.lpParms, acd->lpParms, opts.cbParms);
 
569
                }
 
570
        }
 
571
}
 
572
 
 
573
static void free_opts_data()
 
574
{
 
575
        if (opts.lpFormat) {
 
576
                MEM_freeN(opts.lpFormat);
 
577
                opts.lpFormat = NULL;
 
578
        }
 
579
        if (opts.lpParms) {
 
580
                MEM_freeN(opts.lpParms);
 
581
                opts.lpParms = NULL;
 
582
        }
 
583
}
 
584
 
 
585
static int open_avi_codec_file(char * name,RenderData *rd,int rectx, int recty )
 
586
{
 
587
        HRESULT hr;
 
588
        WORD wVer;
 
589
        BITMAPINFOHEADER bmi;
 
590
        AVISTREAMINFO strhdr;
 
591
        int ret_val = 0;
 
592
 
 
593
        wVer = HIWORD(VideoForWindowsVersion());
 
594
        if (wVer < 0x010a){
 
595
                // this is probably an obsolete check...
 
596
                ret_val = 1;
 
597
        } else {
 
598
                AVIFileInit();
 
599
                avifileinitdone++;
 
600
 
 
601
                hr = AVIFileOpen(&pfile,                // returned file pointer
 
602
                                name,                                   // file name
 
603
                                OF_WRITE | OF_CREATE,   // mode to open file with
 
604
                                NULL);                                  // use handler determined
 
605
 
 
606
                if (hr != AVIERR_OK) {
 
607
                        ret_val = 1;
 
608
                } else {
 
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;
 
616
                        }
 
617
                        strhdr.dwScale                = 1;
 
618
                        strhdr.dwRate                 = rd->frs_sec;
 
619
                        strhdr.dwSuggestedBufferSize  = bmi.biSizeImage;
 
620
                        SetRect(&strhdr.rcFrame, 0, 0,                                          // rectangle for stream
 
621
                                (int) bmi.biWidth,
 
622
                                (int) bmi.biHeight);
 
623
 
 
624
                        // And create the stream
 
625
                        hr = AVIFileCreateStream(
 
626
                                        pfile,              // file pointer
 
627
                                        &psUncompressed,// returned stream pointer
 
628
                                        &strhdr);           // stream header
 
629
 
 
630
                        if (hr != AVIERR_OK) {
 
631
                                ret_val = 1;
 
632
                        } else {
 
633
                                acd_to_opts(G.scene->r.avicodecdata);
 
634
                        }
 
635
                }
 
636
        }
 
637
 
 
638
        return(ret_val);
 
639
}
 
640
 
 
641
 
 
642
void end_avi_codec(void)
 
643
{
 
644
        free_opts_data();
 
645
 
 
646
        if (psUncompressed) {
 
647
                AVIStreamClose(psUncompressed);
 
648
                psUncompressed = NULL;
 
649
        }
 
650
 
 
651
        if (psCompressed) {
 
652
                AVIStreamClose(psCompressed);
 
653
                psCompressed = NULL;
 
654
        }
 
655
 
 
656
        if (pfile) {
 
657
                AVIFileClose(pfile);
 
658
                pfile = NULL;
 
659
        }
 
660
 
 
661
        if (avifileinitdone > 0) {
 
662
                AVIFileExit();
 
663
                avifileinitdone--;
 
664
        }
 
665
}
 
666
 
 
667
 
 
668
void start_avi_codec(RenderData *rd,int rectx, int recty )
 
669
{
 
670
        HRESULT hr;
 
671
        BITMAPINFOHEADER bmi;
 
672
        char name[2048];
 
673
        char bakname[2048];
 
674
        
 
675
        makeavistring(rd,name);
 
676
        sframe = (G.scene->r.sfra);
 
677
 
 
678
        strcpy(bakname, name);
 
679
        strcat(bakname, ".bak");
 
680
 
 
681
        if (BLI_exists(name)) {
 
682
                BLI_move(name, bakname);
 
683
        }
 
684
 
 
685
        // initialize the BITMAPINFOHEADER 
 
686
        init_bmi(&bmi,rectx,recty);
 
687
 
 
688
        if (open_avi_codec_file(name,rd,rectx,recty)) {
 
689
                error("Can not open file %s", name);
 
690
                G.afbreek = 1;
 
691
        } else {
 
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
 
698
                                NULL);                  // Unknown...
 
699
                if (hr != AVIERR_OK) {
 
700
                        error("Codec is locked or not supported.");
 
701
                        G.afbreek = 1;
 
702
                } else {
 
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.");
 
710
                                G.afbreek = 1;
 
711
                        }
 
712
                }
 
713
        }
 
714
 
 
715
        if (G.afbreek != 1) {
 
716
                printf("Created win avi: %s\n", name);
 
717
                if (BLI_exists(bakname)) {
 
718
                        BLI_delete(bakname, 0, 0);
 
719
                }
 
720
        } else {
 
721
                // close the darn thing and remove it.
 
722
                end_avi_codec();
 
723
                if (BLI_exists(name)) {
 
724
                        BLI_delete(name, 0, 0);
 
725
                }
 
726
                if (BLI_exists(bakname)) {
 
727
                        BLI_move(bakname, name);
 
728
                }
 
729
        }
 
730
}
 
731
 
 
732
 
 
733
void append_avi_codec(int frame,int *pixels,int rectx, int recty)
 
734
{
 
735
        HRESULT hr;
 
736
        BITMAPINFOHEADER bmi;
 
737
        RGBTRIPLE *buffer, *to;
 
738
        int x, y ,pad, align =2;
 
739
        unsigned char *from;
 
740
 
 
741
        if (psCompressed) {
 
742
                // initialize the BITMAPINFOHEADER 
 
743
                init_bmi(&bmi, rectx, recty);
 
744
 
 
745
                //windows wants bitmap rows  aligned
 
746
                pad = (rectx*3) - align*((rectx*3)/align);
 
747
                if (pad) {
 
748
                pad = align - pad;
 
749
                }
 
750
 
 
751
                // copy pixels
 
752
                buffer = MEM_mallocN(bmi.biSizeImage + pad * recty, "append_win_avi");
 
753
                to = buffer;
 
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];
 
760
                                to++; from += 4;
 
761
                        }
 
762
                        (unsigned char *)to += pad;
 
763
                }
 
764
 
 
765
                hr = AVIStreamWrite(
 
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....
 
772
                                NULL,
 
773
                                NULL);
 
774
 
 
775
                MEM_freeN(buffer);
 
776
 
 
777
                if (hr != AVIERR_OK) {
 
778
                        G.afbreek = 1;
 
779
                } else {
 
780
                        printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe);
 
781
                }
 
782
        }
 
783
}
 
784
 
 
785
 
 
786
int get_avicodec_settings(void)
 
787
{
 
788
        int ret_val = 0;
 
789
        AVICOMPRESSOPTIONS *aopts[1] = {&opts};
 
790
        AviCodecData *acd = G.scene->r.avicodecdata;
 
791
        static PAVISTREAM psdummy;
 
792
        UINT    uiFlags;
 
793
 
 
794
        acd_to_opts(G.scene->r.avicodecdata);
 
795
 
 
796
        psdummy = NewBall();
 
797
 
 
798
        if(U.uiflag & USER_ALLWINCODECS)
 
799
                uiFlags = ICMF_CHOOSE_ALLCOMPRESSORS;
 
800
        else
 
801
                uiFlags = ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE;
 
802
 
 
803
        if (psdummy == NULL) {
 
804
                ret_val = 1;
 
805
        } else {
 
806
                if (!AVISaveOptions(NULL,
 
807
                                uiFlags,
 
808
//                              ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
 
809
//                              ICMF_CHOOSE_ALLCOMPRESSORS,
 
810
                                1,
 
811
                                &psdummy,
 
812
                                (LPAVICOMPRESSOPTIONS *) &aopts))
 
813
                {
 
814
                        ret_val = 1;
 
815
                } else {
 
816
                        if (acd) {
 
817
                                free_avicodecdata(acd);
 
818
                        } else {
 
819
                                acd = G.scene->r.avicodecdata = MEM_callocN(sizeof(AviCodecData), "AviCodecData");
 
820
                        }
 
821
 
 
822
                        opts_to_acd(acd);
 
823
 
 
824
                        AVISaveOptionsFree(1, aopts);
 
825
                        memset(&opts, 0, sizeof(opts));
 
826
                }
 
827
        }
 
828
 
 
829
        return(ret_val);
 
830
}
 
831
 
 
832
#endif // _WIN32