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