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