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.2 2005/06/21 20:59:39 lilo_booter
25 * src/framework/mlt_consumer.c src/framework/mlt_consumer.h
26 * + Added a general profile handling for size, aspect ratio and display ratio
28 * src/framework/mlt_producer.c
29 * + Correction to aspect ratio properties
32 * + Minimalist support for sdl_preview (still not very good)
34 * src/modules/avformat/consumer_avformat.c
35 * + Takes consumer profile into account
37 * src/modules/core/filter_resize.c
38 * + Corrections for synthesised producers and aspect ratio (inherits from consumer)
40 * src/modules/core/producer_colour.c
41 * src/modules/core/producer_noise.c
42 * src/modules/gtk2/producer_pango.c
43 * + Ensures that resize picks up consumer aspect ratio
45 * src/modules/dv/consumer_libdv.c
46 * + Honour wide screen output
48 * src/modules/gtk2/producer_pixbuf.c
49 * + Correction for 1:1 aspect ratio
51 * src/modules/kino/Makefile
52 * src/modules/kino/avi.cc
53 * src/modules/kino/avi.h
54 * src/modules/kino/configure
55 * src/modules/kino/filehandler.cc
56 * + Attempt to allow mov dv files to provide audio
58 * src/modules/sdl/consumer_sdl.c
59 * src/modules/sdl/consumer_sdl_preview.c
60 * src/modules/sdl/consumer_sdl_still.c
61 * + Takes consumer profile into account
63 * Revision 1.1 2005/04/15 14:28:26 lilo_booter
66 * Revision 1.28 2005/04/01 23:43:10 ddennedy
67 * apply endian fixes from Daniel Kobras
69 * Revision 1.27 2004/10/11 01:37:11 ddennedy
70 * mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
72 * Revision 1.26 2004/01/05 03:43:11 ddennedy
73 * metadata editing, deinterlace options, bugfixes and cleanups
75 * Revision 1.25 2003/11/25 23:00:52 ddennedy
76 * cleanup and a few bugfixes
78 * Revision 1.24 2003/11/12 13:01:56 ddennedy
79 * disable JUNK chunks in MOVI list, FileHandler max file size zero = infinity
81 * Revision 1.23 2003/11/10 01:02:51 ddennedy
82 * bugfix: return error on AVI directory entries with size <0
84 * Revision 1.22 2003/10/28 18:52:32 ddennedy
85 * fix prefs dialog crash, improve WAV import
87 * Revision 1.21 2003/10/21 16:34:32 ddennedy
88 * GNOME2 port phase 1: initial checkin
90 * Revision 1.19.2.9 2003/08/26 20:39:00 ddennedy
91 * relocate mutex unlock and add assert includes
93 * Revision 1.19.2.8 2003/07/24 14:13:57 ddennedy
94 * support for distinct audio stream in type2 AVI and Quicktime; support for more DV FOURCCs
96 * Revision 1.19.2.7 2003/06/10 23:53:35 ddennedy
97 * Daniel Kobras' WriteFrame error handling and automatic OpenDML, bugfixes in scene list updates, export AV/C Record
99 * Revision 1.19.2.6 2003/03/05 15:02:12 ddennedy
100 * yet anther AV/C bugfix, yet another AVI improvement
102 * Revision 1.19.2.5 2003/02/20 21:59:55 ddennedy
103 * bugfixes to capture and AVI
105 * Revision 1.19.2.4 2003/01/13 05:15:31 ddennedy
106 * added More Info panel and supporting methods
108 * Revision 1.19.2.3 2002/12/31 22:40:49 ddennedy
109 * bugfix recent versions Quicktime4Linux build options, extend dvsd fourcc check on AVI to the BITMAPINFOHEADER for compatibility with mencoder
111 * Revision 1.19.2.2 2002/11/25 04:48:30 ddennedy
112 * bugfix to report errors when loading files
114 * Revision 1.19.2.1 2002/11/24 23:36:55 ddennedy
115 * bugfix in AVI writing
117 * Revision 1.19 2002/10/08 12:08:01 ddennedy
118 * more sane frame count, greater potential compatibility
120 * Revision 1.18 2002/10/08 08:33:02 ddennedy
121 * fix number of frames for small dv2
123 * Revision 1.17 2002/10/08 07:46:41 ddennedy
124 * AVI bugfixes, compatibility, optimization, warn bad file in capture and export dv file, allow no mplex
126 * Revision 1.15 2002/06/10 10:39:51 ddennedy
127 * minor fixes for large files
129 * Revision 1.14 2002/05/17 08:04:24 ddennedy
130 * revert const-ness of Frame references in Frame, FileHandler, and AVI classes
132 * Revision 1.13 2002/05/15 04:39:35 ddennedy
133 * bugfixes to dv2 AVI write, audio export, Xv init
135 * Revision 1.12 2002/04/29 05:09:21 ddennedy
136 * raw dv file support, Frame::ExtractAudio uses libdv, audioScrub prefs
138 * Revision 1.11 2002/04/15 19:12:32 schirmacher
139 * removed debugging code causing performance losses and crashes with dv2 files
141 * Revision 1.10 2002/04/09 06:53:42 ddennedy
142 * cleanup, new libdv 0.9.5, large AVI, dnd storyboard
144 * Revision 1.8 2002/03/25 21:34:25 arne
145 * Support for large (64 bit) files mostly completed
147 * Revision 1.7 2002/03/10 21:28:29 arne
148 * release 1.1b1, 64 bit support for type 1 avis
150 * Revision 1.6 2002/03/10 13:29:41 arne
151 * more changes for 64 bit access
153 * Revision 1.5 2002/03/09 17:59:28 arne
154 * moved index routines to AVIFile
156 * Revision 1.4 2002/03/09 10:26:26 arne
157 * improved constructors and assignment operator
159 * Revision 1.3 2002/03/09 08:55:57 arne
160 * moved a few variables to AVIFile
162 * Revision 1.2 2002/03/04 19:22:43 arne
163 * updated to latest Kino avi code
165 * Revision 1.1.1.1 2002/03/03 19:08:08 arne
166 * import of version 1.01
198 #define PADDING_SIZE (512)
199 #define PADDING_1GB (0x40000000)
200 #define IX00_INDEX_SIZE (4028)
202 #define AVIF_HASINDEX 0x00000010
203 #define AVIF_MUSTUSEINDEX 0x00000020
204 #define AVIF_TRUSTCKTYPE 0x00000800
205 #define AVIF_ISINTERLEAVED 0x00000100
206 #define AVIF_WASCAPTUREFILE 0x00010000
207 #define AVIF_COPYRIGHTED 0x00020000
210 //static char g_zeroes[ PADDING_SIZE ];
214 \todo mainHdr not initialized
215 \todo add checking for NULL pointers
219 AVIFile
::AVIFile() : RIFFFile(),
220 idx1( NULL
), file_list( -1 ), riff_list( -1 ),
221 hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
222 index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
224 // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
226 for ( int i
= 0; i
< 2; ++i
)
228 indx
[ i
] = new AVISuperIndex
;
229 memset( indx
[ i
], 0, sizeof( AVISuperIndex
) );
230 ix
[ i
] = new AVIStdIndex
;
231 memset( ix
[ i
], 0, sizeof( AVIStdIndex
) );
232 indx_chunk
[ i
] = -1;
235 strh_chunk
[ i
] = -1;
236 strf_chunk
[ i
] = -1;
238 idx1
= new AVISimpleIndex
;
239 memset( idx1
, 0, sizeof( AVISimpleIndex
) );
243 /** The copy constructor
245 \todo add checking for NULL pointers
249 AVIFile
::AVIFile( const AVIFile
& avi
) : RIFFFile( avi
)
251 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
253 mainHdr
= avi
.mainHdr
;
254 idx1
= new AVISimpleIndex
;
256 file_list
= avi
.file_list
;
257 riff_list
= avi
.riff_list
;
258 hdrl_list
= avi
.hdrl_list
;
259 avih_chunk
= avi
.avih_chunk
;
260 movi_list
= avi
.movi_list
;
261 junk_chunk
= avi
.junk_chunk
;
262 idx1_chunk
= avi
.idx1_chunk
;
264 for ( int i
= 0; i
< 2; ++i
)
266 indx
[ i
] = new AVISuperIndex
;
267 *indx
[ i
] = *avi
.indx
[ i
];
268 ix
[ i
] = new AVIStdIndex
;
269 *ix
[ i
] = *avi
.ix
[ i
];
270 indx_chunk
[ i
] = avi
.indx_chunk
[ i
];
271 ix_chunk
[ i
] = avi
.ix_chunk
[ i
];
272 strl_list
[ i
] = avi
.strl_list
[ i
];
273 strh_chunk
[ i
] = avi
.strh_chunk
[ i
];
274 strf_chunk
[ i
] = avi
.strf_chunk
[ i
];
277 index_type
= avi
.index_type
;
278 current_ix00
= avi
.current_ix00
;
280 for ( int i
= 0; i
< 62; ++i
)
281 dmlh
[ i
] = avi
.dmlh
[ i
];
283 isUpdateIdx1
= avi
.isUpdateIdx1
;
288 /** The assignment operator
292 AVIFile
& AVIFile
::operator=( const AVIFile
& avi
)
294 // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
298 RIFFFile
::operator=( avi
);
299 mainHdr
= avi
.mainHdr
;
301 file_list
= avi
.file_list
;
302 riff_list
= avi
.riff_list
;
303 hdrl_list
= avi
.hdrl_list
;
304 avih_chunk
= avi
.avih_chunk
;
305 movi_list
= avi
.movi_list
;
306 junk_chunk
= avi
.junk_chunk
;
307 idx1_chunk
= avi
.idx1_chunk
;
309 for ( int i
= 0; i
< 2; ++i
)
311 *indx
[ i
] = *avi
.indx
[ i
];
312 *ix
[ i
] = *avi
.ix
[ i
];
313 indx_chunk
[ i
] = avi
.indx_chunk
[ i
];
314 ix_chunk
[ i
] = avi
.ix_chunk
[ i
];
315 strl_list
[ i
] = avi
.strl_list
[ i
];
316 strh_chunk
[ i
] = avi
.strh_chunk
[ i
];
317 strf_chunk
[ i
] = avi
.strf_chunk
[ i
];
320 index_type
= avi
.index_type
;
321 current_ix00
= avi
.current_ix00
;
323 for ( int i
= 0; i
< 62; ++i
)
324 dmlh
[ i
] = avi
.dmlh
[ i
];
326 isUpdateIdx1
= avi
.isUpdateIdx1
;
338 // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
340 for ( int i
= 0; i
< 2; ++i
)
348 /** Initialize the AVI structure to its initial state, either for PAL or NTSC format
350 Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
352 \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant.
353 \param format pass AVI_PAL or AVI_NTSC
354 \param sampleFrequency the sample frequency of the audio content
355 \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX
359 void AVIFile
::Init( int format
, int sampleFrequency
, int indexType
)
363 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
365 index_type
= indexType
;
370 mainHdr
.dwMicroSecPerFrame
= 40000;
371 mainHdr
.dwSuggestedBufferSize
= 144008;
375 mainHdr
.dwMicroSecPerFrame
= 33366;
376 mainHdr
.dwSuggestedBufferSize
= 120008;
379 default: /* no default allowed */
384 /* Initialize the 'avih' chunk */
386 mainHdr
.dwMaxBytesPerSec
= 3600000 + sampleFrequency
* 4;
387 mainHdr
.dwPaddingGranularity
= PADDING_SIZE
;
388 mainHdr
.dwFlags
= AVIF_TRUSTCKTYPE
;
389 if ( indexType
& AVI_SMALL_INDEX
)
390 mainHdr
.dwFlags
|= AVIF_HASINDEX
;
391 mainHdr
.dwTotalFrames
= 0;
392 mainHdr
.dwInitialFrames
= 0;
393 mainHdr
.dwStreams
= 1;
395 mainHdr
.dwHeight
= 0;
396 mainHdr
.dwReserved
[ 0 ] = 0;
397 mainHdr
.dwReserved
[ 1 ] = 0;
398 mainHdr
.dwReserved
[ 2 ] = 0;
399 mainHdr
.dwReserved
[ 3 ] = 0;
401 /* Initialize the 'idx1' chunk */
403 for ( int i
= 0; i
< 8000; ++i
)
405 idx1
->aIndex
[ i
].dwChunkId
= 0;
406 idx1
->aIndex
[ i
].dwFlags
= 0;
407 idx1
->aIndex
[ i
].dwOffset
= 0;
408 idx1
->aIndex
[ i
].dwSize
= 0;
410 idx1
->nEntriesInUse
= 0;
412 /* Initialize the 'indx' chunk */
414 for ( i
= 0; i
< 2; ++i
)
416 indx
[ i
] ->wLongsPerEntry
= 4;
417 indx
[ i
] ->bIndexSubType
= 0;
418 indx
[ i
] ->bIndexType
= KINO_AVI_INDEX_OF_INDEXES
;
419 indx
[ i
] ->nEntriesInUse
= 0;
420 indx
[ i
] ->dwReserved
[ 0 ] = 0;
421 indx
[ i
] ->dwReserved
[ 1 ] = 0;
422 indx
[ i
] ->dwReserved
[ 2 ] = 0;
423 for ( j
= 0; j
< 2014; ++j
)
425 indx
[ i
] ->aIndex
[ j
].qwOffset
= 0;
426 indx
[ i
] ->aIndex
[ j
].dwSize
= 0;
427 indx
[ i
] ->aIndex
[ j
].dwDuration
= 0;
431 /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
434 /* Initialize the 'dmlh' chunk. I have no clue what this means
437 for ( i
= 0; i
< 62; ++i
)
439 //dmlh[0] = -1; /* frame count + 1? */
444 /** Find position and size of a given frame in the file
446 Depending on which index is available, search one of them to
447 find position and frame size
449 \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
450 \todo all index related operations should be isolated
451 \param offset the file offset to the start of the frame
452 \param size the size of the frame
453 \param frameNum the number of the frame we wish to find
454 \return 0 if the frame could be found, -1 otherwise
457 int AVIFile
::GetDVFrameInfo( off_t
&offset
, int &size
, int frameNum
)
459 switch ( index_type
)
461 case AVI_LARGE_INDEX
:
463 /* find relevant index in indx0 */
467 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
470 if ( i
!= current_ix00
)
472 fail_if( lseek( fd
, indx
[ 0 ] ->aIndex
[ i
].qwOffset
+ RIFF_HEADERSIZE
, SEEK_SET
) == ( off_t
) - 1 );
473 fail_neg( read( fd
, ix
[ 0 ], indx
[ 0 ] ->aIndex
[ i
].dwSize
- RIFF_HEADERSIZE
) );
477 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
479 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
480 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
487 case AVI_SMALL_INDEX
:
489 int frameNumIndex
= 0;
490 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
492 FOURCC chunkID1
= make_fourcc( "00dc" );
493 FOURCC chunkID2
= make_fourcc( "00db" );
494 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID1
||
495 idx1
->aIndex
[ i
].dwChunkId
== chunkID2
)
497 if ( frameNumIndex
== frameNum
)
507 // compatibility check for broken dvgrab dv2 format
508 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
510 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
514 // new, correct dv2 format
515 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
517 size
= idx1
->aIndex
[ index
].dwSize
;
527 /** Find position and size of a given frame in the file
529 Depending on which index is available, search one of them to
530 find position and frame size
532 \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
533 \todo all index related operations should be isolated
534 \param offset the file offset to the start of the frame
535 \param size the size of the frame
536 \param frameNum the number of the frame we wish to find
537 \param chunkID the ID of the type of chunk we want
538 \return 0 if the frame could be found, -1 otherwise
541 int AVIFile
::GetFrameInfo( off_t
&offset
, int &size
, int frameNum
, FOURCC chunkID
)
543 if ( index_type
& AVI_LARGE_INDEX
)
547 for ( i
= 0; frameNum
>= indx
[ 0 ] ->aIndex
[ i
].dwDuration
; frameNum
-= indx
[ 0 ] ->aIndex
[ i
].dwDuration
, ++i
)
550 if ( i
!= current_ix00
)
552 fail_if( lseek( fd
, indx
[ 0 ] ->aIndex
[ i
].qwOffset
+ RIFF_HEADERSIZE
, SEEK_SET
) == ( off_t
) - 1 );
553 fail_neg( read( fd
, ix
[ 0 ], indx
[ 0 ] ->aIndex
[ i
].dwSize
- RIFF_HEADERSIZE
) );
557 if ( frameNum
< ix
[ 0 ] ->nEntriesInUse
)
559 if ( ( FOURCC
) ix
[ 0 ] ->dwChunkId
== chunkID
)
561 offset
= ix
[ 0 ] ->qwBaseOffset
+ ix
[ 0 ] ->aIndex
[ frameNum
].dwOffset
;
562 size
= ix
[ 0 ] ->aIndex
[ frameNum
].dwSize
;
567 if ( index_type
& AVI_SMALL_INDEX
)
570 int frameNumIndex
= 0;
571 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
573 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID
)
575 if ( frameNumIndex
== frameNum
)
585 // compatibility check for broken dvgrab dv2 format
586 if ( idx1
->aIndex
[ 0 ].dwOffset
> GetDirectoryEntry( movi_list
).offset
)
588 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
;
592 // new, correct dv2 format
593 offset
= idx1
->aIndex
[ index
].dwOffset
+ RIFF_HEADERSIZE
+ GetDirectoryEntry( movi_list
).offset
;
595 size
= idx1
->aIndex
[ index
].dwSize
;
604 \todo we actually don't need the frame here, we could use just a void pointer
605 \param frame a reference to the frame object that will receive the frame data
606 \param frameNum the frame number to read
607 \return 0 if the frame could be read, -1 otherwise
610 int AVIFile
::GetDVFrame( uint8_t *data
, int frameNum
)
615 if ( GetDVFrameInfo( offset
, size
, frameNum
) != 0 || size
< 0 )
617 pthread_mutex_lock( &file_mutex
);
618 fail_if( lseek( fd
, offset
, SEEK_SET
) == ( off_t
) - 1 );
619 fail_neg( read( fd
, data
, size
) );
620 pthread_mutex_unlock( &file_mutex
);
627 \param data a pointer to the audio buffer
628 \param frameNum the frame number to read
629 \param chunkID the ID of the type of chunk we want
630 \return the size the of the frame data, 0 if could not be read
633 int AVIFile
::getFrame( void *data
, int frameNum
, FOURCC chunkID
)
638 if ( GetFrameInfo( offset
, size
, frameNum
, chunkID
) != 0 )
640 fail_if( lseek( fd
, offset
, SEEK_SET
) == ( off_t
) - 1 );
641 fail_neg( read( fd
, data
, size
) );
646 int AVIFile
::GetTotalFrames() const
648 return mainHdr
.dwTotalFrames
;
652 /** prints out a directory entry in text form
654 Every subclass of RIFFFile is supposed to override this function
655 and to implement it for the entry types it knows about. For all
656 other entry types it should call its parent::PrintDirectoryData.
658 \todo use 64 bit routines
659 \param entry the entry to print
662 void AVIFile
::PrintDirectoryEntryData( const RIFFDirEntry
&entry
) const
664 static FOURCC lastStreamType
= make_fourcc( " " );
666 if ( entry
.type
== make_fourcc( "avih" ) )
670 MainAVIHeader main_avi_header
;
672 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
673 fail_neg( read( fd
, &main_avi_header
, sizeof( MainAVIHeader
) ) );
675 cout
<< " dwMicroSecPerFrame: " << ( int ) main_avi_header
.dwMicroSecPerFrame
<< endl
676 << " dwMaxBytesPerSec: " << ( int ) main_avi_header
.dwMaxBytesPerSec
<< endl
677 << " dwPaddingGranularity: " << ( int ) main_avi_header
.dwPaddingGranularity
<< endl
678 << " dwFlags: " << ( int ) main_avi_header
.dwFlags
<< endl
679 << " dwTotalFrames: " << ( int ) main_avi_header
.dwTotalFrames
<< endl
680 << " dwInitialFrames: " << ( int ) main_avi_header
.dwInitialFrames
<< endl
681 << " dwStreams: " << ( int ) main_avi_header
.dwStreams
<< endl
682 << " dwSuggestedBufferSize: " << ( int ) main_avi_header
.dwSuggestedBufferSize
<< endl
683 << " dwWidth: " << ( int ) main_avi_header
.dwWidth
<< endl
684 << " dwHeight: " << ( int ) main_avi_header
.dwHeight
<< endl
;
685 for ( i
= 0; i
< 4; ++i
)
686 cout
<< " dwReserved[" << i
<< "]: " << ( int ) main_avi_header
.dwReserved
[ i
] << endl
;
689 else if ( entry
.type
== make_fourcc( "strh" ) )
692 AVIStreamHeader avi_stream_header
;
694 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
695 fail_neg( read( fd
, &avi_stream_header
, sizeof( AVIStreamHeader
) ) );
697 lastStreamType
= avi_stream_header
.fccType
;
699 cout
<< " fccType: '"
700 << ((char *)&avi_stream_header
.fccType
)[0]
701 << ((char *)&avi_stream_header
.fccType
)[1]
702 << ((char *)&avi_stream_header
.fccType
)[2]
703 << ((char *)&avi_stream_header
.fccType
)[3]
706 << ((char *)&avi_stream_header
.fccHandler
)[0]
707 << ((char *)&avi_stream_header
.fccHandler
)[1]
708 << ((char *)&avi_stream_header
.fccHandler
)[2]
709 << ((char *)&avi_stream_header
.fccHandler
)[3]
711 << " dwFlags: " << ( int ) avi_stream_header
.dwFlags
<< endl
712 << " wPriority: " << ( int ) avi_stream_header
.wPriority
<< endl
713 << " wLanguage: " << ( int ) avi_stream_header
.wLanguage
<< endl
714 << " dwInitialFrames: " << ( int ) avi_stream_header
.dwInitialFrames
<< endl
715 << " dwScale: " << ( int ) avi_stream_header
.dwScale
<< endl
716 << " dwRate: " << ( int ) avi_stream_header
.dwRate
<< endl
717 << " dwLength: " << ( int ) avi_stream_header
.dwLength
<< endl
718 << " dwQuality: " << ( int ) avi_stream_header
.dwQuality
<< endl
719 << " dwSampleSize: " << ( int ) avi_stream_header
.dwSampleSize
<< endl
;
722 else if ( entry
.type
== make_fourcc( "indx" ) )
726 AVISuperIndex avi_super_index
;
728 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
729 fail_neg( read( fd
, &avi_super_index
, sizeof( AVISuperIndex
) ) );
731 cout
<< " wLongsPerEntry: " << ( int ) avi_super_index
.wLongsPerEntry
733 << " bIndexSubType: " << ( int ) avi_super_index
.bIndexSubType
<< endl
734 << " bIndexType: " << ( int ) avi_super_index
.bIndexType
<< endl
735 << " nEntriesInUse: " << ( int ) avi_super_index
.nEntriesInUse
<< endl
737 << ((char *)&avi_super_index
.dwChunkId
)[0]
738 << ((char *)&avi_super_index
.dwChunkId
)[1]
739 << ((char *)&avi_super_index
.dwChunkId
)[2]
740 << ((char *)&avi_super_index
.dwChunkId
)[3]
742 << " dwReserved[0]: " << ( int ) avi_super_index
.dwReserved
[ 0 ] << endl
743 << " dwReserved[1]: " << ( int ) avi_super_index
.dwReserved
[ 1 ] << endl
744 << " dwReserved[2]: " << ( int ) avi_super_index
.dwReserved
[ 2 ] << endl
;
745 for ( i
= 0; i
< avi_super_index
.nEntriesInUse
; ++i
)
747 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
748 << ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex
<< avi_super_index
.aIndex
[ i
].qwOffset
<< endl
749 << " dwSize : 0x" << setw( 8 ) << avi_super_index
.aIndex
[ i
].dwSize
<< endl
750 << " dwDuration : " << dec
<< avi_super_index
.aIndex
[ i
].dwDuration
<< endl
;
753 else if ( entry
.type
== make_fourcc( "strf" ) )
755 if ( lastStreamType
== make_fourcc( "auds" ) )
757 WAVEFORMATEX waveformatex
;
758 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
759 fail_neg( read( fd
, &waveformatex
, sizeof( WAVEFORMATEX
) ) );
760 cout
<< " waveformatex.wFormatTag : " << waveformatex
.wFormatTag
<< endl
;
761 cout
<< " waveformatex.nChannels : " << waveformatex
.nChannels
<< endl
;
762 cout
<< " waveformatex.nSamplesPerSec : " << waveformatex
.nSamplesPerSec
<< endl
;
763 cout
<< " waveformatex.nAvgBytesPerSec: " << waveformatex
.nAvgBytesPerSec
<< endl
;
764 cout
<< " waveformatex.nBlockAlign : " << waveformatex
.nBlockAlign
<< endl
;
765 cout
<< " waveformatex.wBitsPerSample : " << waveformatex
.wBitsPerSample
<< endl
;
766 cout
<< " waveformatex.cbSize : " << waveformatex
.cbSize
<< endl
;
768 else if ( lastStreamType
== make_fourcc( "vids" ) )
770 BITMAPINFOHEADER bitmapinfo
;
771 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
772 fail_neg( read( fd
, &bitmapinfo
, sizeof( BITMAPINFOHEADER
) ) );
773 cout
<< " bitmapinfo.biSize : " << bitmapinfo
.biSize
<< endl
;
774 cout
<< " bitmapinfo.biWidth : " << bitmapinfo
.biWidth
<< endl
;
775 cout
<< " bitmapinfo.biHeight : " << bitmapinfo
.biHeight
<< endl
;
776 cout
<< " bitmapinfo.biPlanes : " << bitmapinfo
.biPlanes
<< endl
;
777 cout
<< " bitmapinfo.biBitCount : " << bitmapinfo
.biBitCount
<< endl
;
778 cout
<< " bitmapinfo.biCompression : " << bitmapinfo
.biCompression
<< endl
;
779 cout
<< " bitmapinfo.biSizeImage : " << bitmapinfo
.biSizeImage
<< endl
;
780 cout
<< " bitmapinfo.biXPelsPerMeter: " << bitmapinfo
.biXPelsPerMeter
<< endl
;
781 cout
<< " bitmapinfo.biYPelsPerMeter: " << bitmapinfo
.biYPelsPerMeter
<< endl
;
782 cout
<< " bitmapinfo.biClrUsed : " << bitmapinfo
.biClrUsed
<< endl
;
783 cout
<< " bitmapinfo.biClrImportant : " << bitmapinfo
.biClrImportant
<< endl
;
785 else if ( lastStreamType
== make_fourcc( "iavs" ) )
788 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
789 fail_neg( read( fd
, &dvinfo
, sizeof( DVINFO
) ) );
790 cout
<< " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxSrc
<< endl
;
791 cout
<< " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxCtl
<< endl
;
792 cout
<< " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxSrc1
<< endl
;
793 cout
<< " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVAAuxCtl1
<< endl
;
794 cout
<< " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVVAuxSrc
<< endl
;
795 cout
<< " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< dvinfo
.dwDVVAuxCtl
<< endl
;
799 /* This is the Standard Index. It is an array of offsets and
800 sizes relative to some start offset. */
802 else if ( ( entry
.type
== make_fourcc( "ix00" ) ) || ( entry
.type
== make_fourcc( "ix01" ) ) )
806 AVIStdIndex avi_std_index
;
808 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
809 fail_neg( read( fd
, &avi_std_index
, sizeof( AVIStdIndex
) ) );
811 cout
<< " wLongsPerEntry: " << ( int ) avi_std_index
.wLongsPerEntry
813 << " bIndexSubType: " << ( int ) avi_std_index
.bIndexSubType
<< endl
814 << " bIndexType: " << ( int ) avi_std_index
.bIndexType
<< endl
815 << " nEntriesInUse: " << ( int ) avi_std_index
.nEntriesInUse
<< endl
817 << ((char *)&avi_std_index
.dwChunkId
)[0]
818 << ((char *)&avi_std_index
.dwChunkId
)[1]
819 << ((char *)&avi_std_index
.dwChunkId
)[2]
820 << ((char *)&avi_std_index
.dwChunkId
)[3]
822 << " qwBaseOffset: 0x" << setw( 12 ) << hex
<< avi_std_index
.qwBaseOffset
<< endl
823 << " dwReserved: " << dec
<< ( int ) avi_std_index
.dwReserved
<< endl
;
824 for ( i
= 0; i
< avi_std_index
.nEntriesInUse
; ++i
)
826 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
827 << ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex
<< avi_std_index
.aIndex
[ i
].dwOffset
828 << " (0x" << setw( 12 ) << avi_std_index
.qwBaseOffset
+ avi_std_index
.aIndex
[ i
].dwOffset
<< ')' << endl
829 << " dwSize : 0x" << setw( 8 ) << avi_std_index
.aIndex
[ i
].dwSize
<< dec
<< endl
;
833 else if ( entry
.type
== make_fourcc( "idx1" ) )
837 int numEntries
= entry
.length
/ sizeof( int ) / 4;
838 DWORD
*idx1
= new DWORD
[ numEntries
* 4 ];
839 // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
841 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
842 fail_neg( read( fd
, idx1
, entry
.length
) );
844 for ( i
= 0; i
< numEntries
; ++i
)
847 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
<< setfill( '0' ) << ": dwChunkId : '"
848 << ((char *)&idx1
[ i
* 4 + 0 ])[0]
849 << ((char *)&idx1
[ i
* 4 + 0 ])[1]
850 << ((char *)&idx1
[ i
* 4 + 0 ])[2]
851 << ((char *)&idx1
[ i
* 4 + 0 ])[3]
853 << " dwType : 0x" << setw( 8 ) << hex
<< idx1
[ i
* 4 + 1 ] << endl
854 << " dwOffset : 0x" << setw( 8 ) << idx1
[ i
* 4 + 2 ] << endl
855 // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
856 << " dwSize : 0x" << setw( 8 ) << idx1
[ i
* 4 + 3 ] << dec
<< endl
;
861 else if ( entry
.type
== make_fourcc( "dmlh" ) )
864 int numEntries
= entry
.length
/ sizeof( int );
865 DWORD
*dmlh
= new DWORD
[ numEntries
];
867 fail_if( lseek( fd
, entry
.offset
, SEEK_SET
) == ( off_t
) - 1 );
868 fail_neg( read( fd
, dmlh
, entry
.length
) );
870 for ( i
= 0; i
< numEntries
; ++i
)
872 cout
<< ' ' << setw( 4 ) << setfill( ' ' ) << i
<< setfill( '0' ) << ": "
873 << " dwTotalFrames: 0x" << setw( 8 ) << hex
<< dmlh
[ i
]
874 << " (" << dec
<< dmlh
[ i
] << ")" << endl
;
881 /** If this is not a movi list, read its contents
885 void AVIFile
::ParseList( int parent
)
894 /* Read in the chunk header (type and length). */
895 fail_neg( read( fd
, &type
, sizeof( type
) ) );
896 fail_neg( read( fd
, &length
, sizeof( length
) ) );
900 /* The contents of the list starts here. Obtain its offset. The list
901 name (4 bytes) is already part of the contents). */
903 pos
= lseek( fd
, 0, SEEK_CUR
);
904 fail_if( pos
== ( off_t
) - 1 );
905 fail_neg( read( fd
, &name
, sizeof( name
) ) );
907 /* if we encounter a movi list, do not read it. It takes too much time
908 and we don't need it anyway. */
910 if ( name
!= make_fourcc( "movi" ) )
914 /* Add an entry for this list. */
915 list
= AddDirectoryEntry( type
, name
, sizeof( name
), parent
);
917 /* Read in any chunks contained in this list. This list is the
918 parent for all chunks it contains. */
920 listEnd
= pos
+ length
;
921 while ( pos
< listEnd
)
924 pos
= lseek( fd
, 0, SEEK_CUR
);
925 fail_if( pos
== ( off_t
) - 1 );
930 /* Add an entry for this list. */
932 movi_list
= AddDirectoryEntry( type
, name
, length
, parent
);
934 pos
= lseek( fd
, length
- 4, SEEK_CUR
);
935 fail_if( pos
== ( off_t
) - 1 );
940 void AVIFile
::ParseRIFF()
942 RIFFFile
::ParseRIFF();
944 avih_chunk
= FindDirectoryEntry( make_fourcc( "avih" ) );
945 if ( avih_chunk
!= -1 )
946 ReadChunk( avih_chunk
, ( void* ) & mainHdr
);
950 void AVIFile
::ReadIndex()
952 indx_chunk
[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
953 if ( indx_chunk
[ 0 ] != -1 )
955 ReadChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
956 index_type
= AVI_LARGE_INDEX
;
958 /* recalc number of frames from each index */
959 mainHdr
.dwTotalFrames
= 0;
961 i
< indx
[ 0 ] ->nEntriesInUse
;
962 mainHdr
.dwTotalFrames
+= indx
[ 0 ] ->aIndex
[ i
++ ].dwDuration
)
966 idx1_chunk
= FindDirectoryEntry( make_fourcc( "idx1" ) );
967 if ( idx1_chunk
!= -1 )
969 ReadChunk( idx1_chunk
, ( void* ) idx1
);
970 idx1
->nEntriesInUse
= GetDirectoryEntry( idx1_chunk
).length
/ 16;
971 index_type
= AVI_SMALL_INDEX
;
973 /* recalc number of frames from the simple index */
974 int frameNumIndex
= 0;
975 FOURCC chunkID1
= make_fourcc( "00dc" );
976 FOURCC chunkID2
= make_fourcc( "00db" );
977 for ( int i
= 0; i
< idx1
->nEntriesInUse
; ++i
)
979 if ( idx1
->aIndex
[ i
].dwChunkId
== chunkID1
||
980 idx1
->aIndex
[ i
].dwChunkId
== chunkID2
)
985 mainHdr
.dwTotalFrames
= frameNumIndex
;
991 void AVIFile
::FlushIndx( int stream
)
1000 /* Write out the previous index. When this function is
1001 entered for the first time, there is no index to
1002 write. Note: this may be an expensive operation
1003 because of a time consuming seek to the former file
1006 if ( ix_chunk
[ stream
] != -1 )
1007 WriteChunk( ix_chunk
[ stream
], ix
[ stream
] );
1009 /* make a new ix chunk. */
1012 type
= make_fourcc( "ix00" );
1014 type
= make_fourcc( "ix01" );
1015 ix_chunk
[ stream
] = AddDirectoryEntry( type
, 0, sizeof( AVIStdIndex
), movi_list
);
1016 GetDirectoryEntry( ix_chunk
[ stream
], type
, name
, length
, offset
, parent
);
1018 /* fill out all required fields. The offsets in the
1019 array are relative to qwBaseOffset, so fill in the
1020 offset to the next free location in the file
1023 ix
[ stream
] ->wLongsPerEntry
= 2;
1024 ix
[ stream
] ->bIndexSubType
= 0;
1025 ix
[ stream
] ->bIndexType
= KINO_AVI_INDEX_OF_CHUNKS
;
1026 ix
[ stream
] ->nEntriesInUse
= 0;
1027 ix
[ stream
] ->dwChunkId
= indx
[ stream
] ->dwChunkId
;
1028 ix
[ stream
] ->qwBaseOffset
= offset
+ length
;
1029 ix
[ stream
] ->dwReserved
= 0;
1031 for ( i
= 0; i
< IX00_INDEX_SIZE
; ++i
)
1033 ix
[ stream
] ->aIndex
[ i
].dwOffset
= 0;
1034 ix
[ stream
] ->aIndex
[ i
].dwSize
= 0;
1037 /* add a reference to this new index in our super
1040 i
= indx
[ stream
] ->nEntriesInUse
++;
1041 indx
[ stream
] ->aIndex
[ i
].qwOffset
= offset
- RIFF_HEADERSIZE
;
1042 indx
[ stream
] ->aIndex
[ i
].dwSize
= length
+ RIFF_HEADERSIZE
;
1043 indx
[ stream
] ->aIndex
[ i
].dwDuration
= 0;
1047 void AVIFile
::UpdateIndx( int stream
, int chunk
, int duration
)
1056 /* update the appropiate entry in the super index. It reflects
1057 the number of frames in the referenced index. */
1059 i
= indx
[ stream
] ->nEntriesInUse
- 1;
1060 indx
[ stream
] ->aIndex
[ i
].dwDuration
+= duration
;
1062 /* update the standard index. Calculate the file position of
1065 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
1067 indx
[ stream
] ->dwChunkId
= type
;
1068 i
= ix
[ stream
] ->nEntriesInUse
++;
1069 ix
[ stream
] ->aIndex
[ i
].dwOffset
= offset
- ix
[ stream
] ->qwBaseOffset
;
1070 ix
[ stream
] ->aIndex
[ i
].dwSize
= length
;
1074 void AVIFile
::UpdateIdx1( int chunk
, int flags
)
1076 if ( idx1
->nEntriesInUse
< 20000 )
1084 GetDirectoryEntry( chunk
, type
, name
, length
, offset
, parent
);
1086 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwChunkId
= type
;
1087 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwFlags
= flags
;
1088 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwOffset
= offset
- GetDirectoryEntry( movi_list
).offset
- RIFF_HEADERSIZE
;
1089 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwSize
= length
;
1090 idx1
->nEntriesInUse
++;
1094 bool AVIFile
::verifyStreamFormat( FOURCC type
)
1097 AVIStreamHeader avi_stream_header
;
1098 BITMAPINFOHEADER bih
;
1099 FOURCC strh
= make_fourcc( "strh" );
1100 FOURCC strf
= make_fourcc( "strf" );
1102 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1104 ReadChunk( i
, ( void* ) & avi_stream_header
);
1105 if ( avi_stream_header
.fccHandler
== type
)
1109 while ( ( i
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1111 ReadChunk( i
, ( void* ) & bih
);
1112 if ( ( FOURCC
) bih
.biCompression
== type
)
1119 bool AVIFile
::verifyStream( FOURCC type
)
1122 AVIStreamHeader avi_stream_header
;
1123 FOURCC strh
= make_fourcc( "strh" );
1125 while ( ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1127 ReadChunk( i
, ( void* ) & avi_stream_header
);
1128 if ( avi_stream_header
.fccType
== type
)
1134 bool AVIFile
::isOpenDML( void )
1137 FOURCC dmlh
= make_fourcc( "dmlh" );
1139 while ( ( i
= FindDirectoryEntry( dmlh
, j
++ ) ) != -1 )
1146 AVI1File
::AVI1File() : AVIFile()
1150 AVI1File
::~AVI1File()
1154 /* Initialize the AVI structure to its initial state, either for PAL
1157 void AVI1File
::Init( int format
, int sampleFrequency
, int indexType
)
1166 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1168 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1173 mainHdr
.dwWidth
= 720;
1174 mainHdr
.dwHeight
= 576;
1176 streamHdr
[ 0 ].dwScale
= 1;
1177 streamHdr
[ 0 ].dwRate
= 25;
1178 streamHdr
[ 0 ].dwSuggestedBufferSize
= 144008;
1180 /* initialize the 'strf' chunk */
1182 /* Meaning of the DV stream format chunk per Microsoft
1184 Specifies the Audio Auxiliary Data Source Pack for the first audio block
1185 (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
1186 a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
1187 of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
1188 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1189 Consumer-use Digital VCRs.
1191 Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
1192 frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
1193 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1194 Consumer-use Digital VCRs.
1196 Specifies the Audio Auxiliary Data Source Pack for the second audio block
1197 (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
1199 Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
1201 Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
1202 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1203 Consumer-use Digital VCRs.
1205 Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
1206 Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
1207 Consumer-use Digital VCRs.
1209 Reserved. Set this array to zero.
1212 dvinfo
.dwDVAAuxSrc
= 0xd1e030d0;
1213 dvinfo
.dwDVAAuxCtl
= 0xffa0cf3f;
1214 dvinfo
.dwDVAAuxSrc1
= 0xd1e03fd0;
1215 dvinfo
.dwDVAAuxCtl1
= 0xffa0cf3f;
1216 dvinfo
.dwDVVAuxSrc
= 0xff20ffff;
1217 dvinfo
.dwDVVAuxCtl
= 0xfffdc83f;
1218 dvinfo
.dwDVReserved
[ 0 ] = 0;
1219 dvinfo
.dwDVReserved
[ 1 ] = 0;
1223 mainHdr
.dwWidth
= 720;
1224 mainHdr
.dwHeight
= 480;
1226 streamHdr
[ 0 ].dwScale
= 1001;
1227 streamHdr
[ 0 ].dwRate
= 30000;
1228 streamHdr
[ 0 ].dwSuggestedBufferSize
= 120008;
1230 /* initialize the 'strf' chunk */
1231 dvinfo
.dwDVAAuxSrc
= 0xc0c000c0;
1232 dvinfo
.dwDVAAuxCtl
= 0xffa0cf3f;
1233 dvinfo
.dwDVAAuxSrc1
= 0xc0c001c0;
1234 dvinfo
.dwDVAAuxCtl1
= 0xffa0cf3f;
1235 dvinfo
.dwDVVAuxSrc
= 0xff80ffff;
1236 dvinfo
.dwDVVAuxCtl
= 0xfffcc83f;
1237 dvinfo
.dwDVReserved
[ 0 ] = 0;
1238 dvinfo
.dwDVReserved
[ 1 ] = 0;
1241 default: /* no default allowed */
1246 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00__" );
1248 /* Initialize the 'strh' chunk */
1250 streamHdr
[ 0 ].fccType
= make_fourcc( "iavs" );
1251 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1252 streamHdr
[ 0 ].dwFlags
= 0;
1253 streamHdr
[ 0 ].wPriority
= 0;
1254 streamHdr
[ 0 ].wLanguage
= 0;
1255 streamHdr
[ 0 ].dwInitialFrames
= 0;
1256 streamHdr
[ 0 ].dwStart
= 0;
1257 streamHdr
[ 0 ].dwLength
= 0;
1258 streamHdr
[ 0 ].dwQuality
= 0;
1259 streamHdr
[ 0 ].dwSampleSize
= 0;
1260 streamHdr
[ 0 ].rcFrame
.top
= 0;
1261 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1262 streamHdr
[ 0 ].rcFrame
.left
= 0;
1263 streamHdr
[ 0 ].rcFrame
.right
= 0;
1265 /* This is a simple directory structure setup. For details see the
1266 "OpenDML AVI File Format Extensions" document.
1268 An AVI file contains basically two types of objects, a
1269 "chunk" and a "list" object. The list object contains any
1270 number of chunks. Since a list is also a chunk, it is
1271 possible to create a hierarchical "list of lists"
1274 Every AVI file starts with a "RIFF" object, which is a list
1275 of several other required objects. The actual DV data is
1276 contained in a "movi" list, each frame is in its own chunk.
1278 Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
1279 chunk of less than 1 GByte size per file. The current
1280 format which allow for almost arbitrary sizes can contain
1281 several RIFF chunks of less than 1 GByte size. Old software
1282 however would only deal with the first RIFF chunk.
1284 Note that the first entry (FILE) isn´t actually part
1285 of the AVI file. I use this (pseudo-) directory entry to
1286 keep track of the RIFF chunks and their positions in the
1290 /* Create the container directory entry */
1292 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1294 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1296 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE
, file_list
);
1297 hdrl_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE
, riff_list
);
1298 avih_chunk
= AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader
), hdrl_list
);
1299 strl_list
[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1300 strh_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 0 ] );
1301 strf_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo
), strl_list
[ 0 ] );
1302 if ( index_type
& AVI_LARGE_INDEX
)
1303 indx_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 0 ] );
1305 odml_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE
, hdrl_list
);
1306 dmlh_chunk
= AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list
);
1308 /* align movi list to block */
1309 GetDirectoryEntry( hdrl_list
, type
, name
, length
, offset
, parent
);
1310 num_blocks
= length
/ PADDING_SIZE
+ 1;
1311 length
= num_blocks
* PADDING_SIZE
- length
- 5 * RIFF_HEADERSIZE
; // why 5?
1312 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1314 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1316 /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
1323 /* Write a DV video frame. This is somewhat complex... */
1326 bool AVI1File
::WriteFrame( const Frame
&frame
)
1337 /* exit if no large index and 1GB reached */
1338 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
1341 /* Check if we need a new ix00 Standard Index. It has a
1342 capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1343 number, we need a new index. The new ix00 chunk is also
1344 part of the movi list. */
1346 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1349 /* Write the DV frame data.
1351 Make a new 00__ chunk for the new frame, write out the
1354 frame_chunk
= AddDirectoryEntry( make_fourcc( "00__" ), 0, frame
.GetFrameSize(), movi_list
);
1355 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1357 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1358 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1360 WriteChunk( frame_chunk
, frame
.data
);
1361 // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1362 // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1363 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1364 // WriteChunk(junk_chunk, g_zeroes);
1366 if ( index_type
& AVI_LARGE_INDEX
)
1367 UpdateIndx( 0, frame_chunk
, 1 );
1368 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1369 UpdateIdx1( frame_chunk
, 0x10 );
1371 /* update some variables with the new frame count. */
1374 ++mainHdr
.dwTotalFrames
;
1375 ++streamHdr
[ 0 ].dwLength
;
1378 /* Find out if the current riff list is close to 1 GByte in
1379 size. If so, start a new (extended) RIFF. The only allowed
1380 item in the new RIFF chunk is a movi list (with video
1381 frames and indexes as usual). */
1383 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1384 if ( length
> 0x3f000000 )
1386 /* write idx1 only once and before end of first GB */
1387 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1389 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1390 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1392 isUpdateIdx1
= false;
1394 if ( index_type
& AVI_LARGE_INDEX
)
1396 /* pad out to 1GB */
1397 //GetDirectoryEntry(riff_list, type, name, length, offset, parent);
1398 //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
1399 //WriteChunk(junk_chunk, g_zeroes);
1401 /* padding for alignment */
1402 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1403 num_blocks
= ( length
+ 4 * RIFF_HEADERSIZE
) / PADDING_SIZE
+ 1;
1404 length
= ( num_blocks
* PADDING_SIZE
) - length
- 4 * RIFF_HEADERSIZE
- 2 * RIFF_LISTSIZE
;
1407 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1408 WriteChunk( junk_chunk
, g_zeroes
);
1411 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE
, file_list
);
1412 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1419 void AVI1File
::WriteRIFF()
1422 WriteChunk( avih_chunk
, ( void* ) & mainHdr
);
1423 WriteChunk( strh_chunk
[ 0 ], ( void* ) & streamHdr
[ 0 ] );
1424 WriteChunk( strf_chunk
[ 0 ], ( void* ) & dvinfo
);
1425 WriteChunk( dmlh_chunk
, ( void* ) & dmlh
);
1427 if ( index_type
& AVI_LARGE_INDEX
)
1429 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1430 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1433 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1435 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1436 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1439 RIFFFile
::WriteRIFF();
1443 AVI2File
::AVI2File() : AVIFile()
1447 AVI2File
::~AVI2File()
1451 /* Initialize the AVI structure to its initial state, either for PAL
1454 void AVI2File
::Init( int format
, int sampleFrequency
, int indexType
)
1463 assert( ( format
== AVI_PAL
) || ( format
== AVI_NTSC
) );
1465 AVIFile
::Init( format
, sampleFrequency
, indexType
);
1471 mainHdr
.dwStreams
= 2;
1472 mainHdr
.dwWidth
= 720;
1473 mainHdr
.dwHeight
= 576;
1475 /* Initialize the 'strh' chunk */
1477 streamHdr
[ 0 ].fccType
= make_fourcc( "vids" );
1478 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1479 streamHdr
[ 0 ].dwFlags
= 0;
1480 streamHdr
[ 0 ].wPriority
= 0;
1481 streamHdr
[ 0 ].wLanguage
= 0;
1482 streamHdr
[ 0 ].dwInitialFrames
= 0;
1483 streamHdr
[ 0 ].dwScale
= 1;
1484 streamHdr
[ 0 ].dwRate
= 25;
1485 streamHdr
[ 0 ].dwStart
= 0;
1486 streamHdr
[ 0 ].dwLength
= 0;
1487 streamHdr
[ 0 ].dwSuggestedBufferSize
= 144008;
1488 streamHdr
[ 0 ].dwQuality
= -1;
1489 streamHdr
[ 0 ].dwSampleSize
= 0;
1490 streamHdr
[ 0 ].rcFrame
.top
= 0;
1491 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1492 streamHdr
[ 0 ].rcFrame
.left
= 0;
1493 streamHdr
[ 0 ].rcFrame
.right
= 0;
1495 bitmapinfo
.biSize
= sizeof( bitmapinfo
);
1496 bitmapinfo
.biWidth
= 720;
1497 bitmapinfo
.biHeight
= 576;
1498 bitmapinfo
.biPlanes
= 1;
1499 bitmapinfo
.biBitCount
= 24;
1500 bitmapinfo
.biCompression
= make_fourcc( "dvsd" );
1501 bitmapinfo
.biSizeImage
= 144000;
1502 bitmapinfo
.biXPelsPerMeter
= 0;
1503 bitmapinfo
.biYPelsPerMeter
= 0;
1504 bitmapinfo
.biClrUsed
= 0;
1505 bitmapinfo
.biClrImportant
= 0;
1507 streamHdr
[ 1 ].fccType
= make_fourcc( "auds" );
1508 streamHdr
[ 1 ].fccHandler
= 0;
1509 streamHdr
[ 1 ].dwFlags
= 0;
1510 streamHdr
[ 1 ].wPriority
= 0;
1511 streamHdr
[ 1 ].wLanguage
= 0;
1512 streamHdr
[ 1 ].dwInitialFrames
= 0;
1513 streamHdr
[ 1 ].dwScale
= 2 * 2;
1514 streamHdr
[ 1 ].dwRate
= sampleFrequency
* 2 * 2;
1515 streamHdr
[ 1 ].dwStart
= 0;
1516 streamHdr
[ 1 ].dwLength
= 0;
1517 streamHdr
[ 1 ].dwSuggestedBufferSize
= 8192;
1518 streamHdr
[ 1 ].dwQuality
= -1;
1519 streamHdr
[ 1 ].dwSampleSize
= 2 * 2;
1520 streamHdr
[ 1 ].rcFrame
.top
= 0;
1521 streamHdr
[ 1 ].rcFrame
.bottom
= 0;
1522 streamHdr
[ 1 ].rcFrame
.left
= 0;
1523 streamHdr
[ 1 ].rcFrame
.right
= 0;
1528 mainHdr
.dwTotalFrames
= 0;
1529 mainHdr
.dwStreams
= 2;
1530 mainHdr
.dwWidth
= 720;
1531 mainHdr
.dwHeight
= 480;
1533 /* Initialize the 'strh' chunk */
1535 streamHdr
[ 0 ].fccType
= make_fourcc( "vids" );
1536 streamHdr
[ 0 ].fccHandler
= make_fourcc( "dvsd" );
1537 streamHdr
[ 0 ].dwFlags
= 0;
1538 streamHdr
[ 0 ].wPriority
= 0;
1539 streamHdr
[ 0 ].wLanguage
= 0;
1540 streamHdr
[ 0 ].dwInitialFrames
= 0;
1541 streamHdr
[ 0 ].dwScale
= 1001;
1542 streamHdr
[ 0 ].dwRate
= 30000;
1543 streamHdr
[ 0 ].dwStart
= 0;
1544 streamHdr
[ 0 ].dwLength
= 0;
1545 streamHdr
[ 0 ].dwSuggestedBufferSize
= 120008;
1546 streamHdr
[ 0 ].dwQuality
= -1;
1547 streamHdr
[ 0 ].dwSampleSize
= 0;
1548 streamHdr
[ 0 ].rcFrame
.top
= 0;
1549 streamHdr
[ 0 ].rcFrame
.bottom
= 0;
1550 streamHdr
[ 0 ].rcFrame
.left
= 0;
1551 streamHdr
[ 0 ].rcFrame
.right
= 0;
1553 bitmapinfo
.biSize
= sizeof( bitmapinfo
);
1554 bitmapinfo
.biWidth
= 720;
1555 bitmapinfo
.biHeight
= 480;
1556 bitmapinfo
.biPlanes
= 1;
1557 bitmapinfo
.biBitCount
= 24;
1558 bitmapinfo
.biCompression
= make_fourcc( "dvsd" );
1559 bitmapinfo
.biSizeImage
= 120000;
1560 bitmapinfo
.biXPelsPerMeter
= 0;
1561 bitmapinfo
.biYPelsPerMeter
= 0;
1562 bitmapinfo
.biClrUsed
= 0;
1563 bitmapinfo
.biClrImportant
= 0;
1565 streamHdr
[ 1 ].fccType
= make_fourcc( "auds" );
1566 streamHdr
[ 1 ].fccHandler
= 0;
1567 streamHdr
[ 1 ].dwFlags
= 0;
1568 streamHdr
[ 1 ].wPriority
= 0;
1569 streamHdr
[ 1 ].wLanguage
= 0;
1570 streamHdr
[ 1 ].dwInitialFrames
= 1;
1571 streamHdr
[ 1 ].dwScale
= 2 * 2;
1572 streamHdr
[ 1 ].dwRate
= sampleFrequency
* 2 * 2;
1573 streamHdr
[ 1 ].dwStart
= 0;
1574 streamHdr
[ 1 ].dwLength
= 0;
1575 streamHdr
[ 1 ].dwSuggestedBufferSize
= 8192;
1576 streamHdr
[ 1 ].dwQuality
= 0;
1577 streamHdr
[ 1 ].dwSampleSize
= 2 * 2;
1578 streamHdr
[ 1 ].rcFrame
.top
= 0;
1579 streamHdr
[ 1 ].rcFrame
.bottom
= 0;
1580 streamHdr
[ 1 ].rcFrame
.left
= 0;
1581 streamHdr
[ 1 ].rcFrame
.right
= 0;
1585 waveformatex
.wFormatTag
= 1;
1586 waveformatex
.nChannels
= 2;
1587 waveformatex
.nSamplesPerSec
= sampleFrequency
;
1588 waveformatex
.nAvgBytesPerSec
= sampleFrequency
* 2 * 2;
1589 waveformatex
.nBlockAlign
= 4;
1590 waveformatex
.wBitsPerSample
= 16;
1591 waveformatex
.cbSize
= 0;
1593 file_list
= AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT
);
1595 /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
1597 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE
, file_list
);
1598 hdrl_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE
, riff_list
);
1599 avih_chunk
= AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader
), hdrl_list
);
1601 strl_list
[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1602 strh_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 0 ] );
1603 strf_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER
), strl_list
[ 0 ] );
1604 if ( index_type
& AVI_LARGE_INDEX
)
1606 indx_chunk
[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 0 ] );
1608 indx
[ 0 ] ->dwChunkId
= make_fourcc( "00dc" );
1611 strl_list
[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE
, hdrl_list
);
1612 strh_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader
), strl_list
[ 1 ] );
1613 strf_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX
) - 2, strl_list
[ 1 ] );
1614 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list
[ 1 ] );
1615 if ( index_type
& AVI_LARGE_INDEX
)
1617 indx_chunk
[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex
), strl_list
[ 1 ] );
1619 indx
[ 1 ] ->dwChunkId
= make_fourcc( "01wb" );
1621 odml_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE
, hdrl_list
);
1622 dmlh_chunk
= AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list
);
1625 /* align movi list to block */
1626 GetDirectoryEntry( hdrl_list
, type
, name
, length
, offset
, parent
);
1627 num_blocks
= length
/ PADDING_SIZE
+ 1;
1628 length
= num_blocks
* PADDING_SIZE
- length
- 5 * RIFF_HEADERSIZE
; // why 5 headers?
1629 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1631 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1633 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwChunkId
= make_fourcc( "7Fxx" );
1634 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwFlags
= 0;
1635 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwOffset
= 0;
1636 idx1
->aIndex
[ idx1
->nEntriesInUse
].dwSize
= 0;
1637 idx1
->nEntriesInUse
++;
1641 void AVI2File
::WriteRIFF()
1643 WriteChunk( avih_chunk
, ( void* ) & mainHdr
);
1644 WriteChunk( strh_chunk
[ 0 ], ( void* ) & streamHdr
[ 0 ] );
1645 WriteChunk( strf_chunk
[ 0 ], ( void* ) & bitmapinfo
);
1646 if ( index_type
& AVI_LARGE_INDEX
)
1648 WriteChunk( dmlh_chunk
, ( void* ) & dmlh
);
1649 WriteChunk( indx_chunk
[ 0 ], ( void* ) indx
[ 0 ] );
1650 WriteChunk( ix_chunk
[ 0 ], ( void* ) ix
[ 0 ] );
1652 WriteChunk( strh_chunk
[ 1 ], ( void* ) & streamHdr
[ 1 ] );
1653 WriteChunk( strf_chunk
[ 1 ], ( void* ) & waveformatex
);
1654 if ( index_type
& AVI_LARGE_INDEX
)
1656 WriteChunk( indx_chunk
[ 1 ], ( void* ) indx
[ 1 ] );
1657 WriteChunk( ix_chunk
[ 1 ], ( void* ) ix
[ 1 ] );
1660 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1662 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1663 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1665 RIFFFile
::WriteRIFF();
1669 /** Write a DV video frame
1671 \param frame the frame to write
1675 bool AVI2File
::WriteFrame( const Frame
&frame
)
1680 char soundbuf
[ 20000 ];
1689 /* exit if no large index and 1GB reached */
1690 if ( !( index_type
& AVI_LARGE_INDEX
) && isUpdateIdx1
== false )
1693 /* Check if we need a new ix00 Standard Index. It has a
1694 capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
1695 number, we need a new index. The new ix00 chunk is also
1696 part of the movi list. */
1698 if ( ( index_type
& AVI_LARGE_INDEX
) && ( ( ( streamHdr
[ 0 ].dwLength
- 0 ) % IX00_INDEX_SIZE
) == 0 ) )
1704 /* Write audio data if we have it */
1706 audio_size
= frame
.ExtractAudio( soundbuf
);
1707 if ( audio_size
> 0 )
1709 audio_chunk
= AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size
, movi_list
);
1710 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1712 GetDirectoryEntry( audio_chunk
, type
, name
, length
, offset
, parent
);
1713 ix
[ 1 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1715 WriteChunk( audio_chunk
, soundbuf
);
1716 // num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1717 // length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
1718 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1719 // WriteChunk(junk_chunk, g_zeroes);
1720 if ( index_type
& AVI_LARGE_INDEX
)
1721 UpdateIndx( 1, audio_chunk
, audio_size
/ waveformatex
.nChannels
/ 2 );
1722 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1723 UpdateIdx1( audio_chunk
, 0x00 );
1724 streamHdr
[ 1 ].dwLength
+= audio_size
/ waveformatex
.nChannels
/ 2;
1728 /* Write video data */
1730 frame_chunk
= AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame
.GetFrameSize(), movi_list
);
1731 if ( ( index_type
& AVI_LARGE_INDEX
) && ( streamHdr
[ 0 ].dwLength
% IX00_INDEX_SIZE
) == 0 )
1733 GetDirectoryEntry( frame_chunk
, type
, name
, length
, offset
, parent
);
1734 ix
[ 0 ] ->qwBaseOffset
= offset
- RIFF_HEADERSIZE
;
1736 WriteChunk( frame_chunk
, frame
.data
);
1737 // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
1738 // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
1739 // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
1740 // WriteChunk(junk_chunk, g_zeroes);
1741 if ( index_type
& AVI_LARGE_INDEX
)
1742 UpdateIndx( 0, frame_chunk
, 1 );
1743 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1744 UpdateIdx1( frame_chunk
, 0x10 );
1746 /* update some variables with the new frame count. */
1749 ++mainHdr
.dwTotalFrames
;
1750 ++streamHdr
[ 0 ].dwLength
;
1753 /* Find out if the current riff list is close to 1 GByte in
1754 size. If so, start a new (extended) RIFF. The only allowed
1755 item in the new RIFF chunk is a movi list (with video
1756 frames and indexes as usual). */
1758 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1759 if ( length
> 0x3f000000 )
1762 /* write idx1 only once and before end of first GB */
1763 if ( ( index_type
& AVI_SMALL_INDEX
) && isUpdateIdx1
)
1765 int idx1_chunk
= AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1
->nEntriesInUse
* 16, riff_list
);
1766 WriteChunk( idx1_chunk
, ( void* ) idx1
);
1768 isUpdateIdx1
= false;
1770 if ( index_type
& AVI_LARGE_INDEX
)
1772 /* padding for alignment */
1773 GetDirectoryEntry( riff_list
, type
, name
, length
, offset
, parent
);
1774 num_blocks
= ( length
+ 4 * RIFF_HEADERSIZE
) / PADDING_SIZE
+ 1;
1775 length
= ( num_blocks
* PADDING_SIZE
) - length
- 4 * RIFF_HEADERSIZE
- 2 * RIFF_LISTSIZE
;
1778 junk_chunk
= AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length
, riff_list
);
1779 WriteChunk( junk_chunk
, g_zeroes
);
1782 riff_list
= AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE
, file_list
);
1783 movi_list
= AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE
, riff_list
);
1790 void AVI1File
::setDVINFO( DVINFO
&info
)
1792 // do not do this until debugged audio against DirectShow
1795 dvinfo
.dwDVAAuxSrc
= info
.dwDVAAuxSrc
;
1796 dvinfo
.dwDVAAuxCtl
= info
.dwDVAAuxCtl
;
1797 dvinfo
.dwDVAAuxSrc1
= info
.dwDVAAuxSrc1
;
1798 dvinfo
.dwDVAAuxCtl1
= info
.dwDVAAuxCtl1
;
1799 dvinfo
.dwDVVAuxSrc
= info
.dwDVVAuxSrc
;
1800 dvinfo
.dwDVVAuxCtl
= info
.dwDVVAuxCtl
;
1804 void AVI2File
::setDVINFO( DVINFO
&info
)
1807 void AVIFile
::setFccHandler( FOURCC type
, FOURCC handler
)
1809 for ( int i
= 0; i
< mainHdr
.dwStreams
; i
++ )
1811 if ( streamHdr
[ i
].fccType
== type
)
1814 FOURCC strf
= make_fourcc( "strf" );
1815 BITMAPINFOHEADER bih
;
1817 streamHdr
[ i
].fccHandler
= handler
;
1819 while ( ( k
= FindDirectoryEntry( strf
, j
++ ) ) != -1 )
1821 ReadChunk( k
, ( void* ) & bih
);
1822 bih
.biCompression
= handler
;
1828 bool AVIFile
::getStreamFormat( void* data
, FOURCC type
)
1831 FOURCC strh
= make_fourcc( "strh" );
1832 FOURCC strf
= make_fourcc( "strf" );
1833 AVIStreamHeader avi_stream_header
;
1834 bool result
= false;
1836 while ( ( result
== false ) && ( i
= FindDirectoryEntry( strh
, j
++ ) ) != -1 )
1838 ReadChunk( i
, ( void* ) & avi_stream_header
);
1839 if ( avi_stream_header
.fccType
== type
)
1844 pthread_mutex_lock( &file_mutex
);
1845 fail_neg( read( fd
, &chunkID
, sizeof( FOURCC
) ) );
1846 if ( chunkID
== strf
)
1848 fail_neg( read( fd
, &size
, sizeof( int ) ) );
1849 fail_neg( read( fd
, data
, size
) );
1852 pthread_mutex_unlock( &file_mutex
);