--- /dev/null
+include ../../../config.mak
+include config.mak
+
+TARGET=../libmltkino.so
+
+OBJS=factory.o producer_kino.o
+CPPOBJS=kino_wrapper.o avi.o error.o filehandler.o riff.o
+CFLAGS+=-I../../
+LDFLAGS+=-lmlt -lstdc++
+CXXFLAGS+=$(CFLAGS) -Wno-deprecated
+
+ifdef HAVE_LIBQUICKTIME
+CXXFLAGS+=`lqt-config --cflags`
+LDFLAGS+=`lqt-config --libs`
+endif
+
+SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cc)
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS) $(CPPOBJS)
+ $(CC) -shared -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS)
+
+depend: $(SRCS)
+ $(CC) -MM $(CFLAGS) $^ 1>.depend
+
+dist-clean: clean
+ rm -f .depend config.h config.mak
+
+clean:
+ rm -f $(OBJS) $(TARGET) $(CPPOBJS)
+
+install: all
+ install -m 755 $(TARGET) "$(prefix)/share/mlt/modules"
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
--- /dev/null
+/*
+* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Tag: $Name$
+*
+* Change log:
+*
+* $Log$
+* 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>
+
+// 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 = 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 );
+}
+
+
+void AVIFile::ReadIndex()
+{
+ indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) );
+ if ( indx_chunk[ 0 ] != -1 )
+ {
+ ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] );
+ 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 );
+ 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 = 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 );
+ if ( avi_stream_header.fccHandler == type )
+ return true;
+ }
+ j = 0;
+ while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 )
+ {
+ ReadChunk( i, ( void* ) & bih );
+ 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 );
+ 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´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 );
+ 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 );
+ 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;
+}
--- /dev/null
+/*
+* avi.h 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Tag: $Name$
+*
+* Change log:
+*
+* $Log$
+* Revision 1.1 2005/04/15 14:28:26 lilo_booter
+* Initial version
+*
+* Revision 1.16 2005/04/01 23:43:10 ddennedy
+* apply endian fixes from Daniel Kobras
+*
+* Revision 1.15 2004/10/11 01:37:11 ddennedy
+* mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
+*
+* Revision 1.14 2003/11/25 23:00:52 ddennedy
+* cleanup and a few bugfixes
+*
+* Revision 1.13 2003/10/21 16:34:32 ddennedy
+* GNOME2 port phase 1: initial checkin
+*
+* Revision 1.11.2.5 2003/07/24 14:13:57 ddennedy
+* support for distinct audio stream in type2 AVI and Quicktime; support for more DV FOURCCs
+*
+* Revision 1.11.2.4 2003/06/10 23:53:36 ddennedy
+* Daniel Kobras' WriteFrame error handling and automatic OpenDML, bugfixes in scene list updates, export AV/C Record
+*
+* Revision 1.11.2.3 2003/02/20 21:59:57 ddennedy
+* bugfixes to capture and AVI
+*
+* Revision 1.11.2.2 2003/01/13 05:15:31 ddennedy
+* added More Info panel and supporting methods
+*
+* Revision 1.11.2.1 2002/11/25 04:48:31 ddennedy
+* bugfix to report errors when loading files
+*
+* Revision 1.11 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.10 2002/05/17 08:04:25 ddennedy
+* revert const-ness of Frame references in Frame, FileHandler, and AVI classes
+*
+* Revision 1.9 2002/05/15 04:39:35 ddennedy
+* bugfixes to dv2 AVI write, audio export, Xv init
+*
+* Revision 1.8 2002/04/29 05:09:22 ddennedy
+* raw dv file support, Frame::ExtractAudio uses libdv, audioScrub prefs
+*
+* Revision 1.7 2002/04/09 06:53:42 ddennedy
+* cleanup, new libdv 0.9.5, large AVI, dnd storyboard
+*
+* Revision 1.7 2002/03/25 21:34:25 arne
+* Support for large (64 bit) files mostly completed
+*
+* 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
+*
+*/
+
+/** Common AVI declarations
+
+ Some of this comes from the public domain AVI specification, which
+ explains the microsoft-style definitions.
+
+ \file avi.h
+*/
+
+#ifndef _AVI_H
+#define _AVI_H 1
+
+#include "riff.h"
+
+#define PACKED(x) __attribute__((packed)) x
+
+#define AVI_SMALL_INDEX (0x01)
+#define AVI_LARGE_INDEX (0x02)
+#define AVI_INDEX_OF_INDEXES (0x00)
+#define AVI_INDEX_OF_CHUNKS (0x01)
+#define AVI_INDEX_2FIELD (0x01)
+
+enum { AVI_PAL, AVI_NTSC, AVI_AUDIO_48KHZ, AVI_AUDIO_44KHZ, AVI_AUDIO_32KHZ };
+
+/** Declarations of the main AVI file header
+
+ The contents of this struct goes into the 'avih' chunk. */
+
+typedef struct
+{
+ /// frame display rate (or 0L)
+ DWORD dwMicroSecPerFrame;
+
+ /// max. transfer rate
+ DWORD dwMaxBytesPerSec;
+
+ /// pad to multiples of this size, normally 2K
+ DWORD dwPaddingGranularity;
+
+ /// the ever-present flags
+ DWORD dwFlags;
+
+ /// # frames in file
+ DWORD dwTotalFrames;
+ DWORD dwInitialFrames;
+ DWORD dwStreams;
+ DWORD dwSuggestedBufferSize;
+
+ DWORD dwWidth;
+ DWORD dwHeight;
+
+ DWORD dwReserved[ 4 ];
+}
+PACKED(MainAVIHeader);
+
+typedef struct
+{
+ WORD top, bottom, left, right;
+}
+PACKED(RECT);
+
+/** Declaration of a stream header
+
+ The contents of this struct goes into the 'strh' header. */
+
+typedef struct
+{
+ FOURCC fccType;
+ FOURCC fccHandler;
+ DWORD dwFlags; /* Contains AVITF_* flags */
+ WORD wPriority;
+ WORD wLanguage;
+ DWORD dwInitialFrames;
+ DWORD dwScale;
+ DWORD dwRate; /* dwRate / dwScale == samples/second */
+ DWORD dwStart;
+ DWORD dwLength; /* In units above... */
+ DWORD dwSuggestedBufferSize;
+ DWORD dwQuality;
+ DWORD dwSampleSize;
+ RECT rcFrame;
+}
+PACKED(AVIStreamHeader);
+
+typedef struct
+{
+ DWORD dwDVAAuxSrc;
+ DWORD dwDVAAuxCtl;
+ DWORD dwDVAAuxSrc1;
+ DWORD dwDVAAuxCtl1;
+ DWORD dwDVVAuxSrc;
+ DWORD dwDVVAuxCtl;
+ DWORD dwDVReserved[ 2 ];
+}
+PACKED(DVINFO);
+
+typedef struct
+{
+ DWORD biSize;
+ LONG biWidth;
+ LONG biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+}
+PACKED(BITMAPINFOHEADER);
+
+typedef struct
+{
+ WORD wFormatTag;
+ WORD nChannels;
+ DWORD nSamplesPerSec;
+ DWORD nAvgBytesPerSec;
+ WORD nBlockAlign;
+ WORD wBitsPerSample;
+ WORD cbSize;
+ WORD dummy;
+}
+PACKED(WAVEFORMATEX);
+
+typedef struct
+{
+ WORD wLongsPerEntry;
+ BYTE bIndexSubType;
+ BYTE bIndexType;
+ DWORD nEntriesInUse;
+ FOURCC dwChunkId;
+ DWORD dwReserved[ 3 ];
+ struct avisuperindex_entry
+ {
+ QUADWORD qwOffset;
+ DWORD dwSize;
+ DWORD dwDuration;
+ }
+ aIndex[ 2014 ];
+}
+PACKED(AVISuperIndex);
+
+typedef struct
+{
+ WORD wLongsPerEntry;
+ BYTE bIndexSubType;
+ BYTE bIndexType;
+ DWORD nEntriesInUse;
+ FOURCC dwChunkId;
+ QUADWORD qwBaseOffset;
+ DWORD dwReserved;
+ struct avifieldindex_entry
+ {
+ DWORD dwOffset;
+ DWORD dwSize;
+ }
+ aIndex[ 4028 ];
+}
+PACKED(AVIStdIndex);
+
+typedef struct
+{
+ struct avisimpleindex_entry
+ {
+ FOURCC dwChunkId;
+ DWORD dwFlags;
+ DWORD dwOffset;
+ DWORD dwSize;
+ }
+ aIndex[ 20000 ];
+ DWORD nEntriesInUse;
+}
+PACKED(AVISimpleIndex);
+
+typedef struct
+{
+ DWORD dirEntryType;
+ DWORD dirEntryName;
+ DWORD dirEntryLength;
+ size_t dirEntryOffset;
+ int dirEntryWrittenFlag;
+ int dirEntryParentList;
+}
+AviDirEntry;
+
+
+/** base class for all AVI type files
+
+ It contains methods and members which are the same in all AVI type files regardless of the particular compression, number
+ of streams etc.
+
+ The AVIFile class also contains methods for handling several indexes to the video frame content. */
+
+class AVIFile : public RIFFFile
+{
+public:
+ AVIFile();
+ AVIFile( const AVIFile& );
+ virtual ~AVIFile();
+ virtual AVIFile& operator=( const AVIFile& );
+
+ virtual void Init( int format, int sampleFrequency, int indexType );
+ virtual int GetDVFrameInfo( off_t &offset, int &size, int frameNum );
+ virtual int GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID );
+ virtual int GetDVFrame( uint8_t *data, int frameNum );
+ virtual int getFrame( void *data, int frameNum, FOURCC chunkID );
+ virtual int GetTotalFrames() const;
+ virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const;
+ //virtual bool WriteFrame( const Frame &frame ) { return false; }
+ virtual void ParseList( int parent );
+ virtual void ParseRIFF( void );
+ virtual void ReadIndex( void );
+ virtual void WriteRIFF( void )
+ { }
+ virtual void FlushIndx( int stream );
+ virtual void UpdateIndx( int stream, int chunk, int duration );
+ virtual void UpdateIdx1( int chunk, int flags );
+ virtual bool verifyStreamFormat( FOURCC type );
+ virtual bool verifyStream( FOURCC type );
+ virtual bool isOpenDML( void );
+ virtual void setDVINFO( DVINFO& )
+ { }
+ virtual void setFccHandler( FOURCC type, FOURCC handler );
+ virtual bool getStreamFormat( void* data, FOURCC type );
+
+protected:
+ MainAVIHeader mainHdr;
+ AVISimpleIndex *idx1;
+ int file_list;
+ int riff_list;
+ int hdrl_list;
+ int avih_chunk;
+ int movi_list;
+ int junk_chunk;
+ int idx1_chunk;
+
+ AVIStreamHeader streamHdr[ 2 ];
+ AVISuperIndex *indx[ 2 ];
+ AVIStdIndex *ix[ 2 ];
+ int indx_chunk[ 2 ];
+ int ix_chunk[ 2 ];
+ int strl_list[ 2 ];
+ int strh_chunk[ 2 ];
+ int strf_chunk[ 2 ];
+
+ int index_type;
+ int current_ix00;
+
+ DWORD dmlh[ 62 ];
+ int odml_list;
+ int dmlh_chunk;
+ bool isUpdateIdx1;
+
+};
+
+
+/** writing Type 1 DV AVIs
+
+*/
+
+class AVI1File : public AVIFile
+{
+public:
+ AVI1File();
+ virtual ~AVI1File();
+
+ virtual void Init( int format, int sampleFrequency, int indexType );
+ //virtual bool WriteFrame( const Frame &frame );
+ virtual void WriteRIFF( void );
+ virtual void setDVINFO( DVINFO& );
+
+private:
+ DVINFO dvinfo;
+
+ AVI1File( const AVI1File& );
+ AVI1File& operator=( const AVI1File& );
+};
+
+
+/** writing Type 2 (separate audio data) DV AVIs
+
+This file type contains both audio and video tracks. It is therefore more compatible
+to certain Windows programs, which expect any AVI having both audio and video tracks.
+The video tracks contain the raw DV data (as in type 1) and the extracted audio tracks.
+
+Note that because the DV data contains audio information anyway, this means duplication
+of data and a slight increase of file size.
+
+*/
+
+class AVI2File : public AVIFile
+{
+public:
+ AVI2File();
+ virtual ~AVI2File();
+
+ virtual void Init( int format, int sampleFrequency, int indexType );
+ //virtual bool WriteFrame( const Frame &frame );
+ virtual void WriteRIFF( void );
+ virtual void setDVINFO( DVINFO& );
+
+private:
+ BITMAPINFOHEADER bitmapinfo;
+ WAVEFORMATEX waveformatex;
+
+ AVI2File( const AVI2File& );
+ AVI2File& operator=( const AVI2File& );
+};
+#endif
--- /dev/null
+#!/bin/sh
+
+if [ "$help" != "1" ]
+then
+ # Entirely optional...
+ lqt-config --prefix > /dev/null 2>&1
+ lqt_disabled=$?
+
+ echo > config.h
+ [ "$lqt_disabled" == "0" ] && echo "#define HAVE_LIBQUICKTIME" >> config.h
+ echo > config.mak
+ [ "$lqt_disabled" == "0" ] && echo "HAVE_LIBQUICKTIME=1" >> config.mak
+
+ [ "$lqt_disabled" != "0" ] && echo "- libquicktime not found: only enabling dv avi support"
+
+ echo "kino libmltkino$LIBSUF" >> ../producers.dat
+fi
+
--- /dev/null
+/* <endian_types.h>
+ *
+ * Quick hack to handle endianness and word length issues.
+ * Defines _le, _be, and _ne variants to standard ISO types
+ * like int32_t, that are stored in little-endian, big-endian,
+ * and native-endian byteorder in memory, respectively.
+ * Caveat: int32_le_t and friends cannot be used in vararg
+ * functions like printf() without an explicit cast.
+ *
+ * Copyright (c) 2003-2005 Daniel Kobras <kobras@debian.org>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ENDIAN_TYPES_H
+#define _ENDIAN_TYPES_H
+
+/* Needed for BYTE_ORDER and BIG/LITTLE_ENDIAN macros. */
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE
+# include <endian.h>
+# undef _BSD_SOURCE
+#else
+# include <endian.h>
+#endif
+
+#include <sys/types.h>
+#include <byteswap.h>
+
+static inline int8_t bswap(const int8_t& x)
+{
+ return x;
+}
+
+static inline u_int8_t bswap(const u_int8_t& x)
+{
+ return x;
+}
+
+static inline int16_t bswap(const int16_t& x)
+{
+ return bswap_16(x);
+}
+
+static inline u_int16_t bswap(const u_int16_t& x)
+{
+ return bswap_16(x);
+}
+
+static inline int32_t bswap(const int32_t& x)
+{
+ return bswap_32(x);
+}
+
+static inline u_int32_t bswap(const u_int32_t& x)
+{
+ return bswap_32(x);
+}
+
+static inline int64_t bswap(const int64_t& x)
+{
+ return bswap_64(x);
+}
+
+static inline u_int64_t bswap(const u_int64_t& x)
+{
+ return bswap_64(x);
+}
+
+#define le_to_cpu cpu_to_le
+#define be_to_cpu cpu_to_be
+
+template <class T> static inline T cpu_to_le(const T& x)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return x;
+#else
+ return bswap(x);
+#endif
+}
+
+template <class T> static inline T cpu_to_be(const T& x)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return bswap(x);
+#else
+ return x;
+#endif
+}
+
+template <class T> class le_t {
+ T m;
+ T read() const {
+ return le_to_cpu(m);
+ };
+ void write(const T& n) {
+ m = cpu_to_le(n);
+ };
+public:
+ le_t(void) {
+ m = 0;
+ };
+ le_t(const T& o) {
+ write(o);
+ };
+ operator T() const {
+ return read();
+ };
+ le_t<T> operator++() {
+ write(read() + 1);
+ return *this;
+ };
+ le_t<T> operator++(int) {
+ write(read() + 1);
+ return *this;
+ };
+ le_t<T> operator--() {
+ write(read() - 1);
+ return *this;
+ };
+ le_t<T> operator--(int) {
+ write(read() - 1);
+ return *this;
+ };
+ le_t<T>& operator+=(const T& t) {
+ write(read() + t);
+ return *this;
+ };
+ le_t<T>& operator-=(const T& t) {
+ write(read() - t);
+ return *this;
+ };
+ le_t<T>& operator&=(const le_t<T>& t) {
+ m &= t.m;
+ return *this;
+ };
+ le_t<T>& operator|=(const le_t<T>& t) {
+ m |= t.m;
+ return *this;
+ };
+} __attribute__((packed));
+
+/* Just copy-and-pasted from le_t. Too lazy to do it right. */
+
+template <class T> class be_t {
+ T m;
+ T read() const {
+ return be_to_cpu(m);
+ };
+ void write(const T& n) {
+ m = cpu_to_be(n);
+ };
+public:
+ be_t(void) {
+ m = 0;
+ };
+ be_t(const T& o) {
+ write(o);
+ };
+ operator T() const {
+ return read();
+ };
+ be_t<T> operator++() {
+ write(read() + 1);
+ return *this;
+ };
+ be_t<T> operator++(int) {
+ write(read() + 1);
+ return *this;
+ };
+ be_t<T> operator--() {
+ write(read() - 1);
+ return *this;
+ };
+ be_t<T> operator--(int) {
+ write(read() - 1);
+ return *this;
+ };
+ be_t<T>& operator+=(const T& t) {
+ write(read() + t);
+ return *this;
+ };
+ be_t<T>& operator-=(const T& t) {
+ write(read() - t);
+ return *this;
+ };
+ be_t<T>& operator&=(const be_t<T>& t) {
+ m &= t.m;
+ return *this;
+ };
+ be_t<T>& operator|=(const be_t<T>& t) {
+ m |= t.m;
+ return *this;
+ };
+} __attribute__((packed));
+
+/* Define types of native endianness similar to the little and big endian
+ * versions below. Not really necessary but useful occasionally to emphasize
+ * endianness of data.
+ */
+
+typedef int8_t int8_ne_t;
+typedef int16_t int16_ne_t;
+typedef int32_t int32_ne_t;
+typedef int64_t int64_ne_t;
+typedef u_int8_t u_int8_ne_t;
+typedef u_int16_t u_int16_ne_t;
+typedef u_int32_t u_int32_ne_t;
+typedef u_int64_t u_int64_ne_t;
+
+
+/* The classes work on their native endianness as well, but obviously
+ * introduce some overhead. Use the faster typedefs to native types
+ * therefore, unless you're debugging.
+ */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+typedef int8_ne_t int8_le_t;
+typedef int16_ne_t int16_le_t;
+typedef int32_ne_t int32_le_t;
+typedef int64_ne_t int64_le_t;
+typedef u_int8_ne_t u_int8_le_t;
+typedef u_int16_ne_t u_int16_le_t;
+typedef u_int32_ne_t u_int32_le_t;
+typedef u_int64_ne_t u_int64_le_t;
+typedef int8_t int8_be_t;
+typedef be_t<int16_t> int16_be_t;
+typedef be_t<int32_t> int32_be_t;
+typedef be_t<int64_t> int64_be_t;
+typedef u_int8_t u_int8_be_t;
+typedef be_t<u_int16_t> u_int16_be_t;
+typedef be_t<u_int32_t> u_int32_be_t;
+typedef be_t<u_int64_t> u_int64_be_t;
+#else
+typedef int8_ne_t int8_be_t;
+typedef int16_ne_t int16_be_t;
+typedef int32_ne_t int32_be_t;
+typedef int64_ne_t int64_be_t;
+typedef u_int8_ne_t u_int8_be_t;
+typedef u_int16_ne_t u_int16_be_t;
+typedef u_int32_ne_t u_int32_be_t;
+typedef u_int64_ne_t u_int64_be_t;
+typedef int8_t int8_le_t;
+typedef le_t<int16_t> int16_le_t;
+typedef le_t<int32_t> int32_le_t;
+typedef le_t<int64_t> int64_le_t;
+typedef u_int8_t u_int8_le_t;
+typedef le_t<u_int16_t> u_int16_le_t;
+typedef le_t<u_int32_t> u_int32_le_t;
+typedef le_t<u_int64_t> u_int64_le_t;
+#endif
+
+#endif
--- /dev/null
+/*
+* error.cc Error handling
+* Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// C++ includes
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+using std::ostringstream;
+using std::string;
+using std::endl;
+using std::ends;
+using std::cerr;
+
+// C includes
+
+#include <errno.h>
+#include <string.h>
+
+// local includes
+
+#include "error.h"
+
+void real_fail_neg( int eval, const char *eval_str, const char *func, const char *file, int line )
+{
+ if ( eval < 0 )
+ {
+ string exc;
+ ostringstream sb;
+
+ sb << file << ":" << line << ": In function \"" << func << "\": \"" << eval_str << "\" evaluated to " << eval;
+ if ( errno != 0 )
+ sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")";
+ sb << ends;
+ exc = sb.str();
+ cerr << exc << endl;
+ throw exc;
+ }
+}
+
+
+/** error handler for NULL result codes
+
+ Whenever this is called with a NULL argument, it will throw an
+ exception. Typically used with functions like malloc() and new().
+
+*/
+
+void real_fail_null( const void *eval, const char *eval_str, const char *func, const char *file, int line )
+{
+ if ( eval == NULL )
+ {
+
+ string exc;
+ ostringstream sb;
+
+ sb << file << ":" << line << ": In function \"" << func << "\": " << eval_str << " is NULL" << ends;
+ exc = sb.str();
+ cerr << exc << endl;
+ throw exc;
+ }
+}
+
+
+void real_fail_if( bool eval, const char *eval_str, const char *func, const char *file, int line )
+{
+ if ( eval == true )
+ {
+
+ string exc;
+ ostringstream sb;
+
+ sb << file << ":" << line << ": In function \"" << func << "\": condition \"" << eval_str << "\" is true";
+ if ( errno != 0 )
+ sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")";
+ sb << ends;
+ exc = sb.str();
+ cerr << exc << endl;
+ throw exc;
+ }
+}
--- /dev/null
+/*
+* error.h Error handling
+* Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _ERROR_H
+#define _ERROR_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /*
+ * Should check for gcc/g++ and version > 2.6 I suppose
+ */
+#ifndef __ASSERT_FUNCTION
+# define __ASSERT_FUNCTION __PRETTY_FUNCTION__
+#endif
+
+#define fail_neg(eval) real_fail_neg (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__)
+#define fail_null(eval) real_fail_null (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__)
+#define fail_if(eval) real_fail_if (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__)
+
+ void real_fail_neg ( int eval, const char * eval_str, const char * func, const char * file, int line );
+ void real_fail_null ( const void * eval, const char * eval_str, const char * func, const char * file, int line );
+ void real_fail_if ( bool eval, const char * eval_str, const char * func, const char * file, int line );
+
+ extern void sigpipe_clear( );
+ extern int sigpipe_get( );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * factory.c -- the factory method interfaces
+ * Copyright (C) 2005 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "producer_kino.h"
+
+void *mlt_create_producer( char *id, void *arg )
+{
+ if ( !strcmp( id, "kino" ) )
+ return producer_kino_init( arg );
+ return NULL;
+}
+
+void *mlt_create_filter( char *id, void *arg )
+{
+ return NULL;
+}
+
+void *mlt_create_transition( char *id, void *arg )
+{
+ return NULL;
+}
+
+void *mlt_create_consumer( char *id, void *arg )
+{
+ return NULL;
+}
+
--- /dev/null
+/*
+* filehandler.cc -- saving DV data into different file formats
+* Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+using std::cerr;
+using std::endl;
+using std::ostringstream;
+using std::setw;
+using std::setfill;
+
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "filehandler.h"
+#include "error.h"
+#include "riff.h"
+#include "avi.h"
+
+FileTracker *FileTracker::instance = NULL;
+
+FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND )
+{
+ cerr << ">> Constructing File Capture tracker" << endl;
+}
+
+FileTracker::~FileTracker( )
+{
+ cerr << ">> Destroying File Capture tracker" << endl;
+}
+
+FileTracker &FileTracker::GetInstance( )
+{
+ if ( instance == NULL )
+ instance = new FileTracker();
+
+ return *instance;
+}
+
+void FileTracker::SetMode( FileCaptureMode mode )
+{
+ this->mode = mode;
+}
+
+FileCaptureMode FileTracker::GetMode( )
+{
+ return this->mode;
+}
+
+char *FileTracker::Get( int index )
+{
+ return list[ index ];
+}
+
+void FileTracker::Add( const char *file )
+{
+ if ( this->mode != CAPTURE_IGNORE )
+ {
+ cerr << ">>>> Registering " << file << " with the tracker" << endl;
+ list.push_back( strdup( file ) );
+ }
+}
+
+unsigned int FileTracker::Size( )
+{
+ return list.size();
+}
+
+void FileTracker::Clear( )
+{
+ while ( Size() > 0 )
+ {
+ free( list[ Size() - 1 ] );
+ list.pop_back( );
+ }
+ this->mode = CAPTURE_MOVIE_APPEND;
+}
+
+FileHandler::FileHandler() : done( false ), autoSplit( false ), maxFrameCount( 999999 ),
+ framesWritten( 0 ), filename( "" )
+{
+ /* empty body */
+}
+
+
+FileHandler::~FileHandler()
+{
+ /* empty body */
+}
+
+
+bool FileHandler::GetAutoSplit() const
+{
+ return autoSplit;
+}
+
+
+bool FileHandler::GetTimeStamp() const
+{
+ return timeStamp;
+}
+
+
+string FileHandler::GetBaseName() const
+{
+ return base;
+}
+
+
+string FileHandler::GetExtension() const
+{
+ return extension;
+}
+
+
+int FileHandler::GetMaxFrameCount() const
+{
+ return maxFrameCount;
+}
+
+off_t FileHandler::GetMaxFileSize() const
+{
+ return maxFileSize;
+}
+
+string FileHandler::GetFilename() const
+{
+ return filename;
+}
+
+
+void FileHandler::SetAutoSplit( bool flag )
+{
+ autoSplit = flag;
+}
+
+
+void FileHandler::SetTimeStamp( bool flag )
+{
+ timeStamp = flag;
+}
+
+
+void FileHandler::SetBaseName( const string& s )
+{
+ base = s;
+}
+
+
+void FileHandler::SetMaxFrameCount( int count )
+{
+ assert( count >= 0 );
+ maxFrameCount = count;
+}
+
+
+void FileHandler::SetEveryNthFrame( int every )
+{
+ assert ( every > 0 );
+
+ everyNthFrame = every;
+}
+
+
+void FileHandler::SetMaxFileSize( off_t size )
+{
+ assert ( size >= 0 );
+ maxFileSize = size;
+}
+
+
+#if 0
+void FileHandler::SetSampleFrame( const Frame& sample )
+{
+ /* empty body */
+}
+#endif
+
+bool FileHandler::Done()
+{
+ return done;
+}
+
+#if 0
+bool FileHandler::WriteFrame( const Frame& frame )
+{
+ static TimeCode prevTimeCode;
+ TimeCode timeCode;
+
+ /* If the user wants autosplit, start a new file if a
+ new recording is detected. */
+ prevTimeCode.sec = -1;
+ frame.GetTimeCode( timeCode );
+ int time_diff = timeCode.sec - prevTimeCode.sec;
+ bool discontinuity = prevTimeCode.sec != -1 && ( time_diff > 1 || ( time_diff < 0 && time_diff > -59 ) );
+ if ( FileIsOpen() && GetAutoSplit() == true && ( frame.IsNewRecording() || discontinuity ) )
+ {
+ Close();
+ }
+
+ if ( FileIsOpen() == false )
+ {
+
+ string filename;
+ static int counter = 0;
+
+ if ( GetTimeStamp() == true )
+ {
+ ostringstream sb, sb2;
+ struct tm date;
+ string recDate;
+
+ if ( ! frame.GetRecordingDate( date ) )
+ {
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday( &tv, &tz );
+ localtime_r( static_cast< const time_t * >( &tv.tv_sec ), &date );
+ }
+ sb << setfill( '0' )
+ << setw( 4 ) << date.tm_year + 1900 << '.'
+ << setw( 2 ) << date.tm_mon + 1 << '.'
+ << setw( 2 ) << date.tm_mday << '_'
+ << setw( 2 ) << date.tm_hour << '-'
+ << setw( 2 ) << date.tm_min << '-'
+ << setw( 2 ) << date.tm_sec;
+ recDate = sb.str();
+ sb2 << GetBaseName() << recDate << GetExtension();
+ filename = sb2.str();
+ cerr << ">>> Trying " << filename << endl;
+ }
+ else
+ {
+ struct stat stats;
+ do
+ {
+ ostringstream sb;
+ sb << GetBaseName() << setfill( '0' ) << setw( 3 ) << ++ counter << GetExtension();
+ filename = sb.str();
+ cerr << ">>> Trying " << filename << endl;
+ }
+ while ( stat( filename.c_str(), &stats ) == 0 );
+ }
+
+ SetSampleFrame( frame );
+ if ( Create( filename ) == false )
+ {
+ cerr << ">>> Error creating file!" << endl;
+ return false;
+ }
+ framesWritten = 0;
+ framesToSkip = 0;
+ }
+
+ /* write frame */
+
+ if ( framesToSkip == 0 )
+ {
+ if ( 0 > Write( frame ) )
+ {
+ cerr << ">>> Error writing frame!" << endl;
+ return false;
+ }
+ framesToSkip = everyNthFrame;
+ ++framesWritten;
+ }
+ framesToSkip--;
+
+ /* If the frame count is exceeded, close the current file.
+ If the autosplit flag is set, a new file will be created in the next iteration.
+ If the flag is not set, we are done. */
+
+ if ( ( GetMaxFrameCount() > 0 ) &&
+ ( framesWritten >= GetMaxFrameCount() ) )
+ {
+ Close();
+ done = !GetAutoSplit();
+ }
+
+ /* If the file size could be exceeded by another frame, close the current file.
+ If the autosplit flag is set, a new file will be created on the next iteration.
+ If the flag is not set, we are done. */
+ /* not exact, but should be good enough to prevent going over. */
+ if ( FileIsOpen() )
+ {
+ AudioInfo info;
+ frame.GetAudioInfo( info );
+ if ( ( GetFileSize() > 0 ) && ( GetMaxFileSize() > 0 ) &&
+ ( GetFileSize() + frame.GetFrameSize() + info.samples * 4 + 12 )
+ >= GetMaxFileSize() )
+ { // 12 = sizeof chunk metadata
+ Close();
+ done = !GetAutoSplit();
+ }
+ }
+ prevTimeCode.sec = timeCode.sec;
+ return true;
+}
+#endif
+
+RawHandler::RawHandler() : fd( -1 )
+{
+ extension = ".dv";
+}
+
+
+RawHandler::~RawHandler()
+{
+ Close();
+}
+
+
+bool RawHandler::FileIsOpen()
+{
+ return fd != -1;
+}
+
+
+bool RawHandler::Create( const string& filename )
+{
+ fd = open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 );
+ if ( fd != -1 )
+ {
+ FileTracker::GetInstance().Add( filename.c_str() );
+ this->filename = filename;
+ }
+ return ( fd != -1 );
+}
+
+
+#if 0
+int RawHandler::Write( const Frame& frame )
+{
+ int result = write( fd, frame.data, frame.GetFrameSize() );
+ return result;
+}
+#endif
+
+int RawHandler::Close()
+{
+ if ( fd != -1 )
+ {
+ close( fd );
+ fd = -1;
+ }
+ return 0;
+}
+
+
+off_t RawHandler::GetFileSize()
+{
+ struct stat file_status;
+ fstat( fd, &file_status );
+ return file_status.st_size;
+}
+
+int RawHandler::GetTotalFrames()
+{
+ return GetFileSize() / ( 480 * numBlocks );
+}
+
+
+bool RawHandler::Open( const char *s )
+{
+ unsigned char data[ 4 ];
+ assert( fd == -1 );
+ fd = open( s, O_RDONLY | O_NONBLOCK );
+ if ( fd < 0 )
+ return false;
+ if ( read( fd, data, 4 ) < 0 )
+ return false;
+ lseek( fd, 0, SEEK_SET );
+ numBlocks = ( ( data[ 3 ] & 0x80 ) == 0 ) ? 250 : 300;
+ filename = s;
+ return true;
+
+}
+
+int RawHandler::GetFrame( uint8_t *data, int frameNum )
+{
+ assert( fd != -1 );
+ int size = 480 * numBlocks;
+ if ( frameNum < 0 )
+ return -1;
+ off_t offset = ( ( off_t ) frameNum * ( off_t ) size );
+ fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 );
+ if ( read( fd, data, size ) > 0 )
+ return 0;
+ else
+ return -1;
+}
+
+
+/***************************************************************************/
+
+
+AVIHandler::AVIHandler( int format ) : avi( NULL ), aviFormat( format ), isOpenDML( false ),
+ fccHandler( make_fourcc( "dvsd" ) ), channels( 2 ), isFullyInitialized( false ),
+ audioBuffer( NULL )
+{
+ extension = ".avi";
+ for ( int c = 0; c < 4; c++ )
+ audioChannels[ c ] = NULL;
+}
+
+
+AVIHandler::~AVIHandler()
+{
+ if ( audioBuffer != NULL )
+ {
+ delete audioBuffer;
+ audioBuffer = NULL;
+ }
+ for ( int c = 0; c < 4; c++ )
+ {
+ if ( audioChannels[ c ] != NULL )
+ {
+ delete audioChannels[ c ];
+ audioChannels[ c ] = NULL;
+ }
+ }
+
+ delete avi;
+}
+
+#if 0
+void AVIHandler::SetSampleFrame( const Frame& sample )
+{
+ Pack pack;
+ sample.GetAudioInfo( audioInfo );
+ sample.GetVideoInfo( videoInfo );
+
+ sample.GetAAUXPack( 0x50, pack );
+ dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 );
+ sample.GetAAUXPack( 0x51, pack );
+ dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 );
+
+ sample.GetAAUXPack( 0x52, pack );
+ dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 );
+ sample.GetAAUXPack( 0x53, pack );
+ dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 );
+
+ sample.GetVAUXPack( 0x60, pack );
+ dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 );
+ sample.GetVAUXPack( 0x61, pack );
+ dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 );
+
+#ifdef WITH_LIBDV
+
+ if ( sample.decoder->std == e_dv_std_smpte_314m )
+ fccHandler = make_fourcc( "dv25" );
+#endif
+}
+#endif
+
+bool AVIHandler::FileIsOpen()
+{
+ return avi != NULL;
+}
+
+
+bool AVIHandler::Create( const string& filename )
+{
+ assert( avi == NULL );
+
+ switch ( aviFormat )
+ {
+
+ case AVI_DV1_FORMAT:
+ fail_null( avi = new AVI1File );
+ if ( avi->Create( filename.c_str() ) == false )
+ return false;
+ //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, AVI_LARGE_INDEX );
+ break;
+
+ case AVI_DV2_FORMAT:
+ fail_null( avi = new AVI2File );
+ if ( avi->Create( filename.c_str() ) == false )
+ return false;
+ //if ( GetOpenDML() )
+ //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
+ //( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) );
+ //else
+ //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency,
+ //( AVI_SMALL_INDEX ) );
+ break;
+
+ default:
+ assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT );
+ }
+
+ avi->setDVINFO( dvinfo );
+ avi->setFccHandler( make_fourcc( "iavs" ), fccHandler );
+ avi->setFccHandler( make_fourcc( "vids" ), fccHandler );
+ this->filename = filename;
+ FileTracker::GetInstance().Add( filename.c_str() );
+ return ( avi != NULL );
+}
+
+#if 0
+int AVIHandler::Write( const Frame& frame )
+{
+ assert( avi != NULL );
+ try
+ {
+ return avi->WriteFrame( frame ) ? 0 : -1;
+ }
+ catch (...)
+ {
+ return -1;
+ }
+}
+#endif
+
+int AVIHandler::Close()
+{
+ if ( avi != NULL )
+ {
+ avi->WriteRIFF();
+ delete avi;
+ avi = NULL;
+ }
+ if ( audioBuffer != NULL )
+ {
+ delete audioBuffer;
+ audioBuffer = NULL;
+ }
+ for ( int c = 0; c < 4; c++ )
+ {
+ if ( audioChannels[ c ] != NULL )
+ {
+ delete audioChannels[ c ];
+ audioChannels[ c ] = NULL;
+ }
+ }
+ isFullyInitialized = false;
+ return 0;
+}
+
+off_t AVIHandler::GetFileSize()
+{
+ return avi->GetFileSize();
+}
+
+int AVIHandler::GetTotalFrames()
+{
+ return avi->GetTotalFrames();
+}
+
+
+bool AVIHandler::Open( const char *s )
+{
+ assert( avi == NULL );
+ fail_null( avi = new AVI1File );
+ if ( avi->Open( s ) )
+ {
+ avi->ParseRIFF();
+ if ( ! (
+ avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "DV25" ) ) ||
+ avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) )
+ return false;
+ avi->ReadIndex();
+ if ( avi->verifyStream( make_fourcc( "auds" ) ) )
+ aviFormat = AVI_DV2_FORMAT;
+ else
+ aviFormat = AVI_DV1_FORMAT;
+ isOpenDML = avi->isOpenDML();
+ filename = s;
+ return true;
+ }
+ else
+ return false;
+
+}
+
+int AVIHandler::GetFrame( uint8_t *data, int frameNum )
+{
+ int result = avi->GetDVFrame( data, frameNum );
+#if 0
+ if ( result == 0 )
+ {
+ /* get the audio from the audio stream, if available */
+ if ( aviFormat == AVI_DV2_FORMAT )
+ {
+ WAVEFORMATEX wav;
+
+ if ( ! isFullyInitialized &&
+ avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) )
+ {
+ if ( channels > 0 && channels < 5 )
+ {
+ // Allocate interleaved audio buffer
+ audioBuffer = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES * channels ];
+
+ // Allocate non-interleaved audio buffers
+ for ( int c = 0; c < channels; c++ )
+ audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ];
+
+ // Get the audio parameters from AVI for subsequent calls to method
+ audioInfo.channels = wav.nChannels;
+ audioInfo.frequency = wav.nSamplesPerSec;
+
+ // Skip initialization on subsequent calls to method
+ isFullyInitialized = true;
+ cerr << ">>> using audio from separate AVI audio stream" << endl;
+ }
+ }
+
+ // Get the frame from AVI
+ int n = avi->getFrame( audioBuffer, frameNum, make_fourcc( "01wb" ) );
+ if ( n > 0 )
+ {
+ // Temporary pointer to audio scratch buffer
+ int16_t * s = audioBuffer;
+
+ // Determine samples in this frame
+ audioInfo.samples = n / audioInfo.channels / sizeof( int16_t );
+
+ // Convert interleaved audio into non-interleaved
+ for ( int n = 0; n < audioInfo.samples; ++n )
+ for ( int i = 0; i < audioInfo.channels; i++ )
+ audioChannels[ i ][ n ] = *s++;
+
+ // Write interleaved audio into frame
+ frame.EncodeAudio( audioInfo, audioChannels );
+ }
+ }
+
+ // Parse important metadata in DV bitstream
+ frame.ExtractHeader();
+ }
+#endif
+ return result;
+}
+
+
+void AVIHandler::SetOpenDML( bool flag )
+{
+ isOpenDML = flag;
+}
+
+
+bool AVIHandler::GetOpenDML() const
+{
+ return isOpenDML;
+}
+
+
+/***************************************************************************/
+
+#ifdef HAVE_LIBQUICKTIME
+
+#ifndef HAVE_LIBDV
+#define DV_AUDIO_MAX_SAMPLES 1944
+#endif
+
+QtHandler::QtHandler() : fd( NULL )
+{
+ extension = ".mov";
+ Init();
+}
+
+
+QtHandler::~QtHandler()
+{
+ Close();
+}
+
+void QtHandler::Init()
+{
+ if ( fd != NULL )
+ Close();
+
+ fd = NULL;
+ samplingRate = 0;
+ samplesPerBuffer = 0;
+ channels = 2;
+ audioBuffer = NULL;
+ audioChannelBuffer = NULL;
+ isFullyInitialized = false;
+}
+
+
+bool QtHandler::FileIsOpen()
+{
+ return fd != NULL;
+}
+
+
+bool QtHandler::Create( const string& filename )
+{
+ Init();
+
+ if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 )
+ {
+ fd = quicktime_open( const_cast<char*>( filename.c_str() ), 0, 1 );
+ if ( fd != NULL )
+ FileTracker::GetInstance().Add( filename.c_str() );
+ }
+ else
+ return false;
+ this->filename = filename;
+ return true;
+}
+
+void QtHandler::AllocateAudioBuffers()
+{
+ if ( channels > 0 && channels < 5 )
+ {
+ audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2;
+ audioBuffer = new int16_t[ audioBufferSize * channels ];
+
+ audioChannelBuffer = new short int * [ channels ];
+ for ( int c = 0; c < channels; c++ )
+ audioChannelBuffer[ c ] = new short int[ audioBufferSize ];
+ isFullyInitialized = true;
+ }
+}
+
+inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes,
+ void* pLOutput, void* pROutput )
+{
+ short int * piSampleInput = ( short int* ) pInput;
+ short int* piSampleLOutput = ( short int* ) pLOutput;
+ short int* piSampleROutput = ( short int* ) pROutput;
+
+ while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) )
+ {
+ *piSampleLOutput++ = *piSampleInput++;
+ *piSampleROutput++ = *piSampleInput++;
+ }
+}
+
+#if 0
+int QtHandler::Write( const Frame& frame )
+{
+ if ( ! isFullyInitialized )
+ {
+ AudioInfo audio;
+
+ if ( frame.GetAudioInfo( audio ) )
+ {
+ channels = 2;
+ quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS );
+ }
+ else
+ {
+ channels = 0;
+ }
+
+ quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480,
+ frame.GetFrameRate(), QUICKTIME_DV );
+ AllocateAudioBuffers();
+ }
+
+ int result = quicktime_write_frame( fd, const_cast<unsigned char*>( frame.data ),
+ frame.GetFrameSize(), 0 );
+
+ if ( channels > 0 )
+ {
+ AudioInfo audio;
+ if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize )
+ {
+ long bytesRead = frame.ExtractAudio( audioBuffer );
+
+ DeinterlaceStereo16( audioBuffer, bytesRead,
+ audioChannelBuffer[ 0 ],
+ audioChannelBuffer[ 1 ] );
+
+ quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples );
+ }
+ }
+ return result;
+}
+#endif
+
+int QtHandler::Close()
+{
+ if ( fd != NULL )
+ {
+ quicktime_close( fd );
+ fd = NULL;
+ }
+ if ( audioBuffer != NULL )
+ {
+ delete audioBuffer;
+ audioBuffer = NULL;
+ }
+ if ( audioChannelBuffer != NULL )
+ {
+ for ( int c = 0; c < channels; c++ )
+ delete audioChannelBuffer[ c ];
+ delete audioChannelBuffer;
+ audioChannelBuffer = NULL;
+ }
+ return 0;
+}
+
+
+off_t QtHandler::GetFileSize()
+{
+ struct stat file_status;
+ fstat( fileno( fd->stream ), &file_status );
+ return file_status.st_size;
+}
+
+
+int QtHandler::GetTotalFrames()
+{
+ return ( int ) quicktime_video_length( fd, 0 );
+}
+
+
+bool QtHandler::Open( const char *s )
+{
+ Init();
+
+ fd = quicktime_open( ( char * ) s, 1, 0 );
+ if ( fd == NULL )
+ {
+ fprintf( stderr, "Error opening: %s\n", s );
+ return false;
+ }
+
+ if ( quicktime_has_video( fd ) <= 0 )
+ {
+ fprintf( stderr, "There must be at least one video track in the input file (%s).\n",
+ s );
+ Close();
+ return false;
+ }
+ if ( strncmp( quicktime_video_compressor( fd, 0 ), QUICKTIME_DV, 4 ) != 0 )
+ {
+ fprintf( stderr, "Video in input file (%s) must be in DV format.\n", s );
+ Close();
+ return false;
+ }
+ if ( quicktime_has_audio( fd ) )
+ channels = quicktime_track_channels( fd, 0 );
+ filename = s;
+ return true;
+}
+
+int QtHandler::GetFrame( uint8_t *data, int frameNum )
+{
+ assert( fd != NULL );
+
+ quicktime_set_video_position( fd, frameNum, 0 );
+ quicktime_read_frame( fd, data, 0 );
+
+#if 0
+ if ( quicktime_has_audio( fd ) )
+ {
+ AudioInfo info;
+ double samples;
+
+ if ( ! isFullyInitialized )
+ {
+ cerr << ">>> using audio from separarate Quicktime audio track" << endl;
+ AllocateAudioBuffers();
+ }
+
+ info.channels = channels;
+ info.frequency = quicktime_sample_rate( fd, 0 );
+ samples = info.frequency / quicktime_frame_rate( fd, 0 );
+ info.samples = (int) samples;
+ for ( int i = 0; i < channels; i++ )
+ {
+ quicktime_set_audio_position( fd, ( int64_t )( frameNum * samples ), 0 );
+ quicktime_decode_audio( fd, audioChannelBuffer[ i ], NULL, (long) samples, i );
+ }
+ frame.EncodeAudio( info, audioChannelBuffer );
+ }
+ frame.ExtractHeader();
+#endif
+
+ return 0;
+}
+#endif
--- /dev/null
+/*
+* filehandler.h
+* Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _FILEHANDLER_H
+#define _FILEHANDLER_H
+
+// enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED };
+
+#include <vector>
+using std::vector;
+
+#include <string>
+using std::string;
+
+#include "riff.h"
+#include "avi.h"
+#include <sys/types.h>
+#include <stdint.h>
+
+enum { AVI, PLAYLIST, RAW_DV, QT, UNKNOWN_FORMAT };
+enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED };
+enum { DISPLAY_XX, DISPLAY_GDKRGB, DISPLAY_GDKRGB32, DISPLAY_XV, DISPLAY_SDL };
+
+enum { NORM_UNSPECIFIED=0, NORM_PAL=1, NORM_NTSC=2 };
+enum { AUDIO_32KHZ=0, AUDIO_44KHZ=1, AUDIO_48KHZ=2 };
+enum { ASPECT_43=0, ASPECT_169=1 };
+
+enum FileCaptureMode {
+ CAPTURE_IGNORE,
+ CAPTURE_FRAME_APPEND,
+ CAPTURE_FRAME_INSERT,
+ CAPTURE_MOVIE_APPEND
+};
+
+class FileTracker
+{
+protected:
+ FileTracker();
+ ~FileTracker();
+public:
+ static FileTracker &GetInstance( );
+ void SetMode( FileCaptureMode );
+ FileCaptureMode GetMode( );
+ unsigned int Size();
+ char *Get( int );
+ void Add( const char * );
+ void Clear( );
+private:
+ static FileTracker *instance;
+ vector <char *> list;
+ FileCaptureMode mode;
+};
+
+class FileHandler
+{
+public:
+
+ FileHandler();
+ virtual ~FileHandler();
+
+ virtual bool GetAutoSplit() const;
+ virtual bool GetTimeStamp() const;
+ virtual string GetBaseName() const;
+ virtual string GetExtension() const;
+ virtual int GetMaxFrameCount() const;
+ virtual off_t GetMaxFileSize() const;
+ virtual off_t GetFileSize() = 0;
+ virtual int GetTotalFrames() = 0;
+ virtual string GetFilename() const;
+
+ virtual void SetAutoSplit( bool );
+ virtual void SetTimeStamp( bool );
+ virtual void SetBaseName( const string& base );
+ virtual void SetMaxFrameCount( int );
+ virtual void SetEveryNthFrame( int );
+ virtual void SetMaxFileSize( off_t );
+ //virtual void SetSampleFrame( const Frame& sample );
+
+ //virtual bool WriteFrame( const Frame& frame );
+ virtual bool FileIsOpen() = 0;
+ virtual bool Create( const string& filename ) = 0;
+ //virtual int Write( const Frame& frame ) = 0;
+ virtual int Close() = 0;
+ virtual bool Done( void );
+
+ virtual bool Open( const char *s ) = 0;
+ virtual int GetFrame( uint8_t *data, int frameNum ) = 0;
+ int GetFramesWritten() const
+ {
+ return framesWritten;
+ }
+
+protected:
+ bool done;
+ bool autoSplit;
+ bool timeStamp;
+ int maxFrameCount;
+ int framesWritten;
+ int everyNthFrame;
+ int framesToSkip;
+ off_t maxFileSize;
+ string base;
+ string extension;
+ string filename;
+};
+
+
+class RawHandler: public FileHandler
+{
+public:
+ int fd;
+
+ RawHandler();
+ ~RawHandler();
+
+ bool FileIsOpen();
+ bool Create( const string& filename );
+ //int Write( const Frame& frame );
+ int Close();
+ off_t GetFileSize();
+ int GetTotalFrames();
+ bool Open( const char *s );
+ int GetFrame( uint8_t *data, int frameNum );
+private:
+ int numBlocks;
+};
+
+
+class AVIHandler: public FileHandler
+{
+public:
+ AVIHandler( int format = AVI_DV1_FORMAT );
+ ~AVIHandler();
+
+ //void SetSampleFrame( const Frame& sample );
+ bool FileIsOpen();
+ bool Create( const string& filename );
+ //int Write( const Frame& frame );
+ int Close();
+ off_t GetFileSize();
+ int GetTotalFrames();
+ bool Open( const char *s );
+ int GetFrame( uint8_t *data, int frameNum );
+ bool GetOpenDML() const;
+ void SetOpenDML( bool );
+ int GetFormat() const
+ {
+ return aviFormat;
+ }
+
+protected:
+ AVIFile *avi;
+ int aviFormat;
+ //AudioInfo audioInfo;
+ //VideoInfo videoInfo;
+ bool isOpenDML;
+ DVINFO dvinfo;
+ FOURCC fccHandler;
+ int channels;
+ bool isFullyInitialized;
+ int16_t *audioBuffer;
+ int16_t *audioChannels[ 4 ];
+};
+
+
+#ifdef HAVE_LIBQUICKTIME
+#include <quicktime/quicktime.h>
+
+class QtHandler: public FileHandler
+{
+public:
+ QtHandler();
+ ~QtHandler();
+
+ bool FileIsOpen();
+ bool Create( const string& filename );
+ //int Write( const Frame& frame );
+ int Close();
+ off_t GetFileSize();
+ int GetTotalFrames();
+ bool Open( const char *s );
+ int GetFrame( uint8_t *data, int frameNum );
+ void AllocateAudioBuffers();
+
+private:
+ quicktime_t *fd;
+ long samplingRate;
+ int samplesPerBuffer;
+ int channels;
+ bool isFullyInitialized;
+ unsigned int audioBufferSize;
+ int16_t *audioBuffer;
+ short int** audioChannelBuffer;
+
+ void Init();
+ inline void DeinterlaceStereo16( void* pInput, int iBytes, void* pLOutput, void* pROutput );
+
+};
+#endif
+
+#endif
--- /dev/null
+/*
+ * kino_wrapper.cc -- c wrapper for kino file handler
+ * Copyright (C) 2005 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <strings.h>
+#include "kino_wrapper.h"
+#include "filehandler.h"
+
+extern "C"
+{
+
+#include <framework/mlt_pool.h>
+
+struct kino_wrapper_s
+{
+ FileHandler *handler;
+ int is_pal;
+};
+
+kino_wrapper kino_wrapper_init( )
+{
+ kino_wrapper self = ( kino_wrapper )malloc( sizeof( kino_wrapper_s ) );
+ if ( self != NULL )
+ self->handler = NULL;
+ return self;
+}
+
+int kino_wrapper_open( kino_wrapper self, char *src )
+{
+ if ( self != NULL )
+ {
+ // Rough file determination based on file type
+ if ( strncasecmp( strrchr( src, '.' ), ".avi", 4 ) == 0 )
+ self->handler = new AVIHandler( );
+ else if ( strncasecmp( strrchr( src, '.' ), ".dv", 3 ) == 0 || strncasecmp( strrchr( src, '.' ), ".dif", 4 ) == 0 )
+ self->handler = new RawHandler( );
+ #ifdef HAVE_LIBQUICKTIME
+ else if ( strncasecmp( strrchr( src, '.' ), ".mov", 4 ) == 0 )
+ self->handler = new QtHandler( );
+ #endif
+
+ // Open the file if we have a handler
+ if ( self->handler != NULL )
+ if ( !self->handler->Open( src ) )
+ self = NULL;
+
+ // Check the first frame to see if it's PAL or NTSC
+ if ( self != NULL && self->handler != NULL )
+ {
+ uint8_t *data = ( uint8_t * )mlt_pool_alloc( 144000 );
+ if ( self->handler->GetFrame( data, 0 ) == 0 )
+ self->is_pal = data[3] & 0x80;
+ else
+ self = NULL;
+ mlt_pool_release( data );
+ }
+ }
+
+ return kino_wrapper_is_open( self );
+}
+
+int kino_wrapper_get_frame_count( kino_wrapper self )
+{
+ return self != NULL && self->handler != NULL ? self->handler->GetTotalFrames( ) : 0;
+}
+
+int kino_wrapper_is_open( kino_wrapper self )
+{
+ return self != NULL && self->handler != NULL ? self->handler->FileIsOpen( ) : 0;
+}
+
+int kino_wrapper_is_pal( kino_wrapper self )
+{
+ return self != NULL ? self->is_pal : 0;
+}
+
+int kino_wrapper_get_frame( kino_wrapper self, uint8_t *data, int index )
+{
+ return self != NULL && self->handler != NULL ? !self->handler->GetFrame( data, index ) : 0;
+}
+
+void kino_wrapper_close( kino_wrapper self )
+{
+ if ( self )
+ delete self->handler;
+ free( self );
+}
+
+}
+
+
--- /dev/null
+/*
+ * kino_wrapper.h -- c wrapper for kino file handler
+ * Copyright (C) 2005 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MLT_PRODUCER_KINO_WRAPPER_H_
+#define MLT_PRODUCER_KINO_WRAPPER_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct kino_wrapper_s *kino_wrapper;
+
+extern kino_wrapper kino_wrapper_init( );
+extern int kino_wrapper_open( kino_wrapper, char * );
+extern int kino_wrapper_is_open( kino_wrapper );
+extern int kino_wrapper_is_pal( kino_wrapper );
+extern int kino_wrapper_get_frame_count( kino_wrapper );
+extern int kino_wrapper_get_frame( kino_wrapper, uint8_t *, int );
+extern void kino_wrapper_close( kino_wrapper );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * producer_kino.c -- a DV file format parser
+ * Copyright (C) 2005 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include "producer_kino.h"
+#include <framework/mlt_frame.h>
+#include <framework/mlt_deque.h>
+#include <framework/mlt_factory.h>
+#include "kino_wrapper.h"
+
+/* NB: This is an abstract producer - it provides no codec support whatsoever. */
+
+#define FRAME_SIZE_525_60 10 * 150 * 80
+#define FRAME_SIZE_625_50 12 * 150 * 80
+
+typedef struct producer_kino_s *producer_kino;
+
+struct producer_kino_s
+{
+ struct mlt_producer_s parent;
+ kino_wrapper wrapper;
+};
+
+static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
+static void producer_close( mlt_producer parent );
+
+mlt_producer producer_kino_init( char *filename )
+{
+ kino_wrapper wrapper = kino_wrapper_init( );
+
+ if ( kino_wrapper_open( wrapper, filename ) )
+ {
+ producer_kino this = calloc( sizeof( struct producer_kino_s ), 1 );
+
+ if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
+ {
+ mlt_producer producer = &this->parent;
+ mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
+ double fps = kino_wrapper_is_pal( wrapper ) ? 25 : 30000.0 / 1001.0;
+
+ // Assign the wrapper
+ this->wrapper = wrapper;
+
+ // Pass wrapper properties (frame rate, count etc)
+ mlt_properties_set_position( properties, "length", kino_wrapper_get_frame_count( wrapper ) );
+ mlt_properties_set_position( properties, "in", 0 );
+ mlt_properties_set_position( properties, "out", kino_wrapper_get_frame_count( wrapper ) - 1 );
+ mlt_properties_set_double( properties, "real_fps", fps );
+
+ // Register transport implementation with the producer
+ producer->close = ( mlt_destructor )producer_close;
+
+ // Register our get_frame implementation with the producer
+ producer->get_frame = producer_get_frame;
+
+ // Return the producer
+ return producer;
+ }
+ free( this );
+ }
+
+ kino_wrapper_close( wrapper );
+
+ return NULL;
+}
+
+static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
+{
+ producer_kino this = producer->child;
+ uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 );
+
+ // Obtain the current frame number
+ uint64_t position = mlt_producer_frame( producer );
+
+ // Create an empty frame
+ *frame = mlt_frame_init( );
+
+ // Seek and fetch
+ if ( kino_wrapper_get_frame( this->wrapper, data, position ) )
+ {
+ // Get the frames properties
+ mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
+
+ // Determine if we're PAL or NTSC
+ int is_pal = kino_wrapper_is_pal( this->wrapper );
+
+ // Pass the dv data
+ mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL );
+
+ // Update other info on the frame
+ mlt_properties_set_int( properties, "width", 720 );
+ mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 );
+ mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 );
+ }
+ else
+ {
+ mlt_pool_release( data );
+ }
+
+ // Update timecode on the frame we're creating
+ mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
+
+ // Calculate the next timecode
+ mlt_producer_prepare_next( producer );
+
+ return 0;
+}
+
+static void producer_close( mlt_producer parent )
+{
+ if ( parent != NULL )
+ {
+ // Obtain this
+ producer_kino this = parent->child;
+
+ // Close the file
+ if ( this != NULL )
+ kino_wrapper_close( this->wrapper );
+
+ // Close the parent
+ parent->close = NULL;
+ mlt_producer_close( parent );
+
+ // Free the memory
+ free( this );
+ }
+}
--- /dev/null
+/*
+ * producer_kino.h -- a DV file format parser
+ * Copyright (C) 2005 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PRODUCER_KINO_H_
+#define _PRODUCER_KINO_H_
+
+#include <framework/mlt_producer.h>
+
+extern mlt_producer producer_kino_init( char *filename );
+
+#endif
--- /dev/null
+/*
+* riff.cc library for RIFF 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Tag: $Name$
+*
+* Change log:
+*
+* $Log$
+* Revision 1.1 2005/04/15 14:28:26 lilo_booter
+* Initial version
+*
+* Revision 1.18 2005/04/01 23:43:10 ddennedy
+* apply endian fixes from Daniel Kobras
+*
+* Revision 1.17 2004/10/11 01:37:11 ddennedy
+* mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
+*
+* Revision 1.16 2003/11/25 23:01:24 ddennedy
+* cleanup and a few bugfixes
+*
+* Revision 1.15 2003/10/21 16:34:34 ddennedy
+* GNOME2 port phase 1: initial checkin
+*
+* Revision 1.13.2.3 2003/08/26 20:39:00 ddennedy
+* relocate mutex unlock and add assert includes
+*
+* Revision 1.13.2.2 2003/01/28 12:54:13 lilo_booter
+* New 'no change' image transition
+*
+* Revision 1.13.2.1 2002/11/25 04:48:31 ddennedy
+* bugfix to report errors when loading files
+*
+* Revision 1.13 2002/09/13 06:49:49 ddennedy
+* build update, cleanup, bugfixes
+*
+* Revision 1.12 2002/04/21 06:36:40 ddennedy
+* kindler avc and 1394 bus reset support in catpure page, honor max file size
+*
+* Revision 1.11 2002/04/09 06:53:42 ddennedy
+* cleanup, new libdv 0.9.5, large AVI, dnd storyboard
+*
+* Revision 1.4 2002/03/25 21:34:25 arne
+* Support for large (64 bit) files mostly completed
+*
+* Revision 1.3 2002/03/10 21:28:29 arne
+* release 1.1b1, 64 bit support for type 1 avis
+*
+* 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 <stdio.h>
+#include <iostream>
+#include <iomanip>
+#include <byteswap.h>
+
+using std::cout;
+using std::hex;
+using std::dec;
+using std::setw;
+using std::setfill;
+using std::endl;
+
+// C includes
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+// local includes
+
+#include "error.h"
+#include "riff.h"
+
+
+/** make a 32 bit "string-id"
+
+ \param s a pointer to 4 chars
+ \return the 32 bit "string id"
+ \bugs It is not checked whether we really have 4 characters
+
+ Some compilers understand constants like int id = 'ABCD'; but I
+ could not get it working on the gcc compiler so I had to use this
+ workaround. We can now use id = make_fourcc("ABCD") instead. */
+
+FOURCC make_fourcc( char *s )
+{
+ if ( s[ 0 ] == 0 )
+ return 0;
+ else
+ return *( ( FOURCC* ) s );
+}
+
+
+RIFFDirEntry::RIFFDirEntry()
+{}
+
+
+RIFFDirEntry::RIFFDirEntry ( FOURCC t, FOURCC n, int l, int o, int p ) : type( t ), name( n ), length( l ), offset( o ), parent( p ), written( 0 )
+{}
+
+
+/** Creates the object without an output file.
+
+*/
+
+RIFFFile::RIFFFile() : fd( -1 )
+{
+ pthread_mutex_init( &file_mutex, NULL );
+}
+
+
+/* Copy constructor
+
+ Duplicate the file descriptor
+*/
+
+RIFFFile::RIFFFile( const RIFFFile& riff ) : fd( -1 )
+{
+ if ( riff.fd != -1 )
+ {
+ fd = dup( riff.fd );
+ }
+ directory = riff.directory;
+}
+
+
+/** Destroys the object.
+
+ If it has an associated opened file, close it. */
+
+RIFFFile::~RIFFFile()
+{
+ Close();
+ pthread_mutex_destroy( &file_mutex );
+}
+
+
+RIFFFile& RIFFFile::operator=( const RIFFFile& riff )
+{
+ if ( fd != riff.fd )
+ {
+ Close();
+ if ( riff.fd != -1 )
+ {
+ fd = dup( riff.fd );
+ }
+ directory = riff.directory;
+ }
+ return *this;
+}
+
+
+/** Creates or truncates the file.
+
+ \param s the filename
+*/
+
+bool RIFFFile::Create( const char *s )
+{
+ fd = open( s, O_RDWR | O_NONBLOCK | O_CREAT | O_TRUNC, 00644 );
+
+ if ( fd == -1 )
+ return false;
+ else
+ return true;
+}
+
+
+/** Opens the file read only.
+
+ \param s the filename
+*/
+
+bool RIFFFile::Open( const char *s )
+{
+ fd = open( s, O_RDONLY | O_NONBLOCK );
+
+ if ( fd == -1 )
+ return false;
+ else
+ return true;
+}
+
+
+/** Destroys the object.
+
+ If it has an associated opened file, close it. */
+
+void RIFFFile::Close()
+{
+ if ( fd != -1 )
+ {
+ close( fd );
+ fd = -1;
+ }
+}
+
+
+/** Adds an entry to the list of containers.
+
+ \param type the type of this entry
+ \param name the name
+ \param length the length of the data in the container
+ \param list the container in which this object is contained.
+ \return the ID of the newly created entry
+
+ The topmost object is not contained in any other container. Use
+ the special ID RIFF_NO_PARENT to create the topmost object. */
+
+int RIFFFile::AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list )
+{
+ /* Put all parameters in an RIFFDirEntry object. The offset is
+ currently unknown. */
+
+ RIFFDirEntry entry( type, name, length, 0 /* offset */, list );
+
+ /* If the new chunk is in a list, then get the offset and size
+ of that list. The offset of this chunk is the end of the list
+ (parent_offset + parent_length) plus the size of the chunk
+ header. */
+
+ if ( list != RIFF_NO_PARENT )
+ {
+ RIFFDirEntry parent = GetDirectoryEntry( list );
+ entry.offset = parent.offset + parent.length + RIFF_HEADERSIZE;
+ }
+
+ /* The list which this new chunk is a member of has now increased in
+ size. Get that directory entry and bump up its length by the size
+ of the chunk. Since that list may also be contained in another
+ list, walk up to the top of the tree. */
+
+ while ( list != RIFF_NO_PARENT )
+ {
+ RIFFDirEntry parent = GetDirectoryEntry( list );
+ parent.length += RIFF_HEADERSIZE + length;
+ SetDirectoryEntry( list, parent );
+ list = parent.parent;
+ }
+
+ directory.insert( directory.end(), entry );
+
+ return directory.size() - 1;
+}
+
+
+/** Modifies an entry.
+
+ \param i the ID of the entry which is to modify
+ \param type the type of this entry
+ \param name the name
+ \param length the length of the data in the container
+ \param list the container in which this object is contained.
+ \note Do not change length, offset, or the parent container.
+ \note Do not change an empty name ("") to a name and vice versa */
+
+void RIFFFile::SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list )
+{
+ RIFFDirEntry entry( type, name, length, offset, list );
+
+ assert( i >= 0 && i < ( int ) directory.size() );
+
+ directory[ i ] = entry;
+}
+
+
+/** Modifies an entry.
+
+ The entry.written flag is set to false because the contents has been modified
+
+ \param i the ID of the entry which is to modify
+ \param entry the new entry
+ \note Do not change length, offset, or the parent container.
+ \note Do not change an empty name ("") to a name and vice versa */
+
+void RIFFFile::SetDirectoryEntry( int i, RIFFDirEntry &entry )
+{
+ assert( i >= 0 && i < ( int ) directory.size() );
+
+ entry.written = false;
+ directory[ i ] = entry;
+}
+
+
+/** Retrieves an entry.
+
+ Gets the most important member variables.
+
+ \param i the ID of the entry to retrieve
+ \param type
+ \param name
+ \param length
+ \param offset
+ \param list */
+
+void RIFFFile::GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const
+{
+ RIFFDirEntry entry;
+
+ assert( i >= 0 && i < ( int ) directory.size() );
+
+ entry = directory[ i ];
+ type = entry.type;
+ name = entry.name;
+ length = entry.length;
+ offset = entry.offset;
+ list = entry.parent;
+}
+
+
+/** Retrieves an entry.
+
+ Gets the whole RIFFDirEntry object.
+
+ \param i the ID of the entry to retrieve
+ \return the entry */
+
+RIFFDirEntry RIFFFile::GetDirectoryEntry( int i ) const
+{
+ assert( i >= 0 && i < ( int ) directory.size() );
+
+ return directory[ i ];
+}
+
+
+/** Calculates the total size of the file
+
+ \return the size the file in bytes
+*/
+
+off_t RIFFFile::GetFileSize( void ) const
+{
+
+ /* If we have at least one entry, return the length field
+ of the FILE entry, which is the length of its contents,
+ which is the actual size of whatever is currently in the
+ AVI directory structure.
+
+ Note that the first entry does not belong to the AVI
+ file.
+
+ If we don't have any entry, the file size is zero. */
+
+ if ( directory.size() > 0 )
+ return directory[ 0 ].length;
+ else
+ return 0;
+}
+
+
+/** prints the attributes of the entry
+
+ \param i the ID of the entry to print
+*/
+
+void RIFFFile::PrintDirectoryEntry ( int i ) const
+{
+ RIFFDirEntry entry;
+ RIFFDirEntry parent;
+ FOURCC entry_name;
+ FOURCC list_name;
+
+ /* Get all attributes of the chunk object. If it is contained
+ in a list, get the name of the list too (otherwise the name of
+ the list is blank). If the chunk object doesn´t have a name (only
+ LISTs and RIFFs have a name), the name is blank. */
+
+ entry = GetDirectoryEntry( i );
+ if ( entry.parent != RIFF_NO_PARENT )
+ {
+ parent = GetDirectoryEntry( entry.parent );
+ list_name = parent.name;
+ }
+ else
+ {
+ list_name = make_fourcc( " " );
+ }
+ if ( entry.name != 0 )
+ {
+ entry_name = entry.name;
+ }
+ else
+ {
+ entry_name = make_fourcc( " " );
+ }
+
+ /* Print out the ascii representation of type and name, as well as
+ length and file offset. */
+
+ cout << hex << setfill( '0' ) << "type: "
+ << ((char *)&entry.type)[0]
+ << ((char *)&entry.type)[1]
+ << ((char *)&entry.type)[2]
+ << ((char *)&entry.type)[3]
+ << " name: "
+ << ((char *)&entry_name)[0]
+ << ((char *)&entry_name)[1]
+ << ((char *)&entry_name)[2]
+ << ((char *)&entry_name)[3]
+ << " length: 0x" << setw( 12 ) << entry.length
+ << " offset: 0x" << setw( 12 ) << entry.offset
+ << " list: "
+ << ((char *)&list_name)[0]
+ << ((char *)&list_name)[1]
+ << ((char *)&list_name)[2]
+ << ((char *)&list_name)[3] << dec << endl;
+
+ /* print the content itself */
+
+ PrintDirectoryEntryData( entry );
+}
+
+
+/** prints the contents of the entry
+
+ Prints a readable representation of the contents of an index.
+ Override this to print out any objects you store in the RIFF file.
+
+ \param entry the entry to print */
+
+void RIFFFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const
+ {}
+
+
+/** prints the contents of the whole directory
+
+ Prints a readable representation of the contents of an index.
+ Override this to print out any objects you store in the RIFF file.
+
+ \param entry the entry to print */
+
+void RIFFFile::PrintDirectory() const
+{
+ int i;
+ int count = directory.size();
+
+ for ( i = 0; i < count; ++i )
+ PrintDirectoryEntry( i );
+}
+
+
+/** finds the index
+
+ finds the index of a given directory entry type
+
+ \todo inefficient if the directory has lots of items
+ \param type the type of the entry to find
+ \param n the zero-based instance of type to locate
+ \return the index of the found object in the directory, or -1 if not found */
+
+int RIFFFile::FindDirectoryEntry ( FOURCC type, int n ) const
+{
+ int i, j = 0;
+ int count = directory.size();
+
+ for ( i = 0; i < count; ++i )
+ if ( directory[ i ].type == type )
+ {
+ if ( j == n )
+ return i;
+ j++;
+ }
+
+ return -1;
+}
+
+
+/** Reads all items that are contained in one list
+
+ Read in one chunk and add it to the directory. If the chunk
+ happens to be of type LIST, then call ParseList recursively for
+ it.
+
+ \param parent The id of the item to process
+*/
+
+void RIFFFile::ParseChunk( int parent )
+{
+ FOURCC type;
+ DWORD length;
+ int typesize;
+
+ /* Check whether it is a LIST. If so, let ParseList deal with it */
+
+ read( fd, &type, sizeof( type ) );
+ if ( type == make_fourcc( "LIST" ) )
+ {
+ typesize = -sizeof( type );
+ fail_if( lseek( fd, typesize, SEEK_CUR ) == ( off_t ) - 1 );
+ ParseList( parent );
+ }
+
+ /* it is a normal chunk, create a new directory entry for it */
+
+ else
+ {
+ fail_neg( read( fd, &length, sizeof( length ) ) );
+ if ( length & 1 )
+ length++;
+ AddDirectoryEntry( type, 0, length, parent );
+ fail_if( lseek( fd, length, SEEK_CUR ) == ( off_t ) - 1 );
+ }
+}
+
+
+/** Reads all items that are contained in one list
+
+ \param parent The id of the list to process
+
+*/
+
+void RIFFFile::ParseList( int parent )
+{
+ FOURCC type;
+ FOURCC name;
+ int list;
+ DWORD length;
+ 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 ) ) );
+
+ /* 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 );
+ }
+}
+
+
+/** Reads the directory structure of the whole RIFF file
+
+*/
+
+void RIFFFile::ParseRIFF( void )
+{
+ FOURCC type;
+ DWORD length;
+ off_t filesize;
+ off_t pos;
+ int container = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT );
+
+ pos = lseek( fd, 0, SEEK_SET );
+
+ /* calculate file size from RIFF header instead from physical file. */
+
+ while ( ( read( fd, &type, sizeof( type ) ) > 0 ) &&
+ ( read( fd, &length, sizeof( length ) ) > 0 ) &&
+ ( type == make_fourcc( "RIFF" ) ) )
+ {
+
+ filesize += length + RIFF_HEADERSIZE;
+
+ fail_if( lseek( fd, pos, SEEK_SET ) == ( off_t ) - 1 );
+ ParseList( container );
+ pos = lseek( fd, 0, SEEK_CUR );
+ fail_if( pos == ( off_t ) - 1 );
+ }
+}
+
+
+/** Reads one item including its contents from the RIFF file
+
+ \param chunk_index The index of the item to write
+ \param data A pointer to the data
+
+*/
+
+void RIFFFile::ReadChunk( int chunk_index, void *data )
+{
+ RIFFDirEntry entry;
+
+ entry = GetDirectoryEntry( chunk_index );
+ pthread_mutex_lock( &file_mutex );
+ fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 );
+ fail_neg( read( fd, data, entry.length ) );
+ pthread_mutex_unlock( &file_mutex );
+}
+
+
+/** Writes one item including its contents to the RIFF file
+
+ \param chunk_index The index of the item to write
+ \param data A pointer to the data
+
+*/
+
+void RIFFFile::WriteChunk( int chunk_index, const void *data )
+{
+ RIFFDirEntry entry;
+
+ entry = GetDirectoryEntry( chunk_index );
+ pthread_mutex_lock( &file_mutex );
+ fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 );
+ fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) );
+ DWORD length = entry.length;
+ fail_neg( write( fd, &length, sizeof( length ) ) );
+ fail_neg( write( fd, data, entry.length ) );
+ pthread_mutex_unlock( &file_mutex );
+
+ /* Remember that this entry already has been written. */
+
+ directory[ chunk_index ].written = true;
+}
+
+
+/** Writes out the directory structure
+
+ For all items in the directory list that have not been written
+ yet, it seeks to the file position where that item should be
+ stored and writes the type and length field. If the item has a
+ name, it will also write the name field.
+
+ \note It does not write the contents of any item. Use WriteChunk to do that. */
+
+void RIFFFile::WriteRIFF( void )
+{
+ int i;
+ RIFFDirEntry entry;
+ int count = directory.size();
+
+ /* Start at the second entry (RIFF), since the first entry (FILE)
+ is needed only for internal purposes and is not written to the
+ file. */
+
+ for ( i = 1; i < count; ++i )
+ {
+
+ /* Only deal with entries that haven´t been written */
+
+ entry = GetDirectoryEntry( i );
+ if ( entry.written == false )
+ {
+
+ /* A chunk entry consist of its type and length, a list
+ entry has an additional name. Look up the entry, seek
+ to the start of the header, which is at the offset of
+ the data start minus the header size and write out the
+ items. */
+
+ fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ) ;
+ fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) );
+ DWORD length = entry.length;
+ fail_neg( write( fd, &length, sizeof( length ) ) );
+
+ /* If it has a name, it is a list. Write out the extra name
+ field. */
+
+ if ( entry.name != 0 )
+ {
+ fail_neg( write( fd, &entry.name, sizeof( entry.name ) ) );
+ }
+
+ /* Remember that this entry already has been written. */
+
+ directory[ i ].written = true;
+ }
+ }
+}
--- /dev/null
+/*
+* riff.h library for RIFF 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Tag: $Name$
+*
+* Change log:
+*
+* $Log$
+* Revision 1.1 2005/04/15 14:28:26 lilo_booter
+* Initial version
+*
+* Revision 1.14 2005/04/01 23:43:10 ddennedy
+* apply endian fixes from Daniel Kobras
+*
+* Revision 1.13 2004/10/11 01:37:11 ddennedy
+* mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script
+*
+* Revision 1.12 2004/01/06 22:53:42 ddennedy
+* metadata editing tweaks and bugfixes, new ui elements in preparation for publish functions
+*
+* Revision 1.11 2003/11/25 23:01:25 ddennedy
+* cleanup and a few bugfixes
+*
+* Revision 1.10 2003/10/21 16:34:34 ddennedy
+* GNOME2 port phase 1: initial checkin
+*
+* Revision 1.8.4.1 2002/11/25 04:48:31 ddennedy
+* bugfix to report errors when loading files
+*
+* Revision 1.8 2002/04/21 06:36:40 ddennedy
+* kindler avc and 1394 bus reset support in catpure page, honor max file size
+*
+* Revision 1.7 2002/04/09 06:53:42 ddennedy
+* cleanup, new libdv 0.9.5, large AVI, dnd storyboard
+*
+* Revision 1.3 2002/03/25 21:34:25 arne
+* Support for large (64 bit) files mostly completed
+*
+* 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
+*
+*/
+
+#ifndef _RIFF_H
+#define _RIFF_H 1
+
+#include <vector>
+using std::vector;
+
+#include <pthread.h>
+
+#include "endian_types.h"
+
+#define QUADWORD int64_le_t
+#define DWORD int32_le_t
+#define LONG u_int32_le_t
+#define WORD int16_le_t
+#define BYTE u_int8_le_t
+#define FOURCC u_int32_t // No endian conversion needed.
+
+#define RIFF_NO_PARENT (-1)
+#define RIFF_LISTSIZE (4)
+#define RIFF_HEADERSIZE (8)
+
+#ifdef __cplusplus
+extern "C"
+{
+ FOURCC make_fourcc( char * s );
+}
+#endif
+
+class RIFFDirEntry
+{
+public:
+ FOURCC type;
+ FOURCC name;
+ off_t length;
+ off_t offset;
+ int parent;
+ int written;
+
+ RIFFDirEntry();
+ RIFFDirEntry( FOURCC t, FOURCC n, int l, int o, int p );
+};
+
+
+class RIFFFile
+{
+public:
+ RIFFFile();
+ RIFFFile( const RIFFFile& );
+ virtual ~RIFFFile();
+ RIFFFile& operator=( const RIFFFile& );
+
+ virtual bool Open( const char *s );
+ virtual bool Create( const char *s );
+ virtual void Close();
+ virtual int AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list );
+ virtual void SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list );
+ virtual void SetDirectoryEntry( int i, RIFFDirEntry &entry );
+ virtual void GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const;
+ virtual RIFFDirEntry GetDirectoryEntry( int i ) const;
+ virtual off_t GetFileSize( void ) const;
+ virtual void PrintDirectoryEntry( int i ) const;
+ virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const;
+ virtual void PrintDirectory( void ) const;
+ virtual int FindDirectoryEntry( FOURCC type, int n = 0 ) const;
+ virtual void ParseChunk( int parent );
+ virtual void ParseList( int parent );
+ virtual void ParseRIFF( void );
+ virtual void ReadChunk( int chunk_index, void *data );
+ virtual void WriteChunk( int chunk_index, const void *data );
+ virtual void WriteRIFF( void );
+
+protected:
+ int fd;
+ pthread_mutex_t file_mutex;
+
+private:
+ vector<RIFFDirEntry> directory;
+};
+#endif