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