]> git.sesse.net Git - mlt/blob - src/modules/kino/avi.cc
04c5176c8458dfd881847af9ba412e7a3adc3901
[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         memset( &dvinfo, 0, sizeof( dvinfo ) );
1006 }
1007
1008
1009 AVI1File::~AVI1File()
1010 {}
1011
1012
1013 /* Initialize the AVI structure to its initial state, either for PAL
1014    or NTSC format */
1015
1016 void AVI1File::Init( int format, int sampleFrequency, int indexType )
1017 {
1018         int num_blocks;
1019         FOURCC type;
1020         FOURCC name;
1021         off_t length;
1022         off_t offset;
1023         int parent;
1024
1025         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
1026
1027         AVIFile::Init( format, sampleFrequency, indexType );
1028
1029         switch ( format )
1030         {
1031         case AVI_PAL:
1032                 mainHdr.dwWidth = 720;
1033                 mainHdr.dwHeight = 576;
1034
1035                 streamHdr[ 0 ].dwScale = 1;
1036                 streamHdr[ 0 ].dwRate = 25;
1037                 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
1038
1039                 /* initialize the 'strf' chunk */
1040
1041                 /* Meaning of the DV stream format chunk per Microsoft
1042                    dwDVAAuxSrc
1043                       Specifies the Audio Auxiliary Data Source Pack for the first audio block
1044                       (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
1045                       a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
1046                       of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
1047                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1048                       Consumer-use Digital VCRs.
1049                    dwDVAAuxCtl
1050                       Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
1051                       frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
1052                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1053                       Consumer-use Digital VCRs.
1054                    dwDVAAuxSrc1
1055                       Specifies the Audio Auxiliary Data Source Pack for the second audio block
1056                       (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
1057                    dwDVAAuxCtl1
1058                       Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
1059                    dwDVVAuxSrc
1060                       Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
1061                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1062                       Consumer-use Digital VCRs.
1063                    dwDVVAuxCtl
1064                       Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
1065                       Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1066                       Consumer-use Digital VCRs.
1067                    dwDVReserved[2]
1068                       Reserved. Set this array to zero.   
1069                 */
1070
1071                 dvinfo.dwDVAAuxSrc = 0xd1e030d0;
1072                 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
1073                 dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0;
1074                 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
1075                 dvinfo.dwDVVAuxSrc = 0xff20ffff;
1076                 dvinfo.dwDVVAuxCtl = 0xfffdc83f;
1077                 dvinfo.dwDVReserved[ 0 ] = 0;
1078                 dvinfo.dwDVReserved[ 1 ] = 0;
1079                 break;
1080
1081         case AVI_NTSC:
1082                 mainHdr.dwWidth = 720;
1083                 mainHdr.dwHeight = 480;
1084
1085                 streamHdr[ 0 ].dwScale = 1001;
1086                 streamHdr[ 0 ].dwRate = 30000;
1087                 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
1088
1089                 /* initialize the 'strf' chunk */
1090                 dvinfo.dwDVAAuxSrc = 0xc0c000c0;
1091                 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
1092                 dvinfo.dwDVAAuxSrc1 = 0xc0c001c0;
1093                 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
1094                 dvinfo.dwDVVAuxSrc = 0xff80ffff;
1095                 dvinfo.dwDVVAuxCtl = 0xfffcc83f;
1096                 dvinfo.dwDVReserved[ 0 ] = 0;
1097                 dvinfo.dwDVReserved[ 1 ] = 0;
1098                 break;
1099
1100         default:   /* no default allowed */
1101                 assert( 0 );
1102                 break;
1103         }
1104
1105         indx[ 0 ] ->dwChunkId = make_fourcc( "00__" );
1106
1107         /* Initialize the 'strh' chunk */
1108
1109         streamHdr[ 0 ].fccType = make_fourcc( "iavs" );
1110         streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1111         streamHdr[ 0 ].dwFlags = 0;
1112         streamHdr[ 0 ].wPriority = 0;
1113         streamHdr[ 0 ].wLanguage = 0;
1114         streamHdr[ 0 ].dwInitialFrames = 0;
1115         streamHdr[ 0 ].dwStart = 0;
1116         streamHdr[ 0 ].dwLength = 0;
1117         streamHdr[ 0 ].dwQuality = 0;
1118         streamHdr[ 0 ].dwSampleSize = 0;
1119         streamHdr[ 0 ].rcFrame.top = 0;
1120         streamHdr[ 0 ].rcFrame.bottom = 0;
1121         streamHdr[ 0 ].rcFrame.left = 0;
1122         streamHdr[ 0 ].rcFrame.right = 0;
1123
1124         /* This is a simple directory structure setup. For details see the
1125            "OpenDML AVI File Format Extensions" document.
1126            
1127            An AVI file contains basically two types of objects, a
1128            "chunk" and a "list" object. The list object contains any
1129            number of chunks. Since a list is also a chunk, it is
1130            possible to create a hierarchical "list of lists"
1131            structure.
1132
1133            Every AVI file starts with a "RIFF" object, which is a list
1134            of several other required objects. The actual DV data is
1135            contained in a "movi" list, each frame is in its own chunk.
1136
1137            Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
1138            chunk of less than 1 GByte size per file. The current
1139            format which allow for almost arbitrary sizes can contain
1140            several RIFF chunks of less than 1 GByte size. Old software
1141            however would only deal with the first RIFF chunk.
1142
1143            Note that the first entry (FILE) isn�t actually part
1144            of the AVI file. I use this (pseudo-) directory entry to
1145            keep track of the RIFF chunks and their positions in the
1146            AVI file.
1147         */
1148
1149         /* Create the container directory entry */
1150
1151         file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
1152
1153         /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1154
1155         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
1156         hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
1157         avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
1158         strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1159         strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
1160         strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] );
1161         if ( index_type & AVI_LARGE_INDEX )
1162                 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
1163
1164         odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
1165         dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
1166
1167         /* align movi list to block */
1168         GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
1169         num_blocks = length / PADDING_SIZE + 1;
1170         length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5?
1171         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1172
1173         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1174
1175         /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
1176                   as needed */
1177
1178         ix_chunk[ 0 ] = -1;
1179 }
1180
1181
1182 /* Write a DV video frame. This is somewhat complex... */
1183
1184 #if 0
1185 bool AVI1File::WriteFrame( const Frame &frame )
1186 {
1187         int frame_chunk;
1188         int junk_chunk;
1189         int num_blocks;
1190         FOURCC type;
1191         FOURCC name;
1192         off_t length;
1193         off_t offset;
1194         int parent;
1195
1196         /* exit if no large index and 1GB reached */
1197         if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
1198                 return false;
1199
1200         /* Check if we need a new ix00 Standard Index. It has a
1201            capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1202            number, we need a new index. The new ix00 chunk is also
1203            part of the movi list. */
1204
1205         if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
1206                 FlushIndx( 0 );
1207
1208         /* Write the DV frame data.
1209
1210            Make a new 00__ chunk for the new frame, write out the
1211            frame. */
1212
1213         frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list );
1214         if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1215         {
1216                 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
1217                 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1218         }
1219         WriteChunk( frame_chunk, frame.data );
1220         //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1221         //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1222         //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1223         //    WriteChunk(junk_chunk, g_zeroes);
1224
1225         if ( index_type & AVI_LARGE_INDEX )
1226                 UpdateIndx( 0, frame_chunk, 1 );
1227         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1228                 UpdateIdx1( frame_chunk, 0x10 );
1229
1230         /* update some variables with the new frame count. */
1231
1232         if ( isUpdateIdx1 )
1233                 ++mainHdr.dwTotalFrames;
1234         ++streamHdr[ 0 ].dwLength;
1235         ++dmlh[ 0 ];
1236
1237         /* Find out if the current riff list is close to 1 GByte in
1238            size. If so, start a new (extended) RIFF. The only allowed
1239            item in the new RIFF chunk is a movi list (with video
1240            frames and indexes as usual). */
1241
1242         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1243         if ( length > 0x3f000000 )
1244         {
1245                 /* write idx1 only once and before end of first GB */
1246                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1247                 {
1248                         int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1249                         WriteChunk( idx1_chunk, ( void* ) idx1 );
1250                 }
1251                 isUpdateIdx1 = false;
1252
1253                 if ( index_type & AVI_LARGE_INDEX )
1254                 {
1255                         /* pad out to 1GB */
1256                         //GetDirectoryEntry(riff_list, type, name, length, offset, parent);
1257                         //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
1258                         //WriteChunk(junk_chunk, g_zeroes);
1259
1260                         /* padding for alignment */
1261                         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1262                         num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
1263                         length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
1264                         if ( length > 0 )
1265                         {
1266                                 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1267                                 WriteChunk( junk_chunk, g_zeroes );
1268                         }
1269
1270                         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
1271                         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1272                 }
1273         }
1274         return true;
1275 }
1276 #endif
1277
1278 void AVI1File::WriteRIFF()
1279 {
1280
1281         WriteChunk( avih_chunk, ( void* ) & mainHdr );
1282         WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
1283         WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo );
1284         WriteChunk( dmlh_chunk, ( void* ) & dmlh );
1285
1286         if ( index_type & AVI_LARGE_INDEX )
1287         {
1288                 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
1289                 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
1290         }
1291
1292         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1293         {
1294                 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1295                 WriteChunk( idx1_chunk, ( void* ) idx1 );
1296         }
1297
1298         RIFFFile::WriteRIFF();
1299 }
1300
1301
1302 AVI2File::AVI2File() : AVIFile()
1303 {}
1304
1305
1306 AVI2File::~AVI2File()
1307 {}
1308
1309
1310 /* Initialize the AVI structure to its initial state, either for PAL
1311    or NTSC format */
1312
1313 void AVI2File::Init( int format, int sampleFrequency, int indexType )
1314 {
1315         int num_blocks;
1316         FOURCC type;
1317         FOURCC name;
1318         off_t length;
1319         off_t offset;
1320         int parent;
1321
1322         assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
1323
1324         AVIFile::Init( format, sampleFrequency, indexType );
1325
1326         switch ( format )
1327         {
1328
1329         case AVI_PAL:
1330                 mainHdr.dwStreams = 2;
1331                 mainHdr.dwWidth = 720;
1332                 mainHdr.dwHeight = 576;
1333
1334                 /* Initialize the 'strh' chunk */
1335
1336                 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
1337                 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1338                 streamHdr[ 0 ].dwFlags = 0;
1339                 streamHdr[ 0 ].wPriority = 0;
1340                 streamHdr[ 0 ].wLanguage = 0;
1341                 streamHdr[ 0 ].dwInitialFrames = 0;
1342                 streamHdr[ 0 ].dwScale = 1;
1343                 streamHdr[ 0 ].dwRate = 25;
1344                 streamHdr[ 0 ].dwStart = 0;
1345                 streamHdr[ 0 ].dwLength = 0;
1346                 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
1347                 streamHdr[ 0 ].dwQuality = -1;
1348                 streamHdr[ 0 ].dwSampleSize = 0;
1349                 streamHdr[ 0 ].rcFrame.top = 0;
1350                 streamHdr[ 0 ].rcFrame.bottom = 0;
1351                 streamHdr[ 0 ].rcFrame.left = 0;
1352                 streamHdr[ 0 ].rcFrame.right = 0;
1353
1354                 bitmapinfo.biSize = sizeof( bitmapinfo );
1355                 bitmapinfo.biWidth = 720;
1356                 bitmapinfo.biHeight = 576;
1357                 bitmapinfo.biPlanes = 1;
1358                 bitmapinfo.biBitCount = 24;
1359                 bitmapinfo.biCompression = make_fourcc( "dvsd" );
1360                 bitmapinfo.biSizeImage = 144000;
1361                 bitmapinfo.biXPelsPerMeter = 0;
1362                 bitmapinfo.biYPelsPerMeter = 0;
1363                 bitmapinfo.biClrUsed = 0;
1364                 bitmapinfo.biClrImportant = 0;
1365
1366                 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
1367                 streamHdr[ 1 ].fccHandler = 0;
1368                 streamHdr[ 1 ].dwFlags = 0;
1369                 streamHdr[ 1 ].wPriority = 0;
1370                 streamHdr[ 1 ].wLanguage = 0;
1371                 streamHdr[ 1 ].dwInitialFrames = 0;
1372                 streamHdr[ 1 ].dwScale = 2 * 2;
1373                 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
1374                 streamHdr[ 1 ].dwStart = 0;
1375                 streamHdr[ 1 ].dwLength = 0;
1376                 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
1377                 streamHdr[ 1 ].dwQuality = -1;
1378                 streamHdr[ 1 ].dwSampleSize = 2 * 2;
1379                 streamHdr[ 1 ].rcFrame.top = 0;
1380                 streamHdr[ 1 ].rcFrame.bottom = 0;
1381                 streamHdr[ 1 ].rcFrame.left = 0;
1382                 streamHdr[ 1 ].rcFrame.right = 0;
1383
1384                 break;
1385
1386         case AVI_NTSC:
1387                 mainHdr.dwTotalFrames = 0;
1388                 mainHdr.dwStreams = 2;
1389                 mainHdr.dwWidth = 720;
1390                 mainHdr.dwHeight = 480;
1391
1392                 /* Initialize the 'strh' chunk */
1393
1394                 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
1395                 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
1396                 streamHdr[ 0 ].dwFlags = 0;
1397                 streamHdr[ 0 ].wPriority = 0;
1398                 streamHdr[ 0 ].wLanguage = 0;
1399                 streamHdr[ 0 ].dwInitialFrames = 0;
1400                 streamHdr[ 0 ].dwScale = 1001;
1401                 streamHdr[ 0 ].dwRate = 30000;
1402                 streamHdr[ 0 ].dwStart = 0;
1403                 streamHdr[ 0 ].dwLength = 0;
1404                 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
1405                 streamHdr[ 0 ].dwQuality = -1;
1406                 streamHdr[ 0 ].dwSampleSize = 0;
1407                 streamHdr[ 0 ].rcFrame.top = 0;
1408                 streamHdr[ 0 ].rcFrame.bottom = 0;
1409                 streamHdr[ 0 ].rcFrame.left = 0;
1410                 streamHdr[ 0 ].rcFrame.right = 0;
1411
1412                 bitmapinfo.biSize = sizeof( bitmapinfo );
1413                 bitmapinfo.biWidth = 720;
1414                 bitmapinfo.biHeight = 480;
1415                 bitmapinfo.biPlanes = 1;
1416                 bitmapinfo.biBitCount = 24;
1417                 bitmapinfo.biCompression = make_fourcc( "dvsd" );
1418                 bitmapinfo.biSizeImage = 120000;
1419                 bitmapinfo.biXPelsPerMeter = 0;
1420                 bitmapinfo.biYPelsPerMeter = 0;
1421                 bitmapinfo.biClrUsed = 0;
1422                 bitmapinfo.biClrImportant = 0;
1423
1424                 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
1425                 streamHdr[ 1 ].fccHandler = 0;
1426                 streamHdr[ 1 ].dwFlags = 0;
1427                 streamHdr[ 1 ].wPriority = 0;
1428                 streamHdr[ 1 ].wLanguage = 0;
1429                 streamHdr[ 1 ].dwInitialFrames = 1;
1430                 streamHdr[ 1 ].dwScale = 2 * 2;
1431                 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
1432                 streamHdr[ 1 ].dwStart = 0;
1433                 streamHdr[ 1 ].dwLength = 0;
1434                 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
1435                 streamHdr[ 1 ].dwQuality = 0;
1436                 streamHdr[ 1 ].dwSampleSize = 2 * 2;
1437                 streamHdr[ 1 ].rcFrame.top = 0;
1438                 streamHdr[ 1 ].rcFrame.bottom = 0;
1439                 streamHdr[ 1 ].rcFrame.left = 0;
1440                 streamHdr[ 1 ].rcFrame.right = 0;
1441
1442                 break;
1443         }
1444         waveformatex.wFormatTag = 1;
1445         waveformatex.nChannels = 2;
1446         waveformatex.nSamplesPerSec = sampleFrequency;
1447         waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2;
1448         waveformatex.nBlockAlign = 4;
1449         waveformatex.wBitsPerSample = 16;
1450         waveformatex.cbSize = 0;
1451
1452         file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
1453
1454         /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1455
1456         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
1457         hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
1458         avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
1459
1460         strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1461         strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
1462         strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] );
1463         if ( index_type & AVI_LARGE_INDEX )
1464         {
1465                 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
1466                 ix_chunk[ 0 ] = -1;
1467                 indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" );
1468         }
1469
1470         strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
1471         strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] );
1472         strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] );
1473         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] );
1474         if ( index_type & AVI_LARGE_INDEX )
1475         {
1476                 indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] );
1477                 ix_chunk[ 1 ] = -1;
1478                 indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" );
1479
1480                 odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
1481                 dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
1482         }
1483
1484         /* align movi list to block */
1485         GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
1486         num_blocks = length / PADDING_SIZE + 1;
1487         length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5 headers?
1488         junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1489
1490         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1491
1492         idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" );
1493         idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0;
1494         idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0;
1495         idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0;
1496         idx1->nEntriesInUse++;
1497 }
1498
1499
1500 void AVI2File::WriteRIFF()
1501 {
1502         WriteChunk( avih_chunk, ( void* ) & mainHdr );
1503         WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
1504         WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo );
1505         if ( index_type & AVI_LARGE_INDEX )
1506         {
1507                 WriteChunk( dmlh_chunk, ( void* ) & dmlh );
1508                 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
1509                 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
1510         }
1511         WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] );
1512         WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex );
1513         if ( index_type & AVI_LARGE_INDEX )
1514         {
1515                 WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] );
1516                 WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] );
1517         }
1518
1519         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1520         {
1521                 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1522                 WriteChunk( idx1_chunk, ( void* ) idx1 );
1523         }
1524         RIFFFile::WriteRIFF();
1525 }
1526
1527
1528 /** Write a DV video frame
1529  
1530     \param frame the frame to write
1531 */
1532
1533 #if 0
1534 bool AVI2File::WriteFrame( const Frame &frame )
1535 {
1536         int audio_chunk;
1537         int frame_chunk;
1538         int junk_chunk;
1539         char soundbuf[ 20000 ];
1540         int     audio_size;
1541         int num_blocks;
1542         FOURCC type;
1543         FOURCC name;
1544         off_t length;
1545         off_t offset;
1546         int parent;
1547
1548         /* exit if no large index and 1GB reached */
1549         if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
1550                 return false;
1551
1552         /* Check if we need a new ix00 Standard Index. It has a
1553            capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1554            number, we need a new index. The new ix00 chunk is also
1555            part of the movi list. */
1556
1557         if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
1558         {
1559                 FlushIndx( 0 );
1560                 FlushIndx( 1 );
1561         }
1562
1563         /* Write audio data if we have it */
1564
1565         audio_size = frame.ExtractAudio( soundbuf );
1566         if ( audio_size > 0 )
1567         {
1568                 audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list );
1569                 if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1570                 {
1571                         GetDirectoryEntry( audio_chunk, type, name, length, offset, parent );
1572                         ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1573                 }
1574                 WriteChunk( audio_chunk, soundbuf );
1575                 //        num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1576                 //        length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
1577                 //        junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1578                 //        WriteChunk(junk_chunk, g_zeroes);
1579                 if ( index_type & AVI_LARGE_INDEX )
1580                         UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 );
1581                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1582                         UpdateIdx1( audio_chunk, 0x00 );
1583                 streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2;
1584
1585         }
1586
1587         /* Write video data */
1588
1589         frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list );
1590         if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
1591         {
1592                 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
1593                 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
1594         }
1595         WriteChunk( frame_chunk, frame.data );
1596         //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1597         //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1598         //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1599         //    WriteChunk(junk_chunk, g_zeroes);
1600         if ( index_type & AVI_LARGE_INDEX )
1601                 UpdateIndx( 0, frame_chunk, 1 );
1602         if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1603                 UpdateIdx1( frame_chunk, 0x10 );
1604
1605         /* update some variables with the new frame count. */
1606
1607         if ( isUpdateIdx1 )
1608                 ++mainHdr.dwTotalFrames;
1609         ++streamHdr[ 0 ].dwLength;
1610         ++dmlh[ 0 ];
1611
1612         /* Find out if the current riff list is close to 1 GByte in
1613            size. If so, start a new (extended) RIFF. The only allowed
1614            item in the new RIFF chunk is a movi list (with video
1615            frames and indexes as usual). */
1616
1617         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1618         if ( length > 0x3f000000 )
1619         {
1620
1621                 /* write idx1 only once and before end of first GB */
1622                 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
1623                 {
1624                         int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
1625                         WriteChunk( idx1_chunk, ( void* ) idx1 );
1626                 }
1627                 isUpdateIdx1 = false;
1628
1629                 if ( index_type & AVI_LARGE_INDEX )
1630                 {
1631                         /* padding for alignment */
1632                         GetDirectoryEntry( riff_list, type, name, length, offset, parent );
1633                         num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
1634                         length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
1635                         if ( length > 0 )
1636                         {
1637                                 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
1638                                 WriteChunk( junk_chunk, g_zeroes );
1639                         }
1640
1641                         riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
1642                         movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
1643                 }
1644         }
1645         return true;
1646 }
1647 #endif
1648
1649 void AVI1File::setDVINFO( DVINFO &info )
1650 {
1651         // do not do this until debugged audio against DirectShow
1652         return ;
1653
1654         dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc;
1655         dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl;
1656         dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1;
1657         dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1;
1658         dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc;
1659         dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl;
1660 }
1661
1662
1663 void AVI2File::setDVINFO( DVINFO &info )
1664 {}
1665
1666 void AVIFile::setFccHandler( FOURCC type, FOURCC handler )
1667 {
1668         for ( int i = 0; i < mainHdr.dwStreams; i++ )
1669         {
1670                 if ( streamHdr[ i ].fccType == type )
1671                 {
1672                         int k, j = 0;
1673                         FOURCC strf = make_fourcc( "strf" );
1674                         BITMAPINFOHEADER bih;
1675
1676                         streamHdr[ i ].fccHandler = handler;
1677
1678                         while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 )
1679                         {
1680                                 ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
1681                                 bih.biCompression = handler;
1682                         }
1683                 }
1684         }
1685 }
1686
1687 bool AVIFile::getStreamFormat( void* data, FOURCC type )
1688 {
1689         int i, j = 0;
1690         FOURCC strh = make_fourcc( "strh" );
1691         FOURCC strf = make_fourcc( "strf" );
1692         AVIStreamHeader avi_stream_header;
1693         bool result = false;
1694
1695         while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
1696         {
1697                 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
1698                 if ( avi_stream_header.fccType == type )
1699                 {
1700                         FOURCC chunkID;
1701                         int size;
1702
1703                         pthread_mutex_lock( &file_mutex );
1704                         fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) );
1705                         if ( chunkID == strf )
1706                         {
1707                                 fail_neg( read( fd, &size, sizeof( int ) ) );
1708                                 fail_neg( read( fd, data, size ) );
1709                                 result = true;
1710                         }
1711                         pthread_mutex_unlock( &file_mutex );
1712                 }
1713         }
1714         return result;
1715 }