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