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