00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025
00026
00027 #include <string>
00028 #include <iostream>
00029 #include <iomanip>
00030
00031 using std::cout;
00032 using std::hex;
00033 using std::dec;
00034 using std::setw;
00035 using std::setfill;
00036 using std::endl;
00037
00038
00039
00040 #include <stdio.h>
00041 #include <fcntl.h>
00042 #include <unistd.h>
00043 #include <assert.h>
00044
00045
00046
00047 #include "error.h"
00048 #include "riff.h"
00049 #include "avi.h"
00050
00051 #define PADDING_SIZE (512)
00052 #define PADDING_1GB (0x40000000)
00053 #define IX00_INDEX_SIZE (4028)
00054 #define IDX1_INDEX_SIZE (20000)
00055
00056 #define AVIF_HASINDEX 0x00000010
00057 #define AVIF_MUSTUSEINDEX 0x00000020
00058 #define AVIF_TRUSTCKTYPE 0x00000800
00059 #define AVIF_ISINTERLEAVED 0x00000100
00060 #define AVIF_WASCAPTUREFILE 0x00010000
00061 #define AVIF_COPYRIGHTED 0x00020000
00062
00063
00064 static char g_zeroes[ PADDING_SIZE ];
00065
00073 AVIFile::AVIFile() : RIFFFile(),
00074 idx1( NULL ), file_list( -1 ), riff_list( -1 ),
00075 hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
00076 index_type( 0 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
00077 {
00078
00079
00080 for ( int i = 0; i < 2; ++i )
00081 {
00082 indx[ i ] = new AVISuperIndex;
00083 memset( indx[ i ], 0, sizeof( AVISuperIndex ) );
00084 ix[ i ] = new AVIStdIndex;
00085 memset( ix[ i ], 0, sizeof( AVIStdIndex ) );
00086 indx_chunk[ i ] = -1;
00087 ix_chunk[ i ] = -1;
00088 strl_list[ i ] = -1;
00089 strh_chunk[ i ] = -1;
00090 strf_chunk[ i ] = -1;
00091 current_ix[ i ] = -1;
00092 }
00093 idx1 = new AVISimpleIndex;
00094 memset( idx1, 0, sizeof( AVISimpleIndex ) );
00095 }
00096
00097
00104 AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi )
00105 {
00106
00107
00108 mainHdr = avi.mainHdr;
00109 idx1 = new AVISimpleIndex;
00110 *idx1 = *avi.idx1;
00111 file_list = avi.file_list;
00112 riff_list = avi.riff_list;
00113 hdrl_list = avi.hdrl_list;
00114 avih_chunk = avi.avih_chunk;
00115 movi_list = avi.movi_list;
00116 junk_chunk = avi.junk_chunk;
00117 idx1_chunk = avi.idx1_chunk;
00118
00119 for ( int i = 0; i < 2; ++i )
00120 {
00121 indx[ i ] = new AVISuperIndex;
00122 *indx[ i ] = *avi.indx[ i ];
00123 ix[ i ] = new AVIStdIndex;
00124 *ix[ i ] = *avi.ix[ i ];
00125 indx_chunk[ i ] = avi.indx_chunk[ i ];
00126 ix_chunk[ i ] = avi.ix_chunk[ i ];
00127 strl_list[ i ] = avi.strl_list[ i ];
00128 strh_chunk[ i ] = avi.strh_chunk[ i ];
00129 strf_chunk[ i ] = avi.strf_chunk[ i ];
00130 current_ix[ i ] = avi.current_ix[ i ];
00131 }
00132
00133 index_type = avi.index_type;
00134
00135 for ( int i = 0; i < 62; ++i )
00136 dmlh[ i ] = avi.dmlh[ i ];
00137
00138 isUpdateIdx1 = avi.isUpdateIdx1;
00139
00140 }
00141
00142
00147 AVIFile& AVIFile::operator=( const AVIFile& avi )
00148 {
00149
00150
00151 if ( this != &avi )
00152 {
00153 RIFFFile::operator=( avi );
00154 mainHdr = avi.mainHdr;
00155 *idx1 = *avi.idx1;
00156 file_list = avi.file_list;
00157 riff_list = avi.riff_list;
00158 hdrl_list = avi.hdrl_list;
00159 avih_chunk = avi.avih_chunk;
00160 movi_list = avi.movi_list;
00161 junk_chunk = avi.junk_chunk;
00162 idx1_chunk = avi.idx1_chunk;
00163
00164 for ( int i = 0; i < 2; ++i )
00165 {
00166 *indx[ i ] = *avi.indx[ i ];
00167 *ix[ i ] = *avi.ix[ i ];
00168 indx_chunk[ i ] = avi.indx_chunk[ i ];
00169 ix_chunk[ i ] = avi.ix_chunk[ i ];
00170 strl_list[ i ] = avi.strl_list[ i ];
00171 strh_chunk[ i ] = avi.strh_chunk[ i ];
00172 strf_chunk[ i ] = avi.strf_chunk[ i ];
00173 current_ix[ i ] = avi.current_ix[ i ];
00174 }
00175
00176 index_type = avi.index_type;
00177
00178 for ( int i = 0; i < 62; ++i )
00179 dmlh[ i ] = avi.dmlh[ i ];
00180
00181 isUpdateIdx1 = avi.isUpdateIdx1;
00182 }
00183 return *this;
00184 }
00185
00186
00191 AVIFile::~AVIFile()
00192 {
00193 for ( int i = 0; i < 2; ++i )
00194 {
00195 delete ix[ i ];
00196 delete indx[ i ];
00197 }
00198 delete idx1;
00199 }
00200
00212 void AVIFile::Init( int format, int sampleFrequency, int indexType )
00213 {
00214 int i, j;
00215
00216 assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
00217
00218 index_type = indexType;
00219
00220 switch ( format )
00221 {
00222 case AVI_PAL:
00223 mainHdr.dwMicroSecPerFrame = 40000;
00224 mainHdr.dwSuggestedBufferSize = 144008;
00225 break;
00226
00227 case AVI_NTSC:
00228 mainHdr.dwMicroSecPerFrame = 33366;
00229 mainHdr.dwSuggestedBufferSize = 120008;
00230 break;
00231
00232 default:
00233 assert( 0 );
00234 break;
00235 }
00236
00237
00238
00239 mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4;
00240 mainHdr.dwPaddingGranularity = PADDING_SIZE;
00241 mainHdr.dwFlags = AVIF_TRUSTCKTYPE;
00242 if ( indexType & AVI_SMALL_INDEX )
00243 mainHdr.dwFlags |= AVIF_HASINDEX;
00244 mainHdr.dwTotalFrames = 0;
00245 mainHdr.dwInitialFrames = 0;
00246 mainHdr.dwStreams = 1;
00247 mainHdr.dwWidth = 0;
00248 mainHdr.dwHeight = 0;
00249 mainHdr.dwReserved[ 0 ] = 0;
00250 mainHdr.dwReserved[ 1 ] = 0;
00251 mainHdr.dwReserved[ 2 ] = 0;
00252 mainHdr.dwReserved[ 3 ] = 0;
00253
00254
00255
00256 for ( int i = 0; i < 8000; ++i )
00257 {
00258 idx1->aIndex[ i ].dwChunkId = 0;
00259 idx1->aIndex[ i ].dwFlags = 0;
00260 idx1->aIndex[ i ].dwOffset = 0;
00261 idx1->aIndex[ i ].dwSize = 0;
00262 }
00263 idx1->nEntriesInUse = 0;
00264
00265
00266
00267 for ( i = 0; i < 2; ++i )
00268 {
00269 indx[ i ] ->wLongsPerEntry = 4;
00270 indx[ i ] ->bIndexSubType = 0;
00271 indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES;
00272 indx[ i ] ->nEntriesInUse = 0;
00273 indx[ i ] ->dwReserved[ 0 ] = 0;
00274 indx[ i ] ->dwReserved[ 1 ] = 0;
00275 indx[ i ] ->dwReserved[ 2 ] = 0;
00276 for ( j = 0; j < 2014; ++j )
00277 {
00278 indx[ i ] ->aIndex[ j ].qwOffset = 0;
00279 indx[ i ] ->aIndex[ j ].dwSize = 0;
00280 indx[ i ] ->aIndex[ j ].dwDuration = 0;
00281 }
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 for ( i = 0; i < 62; ++i )
00291 dmlh[ i ] = 0;
00292
00293
00294 }
00295
00296
00310 int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum )
00311 {
00312 int result = -1;
00313
00314 if ( index_type & AVI_LARGE_INDEX )
00315 {
00316 int i;
00317
00318
00319 for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i );
00320
00321 if ( i != current_ix[ 0 ] )
00322 {
00323 fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
00324 fail_if( ( unsigned int )( indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) > sizeof( AVIStdIndex ) );
00325 fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
00326 current_ix[ 0 ] = i;
00327 }
00328
00329 if ( i < ix[ 0 ] ->nEntriesInUse )
00330 {
00331 offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ]->aIndex[ frameNum ].dwOffset;
00332 size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
00333 result = 0;
00334 }
00335 }
00336 else if ( index_type & AVI_SMALL_INDEX )
00337 {
00338 int index = -1;
00339 int frameNumIndex = 0;
00340 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
00341 {
00342 FOURCC chunkID1 = make_fourcc( "00dc" );
00343 FOURCC chunkID2 = make_fourcc( "00db" );
00344 if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
00345 idx1->aIndex[ i ].dwChunkId == chunkID2 )
00346 {
00347 if ( frameNumIndex == frameNum )
00348 {
00349 index = i;
00350 break;
00351 }
00352 ++frameNumIndex;
00353 }
00354 }
00355 if ( index != -1 )
00356 {
00357
00358 if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
00359 {
00360 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
00361 }
00362 else
00363 {
00364
00365 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
00366 }
00367 size = idx1->aIndex[ index ].dwSize;
00368 result = 0;
00369 }
00370 }
00371 return result;
00372 }
00373
00388 int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID )
00389 {
00390 int result = -1;
00391
00392 if ( index_type & AVI_LARGE_INDEX )
00393 {
00394
00395 for ( int j = 0; j < 2; j++ )
00396 {
00397 if ( indx_chunk[ j ] != -1 && indx[ j ]->dwChunkId == chunkID )
00398 {
00399 int i = 0;
00400 int totalEntries = 0;
00401 int frameNumIndex = frameNum;
00402
00403
00404 for ( i = 0; i < indx[ j ]->nEntriesInUse; ++i )
00405 {
00406 if ( i != current_ix[ j ] )
00407 {
00408 fail_if( lseek( fd, indx[ j ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
00409 fail_if( ( unsigned int )( indx[ j ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) > sizeof( AVIStdIndex ) );
00410 fail_neg( read( fd, ix[ j ], indx[ j ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
00411 current_ix[ j ] = i;
00412 }
00413 totalEntries += ix[ j ]->nEntriesInUse;
00414 if ( frameNum <= totalEntries )
00415 break;
00416 frameNumIndex -= ix[ j ]->nEntriesInUse;
00417 }
00418 if ( i < indx[ j ]->nEntriesInUse )
00419 {
00420 offset = ix[ j ] ->qwBaseOffset + ix[ j ] ->aIndex[ frameNumIndex ].dwOffset;
00421 size = ix[ j ] ->aIndex[ frameNumIndex ].dwSize;
00422 result = 0;
00423 }
00424 break;
00425 }
00426 }
00427 }
00428 else if ( index_type & AVI_SMALL_INDEX )
00429 {
00430 int index = -1;
00431 int frameNumIndex = 0;
00432 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
00433 {
00434 if ( idx1->aIndex[ i ].dwChunkId == chunkID )
00435 {
00436 if ( frameNumIndex == frameNum )
00437 {
00438 index = i;
00439 break;
00440 }
00441 ++frameNumIndex;
00442 }
00443 }
00444 if ( index != -1 )
00445 {
00446
00447 if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
00448 {
00449 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
00450 }
00451 else
00452 {
00453
00454 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
00455 }
00456 size = idx1->aIndex[ index ].dwSize;
00457 result = 0;
00458 }
00459 }
00460 return result;
00461 }
00462
00471 int AVIFile::GetDVFrame( Frame &frame, int frameNum )
00472 {
00473 off_t offset;
00474 int size;
00475
00476 if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 )
00477 return -1;
00478 pthread_mutex_lock( &file_mutex );
00479 fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
00480 fail_neg( read( fd, frame.data, size ) );
00481 pthread_mutex_unlock( &file_mutex );
00482
00483 return 0;
00484 }
00485
00494 int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID )
00495 {
00496 off_t offset;
00497 int size;
00498
00499 if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 )
00500 return 0;
00501 pthread_mutex_lock( &file_mutex );
00502 fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
00503 fail_neg( read( fd, data, size ) );
00504 pthread_mutex_unlock( &file_mutex );
00505
00506 return size;
00507 }
00508
00509 int AVIFile::GetTotalFrames() const
00510 {
00511 return mainHdr.dwTotalFrames;
00512 }
00513
00517 bool AVIFile::isInterleave1to1()
00518 {
00519 bool result = true;
00520 FOURCC dvChunkID1 = make_fourcc( "00dc" );
00521 FOURCC dvChunkID2 = make_fourcc( "00db" );
00522 FOURCC wavChunkID = make_fourcc( "01wb" );
00523
00524
00525 for ( int i = 2; i < ( idx1->nEntriesInUse - 1 ); ++i )
00526 {
00527
00528 if ( ( idx1->aIndex[ i ].dwChunkId == dvChunkID1 ||
00529 idx1->aIndex[ i ].dwChunkId == dvChunkID2 ) )
00530 {
00531
00532 if ( idx1->aIndex[ i-1 ].dwChunkId != wavChunkID || idx1->aIndex[ i+1 ].dwChunkId != wavChunkID)
00533 {
00534 result = false;
00535 break;
00536 }
00537 }
00538 }
00539 return result;
00540 }
00541
00552 void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const
00553 {
00554 static FOURCC lastStreamType = make_fourcc( " " );
00555
00556 if ( entry.type == make_fourcc( "avih" ) )
00557 {
00558
00559 int i;
00560 MainAVIHeader main_avi_header;
00561
00562 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00563 fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) );
00564
00565 cout << " dwMicroSecPerFrame: " << ( int ) main_avi_header.dwMicroSecPerFrame << endl
00566 << " dwMaxBytesPerSec: " << ( int ) main_avi_header.dwMaxBytesPerSec << endl
00567 << " dwPaddingGranularity: " << ( int ) main_avi_header.dwPaddingGranularity << endl
00568 << " dwFlags: " << ( int ) main_avi_header.dwFlags << endl
00569 << " dwTotalFrames: " << ( int ) main_avi_header.dwTotalFrames << endl
00570 << " dwInitialFrames: " << ( int ) main_avi_header.dwInitialFrames << endl
00571 << " dwStreams: " << ( int ) main_avi_header.dwStreams << endl
00572 << " dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl
00573 << " dwWidth: " << ( int ) main_avi_header.dwWidth << endl
00574 << " dwHeight: " << ( int ) main_avi_header.dwHeight << endl;
00575 for ( i = 0; i < 4; ++i )
00576 cout << " dwReserved[" << i << "]: " << ( int ) main_avi_header.dwReserved[ i ] << endl;
00577
00578 }
00579 else if ( entry.type == make_fourcc( "strh" ) )
00580 {
00581
00582 AVIStreamHeader avi_stream_header;
00583
00584 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00585 fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) );
00586
00587 lastStreamType = avi_stream_header.fccType;
00588
00589 cout << " fccType: '"
00590 << ((char *)&avi_stream_header.fccType)[0]
00591 << ((char *)&avi_stream_header.fccType)[1]
00592 << ((char *)&avi_stream_header.fccType)[2]
00593 << ((char *)&avi_stream_header.fccType)[3]
00594 << '\'' << endl
00595 << " fccHandler: '"
00596 << ((char *)&avi_stream_header.fccHandler)[0]
00597 << ((char *)&avi_stream_header.fccHandler)[1]
00598 << ((char *)&avi_stream_header.fccHandler)[2]
00599 << ((char *)&avi_stream_header.fccHandler)[3]
00600 << '\'' << endl
00601 << " dwFlags: " << ( int ) avi_stream_header.dwFlags << endl
00602 << " wPriority: " << ( int ) avi_stream_header.wPriority << endl
00603 << " wLanguage: " << ( int ) avi_stream_header.wLanguage << endl
00604 << " dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl
00605 << " dwScale: " << ( int ) avi_stream_header.dwScale << endl
00606 << " dwRate: " << ( int ) avi_stream_header.dwRate << endl
00607 << " dwLength: " << ( int ) avi_stream_header.dwLength << endl
00608 << " dwQuality: " << ( int ) avi_stream_header.dwQuality << endl
00609 << " dwSampleSize: " << ( int ) avi_stream_header.dwSampleSize << endl;
00610
00611 }
00612 else if ( entry.type == make_fourcc( "indx" ) )
00613 {
00614
00615 int i;
00616 AVISuperIndex avi_super_index;
00617
00618 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00619 fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) );
00620
00621 cout << " wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry
00622 << endl
00623 << " bIndexSubType: " << ( int ) avi_super_index.bIndexSubType << endl
00624 << " bIndexType: " << ( int ) avi_super_index.bIndexType << endl
00625 << " nEntriesInUse: " << ( int ) avi_super_index.nEntriesInUse << endl
00626 << " dwChunkId: '"
00627 << ((char *)&avi_super_index.dwChunkId)[0]
00628 << ((char *)&avi_super_index.dwChunkId)[1]
00629 << ((char *)&avi_super_index.dwChunkId)[2]
00630 << ((char *)&avi_super_index.dwChunkId)[3]
00631 << '\'' << endl
00632 << " dwReserved[0]: " << ( int ) avi_super_index.dwReserved[ 0 ] << endl
00633 << " dwReserved[1]: " << ( int ) avi_super_index.dwReserved[ 1 ] << endl
00634 << " dwReserved[2]: " << ( int ) avi_super_index.dwReserved[ 2 ] << endl;
00635 for ( i = 0; i < avi_super_index.nEntriesInUse; ++i )
00636 {
00637 cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
00638 << ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl
00639 << " dwSize : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl
00640 << " dwDuration : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl;
00641 }
00642 }
00643 else if ( entry.type == make_fourcc( "strf" ) )
00644 {
00645 if ( lastStreamType == make_fourcc( "auds" ) )
00646 {
00647 WAVEFORMATEX waveformatex;
00648 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00649 fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) );
00650 cout << " waveformatex.wFormatTag : " << waveformatex.wFormatTag << endl;
00651 cout << " waveformatex.nChannels : " << waveformatex.nChannels << endl;
00652 cout << " waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl;
00653 cout << " waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl;
00654 cout << " waveformatex.nBlockAlign : " << waveformatex.nBlockAlign << endl;
00655 cout << " waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl;
00656 cout << " waveformatex.cbSize : " << waveformatex.cbSize << endl;
00657 }
00658 else if ( lastStreamType == make_fourcc( "vids" ) )
00659 {
00660 BITMAPINFOHEADER bitmapinfo;
00661 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00662 fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) );
00663 cout << " bitmapinfo.biSize : " << bitmapinfo.biSize << endl;
00664 cout << " bitmapinfo.biWidth : " << bitmapinfo.biWidth << endl;
00665 cout << " bitmapinfo.biHeight : " << bitmapinfo.biHeight << endl;
00666 cout << " bitmapinfo.biPlanes : " << bitmapinfo.biPlanes << endl;
00667 cout << " bitmapinfo.biBitCount : " << bitmapinfo.biBitCount << endl;
00668 cout << " bitmapinfo.biCompression : " << bitmapinfo.biCompression << endl;
00669 cout << " bitmapinfo.biSizeImage : " << bitmapinfo.biSizeImage << endl;
00670 cout << " bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl;
00671 cout << " bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl;
00672 cout << " bitmapinfo.biClrUsed : " << bitmapinfo.biClrUsed << endl;
00673 cout << " bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl;
00674 }
00675 else if ( lastStreamType == make_fourcc( "iavs" ) )
00676 {
00677 DVINFO dvinfo;
00678 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00679 fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) );
00680 cout << " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl;
00681 cout << " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl;
00682 cout << " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl;
00683 cout << " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl;
00684 cout << " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl;
00685 cout << " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl;
00686 }
00687 }
00688
00689
00690
00691
00692 else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) )
00693 {
00694
00695 int i;
00696 AVIStdIndex avi_std_index;
00697
00698 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00699 fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) );
00700
00701 cout << " wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry
00702 << endl
00703 << " bIndexSubType: " << ( int ) avi_std_index.bIndexSubType << endl
00704 << " bIndexType: " << ( int ) avi_std_index.bIndexType << endl
00705 << " nEntriesInUse: " << ( int ) avi_std_index.nEntriesInUse << endl
00706 << " dwChunkId: '"
00707 << ((char *)&avi_std_index.dwChunkId)[0]
00708 << ((char *)&avi_std_index.dwChunkId)[1]
00709 << ((char *)&avi_std_index.dwChunkId)[2]
00710 << ((char *)&avi_std_index.dwChunkId)[3]
00711 << '\'' << endl
00712 << " qwBaseOffset: 0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl
00713 << " dwReserved: " << dec << ( int ) avi_std_index.dwReserved << endl;
00714 for ( i = 0; i < avi_std_index.nEntriesInUse; ++i )
00715 {
00716 cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
00717 << ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset
00718 << " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl
00719 << " dwSize : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl;
00720 }
00721
00722 }
00723 else if ( entry.type == make_fourcc( "idx1" ) )
00724 {
00725
00726 int i;
00727 int numEntries = entry.length / sizeof( int ) / 4;
00728 DWORD *idx1 = new DWORD[ numEntries * 4 ];
00729
00730
00731 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00732 fail_neg( read( fd, idx1, entry.length ) );
00733
00734 for ( i = 0; i < numEntries; ++i )
00735 {
00736
00737 cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '"
00738 << ((char *)&idx1[ i * 4 + 0 ])[0]
00739 << ((char *)&idx1[ i * 4 + 0 ])[1]
00740 << ((char *)&idx1[ i * 4 + 0 ])[2]
00741 << ((char *)&idx1[ i * 4 + 0 ])[3]
00742 << '\'' << endl
00743 << " dwType : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl
00744 << " dwOffset : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl
00745
00746 << " dwSize : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl;
00747 }
00748
00749 delete[] idx1;
00750 }
00751 else if ( entry.type == make_fourcc( "dmlh" ) )
00752 {
00753 int i;
00754 int numEntries = entry.length / sizeof( int );
00755 DWORD *dmlh = new DWORD[ numEntries ];
00756
00757 fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
00758 fail_neg( read( fd, dmlh, entry.length ) );
00759
00760 for ( i = 0; i < numEntries; ++i )
00761 {
00762 cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": "
00763 << " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ]
00764 << " (" << dec << dmlh[ i ] << ")" << endl;
00765 }
00766 delete[] dmlh;
00767 }
00768 }
00769
00770
00775 void AVIFile::ParseList( int parent )
00776 {
00777 FOURCC type;
00778 FOURCC name;
00779 DWORD length;
00780 int list;
00781 off_t pos;
00782 off_t listEnd;
00783
00784
00785 fail_neg( read( fd, &type, sizeof( type ) ) );
00786 fail_neg( read( fd, &length, sizeof( length ) ) );
00787 if ( length & 1 )
00788 length++;
00789
00790
00791
00792
00793 pos = lseek( fd, 0, SEEK_CUR );
00794 fail_if( pos == ( off_t ) - 1 );
00795 fail_neg( read( fd, &name, sizeof( name ) ) );
00796
00797
00798
00799
00800 if ( name != make_fourcc( "movi" ) )
00801 {
00802
00803
00804
00805 list = AddDirectoryEntry( type, name, sizeof( name ), parent );
00806
00807
00808
00809
00810 listEnd = pos + length;
00811 while ( pos < listEnd )
00812 {
00813 ParseChunk( list );
00814 pos = lseek( fd, 0, SEEK_CUR );
00815 fail_if( pos == ( off_t ) - 1 );
00816 }
00817 }
00818 else
00819 {
00820
00821
00822 movi_list = AddDirectoryEntry( type, name, length, parent );
00823
00824 pos = lseek( fd, length - 4, SEEK_CUR );
00825 fail_if( pos == ( off_t ) - 1 );
00826 }
00827 }
00828
00829
00830 void AVIFile::ParseRIFF()
00831 {
00832 RIFFFile::ParseRIFF();
00833
00834 avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) );
00835 if ( avih_chunk != -1 )
00836 ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) );
00837 }
00838
00839
00840 void AVIFile::ReadIndex()
00841 {
00842 mainHdr.dwTotalFrames = 0;
00843 for ( int j = 0; j < 2; j++ )
00844 {
00845 indx_chunk[ j ] = FindDirectoryEntry( make_fourcc( "indx" ), j );
00846 if ( indx_chunk[ j ] != -1 )
00847 {
00848 ReadChunk( indx_chunk[ j ], ( void* ) indx[ j ], sizeof( AVISuperIndex ) );
00849 index_type |= AVI_LARGE_INDEX;
00850
00851
00852 if ( j == 0 )
00853 {
00854 for ( int i = 0; i < indx[ j ] ->nEntriesInUse;
00855 mainHdr.dwTotalFrames += indx[ j ] ->aIndex[ i++ ].dwDuration );
00856 }
00857 }
00858 }
00859 idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) );
00860 if ( idx1_chunk != -1 )
00861 {
00862 ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISimpleIndex ) );
00863 idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16;
00864 index_type |= AVI_SMALL_INDEX;
00865 if ( mainHdr.dwTotalFrames == 0 )
00866 {
00867
00868 FOURCC chunkID1 = make_fourcc( "00dc" );
00869 FOURCC chunkID2 = make_fourcc( "00db" );
00870
00871 for ( int i = 0; i < idx1->nEntriesInUse; ++i )
00872 {
00873 if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
00874 idx1->aIndex[ i ].dwChunkId == chunkID2 )
00875 {
00876 ++mainHdr.dwTotalFrames;
00877 }
00878 }
00879 }
00880 }
00881 }
00882
00883
00884 void AVIFile::FlushIndx( int stream )
00885 {
00886 FOURCC type;
00887 FOURCC name;
00888 off_t length;
00889 off_t offset;
00890 int parent;
00891 int i;
00892
00893
00894
00895
00896
00897
00898
00899 if ( ix_chunk[ stream ] != -1 )
00900 WriteChunk( ix_chunk[ stream ], ix[ stream ] );
00901
00902
00903
00904 if ( stream == 0 )
00905 type = make_fourcc( "ix00" );
00906 else
00907 type = make_fourcc( "ix01" );
00908 ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list );
00909 GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent );
00910
00911
00912
00913
00914
00915
00916 ix[ stream ] ->wLongsPerEntry = 2;
00917 ix[ stream ] ->bIndexSubType = 0;
00918 ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS;
00919 ix[ stream ] ->nEntriesInUse = 0;
00920 ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId;
00921 ix[ stream ] ->qwBaseOffset = offset + length;
00922 ix[ stream ] ->dwReserved = 0;
00923
00924 for ( i = 0; i < IX00_INDEX_SIZE; ++i )
00925 {
00926 ix[ stream ] ->aIndex[ i ].dwOffset = 0;
00927 ix[ stream ] ->aIndex[ i ].dwSize = 0;
00928 }
00929
00930
00931
00932
00933 i = indx[ stream ] ->nEntriesInUse++;
00934 indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE;
00935 indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE;
00936 indx[ stream ] ->aIndex[ i ].dwDuration = 0;
00937 }
00938
00939
00940 void AVIFile::UpdateIndx( int stream, int chunk, int duration )
00941 {
00942 FOURCC type;
00943 FOURCC name;
00944 off_t length;
00945 off_t offset;
00946 int parent;
00947 int i;
00948
00949
00950
00951
00952 i = indx[ stream ] ->nEntriesInUse - 1;
00953 indx[ stream ] ->aIndex[ i ].dwDuration += duration;
00954
00955
00956
00957
00958 GetDirectoryEntry( chunk, type, name, length, offset, parent );
00959
00960 indx[ stream ] ->dwChunkId = type;
00961 i = ix[ stream ] ->nEntriesInUse++;
00962 ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset;
00963 ix[ stream ] ->aIndex[ i ].dwSize = length;
00964 }
00965
00966
00967 void AVIFile::UpdateIdx1( int chunk, int flags )
00968 {
00969 if ( idx1->nEntriesInUse < IDX1_INDEX_SIZE )
00970 {
00971 FOURCC type;
00972 FOURCC name;
00973 off_t length;
00974 off_t offset;
00975 int parent;
00976
00977 GetDirectoryEntry( chunk, type, name, length, offset, parent );
00978
00979 idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type;
00980 idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags;
00981 idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE;
00982 idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length;
00983 idx1->nEntriesInUse++;
00984 }
00985 }
00986
00987 bool AVIFile::verifyStreamFormat( FOURCC type )
00988 {
00989 int i, j = 0;
00990 AVIStreamHeader avi_stream_header;
00991 BITMAPINFOHEADER bih;
00992 FOURCC strh = make_fourcc( "strh" );
00993 FOURCC strf = make_fourcc( "strf" );
00994
00995 while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
00996 {
00997 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
00998 if ( avi_stream_header.fccHandler == type )
00999 return true;
01000 }
01001 j = 0;
01002 while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 )
01003 {
01004 ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
01005 if ( ( FOURCC ) bih.biCompression == type )
01006 return true;
01007 }
01008
01009 return false;
01010 }
01011
01012 bool AVIFile::verifyStream( FOURCC type )
01013 {
01014 int i, j = 0;
01015 AVIStreamHeader avi_stream_header;
01016 FOURCC strh = make_fourcc( "strh" );
01017
01018 while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
01019 {
01020 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
01021 if ( avi_stream_header.fccType == type )
01022 return true;
01023 }
01024 return false;
01025 }
01026
01027 bool AVIFile::isOpenDML( void )
01028 {
01029 int i, j = 0;
01030 FOURCC dmlh = make_fourcc( "dmlh" );
01031
01032 while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 )
01033 {
01034 return true;
01035 }
01036 return false;
01037 }
01038
01039 AVI1File::AVI1File() : AVIFile()
01040 {}
01041
01042
01043 AVI1File::~AVI1File()
01044 {}
01045
01046
01047
01048
01049
01050 void AVI1File::Init( int format, int sampleFrequency, int indexType )
01051 {
01052 int num_blocks;
01053 FOURCC type;
01054 FOURCC name;
01055 off_t length;
01056 off_t offset;
01057 int parent;
01058
01059 assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
01060
01061 AVIFile::Init( format, sampleFrequency, indexType );
01062
01063 switch ( format )
01064 {
01065 case AVI_PAL:
01066 mainHdr.dwWidth = 720;
01067 mainHdr.dwHeight = 576;
01068
01069 streamHdr[ 0 ].dwScale = 1;
01070 streamHdr[ 0 ].dwRate = 25;
01071 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105 dvinfo.dwDVAAuxSrc = 0xd1e030d0;
01106 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
01107 dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0;
01108 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
01109 dvinfo.dwDVVAuxSrc = 0xff20ffff;
01110 dvinfo.dwDVVAuxCtl = 0xfffdc83f;
01111 dvinfo.dwDVReserved[ 0 ] = 0;
01112 dvinfo.dwDVReserved[ 1 ] = 0;
01113 break;
01114
01115 case AVI_NTSC:
01116 mainHdr.dwWidth = 720;
01117 mainHdr.dwHeight = 480;
01118
01119 streamHdr[ 0 ].dwScale = 1001;
01120 streamHdr[ 0 ].dwRate = 30000;
01121 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
01122
01123
01124 dvinfo.dwDVAAuxSrc = 0xc0c000c0;
01125 dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
01126 dvinfo.dwDVAAuxSrc1 = 0xc0c001c0;
01127 dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
01128 dvinfo.dwDVVAuxSrc = 0xff80ffff;
01129 dvinfo.dwDVVAuxCtl = 0xfffcc83f;
01130 dvinfo.dwDVReserved[ 0 ] = 0;
01131 dvinfo.dwDVReserved[ 1 ] = 0;
01132 break;
01133
01134 default:
01135 assert( 0 );
01136 break;
01137 }
01138
01139 indx[ 0 ] ->dwChunkId = make_fourcc( "00__" );
01140
01141
01142
01143 streamHdr[ 0 ].fccType = make_fourcc( "iavs" );
01144 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
01145 streamHdr[ 0 ].dwFlags = 0;
01146 streamHdr[ 0 ].wPriority = 0;
01147 streamHdr[ 0 ].wLanguage = 0;
01148 streamHdr[ 0 ].dwInitialFrames = 0;
01149 streamHdr[ 0 ].dwStart = 0;
01150 streamHdr[ 0 ].dwLength = 0;
01151 streamHdr[ 0 ].dwQuality = 0;
01152 streamHdr[ 0 ].dwSampleSize = 0;
01153 streamHdr[ 0 ].rcFrame.top = 0;
01154 streamHdr[ 0 ].rcFrame.bottom = 0;
01155 streamHdr[ 0 ].rcFrame.left = 0;
01156 streamHdr[ 0 ].rcFrame.right = 0;
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185 file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
01186
01187
01188
01189 riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
01190 hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
01191 avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
01192 strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
01193 strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
01194 strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] );
01195 if ( index_type & AVI_LARGE_INDEX )
01196 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
01197
01198 odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
01199 dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
01200
01201
01202 GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
01203 num_blocks = length / PADDING_SIZE + 1;
01204 length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE;
01205 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
01206
01207 movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
01208
01209
01210
01211
01212 ix_chunk[ 0 ] = -1;
01213 }
01214
01215
01216
01217
01218 bool AVI1File::WriteFrame( const Frame &frame )
01219 {
01220 int frame_chunk;
01221 int junk_chunk;
01222 int num_blocks;
01223 FOURCC type;
01224 FOURCC name;
01225 off_t length;
01226 off_t offset;
01227 int parent;
01228
01229
01230 if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
01231 return false;
01232
01233
01234
01235
01236
01237
01238 if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
01239 FlushIndx( 0 );
01240
01241
01242
01243
01244
01245
01246 frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list );
01247 if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
01248 {
01249 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
01250 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
01251 }
01252 WriteChunk( frame_chunk, frame.data );
01253
01254
01255
01256
01257
01258 if ( index_type & AVI_LARGE_INDEX )
01259 UpdateIndx( 0, frame_chunk, 1 );
01260 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01261 UpdateIdx1( frame_chunk, 0x10 );
01262
01263
01264
01265 if ( isUpdateIdx1 )
01266 ++mainHdr.dwTotalFrames;
01267 ++streamHdr[ 0 ].dwLength;
01268 ++dmlh[ 0 ];
01269
01270
01271
01272
01273
01274
01275 GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01276 if ( length > 0x3f000000 )
01277 {
01278
01279 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01280 {
01281 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
01282 WriteChunk( idx1_chunk, ( void* ) idx1 );
01283 }
01284 isUpdateIdx1 = false;
01285
01286 if ( index_type & AVI_LARGE_INDEX )
01287 {
01288
01289
01290
01291
01292
01293
01294 GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01295 num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
01296 length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
01297 if ( length > 0 )
01298 {
01299 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
01300 WriteChunk( junk_chunk, g_zeroes );
01301 }
01302
01303 riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
01304 movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
01305 }
01306 }
01307 return true;
01308 }
01309
01310
01311 void AVI1File::WriteRIFF()
01312 {
01313
01314 WriteChunk( avih_chunk, ( void* ) & mainHdr );
01315 WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
01316 WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo );
01317 WriteChunk( dmlh_chunk, ( void* ) & dmlh );
01318
01319 if ( index_type & AVI_LARGE_INDEX )
01320 {
01321 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
01322 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
01323 }
01324
01325 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01326 {
01327 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
01328 WriteChunk( idx1_chunk, ( void* ) idx1 );
01329 }
01330
01331 RIFFFile::WriteRIFF();
01332 }
01333
01334
01335 AVI2File::AVI2File() : AVIFile()
01336 {}
01337
01338
01339 AVI2File::~AVI2File()
01340 {}
01341
01342
01343
01344
01345
01346 void AVI2File::Init( int format, int sampleFrequency, int indexType )
01347 {
01348 int num_blocks;
01349 FOURCC type;
01350 FOURCC name;
01351 off_t length;
01352 off_t offset;
01353 int parent;
01354
01355 assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
01356
01357 AVIFile::Init( format, sampleFrequency, indexType );
01358
01359 switch ( format )
01360 {
01361
01362 case AVI_PAL:
01363 mainHdr.dwStreams = 2;
01364 mainHdr.dwWidth = 720;
01365 mainHdr.dwHeight = 576;
01366
01367
01368
01369 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
01370 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
01371 streamHdr[ 0 ].dwFlags = 0;
01372 streamHdr[ 0 ].wPriority = 0;
01373 streamHdr[ 0 ].wLanguage = 0;
01374 streamHdr[ 0 ].dwInitialFrames = 0;
01375 streamHdr[ 0 ].dwScale = 1;
01376 streamHdr[ 0 ].dwRate = 25;
01377 streamHdr[ 0 ].dwStart = 0;
01378 streamHdr[ 0 ].dwLength = 0;
01379 streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
01380 streamHdr[ 0 ].dwQuality = -1;
01381 streamHdr[ 0 ].dwSampleSize = 0;
01382 streamHdr[ 0 ].rcFrame.top = 0;
01383 streamHdr[ 0 ].rcFrame.bottom = 0;
01384 streamHdr[ 0 ].rcFrame.left = 0;
01385 streamHdr[ 0 ].rcFrame.right = 0;
01386
01387 bitmapinfo.biSize = sizeof( bitmapinfo );
01388 bitmapinfo.biWidth = 720;
01389 bitmapinfo.biHeight = 576;
01390 bitmapinfo.biPlanes = 1;
01391 bitmapinfo.biBitCount = 24;
01392 bitmapinfo.biCompression = make_fourcc( "dvsd" );
01393 bitmapinfo.biSizeImage = 144000;
01394 bitmapinfo.biXPelsPerMeter = 0;
01395 bitmapinfo.biYPelsPerMeter = 0;
01396 bitmapinfo.biClrUsed = 0;
01397 bitmapinfo.biClrImportant = 0;
01398
01399 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
01400 streamHdr[ 1 ].fccHandler = 0;
01401 streamHdr[ 1 ].dwFlags = 0;
01402 streamHdr[ 1 ].wPriority = 0;
01403 streamHdr[ 1 ].wLanguage = 0;
01404 streamHdr[ 1 ].dwInitialFrames = 0;
01405 streamHdr[ 1 ].dwScale = 2 * 2;
01406 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
01407 streamHdr[ 1 ].dwStart = 0;
01408 streamHdr[ 1 ].dwLength = 0;
01409 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
01410 streamHdr[ 1 ].dwQuality = -1;
01411 streamHdr[ 1 ].dwSampleSize = 2 * 2;
01412 streamHdr[ 1 ].rcFrame.top = 0;
01413 streamHdr[ 1 ].rcFrame.bottom = 0;
01414 streamHdr[ 1 ].rcFrame.left = 0;
01415 streamHdr[ 1 ].rcFrame.right = 0;
01416
01417 break;
01418
01419 case AVI_NTSC:
01420 mainHdr.dwTotalFrames = 0;
01421 mainHdr.dwStreams = 2;
01422 mainHdr.dwWidth = 720;
01423 mainHdr.dwHeight = 480;
01424
01425
01426
01427 streamHdr[ 0 ].fccType = make_fourcc( "vids" );
01428 streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
01429 streamHdr[ 0 ].dwFlags = 0;
01430 streamHdr[ 0 ].wPriority = 0;
01431 streamHdr[ 0 ].wLanguage = 0;
01432 streamHdr[ 0 ].dwInitialFrames = 0;
01433 streamHdr[ 0 ].dwScale = 1001;
01434 streamHdr[ 0 ].dwRate = 30000;
01435 streamHdr[ 0 ].dwStart = 0;
01436 streamHdr[ 0 ].dwLength = 0;
01437 streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
01438 streamHdr[ 0 ].dwQuality = -1;
01439 streamHdr[ 0 ].dwSampleSize = 0;
01440 streamHdr[ 0 ].rcFrame.top = 0;
01441 streamHdr[ 0 ].rcFrame.bottom = 0;
01442 streamHdr[ 0 ].rcFrame.left = 0;
01443 streamHdr[ 0 ].rcFrame.right = 0;
01444
01445 bitmapinfo.biSize = sizeof( bitmapinfo );
01446 bitmapinfo.biWidth = 720;
01447 bitmapinfo.biHeight = 480;
01448 bitmapinfo.biPlanes = 1;
01449 bitmapinfo.biBitCount = 24;
01450 bitmapinfo.biCompression = make_fourcc( "dvsd" );
01451 bitmapinfo.biSizeImage = 120000;
01452 bitmapinfo.biXPelsPerMeter = 0;
01453 bitmapinfo.biYPelsPerMeter = 0;
01454 bitmapinfo.biClrUsed = 0;
01455 bitmapinfo.biClrImportant = 0;
01456
01457 streamHdr[ 1 ].fccType = make_fourcc( "auds" );
01458 streamHdr[ 1 ].fccHandler = 0;
01459 streamHdr[ 1 ].dwFlags = 0;
01460 streamHdr[ 1 ].wPriority = 0;
01461 streamHdr[ 1 ].wLanguage = 0;
01462 streamHdr[ 1 ].dwInitialFrames = 1;
01463 streamHdr[ 1 ].dwScale = 2 * 2;
01464 streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
01465 streamHdr[ 1 ].dwStart = 0;
01466 streamHdr[ 1 ].dwLength = 0;
01467 streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
01468 streamHdr[ 1 ].dwQuality = 0;
01469 streamHdr[ 1 ].dwSampleSize = 2 * 2;
01470 streamHdr[ 1 ].rcFrame.top = 0;
01471 streamHdr[ 1 ].rcFrame.bottom = 0;
01472 streamHdr[ 1 ].rcFrame.left = 0;
01473 streamHdr[ 1 ].rcFrame.right = 0;
01474
01475 break;
01476 }
01477 waveformatex.wFormatTag = 1;
01478 waveformatex.nChannels = 2;
01479 waveformatex.nSamplesPerSec = sampleFrequency;
01480 waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2;
01481 waveformatex.nBlockAlign = 4;
01482 waveformatex.wBitsPerSample = 16;
01483 waveformatex.cbSize = 0;
01484
01485 file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
01486
01487
01488
01489 riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
01490 hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
01491 avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
01492
01493 strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
01494 strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
01495 strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] );
01496 if ( index_type & AVI_LARGE_INDEX )
01497 {
01498 indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
01499 ix_chunk[ 0 ] = -1;
01500 indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" );
01501 }
01502
01503 strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
01504 strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] );
01505 strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] );
01506 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] );
01507 if ( index_type & AVI_LARGE_INDEX )
01508 {
01509 indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] );
01510 ix_chunk[ 1 ] = -1;
01511 indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" );
01512
01513 odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
01514 dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
01515 }
01516
01517
01518 GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
01519 num_blocks = length / PADDING_SIZE + 1;
01520 length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE;
01521 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
01522
01523 movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
01524
01525 idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" );
01526 idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0;
01527 idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0;
01528 idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0;
01529 idx1->nEntriesInUse++;
01530 }
01531
01532
01533 void AVI2File::WriteRIFF()
01534 {
01535 WriteChunk( avih_chunk, ( void* ) & mainHdr );
01536 WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
01537 WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo );
01538 if ( index_type & AVI_LARGE_INDEX )
01539 {
01540 WriteChunk( dmlh_chunk, ( void* ) & dmlh );
01541 WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
01542 WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
01543 }
01544 WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] );
01545 WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex );
01546 if ( index_type & AVI_LARGE_INDEX )
01547 {
01548 WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] );
01549 WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] );
01550 }
01551
01552 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01553 {
01554 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
01555 WriteChunk( idx1_chunk, ( void* ) idx1 );
01556 }
01557 RIFFFile::WriteRIFF();
01558 }
01559
01560
01566 bool AVI2File::WriteFrame( const Frame &frame )
01567 {
01568 int audio_chunk;
01569 int frame_chunk;
01570 int junk_chunk;
01571 char soundbuf[ 20000 ];
01572 int audio_size;
01573 int num_blocks;
01574 FOURCC type;
01575 FOURCC name;
01576 off_t length;
01577 off_t offset;
01578 int parent;
01579
01580
01581 if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
01582 return false;
01583
01584
01585
01586
01587
01588
01589 if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
01590 {
01591 FlushIndx( 0 );
01592 FlushIndx( 1 );
01593 }
01594
01595
01596
01597 audio_size = frame.ExtractAudio( soundbuf );
01598 if ( audio_size > 0 )
01599 {
01600 #if BYTE_ORDER == BIG_ENDIAN
01601 int16_t* p = reinterpret_cast< int16_t* >( soundbuf );
01602 for ( int i = 0; i < audio_size / sizeof( int16_t ); ++i, ++p )
01603 *p = bswap_16( *p );
01604 #endif
01605 audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list );
01606 if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
01607 {
01608 GetDirectoryEntry( audio_chunk, type, name, length, offset, parent );
01609 ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
01610 }
01611 WriteChunk( audio_chunk, soundbuf );
01612
01613
01614
01615
01616 if ( index_type & AVI_LARGE_INDEX )
01617 UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 );
01618 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01619 UpdateIdx1( audio_chunk, 0x00 );
01620 streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2;
01621
01622 }
01623
01624
01625
01626 frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list );
01627 if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
01628 {
01629 GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
01630 ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
01631 }
01632 WriteChunk( frame_chunk, frame.data );
01633
01634
01635
01636
01637 if ( index_type & AVI_LARGE_INDEX )
01638 UpdateIndx( 0, frame_chunk, 1 );
01639 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01640 UpdateIdx1( frame_chunk, 0x10 );
01641
01642
01643
01644 if ( isUpdateIdx1 )
01645 ++mainHdr.dwTotalFrames;
01646 ++streamHdr[ 0 ].dwLength;
01647 ++dmlh[ 0 ];
01648
01649
01650
01651
01652
01653
01654 GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01655 if ( length > 0x3f000000 )
01656 {
01657
01658
01659 if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
01660 {
01661 int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
01662 WriteChunk( idx1_chunk, ( void* ) idx1 );
01663 }
01664 isUpdateIdx1 = false;
01665
01666 if ( index_type & AVI_LARGE_INDEX )
01667 {
01668
01669 GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01670 num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
01671 length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
01672 if ( length > 0 )
01673 {
01674 junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
01675 WriteChunk( junk_chunk, g_zeroes );
01676 }
01677
01678 riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
01679 movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
01680 }
01681 }
01682 return true;
01683 }
01684
01685
01686 void AVI1File::setDVINFO( DVINFO &info )
01687 {
01688
01689 return ;
01690
01691 dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc;
01692 dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl;
01693 dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1;
01694 dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1;
01695 dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc;
01696 dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl;
01697 }
01698
01699
01700 void AVI2File::setDVINFO( DVINFO &info )
01701 {}
01702
01703 void AVIFile::setFccHandler( FOURCC type, FOURCC handler )
01704 {
01705 for ( int i = 0; i < mainHdr.dwStreams; i++ )
01706 {
01707 if ( streamHdr[ i ].fccType == type )
01708 {
01709 int k, j = 0;
01710 FOURCC strf = make_fourcc( "strf" );
01711 BITMAPINFOHEADER bih;
01712
01713 streamHdr[ i ].fccHandler = handler;
01714
01715 while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 )
01716 {
01717 ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
01718 bih.biCompression = handler;
01719 }
01720 }
01721 }
01722 }
01723
01724 bool AVIFile::getStreamFormat( void* data, FOURCC type )
01725 {
01726 int i, j = 0;
01727 FOURCC strh = make_fourcc( "strh" );
01728 FOURCC strf = make_fourcc( "strf" );
01729 AVIStreamHeader avi_stream_header;
01730 bool result = false;
01731
01732 while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
01733 {
01734 ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
01735 if ( avi_stream_header.fccType == type )
01736 {
01737 FOURCC chunkID;
01738 int size;
01739
01740 pthread_mutex_lock( &file_mutex );
01741 fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) );
01742 if ( chunkID == strf )
01743 {
01744 fail_neg( read( fd, &size, sizeof( int ) ) );
01745 fail_neg( read( fd, data, size ) );
01746 result = true;
01747 }
01748 pthread_mutex_unlock( &file_mutex );
01749 }
01750 }
01751 return result;
01752 }