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