2 * avi.cc library for AVI file format i/o
3 * Copyright (C) 2000 - 2002 Arne Schirmacher <arne@schirmacher.de>
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.
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.
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.
24 * Revision 1.1 2005/04/15 14:28:26 lilo_booter
27 * Revision 1.28 2005/04/01 23:43:10 ddennedy
28 * apply endian fixes from Daniel Kobras
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
33 * Revision 1.26 2004/01/05 03:43:11 ddennedy
34 * metadata editing, deinterlace options, bugfixes and cleanups
36 * Revision 1.25 2003/11/25 23:00:52 ddennedy
37 * cleanup and a few bugfixes
39 * Revision 1.24 2003/11/12 13:01:56 ddennedy
40 * disable JUNK chunks in MOVI list, FileHandler max file size zero = infinity
42 * Revision 1.23 2003/11/10 01:02:51 ddennedy
43 * bugfix: return error on AVI directory entries with size <0
45 * Revision 1.22 2003/10/28 18:52:32 ddennedy
46 * fix prefs dialog crash, improve WAV import
48 * Revision 1.21 2003/10/21 16:34:32 ddennedy
49 * GNOME2 port phase 1: initial checkin
51 * Revision 1.19.2.9 2003/08/26 20:39:00 ddennedy
52 * relocate mutex unlock and add assert includes
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
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
60 * Revision 1.19.2.6 2003/03/05 15:02:12 ddennedy
61 * yet anther AV/C bugfix, yet another AVI improvement
63 * Revision 1.19.2.5 2003/02/20 21:59:55 ddennedy
64 * bugfixes to capture and AVI
66 * Revision 1.19.2.4 2003/01/13 05:15:31 ddennedy
67 * added More Info panel and supporting methods
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
72 * Revision 1.19.2.2 2002/11/25 04:48:30 ddennedy
73 * bugfix to report errors when loading files
75 * Revision 1.19.2.1 2002/11/24 23:36:55 ddennedy
76 * bugfix in AVI writing
78 * Revision 1.19 2002/10/08 12:08:01 ddennedy
79 * more sane frame count, greater potential compatibility
81 * Revision 1.18 2002/10/08 08:33:02 ddennedy
82 * fix number of frames for small dv2
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
87 * Revision 1.15 2002/06/10 10:39:51 ddennedy
88 * minor fixes for large files
90 * Revision 1.14 2002/05/17 08:04:24 ddennedy
91 * revert const-ness of Frame references in Frame, FileHandler, and AVI classes
93 * Revision 1.13 2002/05/15 04:39:35 ddennedy
94 * bugfixes to dv2 AVI write, audio export, Xv init
96 * Revision 1.12 2002/04/29 05:09:21 ddennedy
97 * raw dv file support, Frame::ExtractAudio uses libdv, audioScrub prefs
99 * Revision 1.11 2002/04/15 19:12:32 schirmacher
100 * removed debugging code causing performance losses and crashes with dv2 files
102 * Revision 1.10 2002/04/09 06:53:42 ddennedy
103 * cleanup, new libdv 0.9.5, large AVI, dnd storyboard
105 * Revision 1.8 2002/03/25 21:34:25 arne
106 * Support for large (64 bit) files mostly completed
108 * Revision 1.7 2002/03/10 21:28:29 arne
109 * release 1.1b1, 64 bit support for type 1 avis
111 * Revision 1.6 2002/03/10 13:29:41 arne
112 * more changes for 64 bit access
114 * Revision 1.5 2002/03/09 17:59:28 arne
115 * moved index routines to AVIFile
117 * Revision 1.4 2002/03/09 10:26:26 arne
118 * improved constructors and assignment operator
120 * Revision 1.3 2002/03/09 08:55:57 arne
121 * moved a few variables to AVIFile
123 * Revision 1.2 2002/03/04 19:22:43 arne
124 * updated to latest Kino avi code
126 * Revision 1.1.1.1 2002/03/03 19:08:08 arne
127 * import of version 1.01
159 #define PADDING_SIZE (512)
160 #define PADDING_1GB (0x40000000)
161 #define IX00_INDEX_SIZE (4028)
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
171 //static char g_zeroes[ PADDING_SIZE ];
175 \todo mainHdr not initialized
176 \todo add checking for NULL pointers
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 )
185 // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
187 for ( int i
= 0; i
< 2; ++i
)
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;
196 strh_chunk
[ i
] = -1;
197 strf_chunk
[ i
] = -1;
199 idx1
= new AVISimpleIndex
;
200 memset( idx1
, 0, sizeof( AVISimpleIndex
) );
204 /** The copy constructor
206 \todo add checking for NULL pointers
210 AVIFile
::AVIFile( const AVIFile
& avi
) : RIFFFile( avi
)
212 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
214 mainHdr
= avi
.mainHdr
;
215 idx1
= new AVISimpleIndex
;
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
;
225 for ( int i
= 0; i
< 2; ++i
)
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
];
238 index_type
= avi
.index_type
;
239 current_ix00
= avi
.current_ix00
;
241 for ( int i
= 0; i
< 62; ++i
)
242 dmlh
[ i
] = avi
.dmlh
[ i
];
244 isUpdateIdx1
= avi
.isUpdateIdx1
;
249 /** The assignment operator
253 AVIFile
& AVIFile
::operator=( const AVIFile
& avi
)
255 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
259 RIFFFile
::operator=( avi
);
260 mainHdr
= avi
.mainHdr
;
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
;
270 for ( int i
= 0; i
< 2; ++i
)
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
];
281 index_type
= avi
.index_type
;
282 current_ix00
= avi
.current_ix00
;
284 for ( int i
= 0; i
< 62; ++i
)
285 dmlh
[ i
] = avi
.dmlh
[ i
];
287 isUpdateIdx1
= avi
.isUpdateIdx1
;
299 // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
301 for ( int i
= 0; i
< 2; ++i
)
309 /** Initialize the AVI structure to its initial state, either for PAL or NTSC format
311 Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
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
320 void AVIFile
::Init( int format
, int sampleFrequency
, int indexType
)
324 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
326 index_type
= indexType
;
331 mainHdr
.dwMicroSecPerFrame
= 40000;
332 mainHdr
.dwSuggestedBufferSize
= 144008;
336 mainHdr
.dwMicroSecPerFrame
= 33366;
337 mainHdr
.dwSuggestedBufferSize
= 120008;
340 default: /* no default allowed */
345 /* Initialize the 'avih' chunk */
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;
356 mainHdr
.dwHeight
= 0;
357 mainHdr
.dwReserved
[ 0 ] = 0;
358 mainHdr
.dwReserved
[ 1 ] = 0;
359 mainHdr
.dwReserved
[ 2 ] = 0;
360 mainHdr
.dwReserved
[ 3 ] = 0;
362 /* Initialize the 'idx1' chunk */
364 for ( int i
= 0; i
< 8000; ++i
)
366 idx1
->aIndex
[ i
].dwChunkId
= 0;
367 idx1
->aIndex
[ i
].dwFlags
= 0;
368 idx1
->aIndex
[ i
].dwOffset
= 0;
369 idx1
->aIndex
[ i
].dwSize
= 0;
371 idx1
->nEntriesInUse
= 0;
373 /* Initialize the 'indx' chunk */
375 for ( i
= 0; i
< 2; ++i
)
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
)
386 indx
[ i
] ->aIndex
[ j
].qwOffset
= 0;
387 indx
[ i
] ->aIndex
[ j
].dwSize
= 0;
388 indx
[ i
] ->aIndex
[ j
].dwDuration
= 0;
392 /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
395 /* Initialize the 'dmlh' chunk. I have no clue what this means
398 for ( i
= 0; i
< 62; ++i
)
400 //dmlh[0] = -1; /* frame count + 1? */
405 /** Find position and size of a given frame in the file
407 Depending on which index is available, search one of them to
408 find position and frame size
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
418 int AVIFile
::GetDVFrameInfo( off_t
&offset
, int &size
, int frameNum
)
420 switch ( index_type
)
422 case AVI_LARGE_INDEX
:
424 /* find relevant index in indx0 */
428 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
431 if ( i
!= current_ix00
)
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
) );
438 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
440 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
441 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
448 case AVI_SMALL_INDEX
:
450 int frameNumIndex
= 0;
451 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
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
)
458 if ( frameNumIndex
== frameNum
)
468 // compatibility check for broken dvgrab dv2 format
469 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
471 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
475 // new, correct dv2 format
476 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
478 size
= idx1
->aIndex
[ index
].dwSize
;
488 /** Find position and size of a given frame in the file
490 Depending on which index is available, search one of them to
491 find position and frame size
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
502 int AVIFile
::GetFrameInfo( off_t
&offset
, int &size
, int frameNum
, FOURCC chunkID
)
504 if ( index_type
& AVI_LARGE_INDEX
)
508 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
511 if ( i
!= current_ix00
)
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
) );
518 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
520 if ( ( FOURCC
) ix
[ 0 ] ->dwChunkId
== chunkID
)
522 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
523 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
528 if ( index_type
& AVI_SMALL_INDEX
)
531 int frameNumIndex
= 0;
532 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
534 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID
)
536 if ( frameNumIndex
== frameNum
)
546 // compatibility check for broken dvgrab dv2 format
547 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
549 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
553 // new, correct dv2 format
554 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
556 size
= idx1
->aIndex
[ index
].dwSize
;
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
571 int AVIFile
::GetDVFrame( uint8_t *data
, int frameNum
)
576 if ( GetDVFrameInfo( offset
, size
, frameNum
) != 0 || size
< 0 )
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
);
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
594 int AVIFile
::getFrame( void *data
, int frameNum
, FOURCC chunkID
)
599 if ( GetFrameInfo( offset
, size
, frameNum
, chunkID
) != 0 )
601 fail_if( lseek( fd
, offset
, SEEK_SET
) == ( off_t
) - 1 );
602 fail_neg( read( fd
, data
, size
) );
607 int AVIFile
::GetTotalFrames() const
609 return mainHdr
.dwTotalFrames
;
613 /** prints out a directory entry in text form
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.
619 \todo use 64 bit routines
620 \param entry the entry to print
623 void AVIFile
::PrintDirectoryEntryData( const RIFFDirEntry
&entry
) const
625 static FOURCC lastStreamType
= make_fourcc( " " );
627 if ( entry
.type
== make_fourcc( "avih" ) )
631 MainAVIHeader main_avi_header
;
633 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
634 fail_neg( read( fd
, &main_avi_header
, sizeof( MainAVIHeader
) ) );
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
;
650 else if ( entry
.type
== make_fourcc( "strh" ) )
653 AVIStreamHeader avi_stream_header
;
655 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
656 fail_neg( read( fd
, &avi_stream_header
, sizeof( AVIStreamHeader
) ) );
658 lastStreamType
= avi_stream_header
.fccType
;
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]
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]
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
;
683 else if ( entry
.type
== make_fourcc( "indx" ) )
687 AVISuperIndex avi_super_index
;
689 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
690 fail_neg( read( fd
, &avi_super_index
, sizeof( AVISuperIndex
) ) );
692 cout
<< " wLongsPerEntry: " << ( int ) avi_super_index
.wLongsPerEntry
694 << " bIndexSubType: " << ( int ) avi_super_index
.bIndexSubType
<< endl
695 << " bIndexType: " << ( int ) avi_super_index
.bIndexType
<< endl
696 << " nEntriesInUse: " << ( int ) avi_super_index
.nEntriesInUse
<< endl
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]
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
)
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
;
714 else if ( entry
.type
== make_fourcc( "strf" ) )
716 if ( lastStreamType
== make_fourcc( "auds" ) )
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
;
729 else if ( lastStreamType
== make_fourcc( "vids" ) )
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
;
746 else if ( lastStreamType
== make_fourcc( "iavs" ) )
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
;
760 /* This is the Standard Index. It is an array of offsets and
761 sizes relative to some start offset. */
763 else if ( ( entry
.type
== make_fourcc( "ix00" ) ) || ( entry
.type
== make_fourcc( "ix01" ) ) )
767 AVIStdIndex avi_std_index
;
769 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
770 fail_neg( read( fd
, &avi_std_index
, sizeof( AVIStdIndex
) ) );
772 cout
<< " wLongsPerEntry: " << ( int ) avi_std_index
.wLongsPerEntry
774 << " bIndexSubType: " << ( int ) avi_std_index
.bIndexSubType
<< endl
775 << " bIndexType: " << ( int ) avi_std_index
.bIndexType
<< endl
776 << " nEntriesInUse: " << ( int ) avi_std_index
.nEntriesInUse
<< endl
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]
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
)
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
;
794 else if ( entry
.type
== make_fourcc( "idx1" ) )
798 int numEntries
= entry
.length
/ sizeof( int ) / 4;
799 DWORD
*idx1
= new DWORD
[ numEntries
* 4 ];
800 // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
802 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
803 fail_neg( read( fd
, idx1
, entry
.length
) );
805 for ( i
= 0; i
< numEntries
; ++i
)
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]
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
;
822 else if ( entry
.type
== make_fourcc( "dmlh" ) )
825 int numEntries
= entry
.length
/ sizeof( int );
826 DWORD
*dmlh
= new DWORD
[ numEntries
];
828 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
829 fail_neg( read( fd
, dmlh
, entry
.length
) );
831 for ( i
= 0; i
< numEntries
; ++i
)
833 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
<< setfill( '0' ) << ": "
834 << " dwTotalFrames: 0x" << setw( 8 ) << hex
<< dmlh
[ i
]
835 << " (" << dec
<< dmlh
[ i
] << ")" << endl
;
842 /** If this is not a movi list, read its contents
846 void AVIFile
::ParseList( int parent
)
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
) ) );
861 /* The contents of the list starts here. Obtain its offset. The list
862 name (4 bytes) is already part of the contents). */
864 pos
= lseek( fd
, 0, SEEK_CUR
);
865 fail_if( pos
== ( off_t
) - 1 );
866 fail_neg( read( fd
, &name
, sizeof( name
) ) );
868 /* if we encounter a movi list, do not read it. It takes too much time
869 and we don't need it anyway. */
871 if ( name
!= make_fourcc( "movi" ) )
875 /* Add an entry for this list. */
876 list
= AddDirectoryEntry( type
, name
, sizeof( name
), parent
);
878 /* Read in any chunks contained in this list. This list is the
879 parent for all chunks it contains. */
881 listEnd
= pos
+ length
;
882 while ( pos
< listEnd
)
885 pos
= lseek( fd
, 0, SEEK_CUR
);
886 fail_if( pos
== ( off_t
) - 1 );
891 /* Add an entry for this list. */
893 movi_list
= AddDirectoryEntry( type
, name
, length
, parent
);
895 pos
= lseek( fd
, length
- 4, SEEK_CUR
);
896 fail_if( pos
== ( off_t
) - 1 );
901 void AVIFile
::ParseRIFF()
903 RIFFFile
::ParseRIFF();
905 avih_chunk
= FindDirectoryEntry( make_fourcc( "avih" ) );
906 if ( avih_chunk
!= -1 )
907 ReadChunk( avih_chunk
, ( void* ) & mainHdr
);
911 void AVIFile
::ReadIndex()
913 indx_chunk
[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
914 if ( indx_chunk
[ 0 ] != -1 )
916 ReadChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
917 index_type
= AVI_LARGE_INDEX
;
919 /* recalc number of frames from each index */
920 mainHdr
.dwTotalFrames
= 0;
922 i
< indx
[ 0 ] ->nEntriesInUse
;
923 mainHdr
.dwTotalFrames
+= indx
[ 0 ] ->aIndex
[ i
++ ].dwDuration
)
927 idx1_chunk
= FindDirectoryEntry( make_fourcc( "idx1" ) );
928 if ( idx1_chunk
!= -1 )
930 ReadChunk( idx1_chunk
, ( void* ) idx1
);
931 idx1
->nEntriesInUse
= GetDirectoryEntry( idx1_chunk
).length
/ 16;
932 index_type
= AVI_SMALL_INDEX
;
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
)
940 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID1
||
941 idx1
->aIndex
[ i
].dwChunkId
== chunkID2
)
946 mainHdr
.dwTotalFrames
= frameNumIndex
;
952 void AVIFile
::FlushIndx( int stream
)
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
967 if ( ix_chunk
[ stream
] != -1 )
968 WriteChunk( ix_chunk
[ stream
], ix
[ stream
] );
970 /* make a new ix chunk. */
973 type
= make_fourcc( "ix00" );
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
);
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
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;
992 for ( i
= 0; i
< IX00_INDEX_SIZE
; ++i
)
994 ix
[ stream
] ->aIndex
[ i
].dwOffset
= 0;
995 ix
[ stream
] ->aIndex
[ i
].dwSize
= 0;
998 /* add a reference to this new index in our super
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;
1008 void AVIFile
::UpdateIndx( int stream
, int chunk
, int duration
)
1017 /* update the appropiate entry in the super index. It reflects
1018 the number of frames in the referenced index. */
1020 i
= indx
[ stream
] ->nEntriesInUse
- 1;
1021 indx
[ stream
] ->aIndex
[ i
].dwDuration
+= duration
;
1023 /* update the standard index. Calculate the file position of
1026 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
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
;
1035 void AVIFile
::UpdateIdx1( int chunk
, int flags
)
1037 if ( idx1
->nEntriesInUse
< 20000 )
1045 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
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
++;
1055 bool AVIFile
::verifyStreamFormat( FOURCC type
)
1058 AVIStreamHeader avi_stream_header
;
1059 BITMAPINFOHEADER bih
;
1060 FOURCC strh
= make_fourcc( "strh" );
1061 FOURCC strf
= make_fourcc( "strf" );
1063 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1065 ReadChunk( i
, ( void* ) & avi_stream_header
);
1066 if ( avi_stream_header
.fccHandler
== type
)
1070 while ( ( i
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1072 ReadChunk( i
, ( void* ) & bih
);
1073 if ( ( FOURCC
) bih
.biCompression
== type
)
1080 bool AVIFile
::verifyStream( FOURCC type
)
1083 AVIStreamHeader avi_stream_header
;
1084 FOURCC strh
= make_fourcc( "strh" );
1086 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1088 ReadChunk( i
, ( void* ) & avi_stream_header
);
1089 if ( avi_stream_header
.fccType
== type
)
1095 bool AVIFile
::isOpenDML( void )
1098 FOURCC dmlh
= make_fourcc( "dmlh" );
1100 while ( ( i
= FindDirectoryEntry( dmlh
, j
++ ) ) != -1 )
1107 AVI1File
::AVI1File() : AVIFile()
1111 AVI1File
::~AVI1File()
1115 /* Initialize the AVI structure to its initial state, either for PAL
1118 void AVI1File
::Init( int format
, int sampleFrequency
, int indexType
)
1127 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1129 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1134 mainHdr
.dwWidth
= 720;
1135 mainHdr
.dwHeight
= 576;
1137 streamHdr
[ 0 ].dwScale
= 1;
1138 streamHdr
[ 0 ].dwRate
= 25;
1139 streamHdr
[ 0 ].dwSuggestedBufferSize
= 144008;
1141 /* initialize the 'strf' chunk */
1143 /* Meaning of the DV stream format chunk per Microsoft
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.
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.
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.
1160 Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
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.
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.
1170 Reserved. Set this array to zero.
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;
1184 mainHdr
.dwWidth
= 720;
1185 mainHdr
.dwHeight
= 480;
1187 streamHdr
[ 0 ].dwScale
= 1001;
1188 streamHdr
[ 0 ].dwRate
= 30000;
1189 streamHdr
[ 0 ].dwSuggestedBufferSize
= 120008;
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;
1202 default: /* no default allowed */
1207 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00__" );
1209 /* Initialize the 'strh' chunk */
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;
1226 /* This is a simple directory structure setup. For details see the
1227 "OpenDML AVI File Format Extensions" document.
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"
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.
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.
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
1251 /* Create the container directory entry */
1253 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1255 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
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 ] );
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
);
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
);
1275 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1277 /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
1284 /* Write a DV video frame. This is somewhat complex... */
1287 bool AVI1File
::WriteFrame( const Frame
&frame
)
1298 /* exit if no large index and 1GB reached */
1299 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
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. */
1307 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1310 /* Write the DV frame data.
1312 Make a new 00__ chunk for the new frame, write out the
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 )
1318 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1319 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
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);
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 );
1332 /* update some variables with the new frame count. */
1335 ++mainHdr
.dwTotalFrames
;
1336 ++streamHdr
[ 0 ].dwLength
;
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). */
1344 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1345 if ( length
> 0x3f000000 )
1347 /* write idx1 only once and before end of first GB */
1348 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1350 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1351 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1353 isUpdateIdx1
= false;
1355 if ( index_type
& AVI_LARGE_INDEX
)
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);
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
;
1368 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1369 WriteChunk( junk_chunk
, g_zeroes
);
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
);
1380 void AVI1File
::WriteRIFF()
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
);
1388 if ( index_type
& AVI_LARGE_INDEX
)
1390 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1391 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1394 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1396 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1397 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1400 RIFFFile
::WriteRIFF();
1404 AVI2File
::AVI2File() : AVIFile()
1408 AVI2File
::~AVI2File()
1412 /* Initialize the AVI structure to its initial state, either for PAL
1415 void AVI2File
::Init( int format
, int sampleFrequency
, int indexType
)
1424 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1426 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1432 mainHdr
.dwStreams
= 2;
1433 mainHdr
.dwWidth
= 720;
1434 mainHdr
.dwHeight
= 576;
1436 /* Initialize the 'strh' chunk */
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;
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;
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;
1489 mainHdr
.dwTotalFrames
= 0;
1490 mainHdr
.dwStreams
= 2;
1491 mainHdr
.dwWidth
= 720;
1492 mainHdr
.dwHeight
= 480;
1494 /* Initialize the 'strh' chunk */
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;
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;
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;
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;
1554 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1556 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
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
);
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
)
1567 indx_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 0 ] );
1569 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00dc" );
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
)
1578 indx_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 1 ] );
1580 indx
[ 1 ] ->dwChunkId
= make_fourcc( "01wb" );
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
);
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
);
1592 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
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
++;
1602 void AVI2File
::WriteRIFF()
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
)
1609 WriteChunk( dmlh_chunk
, ( void* ) & dmlh
);
1610 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1611 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1613 WriteChunk( strh_chunk
[ 1 ], ( void* ) & streamHdr
[ 1 ] );
1614 WriteChunk( strf_chunk
[ 1 ], ( void* ) & waveformatex
);
1615 if ( index_type
& AVI_LARGE_INDEX
)
1617 WriteChunk( indx_chunk
[ 1 ], ( void* ) indx
[ 1 ] );
1618 WriteChunk( ix_chunk
[ 1 ], ( void* ) ix
[ 1 ] );
1621 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1623 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1624 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1626 RIFFFile
::WriteRIFF();
1630 /** Write a DV video frame
1632 \param frame the frame to write
1636 bool AVI2File
::WriteFrame( const Frame
&frame
)
1641 char soundbuf
[ 20000 ];
1650 /* exit if no large index and 1GB reached */
1651 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
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. */
1659 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1665 /* Write audio data if we have it */
1667 audio_size
= frame
.ExtractAudio( soundbuf
);
1668 if ( audio_size
> 0 )
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 )
1673 GetDirectoryEntry( audio_chunk
, type
, name
, length
, offset
, parent
);
1674 ix
[ 1 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
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;
1689 /* Write video data */
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 )
1694 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1695 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
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 );
1707 /* update some variables with the new frame count. */
1710 ++mainHdr
.dwTotalFrames
;
1711 ++streamHdr
[ 0 ].dwLength
;
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). */
1719 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1720 if ( length
> 0x3f000000 )
1723 /* write idx1 only once and before end of first GB */
1724 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1726 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1727 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1729 isUpdateIdx1
= false;
1731 if ( index_type
& AVI_LARGE_INDEX
)
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
;
1739 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1740 WriteChunk( junk_chunk
, g_zeroes
);
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
);
1751 void AVI1File
::setDVINFO( DVINFO
&info
)
1753 // do not do this until debugged audio against DirectShow
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
;
1765 void AVI2File
::setDVINFO( DVINFO
&info
)
1768 void AVIFile
::setFccHandler( FOURCC type
, FOURCC handler
)
1770 for ( int i
= 0; i
< mainHdr
.dwStreams
; i
++ )
1772 if ( streamHdr
[ i
].fccType
== type
)
1775 FOURCC strf
= make_fourcc( "strf" );
1776 BITMAPINFOHEADER bih
;
1778 streamHdr
[ i
].fccHandler
= handler
;
1780 while ( ( k
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1782 ReadChunk( k
, ( void* ) & bih
);
1783 bih
.biCompression
= handler
;
1789 bool AVIFile
::getStreamFormat( void* data
, FOURCC type
)
1792 FOURCC strh
= make_fourcc( "strh" );
1793 FOURCC strf
= make_fourcc( "strf" );
1794 AVIStreamHeader avi_stream_header
;
1795 bool result
= false;
1797 while ( ( result
== false ) && ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1799 ReadChunk( i
, ( void* ) & avi_stream_header
);
1800 if ( avi_stream_header
.fccType
== type
)
1805 pthread_mutex_lock( &file_mutex
);
1806 fail_neg( read( fd
, &chunkID
, sizeof( FOURCC
) ) );
1807 if ( chunkID
== strf
)
1809 fail_neg( read( fd
, &size
, sizeof( int ) ) );
1810 fail_neg( read( fd
, data
, size
) );
1813 pthread_mutex_unlock( &file_mutex
);