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