]> git.sesse.net Git - mlt/blob - src/modules/kino/avi.cc
kino/avi.cc: initialize variables
[mlt] / src / modules / kino / avi.cc
1 /*
2 * avi.cc library for AVI file format i/o
3 * Copyright (C) 2000 - 2002 Arne Schirmacher <arne@schirmacher.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "config.h"
21
22 // C++ includes
23
24 #include <cstring>
25 #include <iostream>
26 #include <iomanip>
27
28 using std::cout;
29 using std::hex;
30 using std::dec;
31 using std::setw;
32 using std::setfill;
33 using std::endl;
34
35 // C includes
36
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <assert.h>
41 #include <string.h>
42
43 // local includes
44
45 #include "error.h"
46 #include "riff.h"
47 #include "avi.h"
48
49 #define PADDING_SIZE (512)
50 #define PADDING_1GB (0x40000000)
51 #define IX00_INDEX_SIZE (4028)
52
53 #define AVIF_HASINDEX 0x00000010
54 #define AVIF_MUSTUSEINDEX 0x00000020
55 #define AVIF_TRUSTCKTYPE 0x00000800
56 #define AVIF_ISINTERLEAVED 0x00000100
57 #define AVIF_WASCAPTUREFILE 0x00010000
58 #define AVIF_COPYRIGHTED 0x00020000
59
60
61 //static char g_zeroes[ PADDING_SIZE ];
62
63 /** The constructor
64  
65     \todo mainHdr not initialized
66     \todo add checking for NULL pointers
67  
68 */
69
70 AVIFile::AVIFile() : RIFFFile(),
71                 idx1( NULL ), file_list( -1 ), riff_list( -1 ),
72                 hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
73                 index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
74 {
75         // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
76
77         for ( int i = 0; i < 2; ++i )
78         {
79                 indx[ i ] = new AVISuperIndex;
80                 memset( indx[ i ], 0, sizeof( AVISuperIndex ) );
81                 ix[ i ] = new AVIStdIndex;
82                 memset( ix[ i ], 0, sizeof( AVIStdIndex ) );
83                 indx_chunk[ i ] = -1;
84                 ix_chunk[ i ] = -1;
85                 strl_list[ i ] = -1;
86                 strh_chunk[ i ] = -1;
87                 strf_chunk[ i ] = -1;
88         }
89         idx1 = new AVISimpleIndex;
90         memset( idx1, 0, sizeof( AVISimpleIndex ) );
91         memset( dmlh, 0, sizeof( dmlh ) );
92         memset( &mainHdr, 0, sizeof( mainHdr ) );
93         memset( &streamHdr, 0, sizeof( streamHdr ) );
94 }
95
96
97 /** The copy constructor
98  
99     \todo add checking for NULL pointers
100  
101 */
102
103 AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi )
104 {
105         // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
106
107         mainHdr = avi.mainHdr;
108         idx1 = new AVISimpleIndex;
109         *idx1 = *avi.idx1;
110         file_list = avi.file_list;
111         riff_list = avi.riff_list;
112         hdrl_list = avi.hdrl_list;
113         avih_chunk = avi.avih_chunk;
114         movi_list = avi.movi_list;
115         junk_chunk = avi.junk_chunk;
116         idx1_chunk = avi.idx1_chunk;
117
118         for ( int i = 0; i < 2; ++i )
119         {
120                 indx[ i ] = new AVISuperIndex;
121                 *indx[ i ] = *avi.indx[ i ];
122                 ix[ i ] = new AVIStdIndex;
123                 *ix[ i ] = *avi.ix[ i ];
124                 indx_chunk[ i ] = avi.indx_chunk[ i ];
125                 ix_chunk[ i ] = avi.ix_chunk[ i ];
126                 strl_list[ i ] = avi.strl_list[ i ];
127                 strh_chunk[ i ] = avi.strh_chunk[ i ];
128                 strf_chunk[ i ] = avi.strf_chunk[ i ];
129         }
130
131         index_type = avi.index_type;
132         current_ix00 = avi.current_ix00;
133
134         for ( int i = 0; i < 62; ++i )
135                 dmlh[ i ] = avi.dmlh[ i ];
136
137         isUpdateIdx1 = avi.isUpdateIdx1;
138
139         odml_list = 0;
140         dmlh_chunk = 0;
141         memset( &streamHdr, 0, sizeof( streamHdr ) );
142 }
143
144
145 /** The assignment operator
146  
147 */
148
149 AVIFile& AVIFile::operator=( const AVIFile& avi )
150 {
151         // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
152
153         if ( this != &avi )
154         {
155                 RIFFFile::operator=( avi );
156                 mainHdr = avi.mainHdr;
157                 *idx1 = *avi.idx1;
158                 file_list = avi.file_list;
159                 riff_list = avi.riff_list;
160                 hdrl_list = avi.hdrl_list;
161                 avih_chunk = avi.avih_chunk;
162                 movi_list = avi.movi_list;
163                 junk_chunk = avi.junk_chunk;
164                 idx1_chunk = avi.idx1_chunk;
165
166                 for ( int i = 0; i < 2; ++i )
167                 {
168                         *indx[ i ] = *avi.indx[ i ];
169                         *ix[ i ] = *avi.ix[ i ];
170                         indx_chunk[ i ] = avi.indx_chunk[ i ];
171                         ix_chunk[ i ] = avi.ix_chunk[ i ];
172                         strl_list[ i ] = avi.strl_list[ i ];
173                         strh_chunk[ i ] = avi.strh_chunk[ i ];
174                         strf_chunk[ i ] = avi.strf_chunk[ i ];
175                 }
176
177                 index_type = avi.index_type;
178                 current_ix00 = avi.current_ix00;
179
180                 for ( int i = 0; i < 62; ++i )
181                         dmlh[ i ] = avi.dmlh[ i ];
182
183                 isUpdateIdx1 = avi.isUpdateIdx1;
184         }
185         return *this;
186 }
187
188
189 /** The destructor
190  
191 */
192
193 AVIFile::~AVIFile()
194 {
195         // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
196
197         for ( int i = 0; i < 2; ++i )
198         {
199                 delete ix[ i ];
200                 delete indx[ i ];
201         }
202         delete idx1;
203 }
204
205 /** Initialize the AVI structure to its initial state, either for PAL or NTSC format
206  
207     Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
208  
209     \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant.
210     \param format pass AVI_PAL or AVI_NTSC
211     \param sampleFrequency the sample frequency of the audio content
212     \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX
213  
214 */
215
216 void AVIFile::Init( int format, int sampleFrequency, int indexType )
217 {
218         int i, j;
219
220         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
221
222         index_type = indexType;
223
224         switch ( format )
225         {
226         case AVI_PAL:
227                 mainHdr.dwMicroSecPerFrame = 40000;
228                 mainHdr.dwSuggestedBufferSize = 144008;
229                 break;
230
231         case AVI_NTSC:
232                 mainHdr.dwMicroSecPerFrame = 33366;
233                 mainHdr.dwSuggestedBufferSize = 120008;
234                 break;
235
236         default:   /* no default allowed */
237                 assert( 0 );
238                 break;
239         }
240
241         /* Initialize the 'avih' chunk */
242
243         mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4;
244         mainHdr.dwPaddingGranularity = PADDING_SIZE;
245         mainHdr.dwFlags = AVIF_TRUSTCKTYPE;
246         if ( indexType & AVI_SMALL_INDEX )
247                 mainHdr.dwFlags |= AVIF_HASINDEX;
248         mainHdr.dwTotalFrames = 0;
249         mainHdr.dwInitialFrames = 0;
250         mainHdr.dwStreams = 1;
251         mainHdr.dwWidth = 0;
252         mainHdr.dwHeight = 0;
253         mainHdr.dwReserved[ 0 ] = 0;
254         mainHdr.dwReserved[ 1 ] = 0;
255         mainHdr.dwReserved[ 2 ] = 0;
256         mainHdr.dwReserved[ 3 ] = 0;
257
258         /* Initialize the 'idx1' chunk */
259
260         for ( int i = 0; i < 8000; ++i )
261         {
262                 idx1->aIndex[ i ].dwChunkId = 0;
263                 idx1->aIndex[ i ].dwFlags = 0;
264                 idx1->aIndex[ i ].dwOffset = 0;
265                 idx1->aIndex[ i ].dwSize = 0;
266         }
267         idx1->nEntriesInUse = 0;
268
269         /* Initialize the 'indx' chunk */
270
271         for ( i = 0; i < 2; ++i )
272         {
273                 indx[ i ] ->wLongsPerEntry = 4;
274                 indx[ i ] ->bIndexSubType = 0;
275                 indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES;
276                 indx[ i ] ->nEntriesInUse = 0;
277                 indx[ i ] ->dwReserved[ 0 ] = 0;
278                 indx[ i ] ->dwReserved[ 1 ] = 0;
279                 indx[ i ] ->dwReserved[ 2 ] = 0;
280                 for ( j = 0; j < 2014; ++j )
281                 {
282                         indx[ i ] ->aIndex[ j ].qwOffset = 0;
283                         indx[ i ] ->aIndex[ j ].dwSize = 0;
284                         indx[ i ] ->aIndex[ j ].dwDuration = 0;
285                 }
286         }
287
288         /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
289                   as needed */
290
291         /* Initialize the 'dmlh' chunk. I have no clue what this means
292            though */
293
294         for ( i = 0; i < 62; ++i )
295                 dmlh[ i ] = 0;
296         //dmlh[0] = -1;            /* frame count + 1? */
297
298 }
299
300
301 /** Find position and size of a given frame in the file
302  
303     Depending on which index is available, search one of them to
304     find position and frame size
305  
306     \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
307     \todo all index related operations should be isolated 
308     \param offset the file offset to the start of the frame
309     \param size the size of the frame
310     \param frameNum the number of the frame we wish to find
311     \return 0 if the frame could be found, -1 otherwise
312 */
313
314 int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum )
315 {
316         switch ( index_type )
317         {
318         case AVI_LARGE_INDEX:
319
320                 /* find relevant index in indx0 */
321
322                 int i;
323
324                 for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
325                         ;
326
327                 if ( i != current_ix00 )
328                 {
329                         fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
330                         fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
331                         current_ix00 = i;
332                 }
333
334                 if ( frameNum < ix[ 0 ] ->nEntriesInUse )
335                 {
336                         offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
337                         size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
338                         return 0;
339                 }
340                 else
341                         return -1;
342                 break;
343
344         case AVI_SMALL_INDEX:
345                 int index = -1;
346                 int frameNumIndex = 0;
347                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
348                 {
349                         FOURCC chunkID1 = make_fourcc( "00dc" );
350                         FOURCC chunkID2 = make_fourcc( "00db" );
351                         if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
352                                 idx1->aIndex[ i ].dwChunkId == chunkID2 )
353                         {
354                                 if ( frameNumIndex == frameNum )
355                                 {
356                                         index = i;
357                                         break;
358                                 }
359                                 ++frameNumIndex;
360                         }
361                 }
362                 if ( index != -1 )
363                 {
364                         // compatibility check for broken dvgrab dv2 format
365                         if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
366                         {
367                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
368                         }
369                         else
370                         {
371                                 // new, correct dv2 format
372                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
373                         }
374                         size = idx1->aIndex[ index ].dwSize;
375                         return 0;
376                 }
377                 else
378                         return -1;
379                 break;
380         }
381         return -1;
382 }
383
384 /** Find position and size of a given frame in the file
385  
386     Depending on which index is available, search one of them to
387     find position and frame size
388  
389     \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
390     \todo all index related operations should be isolated 
391     \param offset the file offset to the start of the frame
392     \param size the size of the frame
393     \param frameNum the number of the frame we wish to find
394         \param chunkID the ID of the type of chunk we want
395     \return 0 if the frame could be found, -1 otherwise
396 */
397
398 int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID )
399 {
400         if ( index_type & AVI_LARGE_INDEX )
401         {
402                 int i;
403
404                 for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
405                         ;
406
407                 if ( i != current_ix00 )
408                 {
409                         fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
410                         fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
411                         current_ix00 = i;
412                 }
413
414                 if ( frameNum < ix[ 0 ] ->nEntriesInUse )
415                 {
416                         if ( ( FOURCC ) ix[ 0 ] ->dwChunkId == chunkID )
417                         {
418                                 offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
419                                 size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
420                                 return 0;
421                         }
422                 }
423         }
424         if ( index_type & AVI_SMALL_INDEX )
425         {
426                 int index = -1;
427                 int frameNumIndex = 0;
428                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
429                 {
430                         if ( idx1->aIndex[ i ].dwChunkId == chunkID )
431                         {
432                                 if ( frameNumIndex == frameNum )
433                                 {
434                                         index = i;
435                                         break;
436                                 }
437                                 ++frameNumIndex;
438                         }
439                 }
440                 if ( index != -1 )
441                 {
442                         // compatibility check for broken dvgrab dv2 format
443                         if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
444                         {
445                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
446                         }
447                         else
448                         {
449                                 // new, correct dv2 format
450                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
451                         }
452                         size = idx1->aIndex[ index ].dwSize;
453                         return 0;
454                 }
455         }
456         return -1;
457 }
458
459 /** Read in a frame
460  
461     \todo we actually don't need the frame here, we could use just a void pointer
462     \param frame a reference to the frame object that will receive the frame data
463     \param frameNum the frame number to read
464     \return 0 if the frame could be read, -1 otherwise
465 */
466
467 int AVIFile::GetDVFrame( uint8_t *data, int frameNum )
468 {
469         off_t   offset;
470         int     size;
471
472         if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 )
473                 return -1;
474         pthread_mutex_lock( &file_mutex );
475         fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
476         fail_neg( read( fd, data, size ) );
477         pthread_mutex_unlock( &file_mutex );
478
479         return 0;
480 }
481
482 /** Read in a frame
483  
484     \param data a pointer to the audio buffer
485     \param frameNum the frame number to read
486         \param chunkID the ID of the type of chunk we want
487     \return the size the of the frame data, 0 if could not be read
488 */
489
490 int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID )
491 {
492         off_t offset;
493         int     size;
494
495         if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 )
496                 return 0;
497         fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
498         fail_neg( read( fd, data, size ) );
499
500         return size;
501 }
502
503 int AVIFile::GetTotalFrames() const
504 {
505         return mainHdr.dwTotalFrames;
506 }
507
508
509 /** prints out a directory entry in text form
510  
511     Every subclass of RIFFFile is supposed to override this function
512     and to implement it for the entry types it knows about. For all
513     other entry types it should call its parent::PrintDirectoryData.
514  
515     \todo use 64 bit routines
516     \param entry the entry to print
517 */
518
519 void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const
520 {
521         static FOURCC lastStreamType = make_fourcc( "    " );
522
523         if ( entry.type == make_fourcc( "avih" ) )
524         {
525
526                 int i;
527                 MainAVIHeader main_avi_header;
528
529                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
530                 fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) );
531
532                 cout << "    dwMicroSecPerFrame:    " << ( int ) main_avi_header.dwMicroSecPerFrame << endl
533                 << "    dwMaxBytesPerSec:      " << ( int ) main_avi_header.dwMaxBytesPerSec << endl
534                 << "    dwPaddingGranularity:  " << ( int ) main_avi_header.dwPaddingGranularity << endl
535                 << "    dwFlags:               " << ( int ) main_avi_header.dwFlags << endl
536                 << "    dwTotalFrames:         " << ( int ) main_avi_header.dwTotalFrames << endl
537                 << "    dwInitialFrames:       " << ( int ) main_avi_header.dwInitialFrames << endl
538                 << "    dwStreams:             " << ( int ) main_avi_header.dwStreams << endl
539                 << "    dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl
540                 << "    dwWidth:               " << ( int ) main_avi_header.dwWidth << endl
541                 << "    dwHeight:              " << ( int ) main_avi_header.dwHeight << endl;
542                 for ( i = 0; i < 4; ++i )
543                         cout << "    dwReserved[" << i << "]:        " << ( int ) main_avi_header.dwReserved[ i ] << endl;
544
545         }
546         else if ( entry.type == make_fourcc( "strh" ) )
547         {
548
549                 AVIStreamHeader avi_stream_header;
550
551                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
552                 fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) );
553
554                 lastStreamType = avi_stream_header.fccType;
555
556                 cout << "    fccType:         '"
557                 << ((char *)&avi_stream_header.fccType)[0]
558                 << ((char *)&avi_stream_header.fccType)[1]
559                 << ((char *)&avi_stream_header.fccType)[2]
560                 << ((char *)&avi_stream_header.fccType)[3]
561                 << '\'' << endl
562                 << "    fccHandler:      '"
563                 << ((char *)&avi_stream_header.fccHandler)[0]
564                 << ((char *)&avi_stream_header.fccHandler)[1]
565                 << ((char *)&avi_stream_header.fccHandler)[2]
566                 << ((char *)&avi_stream_header.fccHandler)[3]
567                 << '\'' << endl
568                 << "    dwFlags:         " << ( int ) avi_stream_header.dwFlags << endl
569                 << "    wPriority:       " << ( int ) avi_stream_header.wPriority << endl
570                 << "    wLanguage:       " << ( int ) avi_stream_header.wLanguage << endl
571                 << "    dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl
572                 << "    dwScale:         " << ( int ) avi_stream_header.dwScale << endl
573                 << "    dwRate:          " << ( int ) avi_stream_header.dwRate << endl
574                 << "    dwLength:        " << ( int ) avi_stream_header.dwLength << endl
575                 << "    dwQuality:       " << ( int ) avi_stream_header.dwQuality << endl
576                 << "    dwSampleSize:    " << ( int ) avi_stream_header.dwSampleSize << endl;
577
578         }
579         else if ( entry.type == make_fourcc( "indx" ) )
580         {
581
582                 int i;
583                 AVISuperIndex avi_super_index;
584
585                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
586                 fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) );
587
588                 cout << "    wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry
589                 << endl
590                 << "    bIndexSubType:  " << ( int ) avi_super_index.bIndexSubType << endl
591                 << "    bIndexType:     " << ( int ) avi_super_index.bIndexType << endl
592                 << "    nEntriesInUse:  " << ( int ) avi_super_index.nEntriesInUse << endl
593                 << "    dwChunkId:      '"
594                 << ((char *)&avi_super_index.dwChunkId)[0]
595                 << ((char *)&avi_super_index.dwChunkId)[1]
596                 << ((char *)&avi_super_index.dwChunkId)[2]
597                 << ((char *)&avi_super_index.dwChunkId)[3]
598                 << '\'' << endl
599                 << "    dwReserved[0]:  " << ( int ) avi_super_index.dwReserved[ 0 ] << endl
600                 << "    dwReserved[1]:  " << ( int ) avi_super_index.dwReserved[ 1 ] << endl
601                 << "    dwReserved[2]:  " << ( int ) avi_super_index.dwReserved[ 2 ] << endl;
602                 for ( i = 0; i < avi_super_index.nEntriesInUse; ++i )
603                 {
604                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
605                         << ": qwOffset    : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl
606                         << "       dwSize      : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl
607                         << "       dwDuration  : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl;
608                 }
609         }
610         else if ( entry.type == make_fourcc( "strf" ) )
611         {
612                 if ( lastStreamType == make_fourcc( "auds" ) )
613                 {
614                         WAVEFORMATEX waveformatex;
615                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
616                         fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) );
617                         cout << "    waveformatex.wFormatTag     : " << waveformatex.wFormatTag << endl;
618                         cout << "    waveformatex.nChannels      : " << waveformatex.nChannels << endl;
619                         cout << "    waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl;
620                         cout << "    waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl;
621                         cout << "    waveformatex.nBlockAlign    : " << waveformatex.nBlockAlign << endl;
622                         cout << "    waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl;
623                         cout << "    waveformatex.cbSize         : " << waveformatex.cbSize << endl;
624                 }
625                 else if ( lastStreamType == make_fourcc( "vids" ) )
626                 {
627                         BITMAPINFOHEADER bitmapinfo;
628                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
629                         fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) );
630                         cout << "    bitmapinfo.biSize         : " << bitmapinfo.biSize << endl;
631                         cout << "    bitmapinfo.biWidth        : " << bitmapinfo.biWidth << endl;
632                         cout << "    bitmapinfo.biHeight       : " << bitmapinfo.biHeight << endl;
633                         cout << "    bitmapinfo.biPlanes       : " << bitmapinfo.biPlanes << endl;
634                         cout << "    bitmapinfo.biBitCount     : " << bitmapinfo.biBitCount << endl;
635                         cout << "    bitmapinfo.biCompression  : " << bitmapinfo.biCompression << endl;
636                         cout << "    bitmapinfo.biSizeImage    : " << bitmapinfo.biSizeImage << endl;
637                         cout << "    bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl;
638                         cout << "    bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl;
639                         cout << "    bitmapinfo.biClrUsed      : " << bitmapinfo.biClrUsed << endl;
640                         cout << "    bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl;
641                 }
642                 else if ( lastStreamType == make_fourcc( "iavs" ) )
643                 {
644                         DVINFO dvinfo;
645                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
646                         fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) );
647                         cout << "    dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl;
648                         cout << "    dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl;
649                         cout << "    dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl;
650                         cout << "    dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl;
651                         cout << "    dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl;
652                         cout << "    dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl;
653                 }
654         }
655
656         /* This is the Standard Index. It is an array of offsets and
657            sizes relative to some start offset. */
658
659         else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) )
660         {
661
662                 int i;
663                 AVIStdIndex avi_std_index;
664
665                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
666                 fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) );
667
668                 cout << "    wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry
669                 << endl
670                 << "    bIndexSubType:  " << ( int ) avi_std_index.bIndexSubType << endl
671                 << "    bIndexType:     " << ( int ) avi_std_index.bIndexType << endl
672                 << "    nEntriesInUse:  " << ( int ) avi_std_index.nEntriesInUse << endl
673                 << "    dwChunkId:      '"
674                 << ((char *)&avi_std_index.dwChunkId)[0]
675                 << ((char *)&avi_std_index.dwChunkId)[1]
676                 << ((char *)&avi_std_index.dwChunkId)[2]
677                 << ((char *)&avi_std_index.dwChunkId)[3]
678                 << '\'' << endl
679                 << "    qwBaseOffset:   0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl
680                 << "    dwReserved:     " << dec << ( int ) avi_std_index.dwReserved << endl;
681                 for ( i = 0; i < avi_std_index.nEntriesInUse; ++i )
682                 {
683                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
684                         << ": dwOffset    : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset
685                         << " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl
686                         << "       dwSize      : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl;
687                 }
688
689         }
690         else if ( entry.type == make_fourcc( "idx1" ) )
691         {
692
693                 int i;
694                 int numEntries = entry.length / sizeof( int ) / 4;
695                 DWORD *idx1 = new DWORD[ numEntries * 4 ];
696                 // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
697
698                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
699                 fail_neg( read( fd, idx1, entry.length ) );
700
701                 for ( i = 0; i < numEntries; ++i )
702                 {
703
704                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '"
705                         << ((char *)&idx1[ i * 4 + 0 ])[0]
706                         << ((char *)&idx1[ i * 4 + 0 ])[1]
707                         << ((char *)&idx1[ i * 4 + 0 ])[2]
708                         << ((char *)&idx1[ i * 4 + 0 ])[3]
709                         << '\'' << endl
710                         << "       dwType    : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl
711                         << "       dwOffset  : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl
712                         // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
713                         << "       dwSize    : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl;
714                 }
715
716                 delete[] idx1;
717         }
718         else if ( entry.type == make_fourcc( "dmlh" ) )
719         {
720                 int i;
721                 int numEntries = entry.length / sizeof( int );
722                 DWORD *dmlh = new DWORD[ numEntries ];
723
724                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
725                 fail_neg( read( fd, dmlh, entry.length ) );
726
727                 for ( i = 0; i < numEntries; ++i )
728                 {
729                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": "
730                         << " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ]
731                         << " (" << dec << dmlh[ i ] << ")" << endl;
732                 }
733                 delete[] dmlh;
734         }
735 }
736
737
738 /** If this is not a movi list, read its contents
739  
740 */
741
742 void AVIFile::ParseList( int parent )
743 {
744         FOURCC type;
745         FOURCC name;
746         DWORD length;
747         int list;
748         off_t pos;
749         off_t listEnd;
750
751         /* Read in the chunk header (type and length). */
752         fail_neg( read( fd, &type, sizeof( type ) ) );
753         fail_neg( read( fd, &length, sizeof( length ) ) );
754         if ( length & 1 )
755                 length++;
756
757         /* The contents of the list starts here. Obtain its offset. The list
758            name (4 bytes) is already part of the contents). */
759
760         pos = lseek( fd, 0, SEEK_CUR );
761         fail_if( pos == ( off_t ) - 1 );
762         fail_neg( read( fd, &name, sizeof( name ) ) );
763
764         /* if we encounter a movi list, do not read it. It takes too much time
765            and we don't need it anyway. */
766
767         if ( name != make_fourcc( "movi" ) )
768         {
769                 //    if (1) {
770
771                 /* Add an entry for this list. */
772                 list = AddDirectoryEntry( type, name, sizeof( name ), parent );
773
774                 /* Read in any chunks contained in this list. This list is the
775                    parent for all chunks it contains. */
776
777                 listEnd = pos + length;
778                 while ( pos < listEnd )
779                 {
780                         ParseChunk( list );
781                         pos = lseek( fd, 0, SEEK_CUR );
782                         fail_if( pos == ( off_t ) - 1 );
783                 }
784         }
785         else
786         {
787                 /* Add an entry for this list. */
788
789                 movi_list = AddDirectoryEntry( type, name, length, parent );
790
791                 pos = lseek( fd, length - 4, SEEK_CUR );
792                 fail_if( pos == ( off_t ) - 1 );
793         }
794 }
795
796
797 void AVIFile::ParseRIFF()
798 {
799         RIFFFile::ParseRIFF();
800
801         avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) );
802         if ( avih_chunk != -1 )
803                 ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) );
804 }
805
806
807 void AVIFile::ReadIndex()
808 {
809         indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
810         if ( indx_chunk[ 0 ] != -1 )
811         {
812                 ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ], sizeof( AVISuperIndex ) );
813                 index_type = AVI_LARGE_INDEX;
814
815                 /* recalc number of frames from each index */
816                 mainHdr.dwTotalFrames = 0;
817                 for ( int i = 0;
818                         i < indx[ 0 ] ->nEntriesInUse;
819                         mainHdr.dwTotalFrames += indx[ 0 ] ->aIndex[ i++ ].dwDuration )
820                         ;
821                 return ;
822         }
823         idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) );
824         if ( idx1_chunk != -1 )
825         {
826                 ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISuperIndex ) );
827                 idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16;
828                 index_type = AVI_SMALL_INDEX;
829
830                 /* recalc number of frames from the simple index */
831                 int frameNumIndex = 0;
832                 FOURCC chunkID1 = make_fourcc( "00dc" );
833                 FOURCC chunkID2 = make_fourcc( "00db" );
834                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
835                 {
836                         if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
837                                 idx1->aIndex[ i ].dwChunkId == chunkID2 )
838                         {
839                                 ++frameNumIndex;
840                         }
841                 }
842                 mainHdr.dwTotalFrames = frameNumIndex;
843                 return ;
844         }
845 }
846
847
848 void AVIFile::FlushIndx( int stream )
849 {
850         FOURCC type;
851         FOURCC name;
852         off_t length;
853         off_t offset;
854         int parent;
855         int i;
856
857         /* Write out the previous index. When this function is
858            entered for the first time, there is no index to
859            write.  Note: this may be an expensive operation
860            because of a time consuming seek to the former file
861            position. */
862
863         if ( ix_chunk[ stream ] != -1 )
864                 WriteChunk( ix_chunk[ stream ], ix[ stream ] );
865
866         /* make a new ix chunk. */
867
868         if ( stream == 0 )
869                 type = make_fourcc( "ix00" );
870         else
871                 type = make_fourcc( "ix01" );
872         ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list );
873         GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent );
874
875         /* fill out all required fields. The offsets in the
876            array are relative to qwBaseOffset, so fill in the
877            offset to the next free location in the file
878            there. */
879
880         ix[ stream ] ->wLongsPerEntry = 2;
881         ix[ stream ] ->bIndexSubType = 0;
882         ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS;
883         ix[ stream ] ->nEntriesInUse = 0;
884         ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId;
885         ix[ stream ] ->qwBaseOffset = offset + length;
886         ix[ stream ] ->dwReserved = 0;
887
888         for ( i = 0; i < IX00_INDEX_SIZE; ++i )
889         {
890                 ix[ stream ] ->aIndex[ i ].dwOffset = 0;
891                 ix[ stream ] ->aIndex[ i ].dwSize = 0;
892         }
893
894         /* add a reference to this new index in our super
895            index. */
896
897         i = indx[ stream ] ->nEntriesInUse++;
898         indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE;
899         indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE;
900         indx[ stream ] ->aIndex[ i ].dwDuration = 0;
901 }
902
903
904 void AVIFile::UpdateIndx( int stream, int chunk, int duration )
905 {
906         FOURCC type;
907         FOURCC name;
908         off_t length;
909         off_t offset;
910         int parent;
911         int i;
912
913         /* update the appropiate entry in the super index. It reflects
914            the number of frames in the referenced index. */
915
916         i = indx[ stream ] ->nEntriesInUse - 1;
917         indx[ stream ] ->aIndex[ i ].dwDuration += duration;
918
919         /* update the standard index. Calculate the file position of
920            the new frame. */
921
922         GetDirectoryEntry( chunk, type, name, length, offset, parent );
923
924         indx[ stream ] ->dwChunkId = type;
925         i = ix[ stream ] ->nEntriesInUse++;
926         ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset;
927         ix[ stream ] ->aIndex[ i ].dwSize = length;
928 }
929
930
931 void AVIFile::UpdateIdx1( int chunk, int flags )
932 {
933         if ( idx1->nEntriesInUse < 20000 )
934         {
935                 FOURCC type;
936                 FOURCC name;
937                 off_t length;
938                 off_t offset;
939                 int parent;
940
941                 GetDirectoryEntry( chunk, type, name, length, offset, parent );
942
943                 idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type;
944                 idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags;
945                 idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE;
946                 idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length;
947                 idx1->nEntriesInUse++;
948         }
949 }
950
951 bool AVIFile::verifyStreamFormat( FOURCC type )
952 {
953         int i, j = 0;
954         AVIStreamHeader avi_stream_header;
955         BITMAPINFOHEADER bih;
956         FOURCC strh = make_fourcc( "strh" );
957         FOURCC strf = make_fourcc( "strf" );
958
959         while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
960         {
961                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
962                 if ( avi_stream_header.fccHandler == type )
963                         return true;
964         }
965         j = 0;
966         while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 )
967         {
968                 ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
969                 if ( ( FOURCC ) bih.biCompression == type )
970                         return true;
971         }
972
973         return false;
974 }
975
976 bool AVIFile::verifyStream( FOURCC type )
977 {
978         int i, j = 0;
979         AVIStreamHeader avi_stream_header;
980         FOURCC strh = make_fourcc( "strh" );
981
982         while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
983         {
984                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
985                 if ( avi_stream_header.fccType == type )
986                         return true;
987         }
988         return false;
989 }
990
991 bool AVIFile::isOpenDML( void )
992 {
993         int i, j = 0;
994         FOURCC dmlh = make_fourcc( "dmlh" );
995
996         while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 )
997         {
998                 return true;
999         }
1000         return false;
1001 }
1002
1003 AVI1File::AVI1File() : AVIFile()
1004 {}
1005
1006
1007 AVI1File::~AVI1File()
1008 {}
1009
1010
1011 /* Initialize the AVI structure to its initial state, either for PAL
1012    or NTSC format */
1013
1014 void AVI1File::Init( int format, int sampleFrequency, int indexType )
1015 {
1016         int num_blocks;
1017         FOURCC type;
1018         FOURCC name;
1019         off_t length;
1020         off_t offset;
1021         int parent;
1022
1023         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
1024
1025         AVIFile::Init( format, sampleFrequency, indexType );
1026
1027         switch ( format )
1028         {
1029         case AVI_PAL:
1030                 mainHdr.dwWidth = 720;
1031                 mainHdr.dwHeight = 576;
1032
1033                 streamHdr[ 0 ].dwScale = 1;
1034                 streamHdr[ 0 ].dwRate = 25;
1035                 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
1036
1037                 /* initialize the 'strf' chunk */
1038
1039                 /* Meaning of the DV stream format chunk per Microsoft
1040                    dwDVAAuxSrc
1041                       Specifies the Audio Auxiliary Data Source Pack for the first audio block
1042                       (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
1043                       a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
1044                       of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
1045                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1046                       Consumer-use Digital VCRs.
1047                    dwDVAAuxCtl
1048                       Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
1049                       frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
1050                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1051                       Consumer-use Digital VCRs.
1052                    dwDVAAuxSrc1
1053                       Specifies the Audio Auxiliary Data Source Pack for the second audio block
1054                       (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
1055                    dwDVAAuxCtl1
1056                       Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
1057                    dwDVVAuxSrc
1058                       Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
1059                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1060                       Consumer-use Digital VCRs.
1061                    dwDVVAuxCtl
1062                       Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
1063                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1064                       Consumer-use Digital VCRs.
1065                    dwDVReserved[2]
1066                       Reserved. Set this array to zero.   
1067                 */
1068
1069                 dvinfo.dwDVAAuxSrc = 0xd1e030d0;
1070                 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
1071                 dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0;
1072                 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
1073                 dvinfo.dwDVVAuxSrc = 0xff20ffff;
1074                 dvinfo.dwDVVAuxCtl = 0xfffdc83f;
1075                 dvinfo.dwDVReserved[ 0 ] = 0;
1076                 dvinfo.dwDVReserved[ 1 ] = 0;
1077                 break;
1078
1079         case AVI_NTSC:
1080                 mainHdr.dwWidth = 720;
1081                 mainHdr.dwHeight = 480;
1082
1083                 streamHdr[ 0 ].dwScale = 1001;
1084                 streamHdr[ 0 ].dwRate = 30000;
1085                 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
1086
1087                 /* initialize the 'strf' chunk */
1088                 dvinfo.dwDVAAuxSrc = 0xc0c000c0;
1089                 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
1090                 dvinfo.dwDVAAuxSrc1 = 0xc0c001c0;
1091                 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
1092                 dvinfo.dwDVVAuxSrc = 0xff80ffff;
1093                 dvinfo.dwDVVAuxCtl = 0xfffcc83f;
1094                 dvinfo.dwDVReserved[ 0 ] = 0;
1095                 dvinfo.dwDVReserved[ 1 ] = 0;
1096                 break;
1097
1098         default:   /* no default allowed */
1099                 assert( 0 );
1100                 break;
1101         }
1102
1103         indx[ 0 ] ->dwChunkId = make_fourcc( "00__" );
1104
1105         /* Initialize the 'strh' chunk */
1106
1107         streamHdr[ 0 ].fccType = make_fourcc( "iavs" );
1108         streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1109         streamHdr[ 0 ].dwFlags = 0;
1110         streamHdr[ 0 ].wPriority = 0;
1111         streamHdr[ 0 ].wLanguage = 0;
1112         streamHdr[ 0 ].dwInitialFrames = 0;
1113         streamHdr[ 0 ].dwStart = 0;
1114         streamHdr[ 0 ].dwLength = 0;
1115         streamHdr[ 0 ].dwQuality = 0;
1116         streamHdr[ 0 ].dwSampleSize = 0;
1117         streamHdr[ 0 ].rcFrame.top = 0;
1118         streamHdr[ 0 ].rcFrame.bottom = 0;
1119         streamHdr[ 0 ].rcFrame.left = 0;
1120         streamHdr[ 0 ].rcFrame.right = 0;
1121
1122         /* This is a simple directory structure setup. For details see the
1123            "OpenDML AVI File Format Extensions" document.
1124            
1125            An AVI file contains basically two types of objects, a
1126            "chunk" and a "list" object. The list object contains any
1127            number of chunks. Since a list is also a chunk, it is
1128            possible to create a hierarchical "list of lists"
1129            structure.
1130
1131            Every AVI file starts with a "RIFF" object, which is a list
1132            of several other required objects. The actual DV data is
1133            contained in a "movi" list, each frame is in its own chunk.
1134
1135            Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
1136            chunk of less than 1 GByte size per file. The current
1137            format which allow for almost arbitrary sizes can contain
1138            several RIFF chunks of less than 1 GByte size. Old software
1139            however would only deal with the first RIFF chunk.
1140
1141            Note that the first entry (FILE) isn�t actually part
1142            of the AVI file. I use this (pseudo-) directory entry to
1143            keep track of the RIFF chunks and their positions in the
1144            AVI file.
1145         */
1146
1147         /* Create the container directory entry */
1148
1149         file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
1150
1151         /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1152
1153         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
1154         hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
1155         avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
1156         strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1157         strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
1158         strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] );
1159         if ( index_type & AVI_LARGE_INDEX )
1160                 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
1161
1162         odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
1163         dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
1164
1165         /* align movi list to block */
1166         GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
1167         num_blocks = length / PADDING_SIZE + 1;
1168         length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5?
1169         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1170
1171         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1172
1173         /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
1174                   as needed */
1175
1176         ix_chunk[ 0 ] = -1;
1177 }
1178
1179
1180 /* Write a DV video frame. This is somewhat complex... */
1181
1182 #if 0
1183 bool AVI1File::WriteFrame( const Frame &frame )
1184 {
1185         int frame_chunk;
1186         int junk_chunk;
1187         int num_blocks;
1188         FOURCC type;
1189         FOURCC name;
1190         off_t length;
1191         off_t offset;
1192         int parent;
1193
1194         /* exit if no large index and 1GB reached */
1195         if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
1196                 return false;
1197
1198         /* Check if we need a new ix00 Standard Index. It has a
1199            capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1200            number, we need a new index. The new ix00 chunk is also
1201            part of the movi list. */
1202
1203         if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
1204                 FlushIndx( 0 );
1205
1206         /* Write the DV frame data.
1207
1208            Make a new 00__ chunk for the new frame, write out the
1209            frame. */
1210
1211         frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list );
1212         if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1213         {
1214                 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
1215                 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1216         }
1217         WriteChunk( frame_chunk, frame.data );
1218         //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1219         //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1220         //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1221         //    WriteChunk(junk_chunk, g_zeroes);
1222
1223         if ( index_type & AVI_LARGE_INDEX )
1224                 UpdateIndx( 0, frame_chunk, 1 );
1225         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1226                 UpdateIdx1( frame_chunk, 0x10 );
1227
1228         /* update some variables with the new frame count. */
1229
1230         if ( isUpdateIdx1 )
1231                 ++mainHdr.dwTotalFrames;
1232         ++streamHdr[ 0 ].dwLength;
1233         ++dmlh[ 0 ];
1234
1235         /* Find out if the current riff list is close to 1 GByte in
1236            size. If so, start a new (extended) RIFF. The only allowed
1237            item in the new RIFF chunk is a movi list (with video
1238            frames and indexes as usual). */
1239
1240         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1241         if ( length > 0x3f000000 )
1242         {
1243                 /* write idx1 only once and before end of first GB */
1244                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1245                 {
1246                         int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1247                         WriteChunk( idx1_chunk, ( void* ) idx1 );
1248                 }
1249                 isUpdateIdx1 = false;
1250
1251                 if ( index_type & AVI_LARGE_INDEX )
1252                 {
1253                         /* pad out to 1GB */
1254                         //GetDirectoryEntry(riff_list, type, name, length, offset, parent);
1255                         //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
1256                         //WriteChunk(junk_chunk, g_zeroes);
1257
1258                         /* padding for alignment */
1259                         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1260                         num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
1261                         length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
1262                         if ( length > 0 )
1263                         {
1264                                 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1265                                 WriteChunk( junk_chunk, g_zeroes );
1266                         }
1267
1268                         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
1269                         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1270                 }
1271         }
1272         return true;
1273 }
1274 #endif
1275
1276 void AVI1File::WriteRIFF()
1277 {
1278
1279         WriteChunk( avih_chunk, ( void* ) & mainHdr );
1280         WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
1281         WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo );
1282         WriteChunk( dmlh_chunk, ( void* ) & dmlh );
1283
1284         if ( index_type & AVI_LARGE_INDEX )
1285         {
1286                 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
1287                 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
1288         }
1289
1290         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1291         {
1292                 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1293                 WriteChunk( idx1_chunk, ( void* ) idx1 );
1294         }
1295
1296         RIFFFile::WriteRIFF();
1297 }
1298
1299
1300 AVI2File::AVI2File() : AVIFile()
1301 {}
1302
1303
1304 AVI2File::~AVI2File()
1305 {}
1306
1307
1308 /* Initialize the AVI structure to its initial state, either for PAL
1309    or NTSC format */
1310
1311 void AVI2File::Init( int format, int sampleFrequency, int indexType )
1312 {
1313         int num_blocks;
1314         FOURCC type;
1315         FOURCC name;
1316         off_t length;
1317         off_t offset;
1318         int parent;
1319
1320         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
1321
1322         AVIFile::Init( format, sampleFrequency, indexType );
1323
1324         switch ( format )
1325         {
1326
1327         case AVI_PAL:
1328                 mainHdr.dwStreams = 2;
1329                 mainHdr.dwWidth = 720;
1330                 mainHdr.dwHeight = 576;
1331
1332                 /* Initialize the 'strh' chunk */
1333
1334                 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
1335                 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1336                 streamHdr[ 0 ].dwFlags = 0;
1337                 streamHdr[ 0 ].wPriority = 0;
1338                 streamHdr[ 0 ].wLanguage = 0;
1339                 streamHdr[ 0 ].dwInitialFrames = 0;
1340                 streamHdr[ 0 ].dwScale = 1;
1341                 streamHdr[ 0 ].dwRate = 25;
1342                 streamHdr[ 0 ].dwStart = 0;
1343                 streamHdr[ 0 ].dwLength = 0;
1344                 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
1345                 streamHdr[ 0 ].dwQuality = -1;
1346                 streamHdr[ 0 ].dwSampleSize = 0;
1347                 streamHdr[ 0 ].rcFrame.top = 0;
1348                 streamHdr[ 0 ].rcFrame.bottom = 0;
1349                 streamHdr[ 0 ].rcFrame.left = 0;
1350                 streamHdr[ 0 ].rcFrame.right = 0;
1351
1352                 bitmapinfo.biSize = sizeof( bitmapinfo );
1353                 bitmapinfo.biWidth = 720;
1354                 bitmapinfo.biHeight = 576;
1355                 bitmapinfo.biPlanes = 1;
1356                 bitmapinfo.biBitCount = 24;
1357                 bitmapinfo.biCompression = make_fourcc( "dvsd" );
1358                 bitmapinfo.biSizeImage = 144000;
1359                 bitmapinfo.biXPelsPerMeter = 0;
1360                 bitmapinfo.biYPelsPerMeter = 0;
1361                 bitmapinfo.biClrUsed = 0;
1362                 bitmapinfo.biClrImportant = 0;
1363
1364                 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
1365                 streamHdr[ 1 ].fccHandler = 0;
1366                 streamHdr[ 1 ].dwFlags = 0;
1367                 streamHdr[ 1 ].wPriority = 0;
1368                 streamHdr[ 1 ].wLanguage = 0;
1369                 streamHdr[ 1 ].dwInitialFrames = 0;
1370                 streamHdr[ 1 ].dwScale = 2 * 2;
1371                 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
1372                 streamHdr[ 1 ].dwStart = 0;
1373                 streamHdr[ 1 ].dwLength = 0;
1374                 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
1375                 streamHdr[ 1 ].dwQuality = -1;
1376                 streamHdr[ 1 ].dwSampleSize = 2 * 2;
1377                 streamHdr[ 1 ].rcFrame.top = 0;
1378                 streamHdr[ 1 ].rcFrame.bottom = 0;
1379                 streamHdr[ 1 ].rcFrame.left = 0;
1380                 streamHdr[ 1 ].rcFrame.right = 0;
1381
1382                 break;
1383
1384         case AVI_NTSC:
1385                 mainHdr.dwTotalFrames = 0;
1386                 mainHdr.dwStreams = 2;
1387                 mainHdr.dwWidth = 720;
1388                 mainHdr.dwHeight = 480;
1389
1390                 /* Initialize the 'strh' chunk */
1391
1392                 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
1393                 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1394                 streamHdr[ 0 ].dwFlags = 0;
1395                 streamHdr[ 0 ].wPriority = 0;
1396                 streamHdr[ 0 ].wLanguage = 0;
1397                 streamHdr[ 0 ].dwInitialFrames = 0;
1398                 streamHdr[ 0 ].dwScale = 1001;
1399                 streamHdr[ 0 ].dwRate = 30000;
1400                 streamHdr[ 0 ].dwStart = 0;
1401                 streamHdr[ 0 ].dwLength = 0;
1402                 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
1403                 streamHdr[ 0 ].dwQuality = -1;
1404                 streamHdr[ 0 ].dwSampleSize = 0;
1405                 streamHdr[ 0 ].rcFrame.top = 0;
1406                 streamHdr[ 0 ].rcFrame.bottom = 0;
1407                 streamHdr[ 0 ].rcFrame.left = 0;
1408                 streamHdr[ 0 ].rcFrame.right = 0;
1409
1410                 bitmapinfo.biSize = sizeof( bitmapinfo );
1411                 bitmapinfo.biWidth = 720;
1412                 bitmapinfo.biHeight = 480;
1413                 bitmapinfo.biPlanes = 1;
1414                 bitmapinfo.biBitCount = 24;
1415                 bitmapinfo.biCompression = make_fourcc( "dvsd" );
1416                 bitmapinfo.biSizeImage = 120000;
1417                 bitmapinfo.biXPelsPerMeter = 0;
1418                 bitmapinfo.biYPelsPerMeter = 0;
1419                 bitmapinfo.biClrUsed = 0;
1420                 bitmapinfo.biClrImportant = 0;
1421
1422                 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
1423                 streamHdr[ 1 ].fccHandler = 0;
1424                 streamHdr[ 1 ].dwFlags = 0;
1425                 streamHdr[ 1 ].wPriority = 0;
1426                 streamHdr[ 1 ].wLanguage = 0;
1427                 streamHdr[ 1 ].dwInitialFrames = 1;
1428                 streamHdr[ 1 ].dwScale = 2 * 2;
1429                 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
1430                 streamHdr[ 1 ].dwStart = 0;
1431                 streamHdr[ 1 ].dwLength = 0;
1432                 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
1433                 streamHdr[ 1 ].dwQuality = 0;
1434                 streamHdr[ 1 ].dwSampleSize = 2 * 2;
1435                 streamHdr[ 1 ].rcFrame.top = 0;
1436                 streamHdr[ 1 ].rcFrame.bottom = 0;
1437                 streamHdr[ 1 ].rcFrame.left = 0;
1438                 streamHdr[ 1 ].rcFrame.right = 0;
1439
1440                 break;
1441         }
1442         waveformatex.wFormatTag = 1;
1443         waveformatex.nChannels = 2;
1444         waveformatex.nSamplesPerSec = sampleFrequency;
1445         waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2;
1446         waveformatex.nBlockAlign = 4;
1447         waveformatex.wBitsPerSample = 16;
1448         waveformatex.cbSize = 0;
1449
1450         file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
1451
1452         /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1453
1454         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
1455         hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
1456         avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
1457
1458         strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1459         strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
1460         strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] );
1461         if ( index_type & AVI_LARGE_INDEX )
1462         {
1463                 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
1464                 ix_chunk[ 0 ] = -1;
1465                 indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" );
1466         }
1467
1468         strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1469         strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] );
1470         strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] );
1471         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] );
1472         if ( index_type & AVI_LARGE_INDEX )
1473         {
1474                 indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] );
1475                 ix_chunk[ 1 ] = -1;
1476                 indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" );
1477
1478                 odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
1479                 dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
1480         }
1481
1482         /* align movi list to block */
1483         GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
1484         num_blocks = length / PADDING_SIZE + 1;
1485         length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5 headers?
1486         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1487
1488         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1489
1490         idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" );
1491         idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0;
1492         idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0;
1493         idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0;
1494         idx1->nEntriesInUse++;
1495 }
1496
1497
1498 void AVI2File::WriteRIFF()
1499 {
1500         WriteChunk( avih_chunk, ( void* ) & mainHdr );
1501         WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
1502         WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo );
1503         if ( index_type & AVI_LARGE_INDEX )
1504         {
1505                 WriteChunk( dmlh_chunk, ( void* ) & dmlh );
1506                 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
1507                 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
1508         }
1509         WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] );
1510         WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex );
1511         if ( index_type & AVI_LARGE_INDEX )
1512         {
1513                 WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] );
1514                 WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] );
1515         }
1516
1517         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1518         {
1519                 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1520                 WriteChunk( idx1_chunk, ( void* ) idx1 );
1521         }
1522         RIFFFile::WriteRIFF();
1523 }
1524
1525
1526 /** Write a DV video frame
1527  
1528     \param frame the frame to write
1529 */
1530
1531 #if 0
1532 bool AVI2File::WriteFrame( const Frame &frame )
1533 {
1534         int audio_chunk;
1535         int frame_chunk;
1536         int junk_chunk;
1537         char soundbuf[ 20000 ];
1538         int     audio_size;
1539         int num_blocks;
1540         FOURCC type;
1541         FOURCC name;
1542         off_t length;
1543         off_t offset;
1544         int parent;
1545
1546         /* exit if no large index and 1GB reached */
1547         if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
1548                 return false;
1549
1550         /* Check if we need a new ix00 Standard Index. It has a
1551            capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1552            number, we need a new index. The new ix00 chunk is also
1553            part of the movi list. */
1554
1555         if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
1556         {
1557                 FlushIndx( 0 );
1558                 FlushIndx( 1 );
1559         }
1560
1561         /* Write audio data if we have it */
1562
1563         audio_size = frame.ExtractAudio( soundbuf );
1564         if ( audio_size > 0 )
1565         {
1566                 audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list );
1567                 if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1568                 {
1569                         GetDirectoryEntry( audio_chunk, type, name, length, offset, parent );
1570                         ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1571                 }
1572                 WriteChunk( audio_chunk, soundbuf );
1573                 //        num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1574                 //        length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
1575                 //        junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1576                 //        WriteChunk(junk_chunk, g_zeroes);
1577                 if ( index_type & AVI_LARGE_INDEX )
1578                         UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 );
1579                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1580                         UpdateIdx1( audio_chunk, 0x00 );
1581                 streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2;
1582
1583         }
1584
1585         /* Write video data */
1586
1587         frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list );
1588         if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1589         {
1590                 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
1591                 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1592         }
1593         WriteChunk( frame_chunk, frame.data );
1594         //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1595         //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1596         //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1597         //    WriteChunk(junk_chunk, g_zeroes);
1598         if ( index_type & AVI_LARGE_INDEX )
1599                 UpdateIndx( 0, frame_chunk, 1 );
1600         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1601                 UpdateIdx1( frame_chunk, 0x10 );
1602
1603         /* update some variables with the new frame count. */
1604
1605         if ( isUpdateIdx1 )
1606                 ++mainHdr.dwTotalFrames;
1607         ++streamHdr[ 0 ].dwLength;
1608         ++dmlh[ 0 ];
1609
1610         /* Find out if the current riff list is close to 1 GByte in
1611            size. If so, start a new (extended) RIFF. The only allowed
1612            item in the new RIFF chunk is a movi list (with video
1613            frames and indexes as usual). */
1614
1615         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1616         if ( length > 0x3f000000 )
1617         {
1618
1619                 /* write idx1 only once and before end of first GB */
1620                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1621                 {
1622                         int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1623                         WriteChunk( idx1_chunk, ( void* ) idx1 );
1624                 }
1625                 isUpdateIdx1 = false;
1626
1627                 if ( index_type & AVI_LARGE_INDEX )
1628                 {
1629                         /* padding for alignment */
1630                         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1631                         num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
1632                         length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
1633                         if ( length > 0 )
1634                         {
1635                                 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1636                                 WriteChunk( junk_chunk, g_zeroes );
1637                         }
1638
1639                         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
1640                         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1641                 }
1642         }
1643         return true;
1644 }
1645 #endif
1646
1647 void AVI1File::setDVINFO( DVINFO &info )
1648 {
1649         // do not do this until debugged audio against DirectShow
1650         return ;
1651
1652         dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc;
1653         dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl;
1654         dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1;
1655         dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1;
1656         dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc;
1657         dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl;
1658 }
1659
1660
1661 void AVI2File::setDVINFO( DVINFO &info )
1662 {}
1663
1664 void AVIFile::setFccHandler( FOURCC type, FOURCC handler )
1665 {
1666         for ( int i = 0; i < mainHdr.dwStreams; i++ )
1667         {
1668                 if ( streamHdr[ i ].fccType == type )
1669                 {
1670                         int k, j = 0;
1671                         FOURCC strf = make_fourcc( "strf" );
1672                         BITMAPINFOHEADER bih;
1673
1674                         streamHdr[ i ].fccHandler = handler;
1675
1676                         while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 )
1677                         {
1678                                 ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
1679                                 bih.biCompression = handler;
1680                         }
1681                 }
1682         }
1683 }
1684
1685 bool AVIFile::getStreamFormat( void* data, FOURCC type )
1686 {
1687         int i, j = 0;
1688         FOURCC strh = make_fourcc( "strh" );
1689         FOURCC strf = make_fourcc( "strf" );
1690         AVIStreamHeader avi_stream_header;
1691         bool result = false;
1692
1693         while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
1694         {
1695                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
1696                 if ( avi_stream_header.fccType == type )
1697                 {
1698                         FOURCC chunkID;
1699                         int size;
1700
1701                         pthread_mutex_lock( &file_mutex );
1702                         fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) );
1703                         if ( chunkID == strf )
1704                         {
1705                                 fail_neg( read( fd, &size, sizeof( int ) ) );
1706                                 fail_neg( read( fd, data, size ) );
1707                                 result = true;
1708                         }
1709                         pthread_mutex_unlock( &file_mutex );
1710                 }
1711         }
1712         return result;
1713 }