You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mlt/src/modules/kino/avi.cc

1861 lines
58 KiB

/*
* avi.cc library for AVI file format i/o
* Copyright (C) 2000 - 2002 Arne Schirmacher <arne@schirmacher.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Tag: $Name$
*
* Change log:
*
* $Log$
* Revision 1.3 2005/07/25 07:21:39 lilo_booter
* + fixes for opendml dv avi
*
* Revision 1.2 2005/06/21 20:59:39 lilo_booter
* src/framework/mlt_consumer.c src/framework/mlt_consumer.h
* + Added a general profile handling for size, aspect ratio and display ratio
*
* src/framework/mlt_producer.c
* + Correction to aspect ratio properties
*
* src/inigo/inigo.c
* + Minimalist support for sdl_preview (still not very good)
*
* src/modules/avformat/consumer_avformat.c
* + Takes consumer profile into account
*
* src/modules/core/filter_resize.c
* + Corrections for synthesised producers and aspect ratio (inherits from consumer)
*
* src/modules/core/producer_colour.c
* src/modules/core/producer_noise.c
* src/modules/gtk2/producer_pango.c
* + Ensures that resize picks up consumer aspect ratio
*
* src/modules/dv/consumer_libdv.c
* + Honour wide screen output
*
* src/modules/gtk2/producer_pixbuf.c
* + Correction for 1:1 aspect ratio
*
* src/modules/kino/Makefile
* src/modules/kino/avi.cc
* src/modules/kino/avi.h
* src/modules/kino/configure
* src/modules/kino/filehandler.cc
* + Attempt to allow mov dv files to provide audio
*
* src/modules/sdl/consumer_sdl.c
* src/modules/sdl/consumer_sdl_preview.c
* src/modules/sdl/consumer_sdl_still.c
* + Takes consumer profile into account
*
* Revision 1.1 2005/04/15 14:28:26 lilo_booter
* Initial version
*
* Revision 1.28 2005/04/01 23:43:10 ddennedy
* apply endian fixes from Daniel Kobras
*
* Revision 1.27 2004/10/11 01:37:11 ddennedy
* mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
*
* Revision 1.26 2004/01/05 03:43:11 ddennedy
* metadata editing, deinterlace options, bugfixes and cleanups
*
* Revision 1.25 2003/11/25 23:00:52 ddennedy
* cleanup and a few bugfixes
*
* Revision 1.24 2003/11/12 13:01:56 ddennedy
* disable JUNK chunks in MOVI list, FileHandler max file size zero = infinity
*
* Revision 1.23 2003/11/10 01:02:51 ddennedy
* bugfix: return error on AVI directory entries with size <0
*
* Revision 1.22 2003/10/28 18:52:32 ddennedy
* fix prefs dialog crash, improve WAV import
*
* Revision 1.21 2003/10/21 16:34:32 ddennedy
* GNOME2 port phase 1: initial checkin
*
* Revision 1.19.2.9 2003/08/26 20:39:00 ddennedy
* relocate mutex unlock and add assert includes
*
* Revision 1.19.2.8 2003/07/24 14:13:57 ddennedy
* support for distinct audio stream in type2 AVI and Quicktime; support for more DV FOURCCs
*
* Revision 1.19.2.7 2003/06/10 23:53:35 ddennedy
* Daniel Kobras' WriteFrame error handling and automatic OpenDML, bugfixes in scene list updates, export AV/C Record
*
* Revision 1.19.2.6 2003/03/05 15:02:12 ddennedy
* yet anther AV/C bugfix, yet another AVI improvement
*
* Revision 1.19.2.5 2003/02/20 21:59:55 ddennedy
* bugfixes to capture and AVI
*
* Revision 1.19.2.4 2003/01/13 05:15:31 ddennedy
* added More Info panel and supporting methods
*
* Revision 1.19.2.3 2002/12/31 22:40:49 ddennedy
* bugfix recent versions Quicktime4Linux build options, extend dvsd fourcc check on AVI to the BITMAPINFOHEADER for compatibility with mencoder
*
* Revision 1.19.2.2 2002/11/25 04:48:30 ddennedy
* bugfix to report errors when loading files
*
* Revision 1.19.2.1 2002/11/24 23:36:55 ddennedy
* bugfix in AVI writing
*
* Revision 1.19 2002/10/08 12:08:01 ddennedy
* more sane frame count, greater potential compatibility
*
* Revision 1.18 2002/10/08 08:33:02 ddennedy
* fix number of frames for small dv2
*
* Revision 1.17 2002/10/08 07:46:41 ddennedy
* AVI bugfixes, compatibility, optimization, warn bad file in capture and export dv file, allow no mplex
*
* Revision 1.15 2002/06/10 10:39:51 ddennedy
* minor fixes for large files
*
* Revision 1.14 2002/05/17 08:04:24 ddennedy
* revert const-ness of Frame references in Frame, FileHandler, and AVI classes
*
* Revision 1.13 2002/05/15 04:39:35 ddennedy
* bugfixes to dv2 AVI write, audio export, Xv init
*
* Revision 1.12 2002/04/29 05:09:21 ddennedy
* raw dv file support, Frame::ExtractAudio uses libdv, audioScrub prefs
*
* Revision 1.11 2002/04/15 19:12:32 schirmacher
* removed debugging code causing performance losses and crashes with dv2 files
*
* Revision 1.10 2002/04/09 06:53:42 ddennedy
* cleanup, new libdv 0.9.5, large AVI, dnd storyboard
*
* Revision 1.8 2002/03/25 21:34:25 arne
* Support for large (64 bit) files mostly completed
*
* Revision 1.7 2002/03/10 21:28:29 arne
* release 1.1b1, 64 bit support for type 1 avis
*
* Revision 1.6 2002/03/10 13:29:41 arne
* more changes for 64 bit access
*
* Revision 1.5 2002/03/09 17:59:28 arne
* moved index routines to AVIFile
*
* Revision 1.4 2002/03/09 10:26:26 arne
* improved constructors and assignment operator
*
* Revision 1.3 2002/03/09 08:55:57 arne
* moved a few variables to AVIFile
*
* Revision 1.2 2002/03/04 19:22:43 arne
* updated to latest Kino avi code
*
* Revision 1.1.1.1 2002/03/03 19:08:08 arne
* import of version 1.01
*
*/
#include "config.h"
// C++ includes
#include <string>
#include <iostream>
#include <iomanip>
using std::cout;
using std::hex;
using std::dec;
using std::setw;
using std::setfill;
using std::endl;
// C includes
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
// local includes
#include "error.h"
#include "riff.h"
#include "avi.h"
#define PADDING_SIZE (512)
#define PADDING_1GB (0x40000000)
#define IX00_INDEX_SIZE (4028)
#define AVIF_HASINDEX 0x00000010
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_TRUSTCKTYPE 0x00000800
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
//static char g_zeroes[ PADDING_SIZE ];
/** The constructor
\todo mainHdr not initialized
\todo add checking for NULL pointers
*/
AVIFile::AVIFile() : RIFFFile(),
idx1( NULL ), file_list( -1 ), riff_list( -1 ),
hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ),
index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true )
{
// cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl;
for ( int i = 0; i < 2; ++i )
{
indx[ i ] = new AVISuperIndex;
memset( indx[ i ], 0, sizeof( AVISuperIndex ) );
ix[ i ] = new AVIStdIndex;
memset( ix[ i ], 0, sizeof( AVIStdIndex ) );
indx_chunk[ i ] = -1;
ix_chunk[ i ] = -1;
strl_list[ i ] = -1;
strh_chunk[ i ] = -1;
strf_chunk[ i ] = -1;
}
idx1 = new AVISimpleIndex;
memset( idx1, 0, sizeof( AVISimpleIndex ) );
}
/** The copy constructor
\todo add checking for NULL pointers
*/
AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi )
{
// cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl;
mainHdr = avi.mainHdr;
idx1 = new AVISimpleIndex;
*idx1 = *avi.idx1;
file_list = avi.file_list;
riff_list = avi.riff_list;
hdrl_list = avi.hdrl_list;
avih_chunk = avi.avih_chunk;
movi_list = avi.movi_list;
junk_chunk = avi.junk_chunk;
idx1_chunk = avi.idx1_chunk;
for ( int i = 0; i < 2; ++i )
{
indx[ i ] = new AVISuperIndex;
*indx[ i ] = *avi.indx[ i ];
ix[ i ] = new AVIStdIndex;
*ix[ i ] = *avi.ix[ i ];
indx_chunk[ i ] = avi.indx_chunk[ i ];
ix_chunk[ i ] = avi.ix_chunk[ i ];
strl_list[ i ] = avi.strl_list[ i ];
strh_chunk[ i ] = avi.strh_chunk[ i ];
strf_chunk[ i ] = avi.strf_chunk[ i ];
}
index_type = avi.index_type;
current_ix00 = avi.current_ix00;
for ( int i = 0; i < 62; ++i )
dmlh[ i ] = avi.dmlh[ i ];
isUpdateIdx1 = avi.isUpdateIdx1;
}
/** The assignment operator
*/
AVIFile& AVIFile::operator=( const AVIFile& avi )
{
// cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl;
if ( this != &avi )
{
RIFFFile::operator=( avi );
mainHdr = avi.mainHdr;
*idx1 = *avi.idx1;
file_list = avi.file_list;
riff_list = avi.riff_list;
hdrl_list = avi.hdrl_list;
avih_chunk = avi.avih_chunk;
movi_list = avi.movi_list;
junk_chunk = avi.junk_chunk;
idx1_chunk = avi.idx1_chunk;
for ( int i = 0; i < 2; ++i )
{
*indx[ i ] = *avi.indx[ i ];
*ix[ i ] = *avi.ix[ i ];
indx_chunk[ i ] = avi.indx_chunk[ i ];
ix_chunk[ i ] = avi.ix_chunk[ i ];
strl_list[ i ] = avi.strl_list[ i ];
strh_chunk[ i ] = avi.strh_chunk[ i ];
strf_chunk[ i ] = avi.strf_chunk[ i ];
}
index_type = avi.index_type;
current_ix00 = avi.current_ix00;
for ( int i = 0; i < 62; ++i )
dmlh[ i ] = avi.dmlh[ i ];
isUpdateIdx1 = avi.isUpdateIdx1;
}
return *this;
}
/** The destructor
*/
AVIFile::~AVIFile()
{
// cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl;
for ( int i = 0; i < 2; ++i )
{
delete ix[ i ];
delete indx[ i ];
}
delete idx1;
}
/** Initialize the AVI structure to its initial state, either for PAL or NTSC format
Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1
\todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant.
\param format pass AVI_PAL or AVI_NTSC
\param sampleFrequency the sample frequency of the audio content
\param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX
*/
void AVIFile::Init( int format, int sampleFrequency, int indexType )
{
int i, j;
assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
index_type = indexType;
switch ( format )
{
case AVI_PAL:
mainHdr.dwMicroSecPerFrame = 40000;
mainHdr.dwSuggestedBufferSize = 144008;
break;
case AVI_NTSC:
mainHdr.dwMicroSecPerFrame = 33366;
mainHdr.dwSuggestedBufferSize = 120008;
break;
default: /* no default allowed */
assert( 0 );
break;
}
/* Initialize the 'avih' chunk */
mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4;
mainHdr.dwPaddingGranularity = PADDING_SIZE;
mainHdr.dwFlags = AVIF_TRUSTCKTYPE;
if ( indexType & AVI_SMALL_INDEX )
mainHdr.dwFlags |= AVIF_HASINDEX;
mainHdr.dwTotalFrames = 0;
mainHdr.dwInitialFrames = 0;
mainHdr.dwStreams = 1;
mainHdr.dwWidth = 0;
mainHdr.dwHeight = 0;
mainHdr.dwReserved[ 0 ] = 0;
mainHdr.dwReserved[ 1 ] = 0;
mainHdr.dwReserved[ 2 ] = 0;
mainHdr.dwReserved[ 3 ] = 0;
/* Initialize the 'idx1' chunk */
for ( int i = 0; i < 8000; ++i )
{
idx1->aIndex[ i ].dwChunkId = 0;
idx1->aIndex[ i ].dwFlags = 0;
idx1->aIndex[ i ].dwOffset = 0;
idx1->aIndex[ i ].dwSize = 0;
}
idx1->nEntriesInUse = 0;
/* Initialize the 'indx' chunk */
for ( i = 0; i < 2; ++i )
{
indx[ i ] ->wLongsPerEntry = 4;
indx[ i ] ->bIndexSubType = 0;
indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES;
indx[ i ] ->nEntriesInUse = 0;
indx[ i ] ->dwReserved[ 0 ] = 0;
indx[ i ] ->dwReserved[ 1 ] = 0;
indx[ i ] ->dwReserved[ 2 ] = 0;
for ( j = 0; j < 2014; ++j )
{
indx[ i ] ->aIndex[ j ].qwOffset = 0;
indx[ i ] ->aIndex[ j ].dwSize = 0;
indx[ i ] ->aIndex[ j ].dwDuration = 0;
}
}
/* The ix00 and ix01 chunk will be added dynamically in avi_write_frame
as needed */
/* Initialize the 'dmlh' chunk. I have no clue what this means
though */
for ( i = 0; i < 62; ++i )
dmlh[ i ] = 0;
//dmlh[0] = -1; /* frame count + 1? */
}
/** Find position and size of a given frame in the file
Depending on which index is available, search one of them to
find position and frame size
\todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
\todo all index related operations should be isolated
\param offset the file offset to the start of the frame
\param size the size of the frame
\param frameNum the number of the frame we wish to find
\return 0 if the frame could be found, -1 otherwise
*/
int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum )
{
switch ( index_type )
{
case AVI_LARGE_INDEX:
/* find relevant index in indx0 */
int i;
for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
;
if ( i != current_ix00 )
{
fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
current_ix00 = i;
}
if ( frameNum < ix[ 0 ] ->nEntriesInUse )
{
offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
return 0;
}
else
return -1;
break;
case AVI_SMALL_INDEX:
int index = -1;
int frameNumIndex = 0;
for ( int i = 0; i < idx1->nEntriesInUse; ++i )
{
FOURCC chunkID1 = make_fourcc( "00dc" );
FOURCC chunkID2 = make_fourcc( "00db" );
if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
idx1->aIndex[ i ].dwChunkId == chunkID2 )
{
if ( frameNumIndex == frameNum )
{
index = i;
break;
}
++frameNumIndex;
}
}
if ( index != -1 )
{
// compatibility check for broken dvgrab dv2 format
if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
{
offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
}
else
{
// new, correct dv2 format
offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
}
size = idx1->aIndex[ index ].dwSize;
return 0;
}
else
return -1;
break;
}
return -1;
}
/** Find position and size of a given frame in the file
Depending on which index is available, search one of them to
find position and frame size
\todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr.
\todo all index related operations should be isolated
\param offset the file offset to the start of the frame
\param size the size of the frame
\param frameNum the number of the frame we wish to find
\param chunkID the ID of the type of chunk we want
\return 0 if the frame could be found, -1 otherwise
*/
int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID )
{
if ( index_type & AVI_LARGE_INDEX )
{
int i;
for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i )
;
if ( i != current_ix00 )
{
fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) );
current_ix00 = i;
}
if ( frameNum < ix[ 0 ] ->nEntriesInUse )
{
if ( ( FOURCC ) ix[ 0 ] ->dwChunkId == chunkID )
{
offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset;
size = ix[ 0 ] ->aIndex[ frameNum ].dwSize;
return 0;
}
}
}
if ( index_type & AVI_SMALL_INDEX )
{
int index = -1;
int frameNumIndex = 0;
for ( int i = 0; i < idx1->nEntriesInUse; ++i )
{
if ( idx1->aIndex[ i ].dwChunkId == chunkID )
{
if ( frameNumIndex == frameNum )
{
index = i;
break;
}
++frameNumIndex;
}
}
if ( index != -1 )
{
// compatibility check for broken dvgrab dv2 format
if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset )
{
offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE;
}
else
{
// new, correct dv2 format
offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset;
}
size = idx1->aIndex[ index ].dwSize;
return 0;
}
}
return -1;
}
/** Read in a frame
\todo we actually don't need the frame here, we could use just a void pointer
\param frame a reference to the frame object that will receive the frame data
\param frameNum the frame number to read
\return 0 if the frame could be read, -1 otherwise
*/
int AVIFile::GetDVFrame( uint8_t *data, int frameNum )
{
off_t offset;
int size;
if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 )
return -1;
pthread_mutex_lock( &file_mutex );
fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, data, size ) );
pthread_mutex_unlock( &file_mutex );
return 0;
}
/** Read in a frame
\param data a pointer to the audio buffer
\param frameNum the frame number to read
\param chunkID the ID of the type of chunk we want
\return the size the of the frame data, 0 if could not be read
*/
int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID )
{
off_t offset;
int size;
if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 )
return 0;
fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, data, size ) );
return size;
}
int AVIFile::GetTotalFrames() const
{
return mainHdr.dwTotalFrames;
}
/** prints out a directory entry in text form
Every subclass of RIFFFile is supposed to override this function
and to implement it for the entry types it knows about. For all
other entry types it should call its parent::PrintDirectoryData.
\todo use 64 bit routines
\param entry the entry to print
*/
void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const
{
static FOURCC lastStreamType = make_fourcc( " " );
if ( entry.type == make_fourcc( "avih" ) )
{
int i;
MainAVIHeader main_avi_header;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) );
cout << " dwMicroSecPerFrame: " << ( int ) main_avi_header.dwMicroSecPerFrame << endl
<< " dwMaxBytesPerSec: " << ( int ) main_avi_header.dwMaxBytesPerSec << endl
<< " dwPaddingGranularity: " << ( int ) main_avi_header.dwPaddingGranularity << endl
<< " dwFlags: " << ( int ) main_avi_header.dwFlags << endl
<< " dwTotalFrames: " << ( int ) main_avi_header.dwTotalFrames << endl
<< " dwInitialFrames: " << ( int ) main_avi_header.dwInitialFrames << endl
<< " dwStreams: " << ( int ) main_avi_header.dwStreams << endl
<< " dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl
<< " dwWidth: " << ( int ) main_avi_header.dwWidth << endl
<< " dwHeight: " << ( int ) main_avi_header.dwHeight << endl;
for ( i = 0; i < 4; ++i )
cout << " dwReserved[" << i << "]: " << ( int ) main_avi_header.dwReserved[ i ] << endl;
}
else if ( entry.type == make_fourcc( "strh" ) )
{
AVIStreamHeader avi_stream_header;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) );
lastStreamType = avi_stream_header.fccType;
cout << " fccType: '"
<< ((char *)&avi_stream_header.fccType)[0]
<< ((char *)&avi_stream_header.fccType)[1]
<< ((char *)&avi_stream_header.fccType)[2]
<< ((char *)&avi_stream_header.fccType)[3]
<< '\'' << endl
<< " fccHandler: '"
<< ((char *)&avi_stream_header.fccHandler)[0]
<< ((char *)&avi_stream_header.fccHandler)[1]
<< ((char *)&avi_stream_header.fccHandler)[2]
<< ((char *)&avi_stream_header.fccHandler)[3]
<< '\'' << endl
<< " dwFlags: " << ( int ) avi_stream_header.dwFlags << endl
<< " wPriority: " << ( int ) avi_stream_header.wPriority << endl
<< " wLanguage: " << ( int ) avi_stream_header.wLanguage << endl
<< " dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl
<< " dwScale: " << ( int ) avi_stream_header.dwScale << endl
<< " dwRate: " << ( int ) avi_stream_header.dwRate << endl
<< " dwLength: " << ( int ) avi_stream_header.dwLength << endl
<< " dwQuality: " << ( int ) avi_stream_header.dwQuality << endl
<< " dwSampleSize: " << ( int ) avi_stream_header.dwSampleSize << endl;
}
else if ( entry.type == make_fourcc( "indx" ) )
{
int i;
AVISuperIndex avi_super_index;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) );
cout << " wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry
<< endl
<< " bIndexSubType: " << ( int ) avi_super_index.bIndexSubType << endl
<< " bIndexType: " << ( int ) avi_super_index.bIndexType << endl
<< " nEntriesInUse: " << ( int ) avi_super_index.nEntriesInUse << endl
<< " dwChunkId: '"
<< ((char *)&avi_super_index.dwChunkId)[0]
<< ((char *)&avi_super_index.dwChunkId)[1]
<< ((char *)&avi_super_index.dwChunkId)[2]
<< ((char *)&avi_super_index.dwChunkId)[3]
<< '\'' << endl
<< " dwReserved[0]: " << ( int ) avi_super_index.dwReserved[ 0 ] << endl
<< " dwReserved[1]: " << ( int ) avi_super_index.dwReserved[ 1 ] << endl
<< " dwReserved[2]: " << ( int ) avi_super_index.dwReserved[ 2 ] << endl;
for ( i = 0; i < avi_super_index.nEntriesInUse; ++i )
{
cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
<< ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl
<< " dwSize : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl
<< " dwDuration : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl;
}
}
else if ( entry.type == make_fourcc( "strf" ) )
{
if ( lastStreamType == make_fourcc( "auds" ) )
{
WAVEFORMATEX waveformatex;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) );
cout << " waveformatex.wFormatTag : " << waveformatex.wFormatTag << endl;
cout << " waveformatex.nChannels : " << waveformatex.nChannels << endl;
cout << " waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl;
cout << " waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl;
cout << " waveformatex.nBlockAlign : " << waveformatex.nBlockAlign << endl;
cout << " waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl;
cout << " waveformatex.cbSize : " << waveformatex.cbSize << endl;
}
else if ( lastStreamType == make_fourcc( "vids" ) )
{
BITMAPINFOHEADER bitmapinfo;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) );
cout << " bitmapinfo.biSize : " << bitmapinfo.biSize << endl;
cout << " bitmapinfo.biWidth : " << bitmapinfo.biWidth << endl;
cout << " bitmapinfo.biHeight : " << bitmapinfo.biHeight << endl;
cout << " bitmapinfo.biPlanes : " << bitmapinfo.biPlanes << endl;
cout << " bitmapinfo.biBitCount : " << bitmapinfo.biBitCount << endl;
cout << " bitmapinfo.biCompression : " << bitmapinfo.biCompression << endl;
cout << " bitmapinfo.biSizeImage : " << bitmapinfo.biSizeImage << endl;
cout << " bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl;
cout << " bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl;
cout << " bitmapinfo.biClrUsed : " << bitmapinfo.biClrUsed << endl;
cout << " bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl;
}
else if ( lastStreamType == make_fourcc( "iavs" ) )
{
DVINFO dvinfo;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) );
cout << " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl;
cout << " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl;
cout << " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl;
cout << " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl;
cout << " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl;
cout << " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl;
}
}
/* This is the Standard Index. It is an array of offsets and
sizes relative to some start offset. */
else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) )
{
int i;
AVIStdIndex avi_std_index;
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) );
cout << " wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry
<< endl
<< " bIndexSubType: " << ( int ) avi_std_index.bIndexSubType << endl
<< " bIndexType: " << ( int ) avi_std_index.bIndexType << endl
<< " nEntriesInUse: " << ( int ) avi_std_index.nEntriesInUse << endl
<< " dwChunkId: '"
<< ((char *)&avi_std_index.dwChunkId)[0]
<< ((char *)&avi_std_index.dwChunkId)[1]
<< ((char *)&avi_std_index.dwChunkId)[2]
<< ((char *)&avi_std_index.dwChunkId)[3]
<< '\'' << endl
<< " qwBaseOffset: 0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl
<< " dwReserved: " << dec << ( int ) avi_std_index.dwReserved << endl;
for ( i = 0; i < avi_std_index.nEntriesInUse; ++i )
{
cout << ' ' << setw( 4 ) << setfill( ' ' ) << i
<< ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset
<< " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl
<< " dwSize : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl;
}
}
else if ( entry.type == make_fourcc( "idx1" ) )
{
int i;
int numEntries = entry.length / sizeof( int ) / 4;
DWORD *idx1 = new DWORD[ numEntries * 4 ];
// FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi"));
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, idx1, entry.length ) );
for ( i = 0; i < numEntries; ++i )
{
cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '"
<< ((char *)&idx1[ i * 4 + 0 ])[0]
<< ((char *)&idx1[ i * 4 + 0 ])[1]
<< ((char *)&idx1[ i * 4 + 0 ])[2]
<< ((char *)&idx1[ i * 4 + 0 ])[3]
<< '\'' << endl
<< " dwType : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl
<< " dwOffset : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl
// << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl
<< " dwSize : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl;
}
delete[] idx1;
}
else if ( entry.type == make_fourcc( "dmlh" ) )
{
int i;
int numEntries = entry.length / sizeof( int );
DWORD *dmlh = new DWORD[ numEntries ];
fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
fail_neg( read( fd, dmlh, entry.length ) );
for ( i = 0; i < numEntries; ++i )
{
cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": "
<< " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ]
<< " (" << dec << dmlh[ i ] << ")" << endl;
}
delete[] dmlh;
}
}
/** If this is not a movi list, read its contents
*/
void AVIFile::ParseList( int parent )
{
FOURCC type;
FOURCC name;
DWORD length;
int list;
off_t pos;
off_t listEnd;
/* Read in the chunk header (type and length). */
fail_neg( read( fd, &type, sizeof( type ) ) );
fail_neg( read( fd, &length, sizeof( length ) ) );
if ( length & 1 )
length++;
/* The contents of the list starts here. Obtain its offset. The list
name (4 bytes) is already part of the contents). */
pos = lseek( fd, 0, SEEK_CUR );
fail_if( pos == ( off_t ) - 1 );
fail_neg( read( fd, &name, sizeof( name ) ) );
/* if we encounter a movi list, do not read it. It takes too much time
and we don't need it anyway. */
if ( name != make_fourcc( "movi" ) )
{
// if (1) {
/* Add an entry for this list. */
list = AddDirectoryEntry( type, name, sizeof( name ), parent );
/* Read in any chunks contained in this list. This list is the
parent for all chunks it contains. */
listEnd = pos + length;
while ( pos < listEnd )
{
ParseChunk( list );
pos = lseek( fd, 0, SEEK_CUR );
fail_if( pos == ( off_t ) - 1 );
}
}
else
{
/* Add an entry for this list. */
movi_list = AddDirectoryEntry( type, name, length, parent );
pos = lseek( fd, length - 4, SEEK_CUR );
fail_if( pos == ( off_t ) - 1 );
}
}
void AVIFile::ParseRIFF()
{
RIFFFile::ParseRIFF();
avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) );
if ( avih_chunk != -1 )
ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) );
}
void AVIFile::ReadIndex()
{
indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
if ( indx_chunk[ 0 ] != -1 )
{
ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ], sizeof( AVISuperIndex ) );
index_type = AVI_LARGE_INDEX;
/* recalc number of frames from each index */
mainHdr.dwTotalFrames = 0;
for ( int i = 0;
i < indx[ 0 ] ->nEntriesInUse;
mainHdr.dwTotalFrames += indx[ 0 ] ->aIndex[ i++ ].dwDuration )
;
return ;
}
idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) );
if ( idx1_chunk != -1 )
{
ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISuperIndex ) );
idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16;
index_type = AVI_SMALL_INDEX;
/* recalc number of frames from the simple index */
int frameNumIndex = 0;
FOURCC chunkID1 = make_fourcc( "00dc" );
FOURCC chunkID2 = make_fourcc( "00db" );
for ( int i = 0; i < idx1->nEntriesInUse; ++i )
{
if ( idx1->aIndex[ i ].dwChunkId == chunkID1 ||
idx1->aIndex[ i ].dwChunkId == chunkID2 )
{
++frameNumIndex;
}
}
mainHdr.dwTotalFrames = frameNumIndex;
return ;
}
}
void AVIFile::FlushIndx( int stream )
{
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
int i;
/* Write out the previous index. When this function is
entered for the first time, there is no index to
write. Note: this may be an expensive operation
because of a time consuming seek to the former file
position. */
if ( ix_chunk[ stream ] != -1 )
WriteChunk( ix_chunk[ stream ], ix[ stream ] );
/* make a new ix chunk. */
if ( stream == 0 )
type = make_fourcc( "ix00" );
else
type = make_fourcc( "ix01" );
ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list );
GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent );
/* fill out all required fields. The offsets in the
array are relative to qwBaseOffset, so fill in the
offset to the next free location in the file
there. */
ix[ stream ] ->wLongsPerEntry = 2;
ix[ stream ] ->bIndexSubType = 0;
ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS;
ix[ stream ] ->nEntriesInUse = 0;
ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId;
ix[ stream ] ->qwBaseOffset = offset + length;
ix[ stream ] ->dwReserved = 0;
for ( i = 0; i < IX00_INDEX_SIZE; ++i )
{
ix[ stream ] ->aIndex[ i ].dwOffset = 0;
ix[ stream ] ->aIndex[ i ].dwSize = 0;
}
/* add a reference to this new index in our super
index. */
i = indx[ stream ] ->nEntriesInUse++;
indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE;
indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE;
indx[ stream ] ->aIndex[ i ].dwDuration = 0;
}
void AVIFile::UpdateIndx( int stream, int chunk, int duration )
{
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
int i;
/* update the appropiate entry in the super index. It reflects
the number of frames in the referenced index. */
i = indx[ stream ] ->nEntriesInUse - 1;
indx[ stream ] ->aIndex[ i ].dwDuration += duration;
/* update the standard index. Calculate the file position of
the new frame. */
GetDirectoryEntry( chunk, type, name, length, offset, parent );
indx[ stream ] ->dwChunkId = type;
i = ix[ stream ] ->nEntriesInUse++;
ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset;
ix[ stream ] ->aIndex[ i ].dwSize = length;
}
void AVIFile::UpdateIdx1( int chunk, int flags )
{
if ( idx1->nEntriesInUse < 20000 )
{
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
GetDirectoryEntry( chunk, type, name, length, offset, parent );
idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type;
idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags;
idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE;
idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length;
idx1->nEntriesInUse++;
}
}
bool AVIFile::verifyStreamFormat( FOURCC type )
{
int i, j = 0;
AVIStreamHeader avi_stream_header;
BITMAPINFOHEADER bih;
FOURCC strh = make_fourcc( "strh" );
FOURCC strf = make_fourcc( "strf" );
while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
{
ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
if ( avi_stream_header.fccHandler == type )
return true;
}
j = 0;
while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 )
{
ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
if ( ( FOURCC ) bih.biCompression == type )
return true;
}
return false;
}
bool AVIFile::verifyStream( FOURCC type )
{
int i, j = 0;
AVIStreamHeader avi_stream_header;
FOURCC strh = make_fourcc( "strh" );
while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
{
ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
if ( avi_stream_header.fccType == type )
return true;
}
return false;
}
bool AVIFile::isOpenDML( void )
{
int i, j = 0;
FOURCC dmlh = make_fourcc( "dmlh" );
while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 )
{
return true;
}
return false;
}
AVI1File::AVI1File() : AVIFile()
{}
AVI1File::~AVI1File()
{}
/* Initialize the AVI structure to its initial state, either for PAL
or NTSC format */
void AVI1File::Init( int format, int sampleFrequency, int indexType )
{
int num_blocks;
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
AVIFile::Init( format, sampleFrequency, indexType );
switch ( format )
{
case AVI_PAL:
mainHdr.dwWidth = 720;
mainHdr.dwHeight = 576;
streamHdr[ 0 ].dwScale = 1;
streamHdr[ 0 ].dwRate = 25;
streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
/* initialize the 'strf' chunk */
/* Meaning of the DV stream format chunk per Microsoft
dwDVAAuxSrc
Specifies the Audio Auxiliary Data Source Pack for the first audio block
(first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of
a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists
of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2,
Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
Consumer-use Digital VCRs.
dwDVAAuxCtl
Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a
frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2,
Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
Consumer-use Digital VCRs.
dwDVAAuxSrc1
Specifies the Audio Auxiliary Data Source Pack for the second audio block
(second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame.
dwDVAAuxCtl1
Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame.
dwDVVAuxSrc
Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2,
Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
Consumer-use Digital VCRs.
dwDVVAuxCtl
Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2,
Annex D, "The Pack Header Table and Contents of Packs" of the Specification of
Consumer-use Digital VCRs.
dwDVReserved[2]
Reserved. Set this array to zero.
*/
dvinfo.dwDVAAuxSrc = 0xd1e030d0;
dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0;
dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
dvinfo.dwDVVAuxSrc = 0xff20ffff;
dvinfo.dwDVVAuxCtl = 0xfffdc83f;
dvinfo.dwDVReserved[ 0 ] = 0;
dvinfo.dwDVReserved[ 1 ] = 0;
break;
case AVI_NTSC:
mainHdr.dwWidth = 720;
mainHdr.dwHeight = 480;
streamHdr[ 0 ].dwScale = 1001;
streamHdr[ 0 ].dwRate = 30000;
streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
/* initialize the 'strf' chunk */
dvinfo.dwDVAAuxSrc = 0xc0c000c0;
dvinfo.dwDVAAuxCtl = 0xffa0cf3f;
dvinfo.dwDVAAuxSrc1 = 0xc0c001c0;
dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f;
dvinfo.dwDVVAuxSrc = 0xff80ffff;
dvinfo.dwDVVAuxCtl = 0xfffcc83f;
dvinfo.dwDVReserved[ 0 ] = 0;
dvinfo.dwDVReserved[ 1 ] = 0;
break;
default: /* no default allowed */
assert( 0 );
break;
}
indx[ 0 ] ->dwChunkId = make_fourcc( "00__" );
/* Initialize the 'strh' chunk */
streamHdr[ 0 ].fccType = make_fourcc( "iavs" );
streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
streamHdr[ 0 ].dwFlags = 0;
streamHdr[ 0 ].wPriority = 0;
streamHdr[ 0 ].wLanguage = 0;
streamHdr[ 0 ].dwInitialFrames = 0;
streamHdr[ 0 ].dwStart = 0;
streamHdr[ 0 ].dwLength = 0;
streamHdr[ 0 ].dwQuality = 0;
streamHdr[ 0 ].dwSampleSize = 0;
streamHdr[ 0 ].rcFrame.top = 0;
streamHdr[ 0 ].rcFrame.bottom = 0;
streamHdr[ 0 ].rcFrame.left = 0;
streamHdr[ 0 ].rcFrame.right = 0;
/* This is a simple directory structure setup. For details see the
"OpenDML AVI File Format Extensions" document.
An AVI file contains basically two types of objects, a
"chunk" and a "list" object. The list object contains any
number of chunks. Since a list is also a chunk, it is
possible to create a hierarchical "list of lists"
structure.
Every AVI file starts with a "RIFF" object, which is a list
of several other required objects. The actual DV data is
contained in a "movi" list, each frame is in its own chunk.
Old AVI files (pre OpenDML V. 1.02) contain only one RIFF
chunk of less than 1 GByte size per file. The current
format which allow for almost arbitrary sizes can contain
several RIFF chunks of less than 1 GByte size. Old software
however would only deal with the first RIFF chunk.
Note that the first entry (FILE) isn<73>t actually part
of the AVI file. I use this (pseudo-) directory entry to
keep track of the RIFF chunks and their positions in the
AVI file.
*/
/* Create the container directory entry */
file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
/* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] );
if ( index_type & AVI_LARGE_INDEX )
indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
/* align movi list to block */
GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
num_blocks = length / PADDING_SIZE + 1;
length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5?
junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
/* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame
as needed */
ix_chunk[ 0 ] = -1;
}
/* Write a DV video frame. This is somewhat complex... */
#if 0
bool AVI1File::WriteFrame( const Frame &frame )
{
int frame_chunk;
int junk_chunk;
int num_blocks;
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
/* exit if no large index and 1GB reached */
if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
return false;
/* Check if we need a new ix00 Standard Index. It has a
capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
number, we need a new index. The new ix00 chunk is also
part of the movi list. */
if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
FlushIndx( 0 );
/* Write the DV frame data.
Make a new 00__ chunk for the new frame, write out the
frame. */
frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list );
if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
{
GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
}
WriteChunk( frame_chunk, frame.data );
// num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
// length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
// junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
// WriteChunk(junk_chunk, g_zeroes);
if ( index_type & AVI_LARGE_INDEX )
UpdateIndx( 0, frame_chunk, 1 );
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
UpdateIdx1( frame_chunk, 0x10 );
/* update some variables with the new frame count. */
if ( isUpdateIdx1 )
++mainHdr.dwTotalFrames;
++streamHdr[ 0 ].dwLength;
++dmlh[ 0 ];
/* Find out if the current riff list is close to 1 GByte in
size. If so, start a new (extended) RIFF. The only allowed
item in the new RIFF chunk is a movi list (with video
frames and indexes as usual). */
GetDirectoryEntry( riff_list, type, name, length, offset, parent );
if ( length > 0x3f000000 )
{
/* write idx1 only once and before end of first GB */
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
{
int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
WriteChunk( idx1_chunk, ( void* ) idx1 );
}
isUpdateIdx1 = false;
if ( index_type & AVI_LARGE_INDEX )
{
/* pad out to 1GB */
//GetDirectoryEntry(riff_list, type, name, length, offset, parent);
//junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list);
//WriteChunk(junk_chunk, g_zeroes);
/* padding for alignment */
GetDirectoryEntry( riff_list, type, name, length, offset, parent );
num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
if ( length > 0 )
{
junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
WriteChunk( junk_chunk, g_zeroes );
}
riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
}
}
return true;
}
#endif
void AVI1File::WriteRIFF()
{
WriteChunk( avih_chunk, ( void* ) & mainHdr );
WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo );
WriteChunk( dmlh_chunk, ( void* ) & dmlh );
if ( index_type & AVI_LARGE_INDEX )
{
WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
}
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
{
int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
WriteChunk( idx1_chunk, ( void* ) idx1 );
}
RIFFFile::WriteRIFF();
}
AVI2File::AVI2File() : AVIFile()
{}
AVI2File::~AVI2File()
{}
/* Initialize the AVI structure to its initial state, either for PAL
or NTSC format */
void AVI2File::Init( int format, int sampleFrequency, int indexType )
{
int num_blocks;
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) );
AVIFile::Init( format, sampleFrequency, indexType );
switch ( format )
{
case AVI_PAL:
mainHdr.dwStreams = 2;
mainHdr.dwWidth = 720;
mainHdr.dwHeight = 576;
/* Initialize the 'strh' chunk */
streamHdr[ 0 ].fccType = make_fourcc( "vids" );
streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
streamHdr[ 0 ].dwFlags = 0;
streamHdr[ 0 ].wPriority = 0;
streamHdr[ 0 ].wLanguage = 0;
streamHdr[ 0 ].dwInitialFrames = 0;
streamHdr[ 0 ].dwScale = 1;
streamHdr[ 0 ].dwRate = 25;
streamHdr[ 0 ].dwStart = 0;
streamHdr[ 0 ].dwLength = 0;
streamHdr[ 0 ].dwSuggestedBufferSize = 144008;
streamHdr[ 0 ].dwQuality = -1;
streamHdr[ 0 ].dwSampleSize = 0;
streamHdr[ 0 ].rcFrame.top = 0;
streamHdr[ 0 ].rcFrame.bottom = 0;
streamHdr[ 0 ].rcFrame.left = 0;
streamHdr[ 0 ].rcFrame.right = 0;
bitmapinfo.biSize = sizeof( bitmapinfo );
bitmapinfo.biWidth = 720;
bitmapinfo.biHeight = 576;
bitmapinfo.biPlanes = 1;
bitmapinfo.biBitCount = 24;
bitmapinfo.biCompression = make_fourcc( "dvsd" );
bitmapinfo.biSizeImage = 144000;
bitmapinfo.biXPelsPerMeter = 0;
bitmapinfo.biYPelsPerMeter = 0;
bitmapinfo.biClrUsed = 0;
bitmapinfo.biClrImportant = 0;
streamHdr[ 1 ].fccType = make_fourcc( "auds" );
streamHdr[ 1 ].fccHandler = 0;
streamHdr[ 1 ].dwFlags = 0;
streamHdr[ 1 ].wPriority = 0;
streamHdr[ 1 ].wLanguage = 0;
streamHdr[ 1 ].dwInitialFrames = 0;
streamHdr[ 1 ].dwScale = 2 * 2;
streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
streamHdr[ 1 ].dwStart = 0;
streamHdr[ 1 ].dwLength = 0;
streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
streamHdr[ 1 ].dwQuality = -1;
streamHdr[ 1 ].dwSampleSize = 2 * 2;
streamHdr[ 1 ].rcFrame.top = 0;
streamHdr[ 1 ].rcFrame.bottom = 0;
streamHdr[ 1 ].rcFrame.left = 0;
streamHdr[ 1 ].rcFrame.right = 0;
break;
case AVI_NTSC:
mainHdr.dwTotalFrames = 0;
mainHdr.dwStreams = 2;
mainHdr.dwWidth = 720;
mainHdr.dwHeight = 480;
/* Initialize the 'strh' chunk */
streamHdr[ 0 ].fccType = make_fourcc( "vids" );
streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" );
streamHdr[ 0 ].dwFlags = 0;
streamHdr[ 0 ].wPriority = 0;
streamHdr[ 0 ].wLanguage = 0;
streamHdr[ 0 ].dwInitialFrames = 0;
streamHdr[ 0 ].dwScale = 1001;
streamHdr[ 0 ].dwRate = 30000;
streamHdr[ 0 ].dwStart = 0;
streamHdr[ 0 ].dwLength = 0;
streamHdr[ 0 ].dwSuggestedBufferSize = 120008;
streamHdr[ 0 ].dwQuality = -1;
streamHdr[ 0 ].dwSampleSize = 0;
streamHdr[ 0 ].rcFrame.top = 0;
streamHdr[ 0 ].rcFrame.bottom = 0;
streamHdr[ 0 ].rcFrame.left = 0;
streamHdr[ 0 ].rcFrame.right = 0;
bitmapinfo.biSize = sizeof( bitmapinfo );
bitmapinfo.biWidth = 720;
bitmapinfo.biHeight = 480;
bitmapinfo.biPlanes = 1;
bitmapinfo.biBitCount = 24;
bitmapinfo.biCompression = make_fourcc( "dvsd" );
bitmapinfo.biSizeImage = 120000;
bitmapinfo.biXPelsPerMeter = 0;
bitmapinfo.biYPelsPerMeter = 0;
bitmapinfo.biClrUsed = 0;
bitmapinfo.biClrImportant = 0;
streamHdr[ 1 ].fccType = make_fourcc( "auds" );
streamHdr[ 1 ].fccHandler = 0;
streamHdr[ 1 ].dwFlags = 0;
streamHdr[ 1 ].wPriority = 0;
streamHdr[ 1 ].wLanguage = 0;
streamHdr[ 1 ].dwInitialFrames = 1;
streamHdr[ 1 ].dwScale = 2 * 2;
streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2;
streamHdr[ 1 ].dwStart = 0;
streamHdr[ 1 ].dwLength = 0;
streamHdr[ 1 ].dwSuggestedBufferSize = 8192;
streamHdr[ 1 ].dwQuality = 0;
streamHdr[ 1 ].dwSampleSize = 2 * 2;
streamHdr[ 1 ].rcFrame.top = 0;
streamHdr[ 1 ].rcFrame.bottom = 0;
streamHdr[ 1 ].rcFrame.left = 0;
streamHdr[ 1 ].rcFrame.right = 0;
break;
}
waveformatex.wFormatTag = 1;
waveformatex.nChannels = 2;
waveformatex.nSamplesPerSec = sampleFrequency;
waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2;
waveformatex.nBlockAlign = 4;
waveformatex.wBitsPerSample = 16;
waveformatex.cbSize = 0;
file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
/* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */
riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list );
hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list );
avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list );
strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] );
strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] );
if ( index_type & AVI_LARGE_INDEX )
{
indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] );
ix_chunk[ 0 ] = -1;
indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" );
}
strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list );
strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] );
strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] );
junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] );
if ( index_type & AVI_LARGE_INDEX )
{
indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] );
ix_chunk[ 1 ] = -1;
indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" );
odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list );
dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list );
}
/* align movi list to block */
GetDirectoryEntry( hdrl_list, type, name, length, offset, parent );
num_blocks = length / PADDING_SIZE + 1;
length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5 headers?
junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" );
idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0;
idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0;
idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0;
idx1->nEntriesInUse++;
}
void AVI2File::WriteRIFF()
{
WriteChunk( avih_chunk, ( void* ) & mainHdr );
WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] );
WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo );
if ( index_type & AVI_LARGE_INDEX )
{
WriteChunk( dmlh_chunk, ( void* ) & dmlh );
WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] );
}
WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] );
WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex );
if ( index_type & AVI_LARGE_INDEX )
{
WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] );
WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] );
}
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
{
int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
WriteChunk( idx1_chunk, ( void* ) idx1 );
}
RIFFFile::WriteRIFF();
}
/** Write a DV video frame
\param frame the frame to write
*/
#if 0
bool AVI2File::WriteFrame( const Frame &frame )
{
int audio_chunk;
int frame_chunk;
int junk_chunk;
char soundbuf[ 20000 ];
int audio_size;
int num_blocks;
FOURCC type;
FOURCC name;
off_t length;
off_t offset;
int parent;
/* exit if no large index and 1GB reached */
if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false )
return false;
/* Check if we need a new ix00 Standard Index. It has a
capacity of IX00_INDEX_SIZE frames. Whenever we exceed that
number, we need a new index. The new ix00 chunk is also
part of the movi list. */
if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) )
{
FlushIndx( 0 );
FlushIndx( 1 );
}
/* Write audio data if we have it */
audio_size = frame.ExtractAudio( soundbuf );
if ( audio_size > 0 )
{
audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list );
if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
{
GetDirectoryEntry( audio_chunk, type, name, length, offset, parent );
ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
}
WriteChunk( audio_chunk, soundbuf );
// num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
// length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE;
// junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
// WriteChunk(junk_chunk, g_zeroes);
if ( index_type & AVI_LARGE_INDEX )
UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 );
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
UpdateIdx1( audio_chunk, 0x00 );
streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2;
}
/* Write video data */
frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list );
if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 )
{
GetDirectoryEntry( frame_chunk, type, name, length, offset, parent );
ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE;
}
WriteChunk( frame_chunk, frame.data );
// num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1;
// length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE;
// junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list);
// WriteChunk(junk_chunk, g_zeroes);
if ( index_type & AVI_LARGE_INDEX )
UpdateIndx( 0, frame_chunk, 1 );
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
UpdateIdx1( frame_chunk, 0x10 );
/* update some variables with the new frame count. */
if ( isUpdateIdx1 )
++mainHdr.dwTotalFrames;
++streamHdr[ 0 ].dwLength;
++dmlh[ 0 ];
/* Find out if the current riff list is close to 1 GByte in
size. If so, start a new (extended) RIFF. The only allowed
item in the new RIFF chunk is a movi list (with video
frames and indexes as usual). */
GetDirectoryEntry( riff_list, type, name, length, offset, parent );
if ( length > 0x3f000000 )
{
/* write idx1 only once and before end of first GB */
if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 )
{
int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list );
WriteChunk( idx1_chunk, ( void* ) idx1 );
}
isUpdateIdx1 = false;
if ( index_type & AVI_LARGE_INDEX )
{
/* padding for alignment */
GetDirectoryEntry( riff_list, type, name, length, offset, parent );
num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1;
length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE;
if ( length > 0 )
{
junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list );
WriteChunk( junk_chunk, g_zeroes );
}
riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list );
movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list );
}
}
return true;
}
#endif
void AVI1File::setDVINFO( DVINFO &info )
{
// do not do this until debugged audio against DirectShow
return ;
dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc;
dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl;
dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1;
dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1;
dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc;
dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl;
}
void AVI2File::setDVINFO( DVINFO &info )
{}
void AVIFile::setFccHandler( FOURCC type, FOURCC handler )
{
for ( int i = 0; i < mainHdr.dwStreams; i++ )
{
if ( streamHdr[ i ].fccType == type )
{
int k, j = 0;
FOURCC strf = make_fourcc( "strf" );
BITMAPINFOHEADER bih;
streamHdr[ i ].fccHandler = handler;
while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 )
{
ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) );
bih.biCompression = handler;
}
}
}
}
bool AVIFile::getStreamFormat( void* data, FOURCC type )
{
int i, j = 0;
FOURCC strh = make_fourcc( "strh" );
FOURCC strf = make_fourcc( "strf" );
AVIStreamHeader avi_stream_header;
bool result = false;
while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 )
{
ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) );
if ( avi_stream_header.fccType == type )
{
FOURCC chunkID;
int size;
pthread_mutex_lock( &file_mutex );
fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) );
if ( chunkID == strf )
{
fail_neg( read( fd, &size, sizeof( int ) ) );
fail_neg( read( fd, data, size ) );
result = true;
}
pthread_mutex_unlock( &file_mutex );
}
}
return result;
}