~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/ADM_outputs/oplug_avi/op_aviwrite.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2007-12-18 13:53:04 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20071218135304-cdqec2lg2bglyz15
Tags: 1:2.4~preview3-0.0ubuntu1
* Upload to Ubuntu. (LP: #163287, LP: #126572)
* debian/changelog: re-added Ubuntu releases.
* debian/control:
  - Require debhelper >= 5.0.51 (for dh_icons) and imagemagick.
  - Build-depend on libsdl1.2-dev instead of libsdl-dev.
  - Build against newer libx264-dev. (LP: #138854)
  - Removed libamrnb-dev, not in Ubuntu yet.
* debian/rules:
  - Install all icon sizes, using convert (upstream installs none).
  - Added missing calls to dh_installmenu, dh_installman, dh_icons and
    dh_desktop.
* debian/menu, debian/avidemux-qt.menu:
  - Corrected package and executable names.
* debian/avidemux-common.install: Install icons.
* debian/avidemux.common.manpages: Install man/avidemux.1.
* debian/links, debian/avidemux-cli.links, debian/avidemux-gtk.links:
  - Link manpages to avidemux.1.gz.
* debian/install, debian/avidemux-qt.install, debian/avidemux-gtk.desktop,
  debian/avidemux-qt.desktop: Install desktop files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          oplug_avi.cpp  -  description
 
3
                             -------------------
 
4
 
 
5
                This set of function is here to provide a simple api to the gui
 
6
                It will facilitate the use of other function such as audio processing
 
7
                etc...
 
8
 
 
9
    begin                : Mon Feb 11 2002
 
10
    copyright            : (C) 2002 by mean
 
11
    email                : fixounet@free.fr
 
12
 ***************************************************************************/
 
13
 
 
14
 /*
 
15
 * MODIFIED Feb 2005 by GMV: ODML write support
 
16
 */
 
17
 
 
18
/***************************************************************************
 
19
 *                                                                         *
 
20
 *   This program is free software; you can redistribute it and/or modify  *
 
21
 *   it under the terms of the GNU General Public License as published by  *
 
22
 *   the Free Software Foundation; either version 2 of the License, or     *
 
23
 *   (at your option) any later version.                                   *
 
24
 *                                                                         *
 
25
 ***************************************************************************/
 
26
 
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
 
 
30
#include <string.h>
 
31
#include <strings.h>
 
32
#include <ADM_assert.h>
 
33
#include <math.h>
 
34
 
 
35
#include "config.h"
 
36
#include <pthread.h>
 
37
#define WIN32_CLASH
 
38
#include "avifmt.h"
 
39
#include "avifmt2.h"
 
40
#include "ADM_audio/aviaudio.hxx"
 
41
#include "fourcc.h"
 
42
#include "subchunk.h"
 
43
#include "avilist.h"
 
44
#include "op_aviwrite.hxx"
 
45
#include "ADM_toolkit/toolkit.hxx"
 
46
#include "ADM_osSupport/ADM_quota.h"
 
47
#include "ADM_fileio.h"
 
48
 
 
49
// MOD Feb 2005 by GMV
 
50
#include "ADM_osSupport/ADM_debugID.h"
 
51
#define MODULE_NAME MODULE_SAVE_AVI
 
52
#include "ADM_osSupport/ADM_debug.h"
 
53
#include "prefs.h"
 
54
// END MOD Feb 2005 by GMV
 
55
uint32_t ADM_UsecFromFps1000(uint32_t fps1000);
 
56
//------------
 
57
typedef struct
 
58
{
 
59
  uint32_t fcc, flags, offset, len;
 
60
}
 
61
IdxEntry;
 
62
 
 
63
//
 
64
// We put them
 
65
 
 
66
IdxEntry *myindex = NULL;
 
67
 
 
68
 
 
69
aviWrite::aviWrite( void )
 
70
{
 
71
        _out=NULL;
 
72
        LAll=NULL;
 
73
        LMovie=NULL;
 
74
        LMain=NULL;
 
75
        _file=NULL;
 
76
                
 
77
        // MOD Feb 2005 by GMV: ODML support
 
78
        odml_indexes=NULL;
 
79
        // END MOD Feb 2005 by GMV
 
80
}
 
81
 
 
82
// MOD Feb 2005 by GMV: remove ODML index
 
83
aviWrite::~aviWrite(){
 
84
        if (myindex)
 
85
                delete myindex;
 
86
 
 
87
        if (LAll)
 
88
                delete LAll;
 
89
 
 
90
        if (LMovie)
 
91
                delete LMovie;
 
92
 
 
93
        if (LMain)
 
94
                delete LMain;
 
95
 
 
96
        myindex = NULL;
 
97
        LAll = NULL;
 
98
        LMovie = NULL;
 
99
        LMain = NULL;
 
100
 
 
101
        odml_destroy_index();
 
102
}
 
103
// END MOD Feb 2005 by GMV
 
104
 
 
105
uint8_t aviWrite::sync( void )
 
106
{
 
107
        ADM_assert(_file);
 
108
        _file->flush();
 
109
        return 1;
 
110
 
 
111
}
 
112
//
 
113
// Overwrite some headers with their final value
 
114
//
 
115
//
 
116
uint8_t aviWrite::updateHeader (MainAVIHeader * mainheader,
 
117
                        AVIStreamHeader * videostream,
 
118
                        AVIStreamHeader * astream)
 
119
{
 
120
  UNUSED_ARG(astream);
 
121
 
 
122
        ADM_assert(_file);
 
123
        
 
124
        _file->seek(32);
 
125
// Update main header
 
126
#ifdef ADM_BIG_ENDIAN
 
127
        MainAVIHeader ma;
 
128
        memcpy(&ma,mainheader,sizeof(MainAVIHeader));
 
129
        Endian_AviMainHeader(&ma);              
 
130
        _file->write ((uint8_t *)&ma, sizeof (ma));
 
131
#else
 
132
        _file->write ((uint8_t *)mainheader, sizeof (MainAVIHeader));
 
133
#endif
 
134
// now update video stream header
 
135
        _file->seek(0x6c);
 
136
#ifdef ADM_BIG_ENDIAN
 
137
 
 
138
        AVIStreamHeader as;
 
139
        memcpy(&as,videostream,sizeof(as));
 
140
        Endian_AviStreamHeader(&as);            
 
141
        _file->write ((uint8_t *)&as, sizeof (as));
 
142
#else
 
143
        _file->write ((uint8_t *)videostream, sizeof (AVIStreamHeader));
 
144
#endif
 
145
  // should do audio too, but i's relatively harmless...
 
146
  // Yes, indeed it helps for VBR audio :)
 
147
 
 
148
  return 1;
 
149
}
 
150
 
 
151
//________________________________________________
 
152
//   Beginning of the write process
 
153
//   We fill-in the headers
 
154
//      1- Create list and write main header
 
155
//_______________________________________________
 
156
uint8_t aviWrite::writeMainHeader( void )
 
157
{
 
158
 
 
159
  ADM_assert (_file);
 
160
  ADM_assert (LAll == NULL);
 
161
  _file->seek(0);
 
162
  
 
163
 
 
164
  LAll = new AviList ("RIFF", _file);
 
165
  LAll->Begin ("AVI ");
 
166
  // Header chunk
 
167
  LMain = new AviList ("LIST", _file);
 
168
  LMain->Begin ("hdrl");
 
169
  LMain->Write32 ("avih");
 
170
  LMain->Write32 (sizeof (MainAVIHeader));
 
171
#ifdef ADM_BIG_ENDIAN
 
172
        MainAVIHeader ma;
 
173
        memcpy(&ma,&_mainheader,sizeof(ma));
 
174
        Endian_AviMainHeader(&ma);              
 
175
        LMain->Write((uint8_t *)&ma,sizeof(ma));        
 
176
#else
 
177
        LMain->Write ((uint8_t *) &_mainheader, sizeof (MainAVIHeader));
 
178
#endif
 
179
        return 1;
 
180
}
 
181
//________________________________________________
 
182
//   Beginning of the write process
 
183
//   We fill-in the headers
 
184
//      2- Write video headers
 
185
//_______________________________________________
 
186
uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen )
 
187
{
 
188
 
 
189
  ADM_assert (_file);
 
190
 
 
191
      _videostream.fccType = fourCC::get ((uint8_t *) "vids");
 
192
      _bih.biSize=sizeof(_bih)+extraLen;
 
193
        // MOD Feb 2005 by GMV: video super index length
 
194
        uint32_t odml_super_idx_size=24+odml_nbrof_index*16;
 
195
        // END MOD Feb 2005 by GMV
 
196
#ifdef ADM_BIG_ENDIAN
 
197
        // in case of Little endian, do the usual swap crap
 
198
        
 
199
        AVIStreamHeader as;
 
200
        BITMAPINFOHEADER b;
 
201
        memcpy(&as,&_videostream,sizeof(as));
 
202
        Endian_AviStreamHeader(&as);            
 
203
        memcpy(&b,&_bih,sizeof(_bih));
 
204
        Endian_BitMapInfo( &b );
 
205
        setStreamInfo (_file, (uint8_t *) &as,
 
206
                  (uint8_t *)&b,sizeof(BITMAPINFOHEADER),
 
207
                // MOD Feb 2005 by GMV: ODML support
 
208
                odml_super_idx_size,0,
 
209
                // END MOD Feb 2005 by GMV
 
210
                  extra,extraLen,        
 
211
                 0x1000);
 
212
#else
 
213
        setStreamInfo (_file, (uint8_t *) &_videostream,
 
214
                  (uint8_t *)&_bih,sizeof(BITMAPINFOHEADER),
 
215
                // MOD Feb 2005 by GMV: ODML support
 
216
                odml_super_idx_size,0,
 
217
                // END MOD Feb 2005 by GMV
 
218
                  extra,extraLen,        
 
219
                 0x1000);
 
220
 
 
221
#endif
 
222
        return 1;
 
223
}
 
224
typedef struct VBRext
 
225
    {
 
226
  uint16_t          cbsize ;
 
227
  uint16_t          wId ;
 
228
  uint32_t          fdwflags ;
 
229
  uint16_t          nblocksize ;
 
230
  uint16_t          nframesperblock  ;
 
231
  uint16_t          ncodecdelay ;
 
232
} VBRext;
 
233
 
 
234
 
 
235
//________________________________________________
 
236
//   Beginning of the write process
 
237
//   We fill-in the headers
 
238
//      3- Write audio headers 
 
239
//   That one can be used several times so we pass stuff
 
240
//   as parameter
 
241
//_______________________________________________
 
242
static  uint32_t aacBitrate[16]=
 
243
{
 
244
        96000, 88200, 64000, 48000,
 
245
        44100, 32000, 24000, 22050,
 
246
        16000, 12000, 11025,  8000,
 
247
        0,     0,     0,     0 
 
248
};
 
249
 
 
250
uint8_t aviWrite::writeAudioHeader (    AVDMGenericAudioStream * stream, AVIStreamHeader *header
 
251
// MOD Feb 2005 by GMV: ODML support
 
252
,uint8_t        odml_stream_nbr
 
253
// END MOD Feb 2005 by GMV
 
254
)
 
255
{
 
256
// MOD Feb 2005 by GMV: audio super index length
 
257
uint32_t odml_super_idx_size=24+odml_nbrof_index*16;
 
258
// END MOD Feb 2005 by GMV
 
259
WAVHeader wav;
 
260
// pre compute some headers with extra data in...
 
261
uint8_t wmaheader[12];
 
262
VBRext  mp3vbr;
 
263
uint8_t aacHeader[12];
 
264
uint8_t *extra=NULL;
 
265
uint32_t extraLen=0;
 
266
     
 
267
        if(!stream) return 1;
 
268
 
 
269
        memset(wmaheader,0,12);
 
270
        memset(&mp3vbr,0,sizeof(mp3vbr));
 
271
 
 
272
        wmaheader[16-16]=0x0a;
 
273
        wmaheader[19-16]=0x08;
 
274
        wmaheader[22-16]=0x01;
 
275
        wmaheader[24-16]=0x74;
 
276
        wmaheader[25-16]=01;
 
277
 
 
278
        memcpy(&wav,stream->getInfo (),sizeof(wav));
 
279
      
 
280
 
 
281
      memset (header, 0, sizeof (AVIStreamHeader));
 
282
      header->fccType = fourCC::get ((uint8_t *) "auds");
 
283
      header->dwInitialFrames = 0;
 
284
      header->dwStart = 0;
 
285
      header->dwRate = wav.byterate;
 
286
      header->dwSampleSize = 1;
 
287
      header->dwQuality = 0xffffffff;
 
288
      header->dwSuggestedBufferSize = 8000;
 
289
      header->dwLength = stream->getLength ();
 
290
      
 
291
        switch(wav.encoding)
 
292
        {
 
293
                case WAV_IMAADPCM:
 
294
                        wav.blockalign=1024;
 
295
                        header->dwScale         = wav.blockalign;
 
296
                        header->dwSampleSize    = 1;
 
297
                        header->dwInitialFrames =1;                             
 
298
                        header->dwSuggestedBufferSize=2048;                                
 
299
                        break;
 
300
                case WAV_AAC:
 
301
                {
 
302
                // nb sample in stream  
 
303
                
 
304
                        double len;
 
305
                        len=_videostream.dwLength;
 
306
#if 1                   
 
307
                        len/=_videostream.dwRate;
 
308
                        len*=_videostream.dwScale;                      
 
309
                        len*=wav.frequency;
 
310
                        len/=1024;
 
311
#else           
 
312
                        header->dwLength= floor(len);//_videostream.dwLength; 
 
313
#endif                  
 
314
                 // AAC is mostly VBR
 
315
                 header->dwFlags=1;
 
316
                 header->dwInitialFrames=0;
 
317
                 header->dwRate=wav.frequency;
 
318
                 
 
319
                        
 
320
                 
 
321
                 header->dwScale=1024; //sample/packet 1024 seems good for aac
 
322
                 header->dwSampleSize = 0;
 
323
                 header->dwSuggestedBufferSize=8192;
 
324
                 header->dwInitialFrames = 0;    
 
325
                
 
326
                // header->dwLength= _videostream.dwLength; 
 
327
                 wav.blockalign=1024;     
 
328
                 wav.bitspersample = 0; 
 
329
                 
 
330
                //*b++ = (BYTE)((profile +1) << 3 | (SRI >> 1));
 
331
                //*b++ = (BYTE)(((SRI & 0x1) << 7) | (aacsource->GetChannelCount() << 3));
 
332
                
 
333
                int SRI=4;      // Default 44.1 khz
 
334
                for(int i=0;i<16;i++) if(wav.frequency==aacBitrate[i]) SRI=i;
 
335
                aacHeader[0]=0x2;
 
336
                aacHeader[1]=0x0;
 
337
                aacHeader[2]=(2<<3)+(SRI>>1); // Profile LOW
 
338
                aacHeader[3]=((SRI&1)<<7)+((wav.channels)<<3);
 
339
                
 
340
 
 
341
                extra=&(aacHeader[0]);
 
342
                extraLen=4;
 
343
                }
 
344
                break;
 
345
        case WAV_MP3:                                                   
 
346
                  // then update VBR fields
 
347
                  mp3vbr.cbsize = R16(12);
 
348
                  mp3vbr.wId = R16(1);
 
349
                  mp3vbr.fdwflags = R32(2);                               
 
350
                  mp3vbr.nframesperblock = R16(1);
 
351
                  mp3vbr.ncodecdelay = 0;
 
352
                  
 
353
                  wav.bitspersample = 0;
 
354
                  mp3vbr.nblocksize=R16(0x180); //384; // ??
 
355
    
 
356
                  header->dwScale = 1;
 
357
                  header->dwInitialFrames = 1;
 
358
                  extra=(uint8_t *)&mp3vbr;
 
359
                  extraLen=sizeof(mp3vbr);
 
360
                  if (stream->isVBR()) //wav->blockalign ==1152)        // VBR audio
 
361
                        {                       // We do like nandub do
 
362
                        //ADM_assert (audiostream->asTimeTrack ());
 
363
                        wav.blockalign = 1152;  // just a try
 
364
                        wav.bitspersample = 16;
 
365
                  
 
366
                        header->dwRate  = wav.frequency;        //wav->byterate;
 
367
                        header->dwScale = wav.blockalign;
 
368
                        header->dwLength= _videostream.dwLength;
 
369
                   
 
370
                        header->dwSampleSize = 0;
 
371
                        printf ("\n VBR audio detected\n");
 
372
                        //
 
373
                        // use extended headers
 
374
                        //              
 
375
                        //
 
376
                        mp3vbr.nblocksize=1152; 
 
377
                        
 
378
                   }    
 
379
                   else 
 
380
                   {
 
381
                     wav.blockalign=1;
 
382
                     
 
383
                     
 
384
                   }
 
385
 
 
386
                        
 
387
 
 
388
                          break;
 
389
        
 
390
                                         
 
391
        case WAV_WMA:
 
392
                        header->dwScale         = wav.blockalign;
 
393
                        header->dwSampleSize    = wav.blockalign;
 
394
                        header->dwInitialFrames =1;                             
 
395
                        header->dwSuggestedBufferSize=10*wav.blockalign;                                
 
396
                        
 
397
                        extra=(uint8_t *)&wmaheader;
 
398
                        extraLen=12;
 
399
                        break;
 
400
          case WAV_8BITS_UNSIGNED:
 
401
                        wav.encoding=WAV_PCM;
 
402
                        header->dwScale         = 1;
 
403
                        wav.bitspersample=8;
 
404
                        break;
 
405
                        
 
406
                        
 
407
        default:
 
408
                        header->dwScale = 1;  
 
409
                        wav.blockalign=1;       
 
410
                        break;
 
411
    }
 
412
#ifdef ADM_BIG_ENDIAN
 
413
        // in case of Little endian, do the usual swap crap
 
414
        
 
415
        AVIStreamHeader as;
 
416
        WAVHeader w;
 
417
        memcpy(&as,header,sizeof(as));
 
418
        Endian_AviStreamHeader(&as);            
 
419
        memcpy(&w,&wav,sizeof(w));
 
420
        Endian_WavHeader( &w );
 
421
        setStreamInfo (_file, 
 
422
                (uint8_t *) &as,
 
423
                  (uint8_t *)&w,sizeof(WAVHeader),
 
424
                // MOD Feb 2005 by GMV: ODML support
 
425
                odml_super_idx_size,odml_stream_nbr,
 
426
                // END MOD Feb 2005 by GMV
 
427
                  extra,extraLen,        
 
428
                 0x1000);
 
429
#else
 
430
        setStreamInfo (_file,
 
431
                        (uint8_t *) header,
 
432
                        (uint8_t *) &wav, sizeof (WAVHeader),
 
433
                        // MOD Feb 2005 by GMV: ODML support
 
434
                        odml_super_idx_size,odml_stream_nbr,
 
435
                        // END MOD Feb 2005 by GMV
 
436
                        extra,extraLen, 0x1000);
 
437
#endif
 
438
 
 
439
  return 1;
 
440
}
 
441
 
 
442
//_______________________________________________________
 
443
//
 
444
//   Begin to save, built header and prepare structure
 
445
//   The nb frames is indicative but the real value
 
446
//   must be smaller than this parameter
 
447
//
 
448
//_______________________________________________________
 
449
uint8_t aviWrite::saveBegin (char       *name,
 
450
                     MainAVIHeader      *inmainheader, 
 
451
                     uint32_t           nb_frame,
 
452
                     AVIStreamHeader * invideostream,
 
453
                     BITMAPINFOHEADER   *bih,
 
454
                     uint8_t            *videoextra,
 
455
                     uint32_t           videoextraLen,
 
456
                     AVDMGenericAudioStream * inaudiostream,
 
457
                     AVDMGenericAudioStream * inaudiostream2)
 
458
{
 
459
 
 
460
        asize=asize2=0;
 
461
 
 
462
//  Sanity Check
 
463
        ADM_assert (_out == NULL);
 
464
        if (!(_out = qfopen (name, "wb")))
 
465
        {
 
466
                printf("Problem writing : %s\n",name);
 
467
                return 0;
 
468
        }
 
469
        _file=new ADMFile();
 
470
        if(!_file->open(_out))
 
471
        {
 
472
                printf("Cannot create ADMfileio\n");
 
473
                delete _file;
 
474
                _file=NULL;
 
475
                return 0;
 
476
        }
 
477
        curindex = 0;
 
478
        vframe = asize = 0;
 
479
        nb_audio=0;
 
480
        
 
481
// update avi header according to the information WE want
 
482
//
 
483
        memcpy (&_mainheader, inmainheader, sizeof (MainAVIHeader));
 
484
        _mainheader.dwFlags = AVIF_HASINDEX + AVIF_ISINTERLEAVED;
 
485
 
 
486
 
 
487
        
 
488
// update main header codec with video codev
 
489
        if (inaudiostream)
 
490
        {
 
491
                _mainheader.dwStreams = 2;
 
492
                nb_audio=1;
 
493
        }
 
494
        else
 
495
                _mainheader.dwStreams = 1;
 
496
 
 
497
        if(inaudiostream2)
 
498
        {
 
499
                printf("\n +++Dual audio stream...\n");
 
500
                _mainheader.dwStreams ++;
 
501
                nb_audio++;
 
502
        }
 
503
 
 
504
        _mainheader.dwTotalFrames = nb_frame;
 
505
//  Idem for video stream
 
506
//
 
507
        memcpy (&_videostream, invideostream, sizeof (AVIStreamHeader));
 
508
        _videostream.dwLength = nb_frame;
 
509
        _videostream.fccType=fourCC::get((uint8_t *)"vids");
 
510
        memcpy(&_bih,bih,sizeof(_bih));
 
511
 
 
512
// Update usecperframe
 
513
double f;
 
514
        f=_videostream.dwRate;
 
515
        f*=1000;
 
516
        f/=_videostream.dwScale;
 
517
        _mainheader.dwMicroSecPerFrame=ADM_UsecFromFps1000( (uint32_t)floor(f));
 
518
        
 
519
 
 
520
        // Recompute image size
 
521
uint32_t is;    
 
522
        is=_bih.biWidth*_bih.biHeight;
 
523
        is*=(_bih.biBitCount+7)/8;
 
524
        _bih.biSizeImage=is;
 
525
 
 
526
 
 
527
 
 
528
        // MOD Feb 2005 by GMV: initialize ODML data
 
529
        // test for free data structures
 
530
        if(odml_indexes!=NULL){
 
531
                aprintf("\n ODML writer error: data structures not empty for init!");
 
532
                return 0;
 
533
        }
 
534
        // set generation mode
 
535
        uint32_t pref_odml=0;
 
536
        
 
537
        if(!prefs->get(FEATURE_USE_ODML, &pref_odml))
 
538
        {
 
539
          pref_odml=0;                
 
540
        }            
 
541
        
 
542
        doODML=NO;      // only option for users without largefile support
 
543
        #if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
 
544
        if(pref_odml)        
 
545
               doODML=HIDDEN;   // default; TODO: user should be able to choose NO for plain avi
 
546
        #endif
 
547
        if(doODML!=NO){
 
548
                // get number of streams
 
549
                odml_nbrof_streams=_mainheader.dwStreams;
 
550
                aprintf("\nnumber of streams: %lu\n",odml_nbrof_streams);
 
551
                // get number of frames per index
 
552
 
 
553
                odml_index_size=(long)ceil(1000000.0/(double)_mainheader.dwMicroSecPerFrame*600.0);     // one index per 10 Minutes; decrease if 4GB are not enough for this amount of time 
 
554
                aprintf("\n old number of frames per index: %lu\n",odml_index_size);
 
555
                double fps=invideostream->dwRate/invideostream->dwScale;      
 
556
 
 
557
                        aprintf("Fps1000:%f\n",fps);
 
558
                        fps=600*fps; // 10 mn worth;
 
559
                odml_index_size=(int)floor(fps);
 
560
 
 
561
                aprintf("\nnumber of frames per index: %lu\n",odml_index_size);
 
562
                // get number or indexes per stream
 
563
                odml_nbrof_index=(long)ceil((double)nb_frame/(double)odml_index_size);
 
564
                aprintf("\nnumber of indexes per stream: %lu\n",odml_nbrof_index);
 
565
                // init some other values
 
566
                odml_header_fpos=0;
 
567
                odml_riff_fpos[0]=0;odml_riff_fpos[1]=0;odml_riff_fpos[2]=0;odml_riff_fpos[3]=0;
 
568
                odml_riff_count=0;
 
569
                odml_frames_inAVI=0;
 
570
                // create odml index data structure
 
571
                odml_indexes=(odml_super_index_t*) ADM_alloc (sizeof(odml_super_index_t) * odml_nbrof_streams); // super index list
 
572
                memset(odml_indexes,0,sizeof(odml_super_index_t) * odml_nbrof_streams);
 
573
                for(int a=0;a<odml_nbrof_streams;++a){  // for each stream -> one super index
 
574
                        odml_indexes[a].odml_index= (odml_index_t*) ADM_alloc (sizeof(odml_index_t) * odml_nbrof_index); // index list
 
575
                        memset(odml_indexes[a].odml_index,0,sizeof(odml_index_t) * odml_nbrof_index);
 
576
                        for(int b=0;b<odml_nbrof_index;++b){    // for each index
 
577
                                odml_indexes[a].odml_index[b].index=(odml_index_data_t*) ADM_alloc (sizeof(odml_index_data_t) * odml_index_size);       // index data
 
578
                                memset(odml_indexes[a].odml_index[b].index,0,sizeof(odml_index_data_t) * odml_index_size);
 
579
                                odml_indexes[a].odml_index[b].nEntriesInUse=0;  // (redundant)
 
580
                        }
 
581
                        // init data
 
582
                        odml_indexes[a].index_count=0;
 
583
                }
 
584
        }
 
585
        // END MOD Feb 2005 by GMV
 
586
        
 
587
  //___________________
 
588
  // Prepare header
 
589
  //___________________
 
590
 
 
591
        writeMainHeader( );
 
592
 
 
593
        writeVideoHeader(videoextra,videoextraLen );
 
594
 
 
595
        // MOD Feb 2005 by GMV: ODML support
 
596
        /*writeAudioHeader (    inaudiostream , &_audio1 );
 
597
        writeAudioHeader (      inaudiostream2, &_audio2);*/ 
 
598
        writeAudioHeader (      inaudiostream , &_audio1,1);
 
599
        writeAudioHeader (      inaudiostream2, &_audio2,2); 
 
600
        // odml header placeholder
 
601
        odml_write_dummy_chunk(LMain, &odml_header_fpos, 16);
 
602
        // END MOD Feb 2005 by GMV
 
603
 
 
604
        LMain->End();
 
605
        delete LMain;
 
606
        LMain=NULL;
 
607
  //
 
608
 
 
609
  ADM_assert (!LMovie);
 
610
  
 
611
  LMovie = new AviList ("LIST", _file);
 
612
  LMovie->Begin ("movi");
 
613
  curindex = 0;
 
614
  // the *2 is for audio and video
 
615
  // the *3 if for security sake
 
616
  myindex = (IdxEntry *) ADM_alloc (sizeof (IdxEntry) * (nb_frame * 4));
 
617
  asize = 0;
 
618
  vframe = 0;
 
619
  return 1;
 
620
}
 
621
 
 
622
//_______________________________________________________
 
623
// Write video frames and update index accordingly
 
624
//_______________________________________________________
 
625
uint8_t aviWrite::saveVideoFrame (uint32_t len, uint32_t flags, uint8_t * data)
 
626
{
 
627
  vframe++;
 
628
  // MOD Feb 2005 by GMV:  interleave ODML index dummy and index frame 
 
629
        // write initial index chunks
 
630
        if(vframe==2 && doODML!=NO){    // apparently some players require a video frame at first in the movi list, so we put the initial index dummys behind it (bye bye index before data)
 
631
                odml_write_dummy_chunk(LMovie, &(odml_indexes[0].odml_index[0].fpos), 24+8*odml_index_size);
 
632
                if(odml_nbrof_streams>1)
 
633
                        odml_write_dummy_chunk(LMovie, &(odml_indexes[1].odml_index[0].fpos), 24+8*odml_index_size);
 
634
                if(odml_nbrof_streams>2)
 
635
                        odml_write_dummy_chunk(LMovie, &(odml_indexes[2].odml_index[0].fpos), 24+8*odml_index_size);
 
636
        }
 
637
        // test for new riff
 
638
        odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
 
639
        // index frame
 
640
        if(!odml_index_frame(0, len,flags&AVI_KEY_FRAME)){
 
641
                aprintf("\ncan not index video frame %lu\n",vframe);
 
642
        }
 
643
// END MOD Feb 2005 by GMV
 
644
  return saveFrame (len, flags, data, (uint8_t *) "00dc");
 
645
 
 
646
}
 
647
 
 
648
uint8_t aviWrite::saveAudioFrame (uint32_t len, uint8_t * data)
 
649
{
 
650
  asize += len;
 
651
// MOD Feb 2005 by GMV: index frame and interleave ODML index dummy
 
652
        odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
 
653
        if(!odml_index_frame(1, len,false)){
 
654
                aprintf("\ncan not index audio frame %lu\n",asize);
 
655
        }
 
656
// END MOD Feb 2005 by GMV
 
657
  return saveFrame (len, (uint32_t) 0, data, (uint8_t *) "01wb");
 
658
}
 
659
uint8_t aviWrite::saveAudioFrameDual (uint32_t len, uint8_t * data)
 
660
{
 
661
  asize2 += len;
 
662
// MOD Feb 2005 by GMV: index frame and interleave ODML index dummy
 
663
        odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
 
664
        if(!odml_index_frame(2, len,false)){
 
665
                aprintf("\ncan not index audio (dual) frame %lu\n",asize);
 
666
        }
 
667
// END MOD Feb 2005 by GMV
 
668
  return saveFrame (len, (uint32_t) 0, data, (uint8_t *) "02wb");
 
669
}
 
670
 
 
671
 
 
672
 
 
673
uint8_t aviWrite::saveFrame (uint32_t len, uint32_t flags,
 
674
                     uint8_t * data, uint8_t * fcc)
 
675
{
 
676
  uint32_t offset;
 
677
  // offset of this chunk compared to the beginning
 
678
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
 
679
  //offset = LMovie->Tell () - 8 - LMovie->TellBegin ();
 
680
if(doODML!=NORMAL){
 
681
  offset = LMovie->Tell () - 8 - LMovie->TellBegin ();
 
682
}
 
683
// END MOD Feb 2005 by GMV
 
684
  LMovie->WriteChunk (fcc, len, data);
 
685
  // Now store the index part
 
686
 
 
687
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
 
688
if(doODML!=NORMAL){
 
689
// END MOD Feb 2005 by GMV
 
690
  myindex[curindex].fcc = fourCC::get (fcc);
 
691
  myindex[curindex].len = len;
 
692
  myindex[curindex].flags = flags;
 
693
  myindex[curindex].offset = offset;
 
694
  curindex++;
 
695
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
 
696
}
 
697
// END MOD Feb 2005 by GMV
 
698
  return 1;
 
699
}
 
700
 
 
701
//_______________________________________________________
 
702
// End movie
 
703
//_______________________________________________________
 
704
uint8_t aviWrite::setEnd (void)
 
705
{
 
706
 
 
707
  // First close the movie
 
708
  LMovie->End ();
 
709
  delete LMovie;
 
710
  LMovie = NULL;
 
711
 
 
712
 
 
713
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
 
714
if(doODML!=NORMAL){
 
715
// END MOD Feb 2005 by GMV
 
716
  printf ("\n writing %lu index parts", curindex);
 
717
  printf ("\n received %lu video parts", vframe);
 
718
 
 
719
// Updating compared to what has been really written
 
720
//
 
721
 
 
722
  // Write index  
 
723
  LAll->Write32 ("idx1");
 
724
  LAll->Write32 (curindex * 16);
 
725
 
 
726
  for (uint32_t i = 0; i < curindex; i++)
 
727
    {
 
728
      LAll->Write32 (myindex[i].fcc);
 
729
      LAll->Write32 (myindex[i].flags);
 
730
      LAll->Write32 (myindex[i].offset);        // abs position
 
731
      LAll->Write32 (myindex[i].len);
 
732
    }
 
733
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
 
734
}
 
735
// END MOD Feb 2005 by GMV
 
736
  // Close movie
 
737
 
 
738
 
 
739
  LAll->End ();
 
740
  delete
 
741
    LAll;
 
742
  LAll = NULL;
 
743
 printf ("\n Updating headers...\n");
 
744
 
 
745
// MOD Feb 2005 by GMV: ODML header and index
 
746
        if(doODML==NORMAL){
 
747
                odml_write_sindex(0, "00dc");   // video super index
 
748
                if(odml_nbrof_streams>1)odml_write_sindex(1,"01wb");    // audio super index
 
749
                if(odml_nbrof_streams>2)odml_write_sindex(2,"02wb");    // audio super index (dual)
 
750
                // odml header
 
751
                _file->seek(odml_header_fpos);
 
752
                AviList* LHeader =  new AviList("LIST", _file);
 
753
                LHeader->Begin("odml");
 
754
                LHeader->Write32("dmlh");
 
755
                LHeader->Write32((uint32_t)4);  // chunk size
 
756
                LHeader->Write32(vframe);       // total number of frames
 
757
                LHeader->End();
 
758
                delete LHeader;
 
759
                // indexes
 
760
                if(!odml_write_index(0, "00dc", "ix00")){       // video indexes
 
761
                        aprintf("error writing video indexes");
 
762
                }
 
763
                if(odml_nbrof_streams>1)
 
764
                        if(!odml_write_index(1, "01wb", "ix01")){       // audio indexes
 
765
                                aprintf("error writing audio indexes");
 
766
                        }
 
767
                if(odml_nbrof_streams>2)
 
768
                        if(!odml_write_index(2, "02wb", "ix02")){       // audio indexes (dual)
 
769
                                printf("error writing audio (dual) indexes");
 
770
                        }
 
771
        }
 
772
        odml_destroy_index();           
 
773
// END MOD Feb 2005 by GMV
 
774
 
 
775
 
 
776
// MOD Feb 2005 by GMV: set number or frames in first riff
 
777
  //_mainheader.dwTotalFrames = vframe;
 
778
        if(doODML==NORMAL)
 
779
                _mainheader.dwTotalFrames=odml_frames_inAVI;
 
780
        else
 
781
  _mainheader.dwTotalFrames = vframe;
 
782
// END MOD Feb 2005 by GMV
 
783
        
 
784
  _videostream.dwLength = vframe;
 
785
  //astream.dwLength = asize;
 
786
 
 
787
// Update Header
 
788
  updateHeader (&_mainheader, &_videostream, NULL);
 
789
 
 
790
 
 
791
        printf("\n End of movie, \n video frames : %lu\n audio frames : %lu",vframe,asize);
 
792
  // need to update headers now
 
793
  // AUDIO SIZE ->TODO
 
794
  delete _file;
 
795
  _file=NULL;
 
796
  
 
797
  qfclose (_out);
 
798
  _out = NULL;
 
799
  return 1;
 
800
 
 
801
}
 
802
 
 
803
//
 
804
//
 
805
//
 
806
uint8_t aviWrite::setStreamInfo (ADMFile * fo,
 
807
                         uint8_t * stream,
 
808
                         uint8_t * info, uint32_t infolen, 
 
809
                        // MOD Feb 2005 by GMV: ODML support
 
810
                         uint32_t odml_headerlen,
 
811
                         uint8_t odml_stream_nbr,
 
812
                        // END MOD Feb 2005 by GMV
 
813
                         uint8_t * extra, uint32_t extraLen,
 
814
                         uint32_t maxxed)
 
815
{
 
816
 
 
817
 
 
818
  AviList * alist;
 
819
  uint8_t * junk;
 
820
  uint32_t junklen;
 
821
 
 
822
  alist = new AviList ("LIST", fo);
 
823
 
 
824
 
 
825
  // 12 LIST
 
826
  // 8 strf subchunk
 
827
  // 8 strl subchunk
 
828
  // 8 defaultoffset
 
829
  alist->Begin ("strl");
 
830
 
 
831
  // sub chunk 1
 
832
  alist->WriteChunk ((uint8_t *) "strh", sizeof (AVIStreamHeader),
 
833
                     (uint8_t *) stream);
 
834
 
 
835
  uint8_t *buf=new uint8_t[infolen+extraLen];
 
836
 
 
837
        memcpy(buf,info,infolen);
 
838
        if(extraLen)
 
839
                memcpy(infolen+buf,extra,extraLen);
 
840
 
 
841
  alist->WriteChunk ((uint8_t *) "strf", infolen+extraLen, buf);
 
842
 
 
843
  junklen = maxxed - sizeof (AVIStreamHeader) - infolen-extraLen;
 
844
  junk = (uint8_t *) ADM_alloc (junklen);
 
845
  ADM_assert (junk);
 
846
  memset (junk,0, junklen);
 
847
  //
 
848
  // Fill junk with out info string  
 
849
  uint32_t len=strlen("Avidemux");
 
850
  
 
851
  if(junklen>len)
 
852
        memcpy(junk,"Avidemux",len);    
 
853
  
 
854
  alist->WriteChunk ((uint8_t *) "JUNK", junklen, junk);
 
855
  ADM_dealloc (junk);
 
856
 
 
857
  // MOD Feb 2005 by GMV: ODML header
 
858
  odml_write_dummy_chunk(alist, &odml_indexes[odml_stream_nbr].fpos, odml_headerlen);
 
859
  // END MOD Feb 2005 by GMV
 
860
 
 
861
  alist->End ();
 
862
  delete alist;
 
863
  delete[] buf;
 
864
  return 1;
 
865
 
 
866
 
 
867
}
 
868
// return how much has been written
 
869
uint32_t        aviWrite::getPos( void )
 
870
{
 
871
uint32_t pos;
 
872
         // we take size of file + index
 
873
         // with 32 bytes per index entry
 
874
         // 
 
875
         ADM_assert(_file);
 
876
         pos=_file->tell();
 
877
         return pos+curindex*4*4;               
 
878
}
 
879
 
 
880
// MOD Feb 2005 by GMV:  ODML functions
 
881
void aviWrite::odml_destroy_index(void){
 
882
        // destroy odml index data structure
 
883
        if(doODML!=NO){
 
884
                if(odml_indexes){
 
885
                        for(int a=0;a<odml_nbrof_streams;++a){
 
886
                                if(odml_indexes[a].odml_index){
 
887
                                        for(int b=0;b<odml_nbrof_index;++b){
 
888
                                                if(odml_indexes[a].odml_index[b].index)
 
889
                                                        ADM_dealloc (odml_indexes[a].odml_index[b].index);
 
890
                                        }
 
891
                                        ADM_dealloc (odml_indexes[a].odml_index);
 
892
                                }
 
893
                        }
 
894
                        ADM_dealloc (odml_indexes);
 
895
                }
 
896
                odml_indexes=NULL;
 
897
        }
 
898
}
 
899
void aviWrite::odml_write_dummy_chunk(AviList* alist, uint64_t* fpos, uint32_t size){
 
900
        if(doODML!=NO){
 
901
                // save file position
 
902
                *fpos=alist->Tell();
 
903
                aprintf("\nwrite dummy chunk at file position %Lu with data size %lu\n",*fpos, size);
 
904
                // generate dummy data
 
905
                uint8_t* dummy=(uint8_t*)ADM_alloc (size);
 
906
                memset(dummy,0,size);
 
907
                // write dummy chunk
 
908
                alist->WriteChunk ((uint8_t *) "JUNK", size, dummy);    
 
909
                // clean up
 
910
                ADM_dealloc (dummy);
 
911
        }
 
912
}
 
913
bool aviWrite::odml_index_frame(int stream_nbr, uint32_t data_size, bool keyFrame){
 
914
        if(doODML!=NO){
 
915
//              ADM_assert(!stream_nbr<odml_nbrof_streams);
 
916
                odml_super_index_t* sidx=odml_indexes+stream_nbr;       // access to super index
 
917
                if(sidx->odml_index[sidx->index_count].nEntriesInUse==odml_index_size){ // new index needed?
 
918
                        if(sidx->index_count<odml_nbrof_index-1)        // can index counter be increased?
 
919
                                ++(sidx->index_count);  // increment index counter
 
920
                        else{
 
921
                                aprintf("\nindexes full!!\n");
 
922
                                return false;
 
923
                        }
 
924
                        // handle possible riff break
 
925
                        odml_riff_break(data_size+8); // data size + fcc + size info (padding is handled in odml_riff_break)
 
926
                        // write placeholder
 
927
                        odml_write_dummy_chunk(LMovie, &(sidx->odml_index[sidx->index_count].fpos), 24+8*odml_index_size);
 
928
                        sidx->odml_index[sidx->index_count].nEntriesInUse=0;
 
929
                }
 
930
                odml_index_t* idx=sidx->odml_index+(sidx->index_count);         // access to index
 
931
                odml_index_data_t* idxd=idx->index+(idx->nEntriesInUse);        // access to unused index data
 
932
                
 
933
                uint64_t pos=LMovie->Tell()+8;  // preview position of data
 
934
                idxd->fpos=pos; // store file position of data
 
935
                
 
936
                if(keyFrame)
 
937
                        idxd->size=data_size; //store data size
 
938
                else    // if no key frame
 
939
                        idxd->size=data_size|0x80000000; //store data size with bit 31 set
 
940
                
 
941
                ++(idx->nEntriesInUse); // advance to next free index data entry
 
942
        }
 
943
        return true;
 
944
}
 
945
void aviWrite::odml_write_sindex(int stream_nbr, char* stream_fcc){
 
946
        // Warning: This changes the file position
 
947
        if(doODML==NORMAL){
 
948
                _file->seek(odml_indexes[stream_nbr].fpos);
 
949
                aprintf("\nwriting super index at file pos %Lu\n",odml_indexes[stream_nbr].fpos);
 
950
                AviList* LIndex =  new AviList("JUNK", _file);  // abused writing aid (don't call Begin or End; the fcc is unused until 'Begin')
 
951
                LIndex->Write32("indx");                        // 4cc
 
952
                LIndex->Write32(24+odml_nbrof_index*16);        // size
 
953
                LIndex->Write16(4);                             // wLongsPerEntry
 
954
                LIndex->Write8(0);                              // bIndexSubType
 
955
                LIndex->Write8(0);                              // bIndexType (AVI_INDEX_OF_INDEXES)
 
956
                LIndex->Write32(odml_indexes[stream_nbr].index_count+1);// nEntriesInUse
 
957
                LIndex->Write32(stream_fcc);                    // dwChunkId;
 
958
                LIndex->Write32((uint32_t)0);LIndex->Write32((uint32_t)0);LIndex->Write32((uint32_t)0);// reserved
 
959
                for(uint32_t a=0;a<=odml_indexes[stream_nbr].index_count;++a){  // for each chunk index
 
960
                        LIndex->Write64(odml_indexes[stream_nbr].odml_index[a].fpos);   //absolute file position
 
961
                        LIndex->Write32(32 + 8 * odml_index_size);      // complete index chunk size
 
962
                        LIndex->Write32(odml_indexes[stream_nbr].odml_index[a].nEntriesInUse);  // duration
 
963
                        aprintf("\nstream %lu, index %lu EntriesInUse:%lu\n",stream_nbr, a ,odml_indexes[stream_nbr].odml_index[a].nEntriesInUse);
 
964
                }
 
965
                delete LIndex;
 
966
        }       
 
967
}
 
968
bool aviWrite::odml_write_index(int stream_nbr, char* stream_fcc, char* index_fcc){     // write index
 
969
        // Warning: This changes the file position
 
970
        if(doODML==NORMAL){
 
971
                aprintf ("\n writing %lu interleaved ODML indexes for %lu frames in stream %s", odml_indexes[stream_nbr].index_count+1, vframe, stream_fcc);
 
972
                AviList* LIndex =  new AviList("JUNK", _file);  // abused writing aid (don't call Begin or End; the fcc is unused until 'Begin')
 
973
                for(int a=0;a<=odml_indexes[stream_nbr].index_count;++a){       // for each index
 
974
                        odml_index_t* idx=odml_indexes[stream_nbr].odml_index+a;                // access to index
 
975
                        _file->seek(idx->fpos);                                 // shift file pointer
 
976
                        LIndex->Write32(index_fcc);                     // 4cc
 
977
                        LIndex->Write32(24+odml_index_size*8);          // data size
 
978
                        LIndex->Write16(2);                             // wLongsPerEntry
 
979
                        LIndex->Write8(0);                              // bIndexSubType
 
980
                        LIndex->Write8(1);                              // bIndexType (AVI_INDEX_OF_CHUNKS)
 
981
                        LIndex->Write32(idx->nEntriesInUse);            // nEntriesInUse
 
982
                        LIndex->Write32(stream_fcc);                    // dwChunkId;
 
983
                        uint64_t base_off=idx->index[0].fpos-8;         // lets take the position of the first frame in the index as base
 
984
                        uint64_t rel_pos;
 
985
                        LIndex->Write64(base_off);                      // qwBaseOffset
 
986
                        LIndex->Write32((uint32_t)0);                   // reserved
 
987
                        for(int b=0;b<idx->nEntriesInUse;++b){          // for each frame in the current index
 
988
                                odml_index_data_t* idxd=idx->index+b;   // access to index data
 
989
                                rel_pos=idxd->fpos-base_off;    // get relative file position
 
990
                                if(rel_pos>(uint64_t)4*1024*1024*1024){ // index chunks have a maximum offset of 4GB
 
991
                                        printf("\nData rate too high for index size. Decrease index duration.\n"); // decrease the multiplicator in saveBegin that calculates odml_index_size
 
992
                                        printf("base:%Lu abs:%Lu rel:%Lu stream:%lu index:%lu entry:%lu",base_off,idxd->fpos,rel_pos,stream_nbr,a,b);
 
993
                                        delete LIndex;
 
994
                                        return false;
 
995
                                }
 
996
                                LIndex->Write32(rel_pos);       // relative file position
 
997
                                LIndex->Write32(idxd->size);            // data size
 
998
                        }
 
999
                }
 
1000
                delete LIndex;
 
1001
        }
 
1002
        return true;
 
1003
}
 
1004
void aviWrite::odml_riff_break(uint32_t len){   // advance to the next riff if required
 
1005
        if(doODML!=NO){
 
1006
                // get padded size
 
1007
                uint64_t len2=len;
 
1008
                if(len & 1)++len2;
 
1009
                // preview file position
 
1010
                len2+=LMovie->Tell();
 
1011
                // will we get over the next GB border?
 
1012
                if( len2>((uint64_t)1024*1024*1024*(odml_riff_count+1)) ){
 
1013
                        if(doODML==HIDDEN){
 
1014
                                aprintf("\nstarting new (hidden) RIFF at %Lu\n",LMovie->Tell());
 
1015
                                if(odml_riff_count<4)   // we have only 4 buffers but this has to be enough
 
1016
                                        odml_write_dummy_chunk(LMovie, odml_riff_fpos+odml_riff_count, 16);     // write dummy
 
1017
                                if(odml_riff_count==0) odml_frames_inAVI=vframe-1;      // rescue number of frames in first AVI (-1 since there may be no audio for the last video frame)
 
1018
                        }else{  // restart riff and movie
 
1019
                                aprintf("\nstarting new RIFF at %Lu\n",LMovie->Tell());
 
1020
                                // restart lists
 
1021
                                LMovie->End();
 
1022
                                LAll->End();
 
1023
                                LAll->Begin ("AVIX");
 
1024
                                LMovie->Begin ("movi");
 
1025
                        }
 
1026
                        ++odml_riff_count;
 
1027
                }
 
1028
                // ODML required for movie?
 
1029
                if(doODML==HIDDEN){
 
1030
                        if( ((uint64_t)getPos()+len+17) >= ((uint64_t)4*1024*1024*1024) ){      //if (written data + new chunk + index (old type) for new chunk + possible padding) does not fit into 4GB
 
1031
                                printf("\nswitching to ODML mode at %lu\n",LMovie->Tell());
 
1032
                                uint64_t last_pos=LMovie->Tell();       // rescue current file position
 
1033
                                // close First RIFF
 
1034
                                for(int a=0;a<4;++a){   // for each hidden riff
 
1035
                                        if(odml_riff_fpos[a]!=0){
 
1036
                                                _file->seek(odml_riff_fpos[a]); // set file pointer to start of next riff
 
1037
                                                LMovie->End();
 
1038
                                                LAll->End();
 
1039
                                                LAll->Begin("AVIX");
 
1040
                                                LMovie->Begin("movi");
 
1041
                                        }
 
1042
                                }
 
1043
                                // goto end of file
 
1044
                                _file->seek(last_pos);
 
1045
                                // following riffs can start directly
 
1046
                                doODML=NORMAL;  // write RIFF breaks directly
 
1047
                        }
 
1048
                }
 
1049
        }
 
1050
}
 
1051
// END MOD Feb 2005 by GMV
 
1052
 
 
1053
// EOF