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