]> git.sesse.net Git - mlt/commitdiff
Initial version
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 15 Apr 2005 14:28:26 +0000 (14:28 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 15 Apr 2005 14:28:26 +0000 (14:28 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@713 d19143bc-622f-0410-bfdd-b5b2a6649095

17 files changed:
src/modules/kino/Makefile [new file with mode: 0644]
src/modules/kino/avi.cc [new file with mode: 0644]
src/modules/kino/avi.h [new file with mode: 0644]
src/modules/kino/configure [new file with mode: 0755]
src/modules/kino/endian_types.h [new file with mode: 0644]
src/modules/kino/error.cc [new file with mode: 0644]
src/modules/kino/error.h [new file with mode: 0644]
src/modules/kino/factory.c [new file with mode: 0644]
src/modules/kino/filehandler.cc [new file with mode: 0644]
src/modules/kino/filehandler.h [new file with mode: 0644]
src/modules/kino/gpl [new file with mode: 0644]
src/modules/kino/kino_wrapper.cc [new file with mode: 0644]
src/modules/kino/kino_wrapper.h [new file with mode: 0644]
src/modules/kino/producer_kino.c [new file with mode: 0644]
src/modules/kino/producer_kino.h [new file with mode: 0644]
src/modules/kino/riff.cc [new file with mode: 0644]
src/modules/kino/riff.h [new file with mode: 0644]

diff --git a/src/modules/kino/Makefile b/src/modules/kino/Makefile
new file mode 100644 (file)
index 0000000..b595b91
--- /dev/null
@@ -0,0 +1,38 @@
+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
diff --git a/src/modules/kino/avi.cc b/src/modules/kino/avi.cc
new file mode 100644 (file)
index 0000000..1ed29ad
--- /dev/null
@@ -0,0 +1,1817 @@
+/*
+* 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;
+}
diff --git a/src/modules/kino/avi.h b/src/modules/kino/avi.h
new file mode 100644 (file)
index 0000000..864dfe1
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+* 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
diff --git a/src/modules/kino/configure b/src/modules/kino/configure
new file mode 100755 (executable)
index 0000000..d13e2ec
--- /dev/null
@@ -0,0 +1,18 @@
+#!/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
+
diff --git a/src/modules/kino/endian_types.h b/src/modules/kino/endian_types.h
new file mode 100644 (file)
index 0000000..709ccfa
--- /dev/null
@@ -0,0 +1,265 @@
+/* <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
diff --git a/src/modules/kino/error.cc b/src/modules/kino/error.cc
new file mode 100644 (file)
index 0000000..e2b8510
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+* 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;
+       }
+}
diff --git a/src/modules/kino/error.h b/src/modules/kino/error.h
new file mode 100644 (file)
index 0000000..9c04894
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+* 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
+
diff --git a/src/modules/kino/factory.c b/src/modules/kino/factory.c
new file mode 100644 (file)
index 0000000..bbae505
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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;
+}
+
diff --git a/src/modules/kino/filehandler.cc b/src/modules/kino/filehandler.cc
new file mode 100644 (file)
index 0000000..740ee56
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+* 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
diff --git a/src/modules/kino/filehandler.h b/src/modules/kino/filehandler.h
new file mode 100644 (file)
index 0000000..6657951
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+* 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
diff --git a/src/modules/kino/gpl b/src/modules/kino/gpl
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/modules/kino/kino_wrapper.cc b/src/modules/kino/kino_wrapper.cc
new file mode 100644 (file)
index 0000000..85f87c0
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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 );
+}
+
+}
+
+
diff --git a/src/modules/kino/kino_wrapper.h b/src/modules/kino/kino_wrapper.h
new file mode 100644 (file)
index 0000000..0e73b21
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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
diff --git a/src/modules/kino/producer_kino.c b/src/modules/kino/producer_kino.c
new file mode 100644 (file)
index 0000000..de876cb
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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 );
+       }
+}
diff --git a/src/modules/kino/producer_kino.h b/src/modules/kino/producer_kino.h
new file mode 100644 (file)
index 0000000..9f6f69a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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
diff --git a/src/modules/kino/riff.cc b/src/modules/kino/riff.cc
new file mode 100644 (file)
index 0000000..bc616dd
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+* 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;
+               }
+       }
+}
diff --git a/src/modules/kino/riff.h b/src/modules/kino/riff.h
new file mode 100644 (file)
index 0000000..e7a2146
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+* 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