]> git.sesse.net Git - mlt/blob - src/modules/kino/avi.cc
Avoid unnecessary compilation when running "./configure; make; make install" multiple...
[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 // C++ includes
21
22 #include <cstring>
23 #include <iostream>
24 #include <iomanip>
25
26 using std::cout;
27 using std::hex;
28 using std::dec;
29 using std::setw;
30 using std::setfill;
31 using std::endl;
32
33 // C includes
34
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <assert.h>
39 #include <string.h>
40
41 // local includes
42
43 #include "error.h"
44 #include "riff.h"
45 #include "avi.h"
46
47 #define PADDING_SIZE (512)
48 #define PADDING_1GB (0x40000000)
49 #define IX00_INDEX_SIZE (4028)
50
51 #define AVIF_HASINDEX 0x00000010
52 #define AVIF_MUSTUSEINDEX 0x00000020
53 #define AVIF_TRUSTCKTYPE 0x00000800
54 #define AVIF_ISINTERLEAVED 0x00000100
55 #define AVIF_WASCAPTUREFILE 0x00010000
56 #define AVIF_COPYRIGHTED 0x00020000
57
58
59 //static char g_zeroes[ PADDING_SIZE ];
60
61 /** The constructor
62  
63     \todo mainHdr not initialized
64     \todo add checking for NULL pointers
65  
66 */
67
68 AVIFile::AVIFile() : RIFFFile(),
69                 idx1( NULL ), file_list( -1 ), riff_list( -1 ),
70                 hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
71                 index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
72 {
73         // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
74
75         for ( int i = 0; i < 2; ++i )
76         {
77                 indx[ i ] = new AVISuperIndex;
78                 memset( indx[ i ], 0, sizeof( AVISuperIndex ) );
79                 ix[ i ] = new AVIStdIndex;
80                 memset( ix[ i ], 0, sizeof( AVIStdIndex ) );
81                 indx_chunk[ i ] = -1;
82                 ix_chunk[ i ] = -1;
83                 strl_list[ i ] = -1;
84                 strh_chunk[ i ] = -1;
85                 strf_chunk[ i ] = -1;
86         }
87         idx1 = new AVISimpleIndex;
88         memset( idx1, 0, sizeof( AVISimpleIndex ) );
89         memset( dmlh, 0, sizeof( dmlh ) );
90         memset( &mainHdr, 0, sizeof( mainHdr ) );
91         memset( &streamHdr, 0, sizeof( streamHdr ) );
92 }
93
94
95 /** The copy constructor
96  
97     \todo add checking for NULL pointers
98  
99 */
100
101 AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi )
102 {
103         // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
104
105         mainHdr = avi.mainHdr;
106         idx1 = new AVISimpleIndex;
107         *idx1 = *avi.idx1;
108         file_list = avi.file_list;
109         riff_list = avi.riff_list;
110         hdrl_list = avi.hdrl_list;
111         avih_chunk = avi.avih_chunk;
112         movi_list = avi.movi_list;
113         junk_chunk = avi.junk_chunk;
114         idx1_chunk = avi.idx1_chunk;
115
116         for ( int i = 0; i < 2; ++i )
117         {
118                 indx[ i ] = new AVISuperIndex;
119                 *indx[ i ] = *avi.indx[ i ];
120                 ix[ i ] = new AVIStdIndex;
121                 *ix[ i ] = *avi.ix[ i ];
122                 indx_chunk[ i ] = avi.indx_chunk[ i ];
123                 ix_chunk[ i ] = avi.ix_chunk[ i ];
124                 strl_list[ i ] = avi.strl_list[ i ];
125                 strh_chunk[ i ] = avi.strh_chunk[ i ];
126                 strf_chunk[ i ] = avi.strf_chunk[ i ];
127         }
128
129         index_type = avi.index_type;
130         current_ix00 = avi.current_ix00;
131
132         for ( int i = 0; i < 62; ++i )
133                 dmlh[ i ] = avi.dmlh[ i ];
134
135         isUpdateIdx1 = avi.isUpdateIdx1;
136
137         odml_list = 0;
138         dmlh_chunk = 0;
139         memset( &streamHdr, 0, sizeof( streamHdr ) );
140 }
141
142
143 /** The assignment operator
144  
145 */
146
147 AVIFile& AVIFile::operator=( const AVIFile& avi )
148 {
149         // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
150
151         if ( this != &avi )
152         {
153                 RIFFFile::operator=( avi );
154                 mainHdr = avi.mainHdr;
155                 *idx1 = *avi.idx1;
156                 file_list = avi.file_list;
157                 riff_list = avi.riff_list;
158                 hdrl_list = avi.hdrl_list;
159                 avih_chunk = avi.avih_chunk;
160                 movi_list = avi.movi_list;
161                 junk_chunk = avi.junk_chunk;
162                 idx1_chunk = avi.idx1_chunk;
163
164                 for ( int i = 0; i < 2; ++i )
165                 {
166                         *indx[ i ] = *avi.indx[ i ];
167                         *ix[ i ] = *avi.ix[ i ];
168                         indx_chunk[ i ] = avi.indx_chunk[ i ];
169                         ix_chunk[ i ] = avi.ix_chunk[ i ];
170                         strl_list[ i ] = avi.strl_list[ i ];
171                         strh_chunk[ i ] = avi.strh_chunk[ i ];
172                         strf_chunk[ i ] = avi.strf_chunk[ i ];
173                 }
174
175                 index_type = avi.index_type;
176                 current_ix00 = avi.current_ix00;
177
178                 for ( int i = 0; i < 62; ++i )
179                         dmlh[ i ] = avi.dmlh[ i ];
180
181                 isUpdateIdx1 = avi.isUpdateIdx1;
182         }
183         return *this;
184 }
185
186
187 /** The destructor
188  
189 */
190
191 AVIFile::~AVIFile()
192 {
193         // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
194
195         for ( int i = 0; i < 2; ++i )
196         {
197                 delete ix[ i ];
198                 delete indx[ i ];
199         }
200         delete idx1;
201 }
202
203 /** Initialize the AVI structure to its initial state, either for PAL or NTSC format
204  
205     Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
206  
207     \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant.
208     \param format pass AVI_PAL or AVI_NTSC
209     \param sampleFrequency the sample frequency of the audio content
210     \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX
211  
212 */
213
214 void AVIFile::Init( int format, int sampleFrequency, int indexType )
215 {
216         int i, j;
217
218         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
219
220         index_type = indexType;
221
222         switch ( format )
223         {
224         case AVI_PAL:
225                 mainHdr.dwMicroSecPerFrame = 40000;
226                 mainHdr.dwSuggestedBufferSize = 144008;
227                 break;
228
229         case AVI_NTSC:
230                 mainHdr.dwMicroSecPerFrame = 33366;
231                 mainHdr.dwSuggestedBufferSize = 120008;
232                 break;
233
234         default:   /* no default allowed */
235                 assert( 0 );
236                 break;
237         }
238
239         /* Initialize the 'avih' chunk */
240
241         mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4;
242         mainHdr.dwPaddingGranularity = PADDING_SIZE;
243         mainHdr.dwFlags = AVIF_TRUSTCKTYPE;
244         if ( indexType & AVI_SMALL_INDEX )
245                 mainHdr.dwFlags |= AVIF_HASINDEX;
246         mainHdr.dwTotalFrames = 0;
247         mainHdr.dwInitialFrames = 0;
248         mainHdr.dwStreams = 1;
249         mainHdr.dwWidth = 0;
250         mainHdr.dwHeight = 0;
251         mainHdr.dwReserved[ 0 ] = 0;
252         mainHdr.dwReserved[ 1 ] = 0;
253         mainHdr.dwReserved[ 2 ] = 0;
254         mainHdr.dwReserved[ 3 ] = 0;
255
256         /* Initialize the 'idx1' chunk */
257
258         for ( int i = 0; i < 8000; ++i )
259         {
260                 idx1->aIndex[ i ].dwChunkId = 0;
261                 idx1->aIndex[ i ].dwFlags = 0;
262                 idx1->aIndex[ i ].dwOffset = 0;
263                 idx1->aIndex[ i ].dwSize = 0;
264         }
265         idx1->nEntriesInUse = 0;
266
267         /* Initialize the 'indx' chunk */
268
269         for ( i = 0; i < 2; ++i )
270         {
271                 indx[ i ] ->wLongsPerEntry = 4;
272                 indx[ i ] ->bIndexSubType = 0;
273                 indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES;
274                 indx[ i ] ->nEntriesInUse = 0;
275                 indx[ i ] ->dwReserved[ 0 ] = 0;
276                 indx[ i ] ->dwReserved[ 1 ] = 0;
277                 indx[ i ] ->dwReserved[ 2 ] = 0;
278                 for ( j = 0; j < 2014; ++j )
279                 {
280                         indx[ i ] ->aIndex[ j ].qwOffset = 0;
281                         indx[ i ] ->aIndex[ j ].dwSize = 0;
282                         indx[ i ] ->aIndex[ j ].dwDuration = 0;
283                 }
284         }
285
286         /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
287                   as needed */
288
289         /* Initialize the 'dmlh' chunk. I have no clue what this means
290            though */
291
292         for ( i = 0; i < 62; ++i )
293                 dmlh[ i ] = 0;
294         //dmlh[0] = -1;            /* frame count + 1? */
295
296 }
297
298
299 /** Find position and size of a given frame in the file
300  
301     Depending on which index is available, search one of them to
302     find position and frame size
303  
304     \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
305     \todo all index related operations should be isolated 
306     \param offset the file offset to the start of the frame
307     \param size the size of the frame
308     \param frameNum the number of the frame we wish to find
309     \return 0 if the frame could be found, -1 otherwise
310 */
311
312 int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum )
313 {
314         switch ( index_type )
315         {
316         case AVI_LARGE_INDEX:
317
318                 /* find relevant index in indx0 */
319
320                 int i;
321
322                 for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
323                         ;
324
325                 if ( i != current_ix00 )
326                 {
327                         fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
328                         fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
329                         current_ix00 = i;
330                 }
331
332                 if ( frameNum < ix[ 0 ] ->nEntriesInUse )
333                 {
334                         offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
335                         size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
336                         return 0;
337                 }
338                 else
339                         return -1;
340                 break;
341
342         case AVI_SMALL_INDEX:
343                 int index = -1;
344                 int frameNumIndex = 0;
345                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
346                 {
347                         FOURCC chunkID1 = make_fourcc( "00dc" );
348                         FOURCC chunkID2 = make_fourcc( "00db" );
349                         if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
350                                 idx1->aIndex[ i ].dwChunkId == chunkID2 )
351                         {
352                                 if ( frameNumIndex == frameNum )
353                                 {
354                                         index = i;
355                                         break;
356                                 }
357                                 ++frameNumIndex;
358                         }
359                 }
360                 if ( index != -1 )
361                 {
362                         // compatibility check for broken dvgrab dv2 format
363                         if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
364                         {
365                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
366                         }
367                         else
368                         {
369                                 // new, correct dv2 format
370                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
371                         }
372                         size = idx1->aIndex[ index ].dwSize;
373                         return 0;
374                 }
375                 else
376                         return -1;
377                 break;
378         }
379         return -1;
380 }
381
382 /** Find position and size of a given frame in the file
383  
384     Depending on which index is available, search one of them to
385     find position and frame size
386  
387     \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
388     \todo all index related operations should be isolated 
389     \param offset the file offset to the start of the frame
390     \param size the size of the frame
391     \param frameNum the number of the frame we wish to find
392         \param chunkID the ID of the type of chunk we want
393     \return 0 if the frame could be found, -1 otherwise
394 */
395
396 int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID )
397 {
398         if ( index_type & AVI_LARGE_INDEX )
399         {
400                 int i;
401
402                 for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
403                         ;
404
405                 if ( i != current_ix00 )
406                 {
407                         fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
408                         fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
409                         current_ix00 = i;
410                 }
411
412                 if ( frameNum < ix[ 0 ] ->nEntriesInUse )
413                 {
414                         if ( ( FOURCC ) ix[ 0 ] ->dwChunkId == chunkID )
415                         {
416                                 offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
417                                 size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
418                                 return 0;
419                         }
420                 }
421         }
422         if ( index_type & AVI_SMALL_INDEX )
423         {
424                 int index = -1;
425                 int frameNumIndex = 0;
426                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
427                 {
428                         if ( idx1->aIndex[ i ].dwChunkId == chunkID )
429                         {
430                                 if ( frameNumIndex == frameNum )
431                                 {
432                                         index = i;
433                                         break;
434                                 }
435                                 ++frameNumIndex;
436                         }
437                 }
438                 if ( index != -1 )
439                 {
440                         // compatibility check for broken dvgrab dv2 format
441                         if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
442                         {
443                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
444                         }
445                         else
446                         {
447                                 // new, correct dv2 format
448                                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
449                         }
450                         size = idx1->aIndex[ index ].dwSize;
451                         return 0;
452                 }
453         }
454         return -1;
455 }
456
457 /** Read in a frame
458  
459     \todo we actually don't need the frame here, we could use just a void pointer
460     \param frame a reference to the frame object that will receive the frame data
461     \param frameNum the frame number to read
462     \return 0 if the frame could be read, -1 otherwise
463 */
464
465 int AVIFile::GetDVFrame( uint8_t *data, int frameNum )
466 {
467         off_t   offset;
468         int     size;
469
470         if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 )
471                 return -1;
472         pthread_mutex_lock( &file_mutex );
473         fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
474         fail_neg( read( fd, data, size ) );
475         pthread_mutex_unlock( &file_mutex );
476
477         return 0;
478 }
479
480 /** Read in a frame
481  
482     \param data a pointer to the audio buffer
483     \param frameNum the frame number to read
484         \param chunkID the ID of the type of chunk we want
485     \return the size the of the frame data, 0 if could not be read
486 */
487
488 int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID )
489 {
490         off_t offset;
491         int     size;
492
493         if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 )
494                 return 0;
495         fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
496         fail_neg( read( fd, data, size ) );
497
498         return size;
499 }
500
501 int AVIFile::GetTotalFrames() const
502 {
503         return mainHdr.dwTotalFrames;
504 }
505
506
507 /** prints out a directory entry in text form
508  
509     Every subclass of RIFFFile is supposed to override this function
510     and to implement it for the entry types it knows about. For all
511     other entry types it should call its parent::PrintDirectoryData.
512  
513     \todo use 64 bit routines
514     \param entry the entry to print
515 */
516
517 void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const
518 {
519         static FOURCC lastStreamType = make_fourcc( "    " );
520
521         if ( entry.type == make_fourcc( "avih" ) )
522         {
523
524                 int i;
525                 MainAVIHeader main_avi_header;
526
527                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
528                 fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) );
529
530                 cout << "    dwMicroSecPerFrame:    " << ( int ) main_avi_header.dwMicroSecPerFrame << endl
531                 << "    dwMaxBytesPerSec:      " << ( int ) main_avi_header.dwMaxBytesPerSec << endl
532                 << "    dwPaddingGranularity:  " << ( int ) main_avi_header.dwPaddingGranularity << endl
533                 << "    dwFlags:               " << ( int ) main_avi_header.dwFlags << endl
534                 << "    dwTotalFrames:         " << ( int ) main_avi_header.dwTotalFrames << endl
535                 << "    dwInitialFrames:       " << ( int ) main_avi_header.dwInitialFrames << endl
536                 << "    dwStreams:             " << ( int ) main_avi_header.dwStreams << endl
537                 << "    dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl
538                 << "    dwWidth:               " << ( int ) main_avi_header.dwWidth << endl
539                 << "    dwHeight:              " << ( int ) main_avi_header.dwHeight << endl;
540                 for ( i = 0; i < 4; ++i )
541                         cout << "    dwReserved[" << i << "]:        " << ( int ) main_avi_header.dwReserved[ i ] << endl;
542
543         }
544         else if ( entry.type == make_fourcc( "strh" ) )
545         {
546
547                 AVIStreamHeader avi_stream_header;
548
549                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
550                 fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) );
551
552                 lastStreamType = avi_stream_header.fccType;
553
554                 cout << "    fccType:         '"
555                 << ((char *)&avi_stream_header.fccType)[0]
556                 << ((char *)&avi_stream_header.fccType)[1]
557                 << ((char *)&avi_stream_header.fccType)[2]
558                 << ((char *)&avi_stream_header.fccType)[3]
559                 << '\'' << endl
560                 << "    fccHandler:      '"
561                 << ((char *)&avi_stream_header.fccHandler)[0]
562                 << ((char *)&avi_stream_header.fccHandler)[1]
563                 << ((char *)&avi_stream_header.fccHandler)[2]
564                 << ((char *)&avi_stream_header.fccHandler)[3]
565                 << '\'' << endl
566                 << "    dwFlags:         " << ( int ) avi_stream_header.dwFlags << endl
567                 << "    wPriority:       " << ( int ) avi_stream_header.wPriority << endl
568                 << "    wLanguage:       " << ( int ) avi_stream_header.wLanguage << endl
569                 << "    dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl
570                 << "    dwScale:         " << ( int ) avi_stream_header.dwScale << endl
571                 << "    dwRate:          " << ( int ) avi_stream_header.dwRate << endl
572                 << "    dwLength:        " << ( int ) avi_stream_header.dwLength << endl
573                 << "    dwQuality:       " << ( int ) avi_stream_header.dwQuality << endl
574                 << "    dwSampleSize:    " << ( int ) avi_stream_header.dwSampleSize << endl;
575
576         }
577         else if ( entry.type == make_fourcc( "indx" ) )
578         {
579
580                 int i;
581                 AVISuperIndex avi_super_index;
582
583                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
584                 fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) );
585
586                 cout << "    wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry
587                 << endl
588                 << "    bIndexSubType:  " << ( int ) avi_super_index.bIndexSubType << endl
589                 << "    bIndexType:     " << ( int ) avi_super_index.bIndexType << endl
590                 << "    nEntriesInUse:  " << ( int ) avi_super_index.nEntriesInUse << endl
591                 << "    dwChunkId:      '"
592                 << ((char *)&avi_super_index.dwChunkId)[0]
593                 << ((char *)&avi_super_index.dwChunkId)[1]
594                 << ((char *)&avi_super_index.dwChunkId)[2]
595                 << ((char *)&avi_super_index.dwChunkId)[3]
596                 << '\'' << endl
597                 << "    dwReserved[0]:  " << ( int ) avi_super_index.dwReserved[ 0 ] << endl
598                 << "    dwReserved[1]:  " << ( int ) avi_super_index.dwReserved[ 1 ] << endl
599                 << "    dwReserved[2]:  " << ( int ) avi_super_index.dwReserved[ 2 ] << endl;
600                 for ( i = 0; i < avi_super_index.nEntriesInUse; ++i )
601                 {
602                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
603                         << ": qwOffset    : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl
604                         << "       dwSize      : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl
605                         << "       dwDuration  : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl;
606                 }
607         }
608         else if ( entry.type == make_fourcc( "strf" ) )
609         {
610                 if ( lastStreamType == make_fourcc( "auds" ) )
611                 {
612                         WAVEFORMATEX waveformatex;
613                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
614                         fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) );
615                         cout << "    waveformatex.wFormatTag     : " << waveformatex.wFormatTag << endl;
616                         cout << "    waveformatex.nChannels      : " << waveformatex.nChannels << endl;
617                         cout << "    waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl;
618                         cout << "    waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl;
619                         cout << "    waveformatex.nBlockAlign    : " << waveformatex.nBlockAlign << endl;
620                         cout << "    waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl;
621                         cout << "    waveformatex.cbSize         : " << waveformatex.cbSize << endl;
622                 }
623                 else if ( lastStreamType == make_fourcc( "vids" ) )
624                 {
625                         BITMAPINFOHEADER bitmapinfo;
626                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
627                         fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) );
628                         cout << "    bitmapinfo.biSize         : " << bitmapinfo.biSize << endl;
629                         cout << "    bitmapinfo.biWidth        : " << bitmapinfo.biWidth << endl;
630                         cout << "    bitmapinfo.biHeight       : " << bitmapinfo.biHeight << endl;
631                         cout << "    bitmapinfo.biPlanes       : " << bitmapinfo.biPlanes << endl;
632                         cout << "    bitmapinfo.biBitCount     : " << bitmapinfo.biBitCount << endl;
633                         cout << "    bitmapinfo.biCompression  : " << bitmapinfo.biCompression << endl;
634                         cout << "    bitmapinfo.biSizeImage    : " << bitmapinfo.biSizeImage << endl;
635                         cout << "    bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl;
636                         cout << "    bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl;
637                         cout << "    bitmapinfo.biClrUsed      : " << bitmapinfo.biClrUsed << endl;
638                         cout << "    bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl;
639                 }
640                 else if ( lastStreamType == make_fourcc( "iavs" ) )
641                 {
642                         DVINFO dvinfo;
643                         fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
644                         fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) );
645                         cout << "    dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl;
646                         cout << "    dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl;
647                         cout << "    dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl;
648                         cout << "    dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl;
649                         cout << "    dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl;
650                         cout << "    dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl;
651                 }
652         }
653
654         /* This is the Standard Index. It is an array of offsets and
655            sizes relative to some start offset. */
656
657         else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) )
658         {
659
660                 int i;
661                 AVIStdIndex avi_std_index;
662
663                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
664                 fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) );
665
666                 cout << "    wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry
667                 << endl
668                 << "    bIndexSubType:  " << ( int ) avi_std_index.bIndexSubType << endl
669                 << "    bIndexType:     " << ( int ) avi_std_index.bIndexType << endl
670                 << "    nEntriesInUse:  " << ( int ) avi_std_index.nEntriesInUse << endl
671                 << "    dwChunkId:      '"
672                 << ((char *)&avi_std_index.dwChunkId)[0]
673                 << ((char *)&avi_std_index.dwChunkId)[1]
674                 << ((char *)&avi_std_index.dwChunkId)[2]
675                 << ((char *)&avi_std_index.dwChunkId)[3]
676                 << '\'' << endl
677                 << "    qwBaseOffset:   0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl
678                 << "    dwReserved:     " << dec << ( int ) avi_std_index.dwReserved << endl;
679                 for ( i = 0; i < avi_std_index.nEntriesInUse; ++i )
680                 {
681                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
682                         << ": dwOffset    : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset
683                         << " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl
684                         << "       dwSize      : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl;
685                 }
686
687         }
688         else if ( entry.type == make_fourcc( "idx1" ) )
689         {
690
691                 int i;
692                 int numEntries = entry.length / sizeof( int ) / 4;
693                 DWORD *idx1 = new DWORD[ numEntries * 4 ];
694                 // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
695
696                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
697                 fail_neg( read( fd, idx1, entry.length ) );
698
699                 for ( i = 0; i < numEntries; ++i )
700                 {
701
702                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '"
703                         << ((char *)&idx1[ i * 4 + 0 ])[0]
704                         << ((char *)&idx1[ i * 4 + 0 ])[1]
705                         << ((char *)&idx1[ i * 4 + 0 ])[2]
706                         << ((char *)&idx1[ i * 4 + 0 ])[3]
707                         << '\'' << endl
708                         << "       dwType    : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl
709                         << "       dwOffset  : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl
710                         // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
711                         << "       dwSize    : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl;
712                 }
713
714                 delete[] idx1;
715         }
716         else if ( entry.type == make_fourcc( "dmlh" ) )
717         {
718                 int i;
719                 int numEntries = entry.length / sizeof( int );
720                 DWORD *dmlh = new DWORD[ numEntries ];
721
722                 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
723                 fail_neg( read( fd, dmlh, entry.length ) );
724
725                 for ( i = 0; i < numEntries; ++i )
726                 {
727                         cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": "
728                         << " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ]
729                         << " (" << dec << dmlh[ i ] << ")" << endl;
730                 }
731                 delete[] dmlh;
732         }
733 }
734
735
736 /** If this is not a movi list, read its contents
737  
738 */
739
740 void AVIFile::ParseList( int parent )
741 {
742         FOURCC type;
743         FOURCC name;
744         DWORD length;
745         int list;
746         off_t pos;
747         off_t listEnd;
748
749         /* Read in the chunk header (type and length). */
750         fail_neg( read( fd, &type, sizeof( type ) ) );
751         fail_neg( read( fd, &length, sizeof( length ) ) );
752         if ( length & 1 )
753                 length++;
754
755         /* The contents of the list starts here. Obtain its offset. The list
756            name (4 bytes) is already part of the contents). */
757
758         pos = lseek( fd, 0, SEEK_CUR );
759         fail_if( pos == ( off_t ) - 1 );
760         fail_neg( read( fd, &name, sizeof( name ) ) );
761
762         /* if we encounter a movi list, do not read it. It takes too much time
763            and we don't need it anyway. */
764
765         if ( name != make_fourcc( "movi" ) )
766         {
767                 //    if (1) {
768
769                 /* Add an entry for this list. */
770                 list = AddDirectoryEntry( type, name, sizeof( name ), parent );
771
772                 /* Read in any chunks contained in this list. This list is the
773                    parent for all chunks it contains. */
774
775                 listEnd = pos + length;
776                 while ( pos < listEnd )
777                 {
778                         ParseChunk( list );
779                         pos = lseek( fd, 0, SEEK_CUR );
780                         fail_if( pos == ( off_t ) - 1 );
781                 }
782         }
783         else
784         {
785                 /* Add an entry for this list. */
786
787                 movi_list = AddDirectoryEntry( type, name, length, parent );
788
789                 pos = lseek( fd, length - 4, SEEK_CUR );
790                 fail_if( pos == ( off_t ) - 1 );
791         }
792 }
793
794
795 void AVIFile::ParseRIFF()
796 {
797         RIFFFile::ParseRIFF();
798
799         avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) );
800         if ( avih_chunk != -1 )
801                 ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) );
802 }
803
804
805 void AVIFile::ReadIndex()
806 {
807         indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
808         if ( indx_chunk[ 0 ] != -1 )
809         {
810                 ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ], sizeof( AVISuperIndex ) );
811                 index_type = AVI_LARGE_INDEX;
812
813                 /* recalc number of frames from each index */
814                 mainHdr.dwTotalFrames = 0;
815                 for ( int i = 0;
816                         i < indx[ 0 ] ->nEntriesInUse;
817                         mainHdr.dwTotalFrames += indx[ 0 ] ->aIndex[ i++ ].dwDuration )
818                         ;
819                 return ;
820         }
821         idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) );
822         if ( idx1_chunk != -1 )
823         {
824                 ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISuperIndex ) );
825                 idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16;
826                 index_type = AVI_SMALL_INDEX;
827
828                 /* recalc number of frames from the simple index */
829                 int frameNumIndex = 0;
830                 FOURCC chunkID1 = make_fourcc( "00dc" );
831                 FOURCC chunkID2 = make_fourcc( "00db" );
832                 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
833                 {
834                         if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
835                                 idx1->aIndex[ i ].dwChunkId == chunkID2 )
836                         {
837                                 ++frameNumIndex;
838                         }
839                 }
840                 mainHdr.dwTotalFrames = frameNumIndex;
841                 return ;
842         }
843 }
844
845
846 void AVIFile::FlushIndx( int stream )
847 {
848         FOURCC type;
849         FOURCC name;
850         off_t length;
851         off_t offset;
852         int parent;
853         int i;
854
855         /* Write out the previous index. When this function is
856            entered for the first time, there is no index to
857            write.  Note: this may be an expensive operation
858            because of a time consuming seek to the former file
859            position. */
860
861         if ( ix_chunk[ stream ] != -1 )
862                 WriteChunk( ix_chunk[ stream ], ix[ stream ] );
863
864         /* make a new ix chunk. */
865
866         if ( stream == 0 )
867                 type = make_fourcc( "ix00" );
868         else
869                 type = make_fourcc( "ix01" );
870         ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list );
871         GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent );
872
873         /* fill out all required fields. The offsets in the
874            array are relative to qwBaseOffset, so fill in the
875            offset to the next free location in the file
876            there. */
877
878         ix[ stream ] ->wLongsPerEntry = 2;
879         ix[ stream ] ->bIndexSubType = 0;
880         ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS;
881         ix[ stream ] ->nEntriesInUse = 0;
882         ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId;
883         ix[ stream ] ->qwBaseOffset = offset + length;
884         ix[ stream ] ->dwReserved = 0;
885
886         for ( i = 0; i < IX00_INDEX_SIZE; ++i )
887         {
888                 ix[ stream ] ->aIndex[ i ].dwOffset = 0;
889                 ix[ stream ] ->aIndex[ i ].dwSize = 0;
890         }
891
892         /* add a reference to this new index in our super
893            index. */
894
895         i = indx[ stream ] ->nEntriesInUse++;
896         indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE;
897         indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE;
898         indx[ stream ] ->aIndex[ i ].dwDuration = 0;
899 }
900
901
902 void AVIFile::UpdateIndx( int stream, int chunk, int duration )
903 {
904         FOURCC type;
905         FOURCC name;
906         off_t length;
907         off_t offset;
908         int parent;
909         int i;
910
911         /* update the appropiate entry in the super index. It reflects
912            the number of frames in the referenced index. */
913
914         i = indx[ stream ] ->nEntriesInUse - 1;
915         indx[ stream ] ->aIndex[ i ].dwDuration += duration;
916
917         /* update the standard index. Calculate the file position of
918            the new frame. */
919
920         GetDirectoryEntry( chunk, type, name, length, offset, parent );
921
922         indx[ stream ] ->dwChunkId = type;
923         i = ix[ stream ] ->nEntriesInUse++;
924         ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset;
925         ix[ stream ] ->aIndex[ i ].dwSize = length;
926 }
927
928
929 void AVIFile::UpdateIdx1( int chunk, int flags )
930 {
931         if ( idx1->nEntriesInUse < 20000 )
932         {
933                 FOURCC type;
934                 FOURCC name;
935                 off_t length;
936                 off_t offset;
937                 int parent;
938
939                 GetDirectoryEntry( chunk, type, name, length, offset, parent );
940
941                 idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type;
942                 idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags;
943                 idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE;
944                 idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length;
945                 idx1->nEntriesInUse++;
946         }
947 }
948
949 bool AVIFile::verifyStreamFormat( FOURCC type )
950 {
951         int i, j = 0;
952         AVIStreamHeader avi_stream_header;
953         BITMAPINFOHEADER bih;
954         FOURCC strh = make_fourcc( "strh" );
955         FOURCC strf = make_fourcc( "strf" );
956
957         while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
958         {
959                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
960                 if ( avi_stream_header.fccHandler == type )
961                         return true;
962         }
963         j = 0;
964         while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 )
965         {
966                 ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
967                 if ( ( FOURCC ) bih.biCompression == type )
968                         return true;
969         }
970
971         return false;
972 }
973
974 bool AVIFile::verifyStream( FOURCC type )
975 {
976         int i, j = 0;
977         AVIStreamHeader avi_stream_header;
978         FOURCC strh = make_fourcc( "strh" );
979
980         while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
981         {
982                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
983                 if ( avi_stream_header.fccType == type )
984                         return true;
985         }
986         return false;
987 }
988
989 bool AVIFile::isOpenDML( void )
990 {
991         int i, j = 0;
992         FOURCC dmlh = make_fourcc( "dmlh" );
993
994         while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 )
995         {
996                 return true;
997         }
998         return false;
999 }
1000
1001 AVI1File::AVI1File() : AVIFile()
1002 {
1003         memset( &dvinfo, 0, sizeof( dvinfo ) );
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 }