Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

avi.cc

Go to the documentation of this file.
00001 /*
00002 * avi.cc library for AVI file format i/o
00003 * Copyright (C) 2000 - 2002 Arne Schirmacher <arne@schirmacher.de>
00004 * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
00005 *
00006 * This program is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software Foundation,
00018 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 
00025 // C++ includes
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 // C includes
00039 
00040 #include <stdio.h>
00041 #include <fcntl.h>
00042 #include <unistd.h>
00043 #include <assert.h>
00044 
00045 // local includes
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     // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
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     // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
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     // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
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:   /* no default allowed */
00233         assert( 0 );
00234         break;
00235     }
00236 
00237     /* Initialize the 'avih' chunk */
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     /* Initialize the 'idx1' chunk */
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     /* Initialize the 'indx' chunk */
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     /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
00285               as needed */
00286 
00287     /* Initialize the 'dmlh' chunk. I have no clue what this means
00288        though */
00289 
00290     for ( i = 0; i < 62; ++i )
00291         dmlh[ i ] = 0;
00292     //dmlh[0] = -1;            /* frame count + 1? */
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         /* find relevant index in indx0 */
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             // compatibility check for broken dvgrab dv2 format
00358             if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
00359             {
00360                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
00361             }
00362             else
00363             {
00364                 // new, correct dv2 format
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         // Find the super index matches chunkID
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                 // Find the standard index
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             // compatibility check for broken dvgrab dv2 format
00447             if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
00448             {
00449                 offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
00450             }
00451             else
00452             {
00453                 // new, correct dv2 format
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     // Scan the index, skipping first entry, which might be bogus (7Fxx).
00525     for ( int i = 2; i < ( idx1->nEntriesInUse - 1 ); ++i )
00526     {
00527         // Look for DV data
00528         if ( ( idx1->aIndex[ i ].dwChunkId == dvChunkID1 ||
00529                idx1->aIndex[ i ].dwChunkId == dvChunkID2 ) )
00530         {
00531             // Determine if WAV data is both prior and following index entries
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     /* This is the Standard Index. It is an array of offsets and
00690        sizes relative to some start offset. */
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         // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
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             // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
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     /* Read in the chunk header (type and length). */
00785     fail_neg( read( fd, &type, sizeof( type ) ) );
00786     fail_neg( read( fd, &length, sizeof( length ) ) );
00787     if ( length & 1 )
00788         length++;
00789 
00790     /* The contents of the list starts here. Obtain its offset. The list
00791        name (4 bytes) is already part of the contents). */
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     /* if we encounter a movi list, do not read it. It takes too much time
00798        and we don't need it anyway. */
00799 
00800     if ( name != make_fourcc( "movi" ) )
00801     {
00802         //    if (1) {
00803 
00804         /* Add an entry for this list. */
00805         list = AddDirectoryEntry( type, name, sizeof( name ), parent );
00806 
00807         /* Read in any chunks contained in this list. This list is the
00808            parent for all chunks it contains. */
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         /* Add an entry for this list. */
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             /* recalc number of frames from each index */
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             /* recalc number of frames from the simple index */
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     /* Write out the previous index. When this function is
00894        entered for the first time, there is no index to
00895        write.  Note: this may be an expensive operation
00896        because of a time consuming seek to the former file
00897        position. */
00898 
00899     if ( ix_chunk[ stream ] != -1 )
00900         WriteChunk( ix_chunk[ stream ], ix[ stream ] );
00901 
00902     /* make a new ix chunk. */
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     /* fill out all required fields. The offsets in the
00912        array are relative to qwBaseOffset, so fill in the
00913        offset to the next free location in the file
00914        there. */
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     /* add a reference to this new index in our super
00931        index. */
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     /* update the appropiate entry in the super index. It reflects
00950        the number of frames in the referenced index. */
00951 
00952     i = indx[ stream ] ->nEntriesInUse - 1;
00953     indx[ stream ] ->aIndex[ i ].dwDuration += duration;
00954 
00955     /* update the standard index. Calculate the file position of
00956        the new frame. */
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 /* Initialize the AVI structure to its initial state, either for PAL
01048    or NTSC format */
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         /* initialize the 'strf' chunk */
01074 
01075         /* Meaning of the DV stream format chunk per Microsoft
01076            dwDVAAuxSrc
01077               Specifies the Audio Auxiliary Data Source Pack for the first audio block
01078               (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
01079               a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
01080               of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
01081               Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
01082               Consumer-use Digital VCRs.
01083            dwDVAAuxCtl
01084               Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
01085               frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
01086               Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
01087               Consumer-use Digital VCRs.
01088            dwDVAAuxSrc1
01089               Specifies the Audio Auxiliary Data Source Pack for the second audio block
01090               (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
01091            dwDVAAuxCtl1
01092               Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
01093            dwDVVAuxSrc
01094               Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
01095               Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
01096               Consumer-use Digital VCRs.
01097            dwDVVAuxCtl
01098               Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
01099               Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
01100               Consumer-use Digital VCRs.
01101            dwDVReserved[2]
01102               Reserved. Set this array to zero.   
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         /* initialize the 'strf' chunk */
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:   /* no default allowed */
01135         assert( 0 );
01136         break;
01137     }
01138 
01139     indx[ 0 ] ->dwChunkId = make_fourcc( "00__" );
01140 
01141     /* Initialize the 'strh' chunk */
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     /* This is a simple directory structure setup. For details see the
01159        "OpenDML AVI File Format Extensions" document.
01160        
01161        An AVI file contains basically two types of objects, a
01162        "chunk" and a "list" object. The list object contains any
01163        number of chunks. Since a list is also a chunk, it is
01164        possible to create a hierarchical "list of lists"
01165        structure.
01166 
01167        Every AVI file starts with a "RIFF" object, which is a list
01168        of several other required objects. The actual DV data is
01169        contained in a "movi" list, each frame is in its own chunk.
01170 
01171        Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
01172        chunk of less than 1 GByte size per file. The current
01173        format which allow for almost arbitrary sizes can contain
01174        several RIFF chunks of less than 1 GByte size. Old software
01175        however would only deal with the first RIFF chunk.
01176 
01177        Note that the first entry (FILE) isn't actually part
01178        of the AVI file. I use this (pseudo-) directory entry to
01179        keep track of the RIFF chunks and their positions in the
01180        AVI file.
01181     */
01182 
01183     /* Create the container directory entry */
01184 
01185     file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
01186 
01187     /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
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     /* align movi list to block */
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; // why 5?
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     /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
01210               as needed */
01211 
01212     ix_chunk[ 0 ] = -1;
01213 }
01214 
01215 
01216 /* Write a DV video frame. This is somewhat complex... */
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     /* exit if no large index and 1GB reached */
01230     if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
01231         return false;
01232 
01233     /* Check if we need a new ix00 Standard Index. It has a
01234        capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
01235        number, we need a new index. The new ix00 chunk is also
01236        part of the movi list. */
01237 
01238     if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
01239         FlushIndx( 0 );
01240 
01241     /* Write the DV frame data.
01242 
01243        Make a new 00__ chunk for the new frame, write out the
01244        frame. */
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     //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
01254     //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
01255     //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
01256     //    WriteChunk(junk_chunk, g_zeroes);
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     /* update some variables with the new frame count. */
01264 
01265     if ( isUpdateIdx1 )
01266         ++mainHdr.dwTotalFrames;
01267     ++streamHdr[ 0 ].dwLength;
01268     ++dmlh[ 0 ];
01269 
01270     /* Find out if the current riff list is close to 1 GByte in
01271        size. If so, start a new (extended) RIFF. The only allowed
01272        item in the new RIFF chunk is a movi list (with video
01273        frames and indexes as usual). */
01274 
01275     GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01276     if ( length > 0x3f000000 )
01277     {
01278         /* write idx1 only once and before end of first GB */
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             /* pad out to 1GB */
01289             //GetDirectoryEntry(riff_list, type, name, length, offset, parent);
01290             //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
01291             //WriteChunk(junk_chunk, g_zeroes);
01292 
01293             /* padding for alignment */
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 /* Initialize the AVI structure to its initial state, either for PAL
01344    or NTSC format */
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         /* Initialize the 'strh' chunk */
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         /* Initialize the 'strh' chunk */
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     /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
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     /* align movi list to block */
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; // why 5 headers?
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     /* exit if no large index and 1GB reached */
01581     if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
01582         return false;
01583 
01584     /* Check if we need a new ix00 Standard Index. It has a
01585        capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
01586        number, we need a new index. The new ix00 chunk is also
01587        part of the movi list. */
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     /* Write audio data if we have it */
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         //        num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
01613         //        length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
01614         //        junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
01615         //        WriteChunk(junk_chunk, g_zeroes);
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     /* Write video data */
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     //    num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
01634     //    length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
01635     //    junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
01636     //    WriteChunk(junk_chunk, g_zeroes);
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     /* update some variables with the new frame count. */
01643 
01644     if ( isUpdateIdx1 )
01645         ++mainHdr.dwTotalFrames;
01646     ++streamHdr[ 0 ].dwLength;
01647     ++dmlh[ 0 ];
01648 
01649     /* Find out if the current riff list is close to 1 GByte in
01650        size. If so, start a new (extended) RIFF. The only allowed
01651        item in the new RIFF chunk is a movi list (with video
01652        frames and indexes as usual). */
01653 
01654     GetDirectoryEntry( riff_list, type, name, length, offset, parent );
01655     if ( length > 0x3f000000 )
01656     {
01657 
01658         /* write idx1 only once and before end of first GB */
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             /* padding for alignment */
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     // do not do this until debugged audio against DirectShow
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 }

Generated on Sun Mar 11 22:11:44 2007 for Kino by  doxygen 1.4.2