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