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.3 2005/07/25 07:21:39 lilo_booter
25 * + fixes for opendml dv avi
27 * Revision 1.2 2005/06/21 20:59:39 lilo_booter
28 * src/framework/mlt_consumer.c src/framework/mlt_consumer.h
29 * + Added a general profile handling for size, aspect ratio and display ratio
31 * src/framework/mlt_producer.c
32 * + Correction to aspect ratio properties
35 * + Minimalist support for sdl_preview (still not very good)
37 * src/modules/avformat/consumer_avformat.c
38 * + Takes consumer profile into account
40 * src/modules/core/filter_resize.c
41 * + Corrections for synthesised producers and aspect ratio (inherits from consumer)
43 * src/modules/core/producer_colour.c
44 * src/modules/core/producer_noise.c
45 * src/modules/gtk2/producer_pango.c
46 * + Ensures that resize picks up consumer aspect ratio
48 * src/modules/dv/consumer_libdv.c
49 * + Honour wide screen output
51 * src/modules/gtk2/producer_pixbuf.c
52 * + Correction for 1:1 aspect ratio
54 * src/modules/kino/Makefile
55 * src/modules/kino/avi.cc
56 * src/modules/kino/avi.h
57 * src/modules/kino/configure
58 * src/modules/kino/filehandler.cc
59 * + Attempt to allow mov dv files to provide audio
61 * src/modules/sdl/consumer_sdl.c
62 * src/modules/sdl/consumer_sdl_preview.c
63 * src/modules/sdl/consumer_sdl_still.c
64 * + Takes consumer profile into account
66 * Revision 1.1 2005/04/15 14:28:26 lilo_booter
69 * Revision 1.28 2005/04/01 23:43:10 ddennedy
70 * apply endian fixes from Daniel Kobras
72 * Revision 1.27 2004/10/11 01:37:11 ddennedy
73 * mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
75 * Revision 1.26 2004/01/05 03:43:11 ddennedy
76 * metadata editing, deinterlace options, bugfixes and cleanups
78 * Revision 1.25 2003/11/25 23:00:52 ddennedy
79 * cleanup and a few bugfixes
81 * Revision 1.24 2003/11/12 13:01:56 ddennedy
82 * disable JUNK chunks in MOVI list, FileHandler max file size zero = infinity
84 * Revision 1.23 2003/11/10 01:02:51 ddennedy
85 * bugfix: return error on AVI directory entries with size <0
87 * Revision 1.22 2003/10/28 18:52:32 ddennedy
88 * fix prefs dialog crash, improve WAV import
90 * Revision 1.21 2003/10/21 16:34:32 ddennedy
91 * GNOME2 port phase 1: initial checkin
93 * Revision 1.19.2.9 2003/08/26 20:39:00 ddennedy
94 * relocate mutex unlock and add assert includes
96 * Revision 1.19.2.8 2003/07/24 14:13:57 ddennedy
97 * support for distinct audio stream in type2 AVI and Quicktime; support for more DV FOURCCs
99 * Revision 1.19.2.7 2003/06/10 23:53:35 ddennedy
100 * Daniel Kobras' WriteFrame error handling and automatic OpenDML, bugfixes in scene list updates, export AV/C Record
102 * Revision 1.19.2.6 2003/03/05 15:02:12 ddennedy
103 * yet anther AV/C bugfix, yet another AVI improvement
105 * Revision 1.19.2.5 2003/02/20 21:59:55 ddennedy
106 * bugfixes to capture and AVI
108 * Revision 1.19.2.4 2003/01/13 05:15:31 ddennedy
109 * added More Info panel and supporting methods
111 * Revision 1.19.2.3 2002/12/31 22:40:49 ddennedy
112 * bugfix recent versions Quicktime4Linux build options, extend dvsd fourcc check on AVI to the BITMAPINFOHEADER for compatibility with mencoder
114 * Revision 1.19.2.2 2002/11/25 04:48:30 ddennedy
115 * bugfix to report errors when loading files
117 * Revision 1.19.2.1 2002/11/24 23:36:55 ddennedy
118 * bugfix in AVI writing
120 * Revision 1.19 2002/10/08 12:08:01 ddennedy
121 * more sane frame count, greater potential compatibility
123 * Revision 1.18 2002/10/08 08:33:02 ddennedy
124 * fix number of frames for small dv2
126 * Revision 1.17 2002/10/08 07:46:41 ddennedy
127 * AVI bugfixes, compatibility, optimization, warn bad file in capture and export dv file, allow no mplex
129 * Revision 1.15 2002/06/10 10:39:51 ddennedy
130 * minor fixes for large files
132 * Revision 1.14 2002/05/17 08:04:24 ddennedy
133 * revert const-ness of Frame references in Frame, FileHandler, and AVI classes
135 * Revision 1.13 2002/05/15 04:39:35 ddennedy
136 * bugfixes to dv2 AVI write, audio export, Xv init
138 * Revision 1.12 2002/04/29 05:09:21 ddennedy
139 * raw dv file support, Frame::ExtractAudio uses libdv, audioScrub prefs
141 * Revision 1.11 2002/04/15 19:12:32 schirmacher
142 * removed debugging code causing performance losses and crashes with dv2 files
144 * Revision 1.10 2002/04/09 06:53:42 ddennedy
145 * cleanup, new libdv 0.9.5, large AVI, dnd storyboard
147 * Revision 1.8 2002/03/25 21:34:25 arne
148 * Support for large (64 bit) files mostly completed
150 * Revision 1.7 2002/03/10 21:28:29 arne
151 * release 1.1b1, 64 bit support for type 1 avis
153 * Revision 1.6 2002/03/10 13:29:41 arne
154 * more changes for 64 bit access
156 * Revision 1.5 2002/03/09 17:59:28 arne
157 * moved index routines to AVIFile
159 * Revision 1.4 2002/03/09 10:26:26 arne
160 * improved constructors and assignment operator
162 * Revision 1.3 2002/03/09 08:55:57 arne
163 * moved a few variables to AVIFile
165 * Revision 1.2 2002/03/04 19:22:43 arne
166 * updated to latest Kino avi code
168 * Revision 1.1.1.1 2002/03/03 19:08:08 arne
169 * import of version 1.01
201 #define PADDING_SIZE (512)
202 #define PADDING_1GB (0x40000000)
203 #define IX00_INDEX_SIZE (4028)
205 #define AVIF_HASINDEX 0x00000010
206 #define AVIF_MUSTUSEINDEX 0x00000020
207 #define AVIF_TRUSTCKTYPE 0x00000800
208 #define AVIF_ISINTERLEAVED 0x00000100
209 #define AVIF_WASCAPTUREFILE 0x00010000
210 #define AVIF_COPYRIGHTED 0x00020000
213 //static char g_zeroes[ PADDING_SIZE ];
217 \todo mainHdr not initialized
218 \todo add checking for NULL pointers
222 AVIFile
::AVIFile() : RIFFFile(),
223 idx1( NULL
), file_list( -1 ), riff_list( -1 ),
224 hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
225 index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
227 // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
229 for ( int i
= 0; i
< 2; ++i
)
231 indx
[ i
] = new AVISuperIndex
;
232 memset( indx
[ i
], 0, sizeof( AVISuperIndex
) );
233 ix
[ i
] = new AVIStdIndex
;
234 memset( ix
[ i
], 0, sizeof( AVIStdIndex
) );
235 indx_chunk
[ i
] = -1;
238 strh_chunk
[ i
] = -1;
239 strf_chunk
[ i
] = -1;
241 idx1
= new AVISimpleIndex
;
242 memset( idx1
, 0, sizeof( AVISimpleIndex
) );
246 /** The copy constructor
248 \todo add checking for NULL pointers
252 AVIFile
::AVIFile( const AVIFile
& avi
) : RIFFFile( avi
)
254 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
256 mainHdr
= avi
.mainHdr
;
257 idx1
= new AVISimpleIndex
;
259 file_list
= avi
.file_list
;
260 riff_list
= avi
.riff_list
;
261 hdrl_list
= avi
.hdrl_list
;
262 avih_chunk
= avi
.avih_chunk
;
263 movi_list
= avi
.movi_list
;
264 junk_chunk
= avi
.junk_chunk
;
265 idx1_chunk
= avi
.idx1_chunk
;
267 for ( int i
= 0; i
< 2; ++i
)
269 indx
[ i
] = new AVISuperIndex
;
270 *indx
[ i
] = *avi
.indx
[ i
];
271 ix
[ i
] = new AVIStdIndex
;
272 *ix
[ i
] = *avi
.ix
[ i
];
273 indx_chunk
[ i
] = avi
.indx_chunk
[ i
];
274 ix_chunk
[ i
] = avi
.ix_chunk
[ i
];
275 strl_list
[ i
] = avi
.strl_list
[ i
];
276 strh_chunk
[ i
] = avi
.strh_chunk
[ i
];
277 strf_chunk
[ i
] = avi
.strf_chunk
[ i
];
280 index_type
= avi
.index_type
;
281 current_ix00
= avi
.current_ix00
;
283 for ( int i
= 0; i
< 62; ++i
)
284 dmlh
[ i
] = avi
.dmlh
[ i
];
286 isUpdateIdx1
= avi
.isUpdateIdx1
;
291 /** The assignment operator
295 AVIFile
& AVIFile
::operator=( const AVIFile
& avi
)
297 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
301 RIFFFile
::operator=( avi
);
302 mainHdr
= avi
.mainHdr
;
304 file_list
= avi
.file_list
;
305 riff_list
= avi
.riff_list
;
306 hdrl_list
= avi
.hdrl_list
;
307 avih_chunk
= avi
.avih_chunk
;
308 movi_list
= avi
.movi_list
;
309 junk_chunk
= avi
.junk_chunk
;
310 idx1_chunk
= avi
.idx1_chunk
;
312 for ( int i
= 0; i
< 2; ++i
)
314 *indx
[ i
] = *avi
.indx
[ i
];
315 *ix
[ i
] = *avi
.ix
[ i
];
316 indx_chunk
[ i
] = avi
.indx_chunk
[ i
];
317 ix_chunk
[ i
] = avi
.ix_chunk
[ i
];
318 strl_list
[ i
] = avi
.strl_list
[ i
];
319 strh_chunk
[ i
] = avi
.strh_chunk
[ i
];
320 strf_chunk
[ i
] = avi
.strf_chunk
[ i
];
323 index_type
= avi
.index_type
;
324 current_ix00
= avi
.current_ix00
;
326 for ( int i
= 0; i
< 62; ++i
)
327 dmlh
[ i
] = avi
.dmlh
[ i
];
329 isUpdateIdx1
= avi
.isUpdateIdx1
;
341 // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
343 for ( int i
= 0; i
< 2; ++i
)
351 /** Initialize the AVI structure to its initial state, either for PAL or NTSC format
353 Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
355 \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant.
356 \param format pass AVI_PAL or AVI_NTSC
357 \param sampleFrequency the sample frequency of the audio content
358 \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX
362 void AVIFile
::Init( int format
, int sampleFrequency
, int indexType
)
366 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
368 index_type
= indexType
;
373 mainHdr
.dwMicroSecPerFrame
= 40000;
374 mainHdr
.dwSuggestedBufferSize
= 144008;
378 mainHdr
.dwMicroSecPerFrame
= 33366;
379 mainHdr
.dwSuggestedBufferSize
= 120008;
382 default: /* no default allowed */
387 /* Initialize the 'avih' chunk */
389 mainHdr
.dwMaxBytesPerSec
= 3600000 + sampleFrequency
* 4;
390 mainHdr
.dwPaddingGranularity
= PADDING_SIZE
;
391 mainHdr
.dwFlags
= AVIF_TRUSTCKTYPE
;
392 if ( indexType
& AVI_SMALL_INDEX
)
393 mainHdr
.dwFlags
|= AVIF_HASINDEX
;
394 mainHdr
.dwTotalFrames
= 0;
395 mainHdr
.dwInitialFrames
= 0;
396 mainHdr
.dwStreams
= 1;
398 mainHdr
.dwHeight
= 0;
399 mainHdr
.dwReserved
[ 0 ] = 0;
400 mainHdr
.dwReserved
[ 1 ] = 0;
401 mainHdr
.dwReserved
[ 2 ] = 0;
402 mainHdr
.dwReserved
[ 3 ] = 0;
404 /* Initialize the 'idx1' chunk */
406 for ( int i
= 0; i
< 8000; ++i
)
408 idx1
->aIndex
[ i
].dwChunkId
= 0;
409 idx1
->aIndex
[ i
].dwFlags
= 0;
410 idx1
->aIndex
[ i
].dwOffset
= 0;
411 idx1
->aIndex
[ i
].dwSize
= 0;
413 idx1
->nEntriesInUse
= 0;
415 /* Initialize the 'indx' chunk */
417 for ( i
= 0; i
< 2; ++i
)
419 indx
[ i
] ->wLongsPerEntry
= 4;
420 indx
[ i
] ->bIndexSubType
= 0;
421 indx
[ i
] ->bIndexType
= KINO_AVI_INDEX_OF_INDEXES
;
422 indx
[ i
] ->nEntriesInUse
= 0;
423 indx
[ i
] ->dwReserved
[ 0 ] = 0;
424 indx
[ i
] ->dwReserved
[ 1 ] = 0;
425 indx
[ i
] ->dwReserved
[ 2 ] = 0;
426 for ( j
= 0; j
< 2014; ++j
)
428 indx
[ i
] ->aIndex
[ j
].qwOffset
= 0;
429 indx
[ i
] ->aIndex
[ j
].dwSize
= 0;
430 indx
[ i
] ->aIndex
[ j
].dwDuration
= 0;
434 /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
437 /* Initialize the 'dmlh' chunk. I have no clue what this means
440 for ( i
= 0; i
< 62; ++i
)
442 //dmlh[0] = -1; /* frame count + 1? */
447 /** Find position and size of a given frame in the file
449 Depending on which index is available, search one of them to
450 find position and frame size
452 \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
453 \todo all index related operations should be isolated
454 \param offset the file offset to the start of the frame
455 \param size the size of the frame
456 \param frameNum the number of the frame we wish to find
457 \return 0 if the frame could be found, -1 otherwise
460 int AVIFile
::GetDVFrameInfo( off_t
&offset
, int &size
, int frameNum
)
462 switch ( index_type
)
464 case AVI_LARGE_INDEX
:
466 /* find relevant index in indx0 */
470 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
473 if ( i
!= current_ix00
)
475 fail_if( lseek( fd
, indx
[ 0 ] ->aIndex
[ i
].qwOffset
+ RIFF_HEADERSIZE
, SEEK_SET
) == ( off_t
) - 1 );
476 fail_neg( read( fd
, ix
[ 0 ], indx
[ 0 ] ->aIndex
[ i
].dwSize
- RIFF_HEADERSIZE
) );
480 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
482 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
483 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
490 case AVI_SMALL_INDEX
:
492 int frameNumIndex
= 0;
493 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
495 FOURCC chunkID1
= make_fourcc( "00dc" );
496 FOURCC chunkID2
= make_fourcc( "00db" );
497 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID1
||
498 idx1
->aIndex
[ i
].dwChunkId
== chunkID2
)
500 if ( frameNumIndex
== frameNum
)
510 // compatibility check for broken dvgrab dv2 format
511 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
513 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
517 // new, correct dv2 format
518 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
520 size
= idx1
->aIndex
[ index
].dwSize
;
530 /** Find position and size of a given frame in the file
532 Depending on which index is available, search one of them to
533 find position and frame size
535 \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
536 \todo all index related operations should be isolated
537 \param offset the file offset to the start of the frame
538 \param size the size of the frame
539 \param frameNum the number of the frame we wish to find
540 \param chunkID the ID of the type of chunk we want
541 \return 0 if the frame could be found, -1 otherwise
544 int AVIFile
::GetFrameInfo( off_t
&offset
, int &size
, int frameNum
, FOURCC chunkID
)
546 if ( index_type
& AVI_LARGE_INDEX
)
550 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
553 if ( i
!= current_ix00
)
555 fail_if( lseek( fd
, indx
[ 0 ] ->aIndex
[ i
].qwOffset
+ RIFF_HEADERSIZE
, SEEK_SET
) == ( off_t
) - 1 );
556 fail_neg( read( fd
, ix
[ 0 ], indx
[ 0 ] ->aIndex
[ i
].dwSize
- RIFF_HEADERSIZE
) );
560 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
562 if ( ( FOURCC
) ix
[ 0 ] ->dwChunkId
== chunkID
)
564 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
565 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
570 if ( index_type
& AVI_SMALL_INDEX
)
573 int frameNumIndex
= 0;
574 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
576 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID
)
578 if ( frameNumIndex
== frameNum
)
588 // compatibility check for broken dvgrab dv2 format
589 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
591 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
595 // new, correct dv2 format
596 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
598 size
= idx1
->aIndex
[ index
].dwSize
;
607 \todo we actually don't need the frame here, we could use just a void pointer
608 \param frame a reference to the frame object that will receive the frame data
609 \param frameNum the frame number to read
610 \return 0 if the frame could be read, -1 otherwise
613 int AVIFile
::GetDVFrame( uint8_t *data
, int frameNum
)
618 if ( GetDVFrameInfo( offset
, size
, frameNum
) != 0 || size
< 0 )
620 pthread_mutex_lock( &file_mutex
);
621 fail_if( lseek( fd
, offset
, SEEK_SET
) == ( off_t
) - 1 );
622 fail_neg( read( fd
, data
, size
) );
623 pthread_mutex_unlock( &file_mutex
);
630 \param data a pointer to the audio buffer
631 \param frameNum the frame number to read
632 \param chunkID the ID of the type of chunk we want
633 \return the size the of the frame data, 0 if could not be read
636 int AVIFile
::getFrame( void *data
, int frameNum
, FOURCC chunkID
)
641 if ( GetFrameInfo( offset
, size
, frameNum
, chunkID
) != 0 )
643 fail_if( lseek( fd
, offset
, SEEK_SET
) == ( off_t
) - 1 );
644 fail_neg( read( fd
, data
, size
) );
649 int AVIFile
::GetTotalFrames() const
651 return mainHdr
.dwTotalFrames
;
655 /** prints out a directory entry in text form
657 Every subclass of RIFFFile is supposed to override this function
658 and to implement it for the entry types it knows about. For all
659 other entry types it should call its parent::PrintDirectoryData.
661 \todo use 64 bit routines
662 \param entry the entry to print
665 void AVIFile
::PrintDirectoryEntryData( const RIFFDirEntry
&entry
) const
667 static FOURCC lastStreamType
= make_fourcc( " " );
669 if ( entry
.type
== make_fourcc( "avih" ) )
673 MainAVIHeader main_avi_header
;
675 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
676 fail_neg( read( fd
, &main_avi_header
, sizeof( MainAVIHeader
) ) );
678 cout
<< " dwMicroSecPerFrame: " << ( int ) main_avi_header
.dwMicroSecPerFrame
<< endl
679 << " dwMaxBytesPerSec: " << ( int ) main_avi_header
.dwMaxBytesPerSec
<< endl
680 << " dwPaddingGranularity: " << ( int ) main_avi_header
.dwPaddingGranularity
<< endl
681 << " dwFlags: " << ( int ) main_avi_header
.dwFlags
<< endl
682 << " dwTotalFrames: " << ( int ) main_avi_header
.dwTotalFrames
<< endl
683 << " dwInitialFrames: " << ( int ) main_avi_header
.dwInitialFrames
<< endl
684 << " dwStreams: " << ( int ) main_avi_header
.dwStreams
<< endl
685 << " dwSuggestedBufferSize: " << ( int ) main_avi_header
.dwSuggestedBufferSize
<< endl
686 << " dwWidth: " << ( int ) main_avi_header
.dwWidth
<< endl
687 << " dwHeight: " << ( int ) main_avi_header
.dwHeight
<< endl
;
688 for ( i
= 0; i
< 4; ++i
)
689 cout
<< " dwReserved[" << i
<< "]: " << ( int ) main_avi_header
.dwReserved
[ i
] << endl
;
692 else if ( entry
.type
== make_fourcc( "strh" ) )
695 AVIStreamHeader avi_stream_header
;
697 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
698 fail_neg( read( fd
, &avi_stream_header
, sizeof( AVIStreamHeader
) ) );
700 lastStreamType
= avi_stream_header
.fccType
;
702 cout
<< " fccType: '"
703 << ((char *)&avi_stream_header
.fccType
)[0]
704 << ((char *)&avi_stream_header
.fccType
)[1]
705 << ((char *)&avi_stream_header
.fccType
)[2]
706 << ((char *)&avi_stream_header
.fccType
)[3]
709 << ((char *)&avi_stream_header
.fccHandler
)[0]
710 << ((char *)&avi_stream_header
.fccHandler
)[1]
711 << ((char *)&avi_stream_header
.fccHandler
)[2]
712 << ((char *)&avi_stream_header
.fccHandler
)[3]
714 << " dwFlags: " << ( int ) avi_stream_header
.dwFlags
<< endl
715 << " wPriority: " << ( int ) avi_stream_header
.wPriority
<< endl
716 << " wLanguage: " << ( int ) avi_stream_header
.wLanguage
<< endl
717 << " dwInitialFrames: " << ( int ) avi_stream_header
.dwInitialFrames
<< endl
718 << " dwScale: " << ( int ) avi_stream_header
.dwScale
<< endl
719 << " dwRate: " << ( int ) avi_stream_header
.dwRate
<< endl
720 << " dwLength: " << ( int ) avi_stream_header
.dwLength
<< endl
721 << " dwQuality: " << ( int ) avi_stream_header
.dwQuality
<< endl
722 << " dwSampleSize: " << ( int ) avi_stream_header
.dwSampleSize
<< endl
;
725 else if ( entry
.type
== make_fourcc( "indx" ) )
729 AVISuperIndex avi_super_index
;
731 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
732 fail_neg( read( fd
, &avi_super_index
, sizeof( AVISuperIndex
) ) );
734 cout
<< " wLongsPerEntry: " << ( int ) avi_super_index
.wLongsPerEntry
736 << " bIndexSubType: " << ( int ) avi_super_index
.bIndexSubType
<< endl
737 << " bIndexType: " << ( int ) avi_super_index
.bIndexType
<< endl
738 << " nEntriesInUse: " << ( int ) avi_super_index
.nEntriesInUse
<< endl
740 << ((char *)&avi_super_index
.dwChunkId
)[0]
741 << ((char *)&avi_super_index
.dwChunkId
)[1]
742 << ((char *)&avi_super_index
.dwChunkId
)[2]
743 << ((char *)&avi_super_index
.dwChunkId
)[3]
745 << " dwReserved[0]: " << ( int ) avi_super_index
.dwReserved
[ 0 ] << endl
746 << " dwReserved[1]: " << ( int ) avi_super_index
.dwReserved
[ 1 ] << endl
747 << " dwReserved[2]: " << ( int ) avi_super_index
.dwReserved
[ 2 ] << endl
;
748 for ( i
= 0; i
< avi_super_index
.nEntriesInUse
; ++i
)
750 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
751 << ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex
<< avi_super_index
.aIndex
[ i
].qwOffset
<< endl
752 << " dwSize : 0x" << setw( 8 ) << avi_super_index
.aIndex
[ i
].dwSize
<< endl
753 << " dwDuration : " << dec
<< avi_super_index
.aIndex
[ i
].dwDuration
<< endl
;
756 else if ( entry
.type
== make_fourcc( "strf" ) )
758 if ( lastStreamType
== make_fourcc( "auds" ) )
760 WAVEFORMATEX waveformatex
;
761 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
762 fail_neg( read( fd
, &waveformatex
, sizeof( WAVEFORMATEX
) ) );
763 cout
<< " waveformatex.wFormatTag : " << waveformatex
.wFormatTag
<< endl
;
764 cout
<< " waveformatex.nChannels : " << waveformatex
.nChannels
<< endl
;
765 cout
<< " waveformatex.nSamplesPerSec : " << waveformatex
.nSamplesPerSec
<< endl
;
766 cout
<< " waveformatex.nAvgBytesPerSec: " << waveformatex
.nAvgBytesPerSec
<< endl
;
767 cout
<< " waveformatex.nBlockAlign : " << waveformatex
.nBlockAlign
<< endl
;
768 cout
<< " waveformatex.wBitsPerSample : " << waveformatex
.wBitsPerSample
<< endl
;
769 cout
<< " waveformatex.cbSize : " << waveformatex
.cbSize
<< endl
;
771 else if ( lastStreamType
== make_fourcc( "vids" ) )
773 BITMAPINFOHEADER bitmapinfo
;
774 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
775 fail_neg( read( fd
, &bitmapinfo
, sizeof( BITMAPINFOHEADER
) ) );
776 cout
<< " bitmapinfo.biSize : " << bitmapinfo
.biSize
<< endl
;
777 cout
<< " bitmapinfo.biWidth : " << bitmapinfo
.biWidth
<< endl
;
778 cout
<< " bitmapinfo.biHeight : " << bitmapinfo
.biHeight
<< endl
;
779 cout
<< " bitmapinfo.biPlanes : " << bitmapinfo
.biPlanes
<< endl
;
780 cout
<< " bitmapinfo.biBitCount : " << bitmapinfo
.biBitCount
<< endl
;
781 cout
<< " bitmapinfo.biCompression : " << bitmapinfo
.biCompression
<< endl
;
782 cout
<< " bitmapinfo.biSizeImage : " << bitmapinfo
.biSizeImage
<< endl
;
783 cout
<< " bitmapinfo.biXPelsPerMeter: " << bitmapinfo
.biXPelsPerMeter
<< endl
;
784 cout
<< " bitmapinfo.biYPelsPerMeter: " << bitmapinfo
.biYPelsPerMeter
<< endl
;
785 cout
<< " bitmapinfo.biClrUsed : " << bitmapinfo
.biClrUsed
<< endl
;
786 cout
<< " bitmapinfo.biClrImportant : " << bitmapinfo
.biClrImportant
<< endl
;
788 else if ( lastStreamType
== make_fourcc( "iavs" ) )
791 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
792 fail_neg( read( fd
, &dvinfo
, sizeof( DVINFO
) ) );
793 cout
<< " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxSrc
<< endl
;
794 cout
<< " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxCtl
<< endl
;
795 cout
<< " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxSrc1
<< endl
;
796 cout
<< " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxCtl1
<< endl
;
797 cout
<< " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVVAuxSrc
<< endl
;
798 cout
<< " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVVAuxCtl
<< endl
;
802 /* This is the Standard Index. It is an array of offsets and
803 sizes relative to some start offset. */
805 else if ( ( entry
.type
== make_fourcc( "ix00" ) ) || ( entry
.type
== make_fourcc( "ix01" ) ) )
809 AVIStdIndex avi_std_index
;
811 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
812 fail_neg( read( fd
, &avi_std_index
, sizeof( AVIStdIndex
) ) );
814 cout
<< " wLongsPerEntry: " << ( int ) avi_std_index
.wLongsPerEntry
816 << " bIndexSubType: " << ( int ) avi_std_index
.bIndexSubType
<< endl
817 << " bIndexType: " << ( int ) avi_std_index
.bIndexType
<< endl
818 << " nEntriesInUse: " << ( int ) avi_std_index
.nEntriesInUse
<< endl
820 << ((char *)&avi_std_index
.dwChunkId
)[0]
821 << ((char *)&avi_std_index
.dwChunkId
)[1]
822 << ((char *)&avi_std_index
.dwChunkId
)[2]
823 << ((char *)&avi_std_index
.dwChunkId
)[3]
825 << " qwBaseOffset: 0x" << setw( 12 ) << hex
<< avi_std_index
.qwBaseOffset
<< endl
826 << " dwReserved: " << dec
<< ( int ) avi_std_index
.dwReserved
<< endl
;
827 for ( i
= 0; i
< avi_std_index
.nEntriesInUse
; ++i
)
829 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
830 << ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< avi_std_index
.aIndex
[ i
].dwOffset
831 << " (0x" << setw( 12 ) << avi_std_index
.qwBaseOffset
+ avi_std_index
.aIndex
[ i
].dwOffset
<< ')' << endl
832 << " dwSize : 0x" << setw( 8 ) << avi_std_index
.aIndex
[ i
].dwSize
<< dec
<< endl
;
836 else if ( entry
.type
== make_fourcc( "idx1" ) )
840 int numEntries
= entry
.length
/ sizeof( int ) / 4;
841 DWORD
*idx1
= new DWORD
[ numEntries
* 4 ];
842 // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
844 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
845 fail_neg( read( fd
, idx1
, entry
.length
) );
847 for ( i
= 0; i
< numEntries
; ++i
)
850 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
<< setfill( '0' ) << ": dwChunkId : '"
851 << ((char *)&idx1
[ i
* 4 + 0 ])[0]
852 << ((char *)&idx1
[ i
* 4 + 0 ])[1]
853 << ((char *)&idx1
[ i
* 4 + 0 ])[2]
854 << ((char *)&idx1
[ i
* 4 + 0 ])[3]
856 << " dwType : 0x" << setw( 8 ) << hex
<< idx1
[ i
* 4 + 1 ] << endl
857 << " dwOffset : 0x" << setw( 8 ) << idx1
[ i
* 4 + 2 ] << endl
858 // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
859 << " dwSize : 0x" << setw( 8 ) << idx1
[ i
* 4 + 3 ] << dec
<< endl
;
864 else if ( entry
.type
== make_fourcc( "dmlh" ) )
867 int numEntries
= entry
.length
/ sizeof( int );
868 DWORD
*dmlh
= new DWORD
[ numEntries
];
870 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
871 fail_neg( read( fd
, dmlh
, entry
.length
) );
873 for ( i
= 0; i
< numEntries
; ++i
)
875 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
<< setfill( '0' ) << ": "
876 << " dwTotalFrames: 0x" << setw( 8 ) << hex
<< dmlh
[ i
]
877 << " (" << dec
<< dmlh
[ i
] << ")" << endl
;
884 /** If this is not a movi list, read its contents
888 void AVIFile
::ParseList( int parent
)
897 /* Read in the chunk header (type and length). */
898 fail_neg( read( fd
, &type
, sizeof( type
) ) );
899 fail_neg( read( fd
, &length
, sizeof( length
) ) );
903 /* The contents of the list starts here. Obtain its offset. The list
904 name (4 bytes) is already part of the contents). */
906 pos
= lseek( fd
, 0, SEEK_CUR
);
907 fail_if( pos
== ( off_t
) - 1 );
908 fail_neg( read( fd
, &name
, sizeof( name
) ) );
910 /* if we encounter a movi list, do not read it. It takes too much time
911 and we don't need it anyway. */
913 if ( name
!= make_fourcc( "movi" ) )
917 /* Add an entry for this list. */
918 list
= AddDirectoryEntry( type
, name
, sizeof( name
), parent
);
920 /* Read in any chunks contained in this list. This list is the
921 parent for all chunks it contains. */
923 listEnd
= pos
+ length
;
924 while ( pos
< listEnd
)
927 pos
= lseek( fd
, 0, SEEK_CUR
);
928 fail_if( pos
== ( off_t
) - 1 );
933 /* Add an entry for this list. */
935 movi_list
= AddDirectoryEntry( type
, name
, length
, parent
);
937 pos
= lseek( fd
, length
- 4, SEEK_CUR
);
938 fail_if( pos
== ( off_t
) - 1 );
943 void AVIFile
::ParseRIFF()
945 RIFFFile
::ParseRIFF();
947 avih_chunk
= FindDirectoryEntry( make_fourcc( "avih" ) );
948 if ( avih_chunk
!= -1 )
949 ReadChunk( avih_chunk
, ( void* ) & mainHdr
, sizeof( MainAVIHeader
) );
953 void AVIFile
::ReadIndex()
955 indx_chunk
[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
956 if ( indx_chunk
[ 0 ] != -1 )
958 ReadChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ], sizeof( AVISuperIndex
) );
959 index_type
= AVI_LARGE_INDEX
;
961 /* recalc number of frames from each index */
962 mainHdr
.dwTotalFrames
= 0;
964 i
< indx
[ 0 ] ->nEntriesInUse
;
965 mainHdr
.dwTotalFrames
+= indx
[ 0 ] ->aIndex
[ i
++ ].dwDuration
)
969 idx1_chunk
= FindDirectoryEntry( make_fourcc( "idx1" ) );
970 if ( idx1_chunk
!= -1 )
972 ReadChunk( idx1_chunk
, ( void* ) idx1
, sizeof( AVISuperIndex
) );
973 idx1
->nEntriesInUse
= GetDirectoryEntry( idx1_chunk
).length
/ 16;
974 index_type
= AVI_SMALL_INDEX
;
976 /* recalc number of frames from the simple index */
977 int frameNumIndex
= 0;
978 FOURCC chunkID1
= make_fourcc( "00dc" );
979 FOURCC chunkID2
= make_fourcc( "00db" );
980 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
982 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID1
||
983 idx1
->aIndex
[ i
].dwChunkId
== chunkID2
)
988 mainHdr
.dwTotalFrames
= frameNumIndex
;
994 void AVIFile
::FlushIndx( int stream
)
1003 /* Write out the previous index. When this function is
1004 entered for the first time, there is no index to
1005 write. Note: this may be an expensive operation
1006 because of a time consuming seek to the former file
1009 if ( ix_chunk
[ stream
] != -1 )
1010 WriteChunk( ix_chunk
[ stream
], ix
[ stream
] );
1012 /* make a new ix chunk. */
1015 type
= make_fourcc( "ix00" );
1017 type
= make_fourcc( "ix01" );
1018 ix_chunk
[ stream
] = AddDirectoryEntry( type
, 0, sizeof( AVIStdIndex
), movi_list
);
1019 GetDirectoryEntry( ix_chunk
[ stream
], type
, name
, length
, offset
, parent
);
1021 /* fill out all required fields. The offsets in the
1022 array are relative to qwBaseOffset, so fill in the
1023 offset to the next free location in the file
1026 ix
[ stream
] ->wLongsPerEntry
= 2;
1027 ix
[ stream
] ->bIndexSubType
= 0;
1028 ix
[ stream
] ->bIndexType
= KINO_AVI_INDEX_OF_CHUNKS
;
1029 ix
[ stream
] ->nEntriesInUse
= 0;
1030 ix
[ stream
] ->dwChunkId
= indx
[ stream
] ->dwChunkId
;
1031 ix
[ stream
] ->qwBaseOffset
= offset
+ length
;
1032 ix
[ stream
] ->dwReserved
= 0;
1034 for ( i
= 0; i
< IX00_INDEX_SIZE
; ++i
)
1036 ix
[ stream
] ->aIndex
[ i
].dwOffset
= 0;
1037 ix
[ stream
] ->aIndex
[ i
].dwSize
= 0;
1040 /* add a reference to this new index in our super
1043 i
= indx
[ stream
] ->nEntriesInUse
++;
1044 indx
[ stream
] ->aIndex
[ i
].qwOffset
= offset
- RIFF_HEADERSIZE
;
1045 indx
[ stream
] ->aIndex
[ i
].dwSize
= length
+ RIFF_HEADERSIZE
;
1046 indx
[ stream
] ->aIndex
[ i
].dwDuration
= 0;
1050 void AVIFile
::UpdateIndx( int stream
, int chunk
, int duration
)
1059 /* update the appropiate entry in the super index. It reflects
1060 the number of frames in the referenced index. */
1062 i
= indx
[ stream
] ->nEntriesInUse
- 1;
1063 indx
[ stream
] ->aIndex
[ i
].dwDuration
+= duration
;
1065 /* update the standard index. Calculate the file position of
1068 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
1070 indx
[ stream
] ->dwChunkId
= type
;
1071 i
= ix
[ stream
] ->nEntriesInUse
++;
1072 ix
[ stream
] ->aIndex
[ i
].dwOffset
= offset
- ix
[ stream
] ->qwBaseOffset
;
1073 ix
[ stream
] ->aIndex
[ i
].dwSize
= length
;
1077 void AVIFile
::UpdateIdx1( int chunk
, int flags
)
1079 if ( idx1
->nEntriesInUse
< 20000 )
1087 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
1089 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwChunkId
= type
;
1090 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwFlags
= flags
;
1091 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwOffset
= offset
- GetDirectoryEntry( movi_list
).offset
- RIFF_HEADERSIZE
;
1092 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwSize
= length
;
1093 idx1
->nEntriesInUse
++;
1097 bool AVIFile
::verifyStreamFormat( FOURCC type
)
1100 AVIStreamHeader avi_stream_header
;
1101 BITMAPINFOHEADER bih
;
1102 FOURCC strh
= make_fourcc( "strh" );
1103 FOURCC strf
= make_fourcc( "strf" );
1105 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1107 ReadChunk( i
, ( void* ) & avi_stream_header
, sizeof( AVIStreamHeader
) );
1108 if ( avi_stream_header
.fccHandler
== type
)
1112 while ( ( i
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1114 ReadChunk( i
, ( void* ) & bih
, sizeof( BITMAPINFOHEADER
) );
1115 if ( ( FOURCC
) bih
.biCompression
== type
)
1122 bool AVIFile
::verifyStream( FOURCC type
)
1125 AVIStreamHeader avi_stream_header
;
1126 FOURCC strh
= make_fourcc( "strh" );
1128 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1130 ReadChunk( i
, ( void* ) & avi_stream_header
, sizeof( AVIStreamHeader
) );
1131 if ( avi_stream_header
.fccType
== type
)
1137 bool AVIFile
::isOpenDML( void )
1140 FOURCC dmlh
= make_fourcc( "dmlh" );
1142 while ( ( i
= FindDirectoryEntry( dmlh
, j
++ ) ) != -1 )
1149 AVI1File
::AVI1File() : AVIFile()
1153 AVI1File
::~AVI1File()
1157 /* Initialize the AVI structure to its initial state, either for PAL
1160 void AVI1File
::Init( int format
, int sampleFrequency
, int indexType
)
1169 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1171 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1176 mainHdr
.dwWidth
= 720;
1177 mainHdr
.dwHeight
= 576;
1179 streamHdr
[ 0 ].dwScale
= 1;
1180 streamHdr
[ 0 ].dwRate
= 25;
1181 streamHdr
[ 0 ].dwSuggestedBufferSize
= 144008;
1183 /* initialize the 'strf' chunk */
1185 /* Meaning of the DV stream format chunk per Microsoft
1187 Specifies the Audio Auxiliary Data Source Pack for the first audio block
1188 (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
1189 a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
1190 of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
1191 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1192 Consumer-use Digital VCRs.
1194 Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
1195 frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
1196 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1197 Consumer-use Digital VCRs.
1199 Specifies the Audio Auxiliary Data Source Pack for the second audio block
1200 (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
1202 Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
1204 Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
1205 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1206 Consumer-use Digital VCRs.
1208 Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
1209 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1210 Consumer-use Digital VCRs.
1212 Reserved. Set this array to zero.
1215 dvinfo
.dwDVAAuxSrc
= 0xd1e030d0;
1216 dvinfo
.dwDVAAuxCtl
= 0xffa0cf3f;
1217 dvinfo
.dwDVAAuxSrc1
= 0xd1e03fd0;
1218 dvinfo
.dwDVAAuxCtl1
= 0xffa0cf3f;
1219 dvinfo
.dwDVVAuxSrc
= 0xff20ffff;
1220 dvinfo
.dwDVVAuxCtl
= 0xfffdc83f;
1221 dvinfo
.dwDVReserved
[ 0 ] = 0;
1222 dvinfo
.dwDVReserved
[ 1 ] = 0;
1226 mainHdr
.dwWidth
= 720;
1227 mainHdr
.dwHeight
= 480;
1229 streamHdr
[ 0 ].dwScale
= 1001;
1230 streamHdr
[ 0 ].dwRate
= 30000;
1231 streamHdr
[ 0 ].dwSuggestedBufferSize
= 120008;
1233 /* initialize the 'strf' chunk */
1234 dvinfo
.dwDVAAuxSrc
= 0xc0c000c0;
1235 dvinfo
.dwDVAAuxCtl
= 0xffa0cf3f;
1236 dvinfo
.dwDVAAuxSrc1
= 0xc0c001c0;
1237 dvinfo
.dwDVAAuxCtl1
= 0xffa0cf3f;
1238 dvinfo
.dwDVVAuxSrc
= 0xff80ffff;
1239 dvinfo
.dwDVVAuxCtl
= 0xfffcc83f;
1240 dvinfo
.dwDVReserved
[ 0 ] = 0;
1241 dvinfo
.dwDVReserved
[ 1 ] = 0;
1244 default: /* no default allowed */
1249 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00__" );
1251 /* Initialize the 'strh' chunk */
1253 streamHdr
[ 0 ].fccType
= make_fourcc( "iavs" );
1254 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1255 streamHdr
[ 0 ].dwFlags
= 0;
1256 streamHdr
[ 0 ].wPriority
= 0;
1257 streamHdr
[ 0 ].wLanguage
= 0;
1258 streamHdr
[ 0 ].dwInitialFrames
= 0;
1259 streamHdr
[ 0 ].dwStart
= 0;
1260 streamHdr
[ 0 ].dwLength
= 0;
1261 streamHdr
[ 0 ].dwQuality
= 0;
1262 streamHdr
[ 0 ].dwSampleSize
= 0;
1263 streamHdr
[ 0 ].rcFrame
.top
= 0;
1264 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1265 streamHdr
[ 0 ].rcFrame
.left
= 0;
1266 streamHdr
[ 0 ].rcFrame
.right
= 0;
1268 /* This is a simple directory structure setup. For details see the
1269 "OpenDML AVI File Format Extensions" document.
1271 An AVI file contains basically two types of objects, a
1272 "chunk" and a "list" object. The list object contains any
1273 number of chunks. Since a list is also a chunk, it is
1274 possible to create a hierarchical "list of lists"
1277 Every AVI file starts with a "RIFF" object, which is a list
1278 of several other required objects. The actual DV data is
1279 contained in a "movi" list, each frame is in its own chunk.
1281 Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
1282 chunk of less than 1 GByte size per file. The current
1283 format which allow for almost arbitrary sizes can contain
1284 several RIFF chunks of less than 1 GByte size. Old software
1285 however would only deal with the first RIFF chunk.
1287 Note that the first entry (FILE) isn´t actually part
1288 of the AVI file. I use this (pseudo-) directory entry to
1289 keep track of the RIFF chunks and their positions in the
1293 /* Create the container directory entry */
1295 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1297 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1299 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE
, file_list
);
1300 hdrl_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE
, riff_list
);
1301 avih_chunk
= AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader
), hdrl_list
);
1302 strl_list
[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1303 strh_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 0 ] );
1304 strf_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo
), strl_list
[ 0 ] );
1305 if ( index_type
& AVI_LARGE_INDEX
)
1306 indx_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 0 ] );
1308 odml_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE
, hdrl_list
);
1309 dmlh_chunk
= AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list
);
1311 /* align movi list to block */
1312 GetDirectoryEntry( hdrl_list
, type
, name
, length
, offset
, parent
);
1313 num_blocks
= length
/ PADDING_SIZE
+ 1;
1314 length
= num_blocks
* PADDING_SIZE
- length
- 5 * RIFF_HEADERSIZE
; // why 5?
1315 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1317 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1319 /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
1326 /* Write a DV video frame. This is somewhat complex... */
1329 bool AVI1File
::WriteFrame( const Frame
&frame
)
1340 /* exit if no large index and 1GB reached */
1341 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
1344 /* Check if we need a new ix00 Standard Index. It has a
1345 capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1346 number, we need a new index. The new ix00 chunk is also
1347 part of the movi list. */
1349 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1352 /* Write the DV frame data.
1354 Make a new 00__ chunk for the new frame, write out the
1357 frame_chunk
= AddDirectoryEntry( make_fourcc( "00__" ), 0, frame
.GetFrameSize(), movi_list
);
1358 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1360 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1361 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1363 WriteChunk( frame_chunk
, frame
.data
);
1364 // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1365 // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1366 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1367 // WriteChunk(junk_chunk, g_zeroes);
1369 if ( index_type
& AVI_LARGE_INDEX
)
1370 UpdateIndx( 0, frame_chunk
, 1 );
1371 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1372 UpdateIdx1( frame_chunk
, 0x10 );
1374 /* update some variables with the new frame count. */
1377 ++mainHdr
.dwTotalFrames
;
1378 ++streamHdr
[ 0 ].dwLength
;
1381 /* Find out if the current riff list is close to 1 GByte in
1382 size. If so, start a new (extended) RIFF. The only allowed
1383 item in the new RIFF chunk is a movi list (with video
1384 frames and indexes as usual). */
1386 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1387 if ( length
> 0x3f000000 )
1389 /* write idx1 only once and before end of first GB */
1390 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1392 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1393 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1395 isUpdateIdx1
= false;
1397 if ( index_type
& AVI_LARGE_INDEX
)
1399 /* pad out to 1GB */
1400 //GetDirectoryEntry(riff_list, type, name, length, offset, parent);
1401 //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
1402 //WriteChunk(junk_chunk, g_zeroes);
1404 /* padding for alignment */
1405 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1406 num_blocks
= ( length
+ 4 * RIFF_HEADERSIZE
) / PADDING_SIZE
+ 1;
1407 length
= ( num_blocks
* PADDING_SIZE
) - length
- 4 * RIFF_HEADERSIZE
- 2 * RIFF_LISTSIZE
;
1410 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1411 WriteChunk( junk_chunk
, g_zeroes
);
1414 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE
, file_list
);
1415 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1422 void AVI1File
::WriteRIFF()
1425 WriteChunk( avih_chunk
, ( void* ) & mainHdr
);
1426 WriteChunk( strh_chunk
[ 0 ], ( void* ) & streamHdr
[ 0 ] );
1427 WriteChunk( strf_chunk
[ 0 ], ( void* ) & dvinfo
);
1428 WriteChunk( dmlh_chunk
, ( void* ) & dmlh
);
1430 if ( index_type
& AVI_LARGE_INDEX
)
1432 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1433 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1436 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1438 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1439 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1442 RIFFFile
::WriteRIFF();
1446 AVI2File
::AVI2File() : AVIFile()
1450 AVI2File
::~AVI2File()
1454 /* Initialize the AVI structure to its initial state, either for PAL
1457 void AVI2File
::Init( int format
, int sampleFrequency
, int indexType
)
1466 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1468 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1474 mainHdr
.dwStreams
= 2;
1475 mainHdr
.dwWidth
= 720;
1476 mainHdr
.dwHeight
= 576;
1478 /* Initialize the 'strh' chunk */
1480 streamHdr
[ 0 ].fccType
= make_fourcc( "vids" );
1481 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1482 streamHdr
[ 0 ].dwFlags
= 0;
1483 streamHdr
[ 0 ].wPriority
= 0;
1484 streamHdr
[ 0 ].wLanguage
= 0;
1485 streamHdr
[ 0 ].dwInitialFrames
= 0;
1486 streamHdr
[ 0 ].dwScale
= 1;
1487 streamHdr
[ 0 ].dwRate
= 25;
1488 streamHdr
[ 0 ].dwStart
= 0;
1489 streamHdr
[ 0 ].dwLength
= 0;
1490 streamHdr
[ 0 ].dwSuggestedBufferSize
= 144008;
1491 streamHdr
[ 0 ].dwQuality
= -1;
1492 streamHdr
[ 0 ].dwSampleSize
= 0;
1493 streamHdr
[ 0 ].rcFrame
.top
= 0;
1494 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1495 streamHdr
[ 0 ].rcFrame
.left
= 0;
1496 streamHdr
[ 0 ].rcFrame
.right
= 0;
1498 bitmapinfo
.biSize
= sizeof( bitmapinfo
);
1499 bitmapinfo
.biWidth
= 720;
1500 bitmapinfo
.biHeight
= 576;
1501 bitmapinfo
.biPlanes
= 1;
1502 bitmapinfo
.biBitCount
= 24;
1503 bitmapinfo
.biCompression
= make_fourcc( "dvsd" );
1504 bitmapinfo
.biSizeImage
= 144000;
1505 bitmapinfo
.biXPelsPerMeter
= 0;
1506 bitmapinfo
.biYPelsPerMeter
= 0;
1507 bitmapinfo
.biClrUsed
= 0;
1508 bitmapinfo
.biClrImportant
= 0;
1510 streamHdr
[ 1 ].fccType
= make_fourcc( "auds" );
1511 streamHdr
[ 1 ].fccHandler
= 0;
1512 streamHdr
[ 1 ].dwFlags
= 0;
1513 streamHdr
[ 1 ].wPriority
= 0;
1514 streamHdr
[ 1 ].wLanguage
= 0;
1515 streamHdr
[ 1 ].dwInitialFrames
= 0;
1516 streamHdr
[ 1 ].dwScale
= 2 * 2;
1517 streamHdr
[ 1 ].dwRate
= sampleFrequency
* 2 * 2;
1518 streamHdr
[ 1 ].dwStart
= 0;
1519 streamHdr
[ 1 ].dwLength
= 0;
1520 streamHdr
[ 1 ].dwSuggestedBufferSize
= 8192;
1521 streamHdr
[ 1 ].dwQuality
= -1;
1522 streamHdr
[ 1 ].dwSampleSize
= 2 * 2;
1523 streamHdr
[ 1 ].rcFrame
.top
= 0;
1524 streamHdr
[ 1 ].rcFrame
.bottom
= 0;
1525 streamHdr
[ 1 ].rcFrame
.left
= 0;
1526 streamHdr
[ 1 ].rcFrame
.right
= 0;
1531 mainHdr
.dwTotalFrames
= 0;
1532 mainHdr
.dwStreams
= 2;
1533 mainHdr
.dwWidth
= 720;
1534 mainHdr
.dwHeight
= 480;
1536 /* Initialize the 'strh' chunk */
1538 streamHdr
[ 0 ].fccType
= make_fourcc( "vids" );
1539 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1540 streamHdr
[ 0 ].dwFlags
= 0;
1541 streamHdr
[ 0 ].wPriority
= 0;
1542 streamHdr
[ 0 ].wLanguage
= 0;
1543 streamHdr
[ 0 ].dwInitialFrames
= 0;
1544 streamHdr
[ 0 ].dwScale
= 1001;
1545 streamHdr
[ 0 ].dwRate
= 30000;
1546 streamHdr
[ 0 ].dwStart
= 0;
1547 streamHdr
[ 0 ].dwLength
= 0;
1548 streamHdr
[ 0 ].dwSuggestedBufferSize
= 120008;
1549 streamHdr
[ 0 ].dwQuality
= -1;
1550 streamHdr
[ 0 ].dwSampleSize
= 0;
1551 streamHdr
[ 0 ].rcFrame
.top
= 0;
1552 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1553 streamHdr
[ 0 ].rcFrame
.left
= 0;
1554 streamHdr
[ 0 ].rcFrame
.right
= 0;
1556 bitmapinfo
.biSize
= sizeof( bitmapinfo
);
1557 bitmapinfo
.biWidth
= 720;
1558 bitmapinfo
.biHeight
= 480;
1559 bitmapinfo
.biPlanes
= 1;
1560 bitmapinfo
.biBitCount
= 24;
1561 bitmapinfo
.biCompression
= make_fourcc( "dvsd" );
1562 bitmapinfo
.biSizeImage
= 120000;
1563 bitmapinfo
.biXPelsPerMeter
= 0;
1564 bitmapinfo
.biYPelsPerMeter
= 0;
1565 bitmapinfo
.biClrUsed
= 0;
1566 bitmapinfo
.biClrImportant
= 0;
1568 streamHdr
[ 1 ].fccType
= make_fourcc( "auds" );
1569 streamHdr
[ 1 ].fccHandler
= 0;
1570 streamHdr
[ 1 ].dwFlags
= 0;
1571 streamHdr
[ 1 ].wPriority
= 0;
1572 streamHdr
[ 1 ].wLanguage
= 0;
1573 streamHdr
[ 1 ].dwInitialFrames
= 1;
1574 streamHdr
[ 1 ].dwScale
= 2 * 2;
1575 streamHdr
[ 1 ].dwRate
= sampleFrequency
* 2 * 2;
1576 streamHdr
[ 1 ].dwStart
= 0;
1577 streamHdr
[ 1 ].dwLength
= 0;
1578 streamHdr
[ 1 ].dwSuggestedBufferSize
= 8192;
1579 streamHdr
[ 1 ].dwQuality
= 0;
1580 streamHdr
[ 1 ].dwSampleSize
= 2 * 2;
1581 streamHdr
[ 1 ].rcFrame
.top
= 0;
1582 streamHdr
[ 1 ].rcFrame
.bottom
= 0;
1583 streamHdr
[ 1 ].rcFrame
.left
= 0;
1584 streamHdr
[ 1 ].rcFrame
.right
= 0;
1588 waveformatex
.wFormatTag
= 1;
1589 waveformatex
.nChannels
= 2;
1590 waveformatex
.nSamplesPerSec
= sampleFrequency
;
1591 waveformatex
.nAvgBytesPerSec
= sampleFrequency
* 2 * 2;
1592 waveformatex
.nBlockAlign
= 4;
1593 waveformatex
.wBitsPerSample
= 16;
1594 waveformatex
.cbSize
= 0;
1596 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1598 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1600 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE
, file_list
);
1601 hdrl_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE
, riff_list
);
1602 avih_chunk
= AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader
), hdrl_list
);
1604 strl_list
[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1605 strh_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 0 ] );
1606 strf_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER
), strl_list
[ 0 ] );
1607 if ( index_type
& AVI_LARGE_INDEX
)
1609 indx_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 0 ] );
1611 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00dc" );
1614 strl_list
[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1615 strh_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 1 ] );
1616 strf_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX
) - 2, strl_list
[ 1 ] );
1617 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list
[ 1 ] );
1618 if ( index_type
& AVI_LARGE_INDEX
)
1620 indx_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 1 ] );
1622 indx
[ 1 ] ->dwChunkId
= make_fourcc( "01wb" );
1624 odml_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE
, hdrl_list
);
1625 dmlh_chunk
= AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list
);
1628 /* align movi list to block */
1629 GetDirectoryEntry( hdrl_list
, type
, name
, length
, offset
, parent
);
1630 num_blocks
= length
/ PADDING_SIZE
+ 1;
1631 length
= num_blocks
* PADDING_SIZE
- length
- 5 * RIFF_HEADERSIZE
; // why 5 headers?
1632 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1634 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1636 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwChunkId
= make_fourcc( "7Fxx" );
1637 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwFlags
= 0;
1638 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwOffset
= 0;
1639 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwSize
= 0;
1640 idx1
->nEntriesInUse
++;
1644 void AVI2File
::WriteRIFF()
1646 WriteChunk( avih_chunk
, ( void* ) & mainHdr
);
1647 WriteChunk( strh_chunk
[ 0 ], ( void* ) & streamHdr
[ 0 ] );
1648 WriteChunk( strf_chunk
[ 0 ], ( void* ) & bitmapinfo
);
1649 if ( index_type
& AVI_LARGE_INDEX
)
1651 WriteChunk( dmlh_chunk
, ( void* ) & dmlh
);
1652 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1653 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1655 WriteChunk( strh_chunk
[ 1 ], ( void* ) & streamHdr
[ 1 ] );
1656 WriteChunk( strf_chunk
[ 1 ], ( void* ) & waveformatex
);
1657 if ( index_type
& AVI_LARGE_INDEX
)
1659 WriteChunk( indx_chunk
[ 1 ], ( void* ) indx
[ 1 ] );
1660 WriteChunk( ix_chunk
[ 1 ], ( void* ) ix
[ 1 ] );
1663 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1665 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1666 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1668 RIFFFile
::WriteRIFF();
1672 /** Write a DV video frame
1674 \param frame the frame to write
1678 bool AVI2File
::WriteFrame( const Frame
&frame
)
1683 char soundbuf
[ 20000 ];
1692 /* exit if no large index and 1GB reached */
1693 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
1696 /* Check if we need a new ix00 Standard Index. It has a
1697 capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1698 number, we need a new index. The new ix00 chunk is also
1699 part of the movi list. */
1701 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1707 /* Write audio data if we have it */
1709 audio_size
= frame
.ExtractAudio( soundbuf
);
1710 if ( audio_size
> 0 )
1712 audio_chunk
= AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size
, movi_list
);
1713 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1715 GetDirectoryEntry( audio_chunk
, type
, name
, length
, offset
, parent
);
1716 ix
[ 1 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1718 WriteChunk( audio_chunk
, soundbuf
);
1719 // num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1720 // length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
1721 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1722 // WriteChunk(junk_chunk, g_zeroes);
1723 if ( index_type
& AVI_LARGE_INDEX
)
1724 UpdateIndx( 1, audio_chunk
, audio_size
/ waveformatex
.nChannels
/ 2 );
1725 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1726 UpdateIdx1( audio_chunk
, 0x00 );
1727 streamHdr
[ 1 ].dwLength
+= audio_size
/ waveformatex
.nChannels
/ 2;
1731 /* Write video data */
1733 frame_chunk
= AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame
.GetFrameSize(), movi_list
);
1734 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1736 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1737 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1739 WriteChunk( frame_chunk
, frame
.data
);
1740 // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1741 // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1742 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1743 // WriteChunk(junk_chunk, g_zeroes);
1744 if ( index_type
& AVI_LARGE_INDEX
)
1745 UpdateIndx( 0, frame_chunk
, 1 );
1746 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1747 UpdateIdx1( frame_chunk
, 0x10 );
1749 /* update some variables with the new frame count. */
1752 ++mainHdr
.dwTotalFrames
;
1753 ++streamHdr
[ 0 ].dwLength
;
1756 /* Find out if the current riff list is close to 1 GByte in
1757 size. If so, start a new (extended) RIFF. The only allowed
1758 item in the new RIFF chunk is a movi list (with video
1759 frames and indexes as usual). */
1761 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1762 if ( length
> 0x3f000000 )
1765 /* write idx1 only once and before end of first GB */
1766 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1768 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1769 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1771 isUpdateIdx1
= false;
1773 if ( index_type
& AVI_LARGE_INDEX
)
1775 /* padding for alignment */
1776 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1777 num_blocks
= ( length
+ 4 * RIFF_HEADERSIZE
) / PADDING_SIZE
+ 1;
1778 length
= ( num_blocks
* PADDING_SIZE
) - length
- 4 * RIFF_HEADERSIZE
- 2 * RIFF_LISTSIZE
;
1781 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1782 WriteChunk( junk_chunk
, g_zeroes
);
1785 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE
, file_list
);
1786 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1793 void AVI1File
::setDVINFO( DVINFO
&info
)
1795 // do not do this until debugged audio against DirectShow
1798 dvinfo
.dwDVAAuxSrc
= info
.dwDVAAuxSrc
;
1799 dvinfo
.dwDVAAuxCtl
= info
.dwDVAAuxCtl
;
1800 dvinfo
.dwDVAAuxSrc1
= info
.dwDVAAuxSrc1
;
1801 dvinfo
.dwDVAAuxCtl1
= info
.dwDVAAuxCtl1
;
1802 dvinfo
.dwDVVAuxSrc
= info
.dwDVVAuxSrc
;
1803 dvinfo
.dwDVVAuxCtl
= info
.dwDVVAuxCtl
;
1807 void AVI2File
::setDVINFO( DVINFO
&info
)
1810 void AVIFile
::setFccHandler( FOURCC type
, FOURCC handler
)
1812 for ( int i
= 0; i
< mainHdr
.dwStreams
; i
++ )
1814 if ( streamHdr
[ i
].fccType
== type
)
1817 FOURCC strf
= make_fourcc( "strf" );
1818 BITMAPINFOHEADER bih
;
1820 streamHdr
[ i
].fccHandler
= handler
;
1822 while ( ( k
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1824 ReadChunk( k
, ( void* ) & bih
, sizeof( BITMAPINFOHEADER
) );
1825 bih
.biCompression
= handler
;
1831 bool AVIFile
::getStreamFormat( void* data
, FOURCC type
)
1834 FOURCC strh
= make_fourcc( "strh" );
1835 FOURCC strf
= make_fourcc( "strf" );
1836 AVIStreamHeader avi_stream_header
;
1837 bool result
= false;
1839 while ( ( result
== false ) && ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1841 ReadChunk( i
, ( void* ) & avi_stream_header
, sizeof( AVIStreamHeader
) );
1842 if ( avi_stream_header
.fccType
== type
)
1847 pthread_mutex_lock( &file_mutex
);
1848 fail_neg( read( fd
, &chunkID
, sizeof( FOURCC
) ) );
1849 if ( chunkID
== strf
)
1851 fail_neg( read( fd
, &size
, sizeof( int ) ) );
1852 fail_neg( read( fd
, data
, size
) );
1855 pthread_mutex_unlock( &file_mutex
);