/* caviwriter.cpp : Windows AVIfile routines
 *
 * MPEG2AVI
 * --------
 *
 * avi_fileopen() - (private) init AVI routines, open AVI file
 * avi_store_picture() - (private) write one frame to AVI-file
 * store_avi_one() - (public) interface to store.c
      (called by store_avi_gdi() 
 * avi_fileclose() - (private) close AVI streams, close AVIfile

   This file was added to the original MSSG (MPEG Software Simulation
   Group) MPEG2V12 codec.  It enables the MPEG2V12 decoder to
   write an AVI file, using the Win32 AVI/VFW interface.
   The target machine must have the "Video Compression" system component
   installed on his Windows operating system.
   This file is *NOT* part of the original MSSG MPEG2V12 distribution!

 *
 *  Revision history
 *  v0.11 first release
 *  v0.12 added encoding-time statistic 
 *  v0.13 added abort-key ('Q') to close AVI-file and exit
 *  v0.14 added rectangular-clipping (centered) and 1/2 resolution output
          Data is inverse telecined prior to entering storeavi.c
		  Functions *depend* on proper-coordinates in
		  Resized_Picture_Height, Resized_Picture_Width, g_AVIcropX,
		  g_AVIcropY, CropRect
	v0.15 abort-key changed to #define KEY_QUIT (in global.h)
	      fixed elapsed-time report for hours:minutes
		  AVI-writer reports "MPEG FRAME # :", not framesWritten.
		  (framesWritten caused confusion with IVTC)
	v0.15B4 swtiched from writing to pAVIstream_compressed, to using
	      ICSeqCompressFrame() functions and writing to the uncompressed
		  AVIstream (pAVIstream)
		  A little more (programming) work on my part, but this new
		  code can directly compress YUV-bitmaps.
		  ICSeqCompressFrame() supports YUV-bitmaps, whereas
		  AVIStreamSetFormat() did not.  So far, only a handful of
		  codecs support YV12.
		  +avi_store_picyv12() ... writes YV12 bitmap to pAVIstream
		   (the regular avi_store_picture() writes to pAVIstream_compressed)
	v0.15B5 recoded the YV12-writer with Avery Lee's VirtualDub code
	      added YUY2 mode.  The YV12/YUY2 framebuffer formatting is handled
		  inside store.c (store_avi_gdi()), the functions here assume
		  the framebuffer has been properly prepared.
		  Finally corrected the code for setting m_iccompressframes's member 
		  variables.  The MPEG-4 KeyFrame-rate issue has been squashed!
		  Unfortunately, the compression bitrate control is now inaccurate (DOH)
		  put an if() statement around the ICCompressframeStart() code in
		    avi_fileopen()... fixes problem when RGB24 "Full Frames" is selected
	v0.15B51 finally the YUV-AVI mode's compressor setup is functioning
	      Turns out, to *properly* initialize the codec, this sequence must be
		  executed :
		    1) ICCompressorChoose();  // dialog-box, user chooses a codec
			2) ICGetState( hic, lpUsersSettings, cbState ); // store user's settings
			3) ICSetState( hic, NULL, cbState );    // reset the codec
			4) ICSetState( hic, lpUsersSettings, cbState ); //restore user's settings 

            The Microsoft MPEG-4 codecs require step #3 (reset codec)
		  also opened avi_fileopen() to the public.  It is no longer called by
		  avi_store_one(), it is now directly called by store_avi_gdi()

    v0.16B1 initial release of CPP object 
	      converted storeavi.c into a C++ object.
	v0.16B22 updated avi_fileclose() to check various pointers, before blindly
		calling VFW close-down functions
	v0.16B23 corrected function-calls that are supposed to return a value, 
	    but didn't.  Also changed the console-screen update rate (updates
		every 16 frames now.)
	v0.16B3 removed the user-query in the event that AVI filename already exists
	    replaced with a flag (m_fOverwrite) which indicates whether the file
		should be overwritten
	v0.16B31 added log-size check for TextLogErr()
	v0.16B34 added "AVIFileExit()" to the destructor
 */

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<time.h>
/*
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
*/
#include "config.h"
#include "global.h"
#include "aviwrite.h"
#include<windows.h>
#include<vfw.h>

#define MAX_FRAMECOUNT 0x7FFFFFFFL  /* max 31-bit positive value */



typedef union tfccDword2Char
{
	DWORD dword;	/* the FCC code */
	BYTE ch[4]; /* character decomposition of dword */
} fccDword2Char;


//
// constructor
//
cAVIwriter::cAVIwriter()
{
	m_pAVIfile = NULL;
	m_pAVIstream = NULL;
	m_pAVIstream_compressed = NULL;
	//m_bmih = ;
	m_lpVideoData = NULL;
	m_lpCompBuf = NULL;
	m_lpCompBufP = NULL;
	m_fUseYUV = FALSE;
	m_fOverwrite = FALSE;	// v0.16B3
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	m_szErrorLog = new char[ LOG_LENGTH ];
	m_szMessageLog = new char[ LOG_LENGTH ];
	m_szText = new char[ TEXTMSG_LENGTH ];
	m_szText2 = new char[ TEXTMSG_LENGTH ];
	m_szLastLogErr = new char[ TEXTMSG_LENGTH ];
	m_logCounter = 0;
#endif
	m_szFileName = NULL; // no file open yet
	
	m_lastError = 0;
	fInUse = FALSE;

	strcpy( m_AVIstreaminfo.szName, "<UNTITLED>" );

#ifdef ENHANCED_ERROR_LOGGING
	if ( (m_szErrorLog == NULL) || ( m_szMessageLog == NULL ) || 
		( m_szText == NULL ) || ( m_szText2 == NULL ) ||
		( m_szLastLogErr == NULL ) )
	{
		// catastrophic error
		fprintf( stderr, "\ncAVIwriter::cAVIwriter() : couldn't allocate memory.");
		// exit( ERROR );
	}
#endif

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	m_szLastLogErr[ 0 ] = 0;  // NULL char
	m_szText2[ 0 ] = 0;  // NULL char
	m_szText[ 0 ] = 0;  // NULL char
	m_szMessageLog[ 0 ] = 0;  // NULL char
	m_szErrorLog[ 0 ] = 0;  // NULL char
#endif

	// these two functions must be called *LAST*, because they attempt to
	// write something into the message logs!
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "cAVIwriter() : " );
#endif
	reset_counters(); 		// reset all counters 
} // cAVIwriter::cAVIwriter()


cAVIwriter::~cAVIwriter()
{
	DWORD dwrc = 0;  // dword result code
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "~cAVIwriter() : " );
#endif
	if ( fIsAVIOpen() )
	{
		// AVIfile is still open, close it before exiting!
		// TODO
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "~cAVIwriter() : AVWERR_OPEN" );
#endif
		dwrc = avi_fileclose();
#ifdef ENHANCED_ERROR_LOGGING
		if ( dwrc != AVWERR_OK )
		{
			fprintf( stderr, "\ncAVIwriter::~cAVIwriter() : failed to close open AVI file!");
		}
#endif
	}

//SVE 20.05.2001 Habe ich in doch in avi_fileclose kopiert - Wer mach schon 2 AVIs? Außerdem gabs Probleme wegen der Reihenfolge
//	ICCompressorFree( &m_compvars );
	//lrc = ICClose( m_compvars.hic );
//	ICClose( m_compvars.hic );

//	AVIFileExit(); 	// v0.16B34
//SVE ENDE

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	if ( m_szErrorLog != NULL )
		delete( m_szErrorLog );

	if ( m_szMessageLog != NULL )
		delete( m_szMessageLog );

	if ( m_szText != NULL )
		delete( m_szText );

	if ( m_szText2 != NULL )
		delete( m_szText2 );

	if ( m_lpState != NULL )
		delete( m_lpState );
#endif
}


//
// -----------------------------------------------------------------------------
//
// Housekeeping functions
//
// -----------------------------------------------------------------------------
//


//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG

void 
cAVIwriter::TextLogErr( DWORD errorID, char text[] )
{
	char temp_text[ TEXTMSG_LENGTH ];

	static DWORD dwPurgeCount = 0;

	if ( strlen( m_szErrorLog ) > ( ( LOG_LENGTH >> 1 ) - TEXTMSG_LENGTH ) )
	{
		++dwPurgeCount;
		printf("\ncAVIwriter::TextLogErr() : Warning log-size exceeded %ld bytes",
			strlen( m_szErrorLog ) );
		printf("\n\tPurging log...");
		sprintf( m_szErrorLog, "<ErrLog purged %ld times>\n", dwPurgeCount );
	}

	sprintf( temp_text, "\n#%lu cAVIwriter::", m_logCounter );
	if ( text != NULL )
		strcat( temp_text, text );
	else
		strcat( temp_text, "<NULL>");
	strcat( m_szErrorLog, temp_text );
	strcpy( m_szLastLogErr, temp_text );

	printf( "%s", temp_text );


	sprintf( temp_text," Error ID = %0X ", errorID );
	strcat( m_szErrorLog, temp_text );
	strcat( m_szLastLogErr, temp_text );

	printf( "%s\n", temp_text );  // uncomment this to echo msgs to console

	m_lastError = errorID; // update last error variable

	// counter is incremented by TextLogMsg()
} // cAVIwriter::TextLogErr()

void 
cAVIwriter::TextLogMsg( DWORD dwFlags, char text[] )
{
	char temp_text[ TEXTMSG_LENGTH ];

	static DWORD dwPurgeCount = 0;

	if ( strlen( m_szMessageLog ) > ( ( LOG_LENGTH >> 1 ) - TEXTMSG_LENGTH ) )
	{
		++dwPurgeCount;
		printf("\ncAVIwriter::TextLogMsg() : Warning log-size exceeded %lu bytes",
			strlen( m_szMessageLog ) );
		printf("\n\tPurging log...");
		sprintf( m_szMessageLog, "<Log purged %lu times>\n", dwPurgeCount );
	}


	if ( dwFlags & LOG_NEW_ENTRY )
	{
		sprintf( temp_text, "\n#%lu cAVIwriter::", m_logCounter );
		if ( text != NULL )
			strcat( temp_text, text );
		else
			strcat( temp_text, "<NULL>");
		strcat( m_szMessageLog, temp_text );

		m_lastError = AVWERR_OK; // clear lastError flag
		strcpy( m_szLastLogErr, "<NO ERROR>"); // clear lasterror msg
		++m_logCounter;  // increment counter
	}
	else
	{
		strcat( m_szMessageLog, text );
	}

	// printf( "\naviWriter Log-> %s", text ); // uncomment this to echo msgs
} // cAVIwriter::TextLogMsg()

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#endif
//SVE ENDE

// center a smaller DEST rectangle in the middle of a larger SRC rectangle
DWORD
cAVIwriter::SetRectCenter( 
  LPRECT lprc, // pointer to structure with rectangle to set
  int src_x,   // X-dimension of source image
  int src_y,    // Y-dimension of source image
  int dest_x,  // X-dimension of destination image
  int dest_y)  // Y-dimension of destination image
{
	int mid_x = 0;
	int mid_y = 0;

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "SetRectCenter() : ");
#endif
	if ( lprc != NULL )
	{
		mid_x = (src_x - dest_x)>>1;
		mid_y = (src_y - dest_y)>>1;
		SetRect( lprc, mid_x, mid_y, src_x - mid_x, src_y - mid_y );
		return AVWERR_OK;
	}
	else
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_INVALID_PARAM, "SetRectCenter() : (lprc == NULL) AVWERR_INVALID_PARAM");
#endif
		return AVWERR_INVALID_PARAM;
	}
}

void
cAVIwriter::reset_counters()
{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "reset_counters() : ");
	if ( fIsAVIOpen() )
		TextLogMsg( 0, "warning an AVIfile is open!" );
#endif
	m_dwStreamSize = 0;
	m_dwFrameCount = 0;
	m_cbWritten = 0;
	m_dwKFCount = 0;
}

DWORD
cAVIwriter::set_fps( DWORD rate, DWORD scale )
{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "set_fps() : " );
#endif
	if ( fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "set_fps() AVWERR_OPEN");
#endif
		return AVWERR_OPEN; // AVIwriter already open, writing an AVI file
	}

	if ( scale == 0 || rate == 0 )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_INVALID_PARAM, "set_fps() AVWERR_INVALID_PARAM");
#endif
		return AVWERR_INVALID_PARAM;
	}

	// good input, record the new values
	m_AVIstreaminfo.dwScale = scale; 
	m_AVIstreaminfo.dwRate = rate;   
	m_iccompressframes.dwRate = rate;   
	m_iccompressframes.dwScale= scale;

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "fps -> %.3f (%lu / %lu )\n", (double)rate / scale,
		rate, scale );
	TextLogMsg( 0, m_szText );
#endif
	return AVWERR_OK;
}


DWORD 
cAVIwriter::set_avistring( const char avistring[] )
{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "set_avistring() : " );
#endif

	if ( fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "set_avistring() AVWERR_OPEN");
#endif
		return AVWERR_OPEN; // AVIwriter already open, writing an AVI file
	}

	strcpy( m_AVIstreaminfo.szName, avistring );
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "AVIstreaminfo.szName[] = '%s'", avistring );
	TextLogMsg( 0, m_szText );
#endif

	return AVWERR_OK;
}


DWORD
cAVIwriter::set_bmi( BITMAPINFO bmi )
{
	fccDword2Char fccD2C; // custom struct for converting DWORD -> char[4]

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "set_bmi() : " );
#endif

	if ( fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "set_bmi() AVWERR_OPEN");
#endif
		return AVWERR_OPEN; // AVIwriter already open, writing an AVI file
	}

	// record the new values
	m_fUseYUV = FALSE;
	m_bmi = bmi;
	m_bmih = bmi.bmiHeader;
	fccD2C.dword = m_bmih.biCompression;

	// now update the AVIwriter status-variables
	// validate the input format

	// note, "IYUV" and "I420" are the same as YV12, but these other two
	// FOURCCs cause "full frames" to be listed, which doesn't work.
	// so we stick with setting biCompression = 'YV12'
	switch ( m_bmih.biCompression )
	{
		case BI_RGB :	// RGB24 ?
			m_fUseYUV = FALSE;
			break;
		case mmioFOURCC( 'Y','V','1','2') : 
			m_fUseYUV = TRUE;
//			m_bmih_yuv.biBitCount = 12;
//			m_bmih_yuv.biSizeImage = ( m_bmih_yuv.biSizeImage * 3 ) >> 1;
			break;
		case mmioFOURCC( 'I','4','2','0') :
			m_fUseYUV = TRUE;
//			m_bmih_yuv.biBitCount = 12;
//			m_bmih_yuv.biSizeImage = ( m_bmih_yuv.biSizeImage * 3 ) >> 1;
			break;
		case mmioFOURCC( 'I','Y','U','V') :
			m_fUseYUV = TRUE;
//			m_bmih_yuv.biBitCount = 12;
//			m_bmih_yuv.biSizeImage = ( m_bmih_yuv.biSizeImage * 3 ) >> 1;
			break;
		case mmioFOURCC( 'Y','U','Y','2') :
			m_fUseYUV = TRUE;
//			m_bmih_yuv.biBitCount = 16;
//			m_bmih_yuv.biSizeImage = m_bmih_yuv.biSizeImage << 1;
			break;
		default :
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "set_bmi() : unrecognized bmiHeader.biCompression FOURCC '%c%c%c%c' !",
				fccD2C.ch[0], fccD2C.ch[1], fccD2C.ch[2], fccD2C.ch[3] );
			TextLogErr( AVWERR_INVALID_PARAM, m_szText );
#endif
			return AVWERR_INVALID_PARAM;
	} /* endswitch */

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "bmiHeader FOURCC = '%c%c%c%c'", fccD2C.ch[0], 
		fccD2C.ch[1], fccD2C.ch[2], fccD2C.ch[3] );
	TextLogMsg( 0, m_szText );
#endif

	return AVWERR_OK;
}


DWORD // v0.16B3
cAVIwriter::set_fileoverwrite( BOOL fOverwrite )
{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "set_fileoverwrite() : " );
#endif
	m_fOverwrite = ( fOverwrite == TRUE );	// set new variable
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "%s", ( m_fOverwrite == TRUE ) ? "TRUE" : "FALSE" );
	TextLogMsg( 0, m_szText );
#endif
	return AVWERR_OK;
}

DWORD 
cAVIwriter::get_bmi( LPBITMAPINFO lpbmi ) // get BITMAP format of AVI-file
{
	//TextLogMsg( LOG_NEW_ENTRY, "get_bmi() : " );

	if ( lpbmi == NULL )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogMsg( LOG_NEW_ENTRY, "get_bmi() : " );
		TextLogErr( AVWERR_INVALID_PARAM, "get_bmi() : (lpbmi == NULL)");
#endif
		return AVWERR_INVALID_PARAM;
	}

	(*lpbmi) = m_bmi;

	return AVWERR_OK;
}


DWORD 
cAVIwriter::get_framecount( void ) // get total frame count (includes KFs)
{  
	//sprintf( m_szText, "get_framecount() -> %lu frames", m_dwFrameCount );
	//TextLogMsg( LOG_NEW_ENTRY, m_szText );
	return m_dwFrameCount;
}

DWORD 
cAVIwriter::get_kfcount( void ) // get keyframe count
{  
	//sprintf( m_szText, "get_kfcount() -> %lu frames", m_dwKFCount );
	//TextLogMsg( LOG_NEW_ENTRY, m_szText );
	return m_dwKFCount;
}


DWORD 
cAVIwriter::get_cbWritten( void ) // get bytesWritten to AVI file
{  
	//sprintf( m_szText, "get_cbWritten() -> %lu bytes", m_cbWritten );
	//TextLogMsg( LOG_NEW_ENTRY, m_szText );
	return m_cbWritten;
}


// fNewCodec : TRUE == query user to select codec
//             FALSE== do nothing
DWORD
cAVIwriter::ui_codec( BOOL fNewCodec )
{
//SVE 03.06.2001 Neues Textfeld
	char lpText[100];

	BOOL brc = FALSE;	// boolean return code
	fccDword2Char fccD2C; // custom struct for converting DWORD -> char[4]

 	//-------- 1)  Ask user to choose a Video Compression Codec

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "ui_codec() : ICCompressorChoose()" );
#endif

	if ( fIsAVIOpen() )
	{	// an AVI-file is already open, can't select new codec
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "ui_codec() AVWERR_OPEN");
#endif
		return AVWERR_OPEN;
	}

//SVE 20.05.2001 compvars muß mit 0 initialisiert werden -> sonst Abbruch unter Win2K
	memset(&m_compvars,0,sizeof( m_compvars ));
//SVE ENDE
	m_compvars.cbSize = sizeof( m_compvars ); //  must initialize cbSize!

  if ( fNewCodec == TRUE )
  {
//SVE 20.05.2001  	printf("\nOutput AVI-resolution : <%d X %d> : pixFormat = ", 
//SVE 20.05.2001		m_bmih.biWidth,m_bmih.biHeight );

	if ( m_fUseYUV )
	{
		fccD2C.dword = m_bmih.biCompression;
//SVE 20.05.2001		printf( "'%c%c%c%c'", fccD2C.ch[0], fccD2C.ch[1], fccD2C.ch[2], 
//SVE 20.05.2001			fccD2C.ch[3] );
//SVE 03.06.2001 Neues Textfeld
		sprintf( lpText, "ICCompressorChoose() : select codec %c%c%c%c",
			fccD2C.ch[0], fccD2C.ch[1], fccD2C.ch[2], fccD2C.ch[3] );
		brc = ICCompressorChoose( NULL, ICMF_CHOOSE_DATARATE | 
			ICMF_CHOOSE_KEYFRAME, &m_bmih, NULL, &m_compvars, lpText );
	}
	else
	{
//SVE 20.05.2001		printf( "RGB24");
		brc = ICCompressorChoose( NULL, ICMF_CHOOSE_DATARATE | 
			ICMF_CHOOSE_KEYFRAME , &m_bmih, NULL, &m_compvars,
			"ICCompressorChoose() : select codec RGB24" );
	} // endif ( m_fUseYUV ) 
	m_compvars.lpbiIn = &m_bmi; // this is sometimes not set 
	m_compvars2 = m_compvars; // make a backup

//SVE 03.06.2001
	time(&m_pRunState->StartTime); 

	if ( brc == 0 )	// did ICCompressorChoose() fail?
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "ui_codec() codec selection failed!");
#endif
		return AVWERR_FAIL;
	}
  } // endif ( fNewCodec == TRUE )
  else
  {	// use old codec
	  ;
	  //m_compvars = m_compvars2;
	  /*m_compvars.hic = ICOpen( m_compvars.fccType, m_compvars.fccHandler,
		  ICMODE_COMPRESS );

	  if ( m_compvars.hic == 0 )
	  {
		TextLogErr( AVWERR_FAIL, "ui_codec() : ICOpen() failed, couldn't reopen old codec!");
		return AVWERR_FAIL;
	  }*/
  }

  return AVWERR_OK;
} // cAVIwriter::ui_codec()


//
// -----------------------------------------------------------------------------
//
// Core member functions
//
// -----------------------------------------------------------------------------
//


/*
 * avi_fileopen()
 * opens a new file for writing
 * Queries user for Compressor (VCM) selection
 * Queries user to choose frame-rate (dwRate, dwScale)
 */
DWORD
cAVIwriter::avi_fileopen( const char aviFilename[], LPRECT CropRect )
{
    HRESULT hr; 
	FILE *fp;
	BOOL brc = FALSE; // boolean return code 
	DWORD dwrc = 0; // DWORD return code 
//	char ch;
	int i = 0;
	fccDword2Char fccD2C; // custom struct for converting DWORD -> char[4] 
	//DWORD fpsScale, fpsRate; // user-input vars for AVI frame-rate selection
	LPAVICOMPRESSOPTIONS m_lpavicompressoptions = &m_avicompressoptions;
	//COMPVARS m_compvars2;
	BITMAPINFOHEADER bmih_rgb24;
	ICINFO icinfo;
	//BOOL m_fUseYUV = (dwPixFormat != BI_RGB); // use m_bmih_yuv to setup AVI? 

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "avi_fileopen() : " );
#endif

	//-------- 0) check to see if a file is already open
	if ( fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_OPEN, "avi_fileopen() AVWERR_OPEN ");
#endif
		return AVWERR_OPEN;
	}

	AVIFileInit();

	// Initialize the RGB24 bitmap structure.
	// bmih_rgb24 will be used later, when we call AVIStreamMakeCompressed()
	bmih_rgb24.biSize = sizeof(BITMAPINFOHEADER); 
	// 0.14 The yuv2rgb24() convertor crops the output to dimensions CropRect,
	// thus the final frame's size is determined by CropRect 
	bmih_rgb24.biWidth = m_bmih.biWidth ;
	bmih_rgb24.biHeight = m_bmih.biHeight ;
	// some codecs *require* valid Height/Width params to avoid ICERR_BADFORMAT
	bmih_rgb24.biPlanes = 1;			// must be 1
	bmih_rgb24.biCompression = BI_RGB;	// standard RGB bitmap
	bmih_rgb24.biBitCount = 24;		// 8 bits-per-pixel R,G,B format 
	//m_bmih.biSizeImage = 0;			// okay to be 0 for BI_RGB
	bmih_rgb24.biSizeImage = bmih_rgb24.biWidth * bmih_rgb24.biHeight * 3;
	bmih_rgb24.biXPelsPerMeter = bmih_rgb24.biYPelsPerMeter = 0;
	bmih_rgb24.biClrUsed = bmih_rgb24.biClrImportant = 0;

	if ( (bmih_rgb24.biWidth & 0x4) || (bmih_rgb24.biHeight & 0x4) )
		printf("\n***WARNING*** chosen viewport dimension(s) are not DIV 16!");


 	//-------- 1)  Ask user to choose a Video Compression Codec
	// could should be chosen prior to entering this function

	if ( m_compvars.cbSize == 0 )
	{	// looks like ui_codec() was never run
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "avi_fileopen() : no codec was ever chosen!");
#endif
		return AVWERR_FAIL;
	}

	// display the chosen codec's FOURCC
	// get info from codec, we'll use this info later for m_iccompressframes
	dwrc = ICGetInfo( m_compvars.hic, &icinfo, sizeof(icinfo) );
	if ( !dwrc )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "avi_fileopen() : ICGetInfo() failed." );
#endif
		return AVWERR_FAIL;
	}

	fccD2C.dword = m_compvars.fccHandler;
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "\n\tAVI Video Compressor fccHandler='%c%c%c%c' ", 
		fccD2C.ch[0], fccD2C.ch[1], fccD2C.ch[2], fccD2C.ch[3] );
	printf( "%s", m_szText );
	TextLogMsg( 0, m_szText );
#endif
	// allocate ram for state, if not already allocated
	if ( m_lpState == NULL )
	{
		m_lpState = (unsigned char *)new char[ m_compvars.cbState ];
		if ( m_lpState == NULL )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( AVWERR_FAIL, "avi_fileopen() : memory allocate failed.");
#endif
			return AVWERR_FAIL;
		}

		ICGetState( m_compvars.hic, m_lpState, m_compvars.cbState ); // store settings
		// reset the codec, very important! 
		ICSetState( m_compvars.hic, NULL, m_compvars.cbState );    // reset
		ICSetState( m_compvars.hic, m_lpState, m_compvars.cbState ); // restore settings

	}


	
	//-------- 2) check if file already exists, check m_fOverwrite to
	// determine proper action (overwrite or abort)
	fp = fopen( aviFilename, "rb");
	if ( fp != NULL )
	{
		fclose( fp );
		if ( m_fOverwrite == FALSE )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( AVWERR_FAIL, "avi_fileopen() : File already exists, but m_fOverwrite==FALSE." );
#endif
			return AVWERR_FAIL;
		}

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "\n\tWARNING '%s' already exists, overwriting!", aviFilename );
		TextLogMsg( 0, m_szText );
#endif
		
		fp = fopen( aviFilename, "wb" );	// effectively wipe out file
		if ( fp == NULL )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( AVWERR_FAIL, "\navi_fileopen() : Could not overwrite AVI file!" );
#endif
			return AVWERR_FAIL;
		}

		fclose( fp );
	}


    //-------- 3) Create our AVI-file using AVIFileOpen(). 
    hr = AVIFileOpen(&m_pAVIfile, aviFilename, OF_WRITE | OF_CREATE, NULL); 
    if (hr != 0)
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "\navi_fileopen() : AVIFileOpen() couldn't create %s!\n", aviFilename );
		switch ( hr ) {
		case AVIERR_BADFORMAT :
			strcat( m_szText, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
			break;
		case AVIERR_MEMORY:
			strcat( m_szText, "The file could not be opened because of insufficient memory.");
			break;
		case AVIERR_FILEREAD :
			strcat( m_szText, "A disk error occurred while reading the file.");
			break;
		case AVIERR_FILEOPEN :
			strcat( m_szText, "A disk error occurred while opening the file. ");
			break;
		case REGDB_E_CLASSNOTREG:
			strcat( m_szText, "According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it.");
			break;
		default:
			sprintf( m_szText2, "Unknown return code %d", hr );
			strcat( m_szText, m_szText2 );
		}
        TextLogErr( AVWERR_FAIL, m_szText );
#endif
		ICCompressorFree( &m_compvars ); 
		return AVWERR_FAIL;
	}


	//-------- 4) Process AVI frame-rate
	// this is now handled by set_fps(), which must be called *prior to* this function


	//-------- 5) load AVIstreaminfo structure, lot of busy work!
	m_AVIstreaminfo.fccType = streamtypeVIDEO; 
    m_AVIstreaminfo.fccHandler = m_compvars.fccHandler;
	m_AVIstreaminfo.dwFlags = 0; 
    m_AVIstreaminfo.dwCaps =0;// unused, must be 0
    m_AVIstreaminfo.wPriority =0 ; // ?
    m_AVIstreaminfo.wLanguage =0;  // ?
	//m_AVIstreaminfo.dwScale = fpsScale; // now set by separate function
	//m_AVIstreaminfo.dwRate = fpsRate;   // now set by separate function
	m_AVIstreaminfo.dwStart = 0; 
    m_AVIstreaminfo.dwLength = 0; 
    m_AVIstreaminfo.dwInitialFrames = 0; // no audio/video skewing
    m_AVIstreaminfo.dwSuggestedBufferSize = m_bmih.biSizeImage; 
    m_AVIstreaminfo.dwQuality = -1; // default
    m_AVIstreaminfo.dwSampleSize = 0; // variable
	SetRect(&m_AVIstreaminfo.rcFrame, 0, 0,(int) m_bmih.biWidth, 
		(int) m_bmih.biHeight );
	m_AVIstreaminfo.dwEditCount = 0; 
    m_AVIstreaminfo.dwFormatChangeCount = 0; 
		// create stream header text
		// now in set_avistring( char avistring )


    //-------- 6) Create a stream using AVIFileCreateStream. 
    hr = AVIFileCreateStream(m_pAVIfile, &m_pAVIstream, &m_AVIstreaminfo); 
    if (hr != ICERR_OK)     //Stream created OK? If not, close file. 
	{
		ICCompressorFree( &m_compvars ); 
        AVIFileRelease( m_pAVIfile );
		m_pAVIfile = NULL;
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, 
			"avi_fileopen() : AVIFileCreateStream() : Couldn't create stream!");
#endif
        return AVWERR_FAIL;
    } 

	//-------- 7) AVI Compression-stream setup
	// prior to 0.15B4, we used AVISaveOptions() to select the codec.
	// but now, ICCompressorChoose() [step 1] replaces AVISaveOptions(), so 
	// m_avicompressoptions must be manually set-up.
	// 
	// The translation process m_compvars -> m_avicompressoptions is 100%
	// accurate, but that's ok.  Some testing showed the translation to be
	// good enough (i.e. no AVI errors.)

	m_avicompressoptions.cbParms = m_compvars.cbState;
	m_avicompressoptions.cbFormat = sizeof( m_bmih );  // critical!
	// m_compvars.lDataRate is in units of KBPS : KBPS = 1024*BPS 
	m_avicompressoptions.dwBytesPerSecond = (m_compvars.lDataRate * 1024);
	m_avicompressoptions.dwFlags=AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES
		| AVICOMPRESSF_DATARATE; // AVICOMPRESSF_VALID is critical!
	m_avicompressoptions.dwInterleaveEvery = 0; // no interleaving...
	m_avicompressoptions.dwKeyFrameEvery = m_compvars.lKey;
	m_avicompressoptions.dwQuality = m_compvars.lQ;
	m_avicompressoptions.fccHandler = m_compvars.fccHandler; // critical!
	m_avicompressoptions.fccType = streamtypeVIDEO; // critical!
	m_avicompressoptions.lpFormat = &m_bmih; // critical!
	//m_avicompressoptions.lpParms = m_compvars.lpState;
	
	// make a 2nd copy of the m_compvars.lpState data
	m_avicompressoptions.lpParms = (LPVOID) new char[ m_compvars.cbState ];
	if ( m_avicompressoptions.lpParms == NULL )
	{
		ICCompressorFree( &m_compvars ); 
		AVIStreamRelease(m_pAVIstream); 
        AVIFileRelease( m_pAVIfile ); 
		m_pAVIstream = NULL;
		m_pAVIfile = NULL;
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "\navi_fileopen() : memory allocate failed.");
#endif
		return AVWERR_FAIL;
	}
	else
		memcpy( m_avicompressoptions.lpParms, m_compvars.lpState, 
			m_compvars.cbState);

	// v0.15B4 no longer used..., now using ICCompressorChoose() 
	// Display Compression-codec dialog-box.  Get AVICOMPRESSOPTIONS

/*  no longer in use
	if (!AVISaveOptions(NULL, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE
		//| ICMF_CHOOSE_PREVIEW, 1, &m_pAVIstream, (LPAVICOMPRESSOPTIONS FAR *) 
		, 1, &m_pAVIstream, (LPAVICOMPRESSOPTIONS FAR *) 
		&m_lpavicompressoptions)) 
	{
		fprintf( stderr, "\nAVISaveOptions() : failed!");
		exit(ERROR);
	}
	else
	{
		fccD2C.dword = m_avicompressoptions.fccHandler;
		printf( "\nAVICOMPRESSOPTIONS.fccHandler='%c%c%c%c'", fccD2C.ch[0], 
			fccD2C.ch[1], fccD2C.ch[2], fccD2C.ch[3] );
		printf(" lKey = %lu", m_avicompressoptions.dwKeyFrameEvery );
	}
	*/


	//-------- 9) make compressed stream
	// To write a compressed frame using the user selected codec, set
	// format with AVIStreamSetFormat(), then write with
	// AVIStreamWrite( m_pAVIstream_compressed, ... )
	hr = AVIMakeCompressedStream(&m_pAVIstream_compressed, m_pAVIstream,
		&m_avicompressoptions, NULL); 
	if (hr != AVIERR_OK)
	{ 
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "avi_fileopen() : AVIMakeCompressedStream(), " );
		switch( hr ) {
			case AVIERR_NOCOMPRESSOR :
				strcat( m_szText, "A suitable compressor cannot be found." );
				break;
			case AVIERR_MEMORY :
				strcat( m_szText, "There is not enough memory to complete the operation.");
				break;
			case AVIERR_UNSUPPORTED :
				strcat( m_szText, "Compression is not supported for this type of data." );
				strcat( m_szText, "\n\tThis error might be returned if you try to compress" );
				strcat( m_szText, "\n\tdata that is not audio or video. ");
				break;
			default:
				sprintf( m_szText2, "Unknown return code %d", hr );
				strcat( m_szText, m_szText2 );
		}
		TextLogErr( AVWERR_FAIL, m_szText );
#endif
		ICCompressorFree( &m_compvars ); 
		AVIStreamRelease(m_pAVIstream); 
        AVIFileRelease(m_pAVIfile); 
		m_pAVIstream = NULL;
		m_pAVIfile = NULL;
		return AVWERR_FAIL;
	} // end if (hr != AVIERR_OK)


	//-------- 10) Set the format of the AVISTREAM object
	// Set format of compressed stream using AVIStreamSetFormat.
    // Note, AVIStreamSetFormat() can *only* be called ONCE 
	// for an pAVIfile.  The 2nd attempt will always fail!
	// Thus, if two pAVIstreams point to the same pAVIfile,
	// SetFormat() can only be called once between these
	// two pAVIstreams.
	
	// v0.11 corrected bug, where the wrong size-info was
	// passed to AVIStreamSetFormat().  The bug caused AVI files written
	// in UNCOMPRESSED mode to report the incorrect color-mask table.
	//hr = AVIStreamSetFormat(m_pAVIstream_compressed,0,&bmih_rgb24,
	hr = AVIStreamSetFormat(m_pAVIstream_compressed,0,&bmih_rgb24,
		sizeof(bmih_rgb24) );
    if (hr != ICERR_OK )
	{ 
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "avi_fileopen() : AVIStreamSetFormat() : Couldn't set format!");
#endif
		ICCompressorFree( &m_compvars );
		AVIStreamRelease(m_pAVIstream_compressed); 
        AVIStreamRelease(m_pAVIstream); 
        AVIFileRelease(m_pAVIfile); 
		m_pAVIstream_compressed = NULL;
		m_pAVIstream = NULL;
		m_pAVIfile = NULL;
        return AVWERR_FAIL;
    }

	// correct Microsoft MPEG-4's bogus keyframe-rate report
	// setting lKeyRate = 0 disables MPEG2AVI's keyrate regulator

  if ( m_fUseYUV )
  {
	// setup BITMAPINFO structure for ICSeqCompressFrameStart()
	m_bmi.bmiHeader = m_bmih;
	//m_bmi.bmiHeader.biBitCount =32;
	m_bmi.bmiColors[0].rgbBlue=m_bmi.bmiColors[0].rgbRed=
		m_bmi.bmiColors[0].rgbGreen=m_bmi.bmiColors[0].rgbReserved = 0;

	if ( ICCompressGetFormat( m_compvars.hic, &m_bmi, &m_outbmi ) != ICERR_OK )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogMsg( 0, "\n\tICCompressGetFormat() failed!\n");
#endif
	}

	// reset BITMAPINFO structure for AVIStreamSetFormat & ICSeqCompressFrame
	m_bmi.bmiHeader = m_bmih;
	m_bmi.bmiColors[0].rgbBlue=m_bmi.bmiColors[0].rgbRed=
		m_bmi.bmiColors[0].rgbGreen=m_bmi.bmiColors[0].rgbReserved = 0;

	m_iccompressframes.dwFlags =0;
	m_iccompressframes.lpbiOutput = &m_outbmi.bmiHeader;
	m_iccompressframes.lpbiInput = &m_bmih;
	m_iccompressframes.lOutput = 0; // reserved
	m_iccompressframes.lInput = 0; // reserved
	m_iccompressframes.lStartFrame = 0;	// start from frame#0
	m_iccompressframes.lFrameCount = MAX_FRAMECOUNT;  // # frames to compress
	if ( (icinfo.dwFlags & VIDCF_QUALITY) )
		m_iccompressframes.lQuality = m_compvars.lQ;
	else
		m_iccompressframes.lQuality = 0; /* disable Quality parameter */
	m_iccompressframes.lDataRate = (m_compvars.lDataRate*1024);
	if ( m_compvars.lKey == 9999 )
		m_iccompressframes.lKeyRate = 0; // disable key-frame regulator
	else
		m_iccompressframes.lKeyRate = m_compvars.lKey;
	//m_iccompressframes.dwRate = fpsRate;   now set in set_fps()
	//m_iccompressframes.dwScale= fpsScale;
	m_iccompressframes.dwOverheadPerFrame = 0; // reserved
	m_iccompressframes.dwReserved2 = 0; // reserved
	m_iccompressframes.GetData = NULL; // not in use
	m_iccompressframes.PutData = NULL; // not in use

	ICSendMessage( m_compvars.hic, ICM_COMPRESS_FRAMES_INFO, (WPARAM)
		&m_iccompressframes, (DWORD) sizeof( m_iccompressframes ) );

	// now initialize the ICSeqCompressFrame() function 
	if ( !ICSeqCompressFrameStart( &m_compvars, &m_bmi )  )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "avi_fileopen() : ICSeqCompressFrameStart() failed!" );
#endif
		ICCompressorFree( &m_compvars ); 
		AVIStreamRelease(m_pAVIstream_compressed); 
		AVIStreamRelease(m_pAVIstream); 
		AVIFileRelease(m_pAVIfile); 
		m_pAVIstream_compressed = NULL;
		m_pAVIstream = NULL;
		m_pAVIfile = NULL;
		return AVWERR_FAIL;
	}
  } // endif ( m_fUseYUV )

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( 0, "\n\tavi_fileopen() : successful!");
#endif
	time( &m_start_time );	// Starting counting the clock NOW 
	
	// set key variables
	fInUse = TRUE;
	m_szFileName = new char[ strlen( aviFilename ) ];
	if ( m_szFileName == NULL )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogMsg( 0, "\n\tavi_fileopen() : couldn't malloc() for m_szFileName" );
#endif
	}
	else
		strcpy( m_szFileName, aviFilename );
	m_dwFrameCount = 0;
	m_dwKFCount = 0;
	m_cbWritten = 0;

	puts("");
	return AVWERR_OK;	// function is successful
} // endfunction avi_fileopen()


DWORD
cAVIwriter::avi_store_rgb24( unsigned char *source_frame )
{
//	BOOL frc; // boolean return code;
	BOOL fIsKeyFrame= 0; // set by ICSeqCompressFrame, key frame?
	DWORD dwFlagsKF = 0; // flag for keyframe

	LONG lSamplesWritten;	// #frames written, return parameter
	LONG lBytesWritten;
	//LONG lCompVideoDataSize;
	
	LPVOID lpCompVideoData = NULL;	// compressed video data

    // Save the compressed data using AVIStreamWrite(). 
    // The AVIStreamWrite function writes data to a stream.
//PX3	frc = AVIStreamWrite( m_pAVIstream_compressed, m_dwFrameCount, 1, 
//PX3		source_frame, m_bmih.biSizeImage, 0, 
//PX3		&lSamplesWritten, &lBytesWritten) ;
//PX3	if ( frc )
	if ( AVIStreamWrite( m_pAVIstream_compressed, m_dwFrameCount, 1, 
		source_frame, m_bmih.biSizeImage, 0, 
		&lSamplesWritten, &lBytesWritten) )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "\navi_store_rgb24() : AVIStreamWrite() failed!");
#endif
		return AVWERR_FAIL;
	}
	else
	{
		// update global counters
		m_dwFrameCount += lSamplesWritten;	// count of all frames
		m_cbWritten += lBytesWritten;		// count of bytes
		m_dwKFCount += (fIsKeyFrame?1:0);	// count of key-frames
		if ( !(m_dwFrameCount & 0x0F) )	// v0.16B23
			printf("AVIStreamWrite() (%lu KB) ", (m_cbWritten>>10) );

//		printf("AVIStreamWrite() (%lu KB) bytes Written=%lu %s",
//			m_cbWritten>>10, lBytesWritten, 
//			(fIsKeyFrame ? "KEYF  ":"      ") );
	}
	return AVWERR_OK;
}

//SVE 20.05.2001 Neuer Parameter: Out-Rect,Erzeungener Keyframe
DWORD
cAVIwriter::avi_store_yuv( unsigned char *source_frame, LPRECT lpOut, BOOL bKeyFrame)
//SVE ENDE
{
//	time_t CurrentTime; // Added PX3 for FPS Counter 
//	BOOL frc; // boolean return code;
	BOOL fIsKeyFrame= 0; // set by ICSeqCompressFrame, key frame?
//	DWORD dwFlagsKF = 0; // flag for keyframe
//	static DWORD dwLastKF = 0; // frame# of last keyframe 


	LONG lSamplesWritten;	// #frames written, return parameter
	LONG lBytesWritten, lCompVideoDataSize;
	
	LPVOID lpCompVideoData = NULL;	// compressed video data

//SVE 20.05.2001
	// Dieses muß ein Keyframe werden
	if(bKeyFrame)
	{
		// Einfach den Frame umkehren
		LONG l1,l2;
		l1=(lpOut->bottom-lpOut->top)*(lpOut->right-lpOut->left);
		for(l2=0; l2<l1; l2++)
			source_frame[l2]=255-source_frame[l2];
		ICSeqCompressFrame( &m_compvars, 0, 
			(LPVOID) source_frame, &fIsKeyFrame, &lCompVideoDataSize );
		for(l2=0; l2<l1; l2++)
			source_frame[l2]=255-source_frame[l2];
	}
//SVE ENDE

	lpCompVideoData = ICSeqCompressFrame( &m_compvars, 0, 
		(LPVOID) source_frame, &fIsKeyFrame, &lCompVideoDataSize );
	if ( lpCompVideoData == NULL )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "\navi_store_yuv() : ICSeqCompressFrame() failed!" );
#endif
		return AVWERR_FAIL;
	}
	else
	{

		if ( AVIStreamWrite( m_pAVIstream, m_dwFrameCount, 1, 
			lpCompVideoData, lCompVideoDataSize, (fIsKeyFrame ? AVIIF_KEYFRAME : 0), 
			&lSamplesWritten, &lBytesWritten) )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( AVWERR_FAIL, "\navi_store_yuv() : AVIStreamWrite() failed!" );
#endif
			return AVWERR_FAIL;
		}
		else
		{
#ifdef ENHANCED_ERROR_LOGGING
			if ( lCompVideoDataSize != lBytesWritten )
				fprintf( stderr, 
					"\n#bytes written by AVIStreamWrite()!=ICSeqCompressFrame()");
#endif
			// update global counters 
			m_dwFrameCount += lSamplesWritten;	// count of all frames
			m_cbWritten += lBytesWritten;		// count of bytes
			m_dwKFCount += (fIsKeyFrame?1:0);	// count of key-frames
//PX3			if ( (m_dwFrameCount & 0x0F) == 0 )	// v0.16B23
//PX3			if ( !(m_dwFrameCount & 0x0F) )	// v0.16B23
//PX3			{
				//st_RunState.lowestFPS = 0;
				//st_RunState.highestFPS = 0;
				//printf("AVISW() (%lu KB) #KF=%lu #FPS=%.2f", (m_cbWritten>>10), 
				//		m_dwKFCount, (m_dwFrameCount/(difftime(CurrentTime,m_start_time))) );
//PX3			}
		}

	}

	return AVWERR_OK;


//PX3   ORIGINAL CODE ..
//PX3    // Save the compressed data using AVIStreamWrite(). 
//PX3    // The AVIStreamWrite function writes data to a stream.
//PX3	if ( lpCompVideoData )
//PX3		frc = AVIStreamWrite( m_pAVIstream, m_dwFrameCount, 1, 
//PX3			lpCompVideoData, lCompVideoDataSize, dwFlagsKF, 
//PX3			&lSamplesWritten, &lBytesWritten) ;
//PX3	if ( frc )
//PX3	{
//PX3		TextLogErr( AVWERR_FAIL, "\navi_store_yuv() : AVIStreamWrite() failed!" );
//PX3		return AVWERR_FAIL;
//PX3	}
//PX3	else
//PX3	{
//PX3		if ( lCompVideoDataSize != lBytesWritten )
//PX3			fprintf( stderr, 
//PX3				"\n#bytes written by AVIStreamWrite()!=ICSeqCompressFrame()");
//PX3		// update global counters 
//PX3		m_dwFrameCount += lSamplesWritten;	// count of all frames
//PX3		m_cbWritten += lBytesWritten;		// count of bytes
//PX3		m_dwKFCount += (fIsKeyFrame?1:0);	// count of key-frames
//PX3		time(&CurrentTime); // Added PX3 for FPS Counter 
//PX3		if ( (m_dwFrameCount & 0x0F) == 0 )	// v0.16B23
//PX3			printf("AVIStreamWrite() (%lu KB) #KF=%lu #FPS=%.2f", (m_cbWritten>>10), 
//PX3				m_dwKFCount, (m_dwFrameCount/(difftime(CurrentTime,m_start_time))) );
//PX3//		printf("AVIStreamWrite() (%lu KB) Bytes written=%lu %s",
//PX3//			m_cbWritten>>10, lBytesWritten, 
//PX3//			(fIsKeyFrame ? "KEYF  ":"      ") );
//PX3	}
//PX3	return AVWERR_OK;

}



DWORD
cAVIwriter::avi_fileclose( void )
{
	time_t finish_time, el_time; /* elapsed time */
	LPAVICOMPRESSOPTIONS lpavicompressoptions = &m_avicompressoptions;
	LRESULT lrc = 0; /* LRESULT code */

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "avi_fileclose() : ");
#endif

	if ( !fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( AVWERR_FAIL, "avi_fileclose() : AVI-file not open.");
#endif
		return AVWERR_FAIL;
	}

	/* clean up code, release resources for requested system services */
//SVE 20.05.2001 Hier den Compressed-Stream schließen (AVI-Header fehlt sonst)
	if ( m_pAVIstream_compressed != NULL )
		AVIStreamRelease(m_pAVIstream_compressed); 
//SVE 20.05.2001 ICSeqCompressFrameEnd nur, wenn oben gestartet
	if ( m_fUseYUV)
//SVE ENDE
	ICSeqCompressFrameEnd( &m_compvars ) ;
//SVE 20.05.2001 Der Kompressor sollte hier schon geschlossen werden (Open DivX erzeugt sonst Abbruch)
	ICClose( m_compvars.hic );
	ICCompressorFree( &m_compvars );
//SVE ENDE
	// ICCompressorFree( &m_compvars ); 
	// lrc = ICClose( m_compvars.hic );
	//if ( lrc != ICERR_OK )
	//{
	//	TextLogMsg( 0, "ICClose() failed." );
	//}

	// ICCompressorFree() & ICClose() are not called here, 
	// because cAVIwriter might re-use
	// the same codec for the next AVI-file to be written.
	// if we call ICCompressorFree() now, then all the setup work done by
	// ui_codec() goes down the drain.  (ICOpen() can't open it back up for
	// some reason.)  So it's better to just leave ICCompressorfree() out
	// of the picture until the object is destroyed (destructor)
 
//SVE 20.05.2001 Die Funktion AVISaveOptions wurde nie aufgerufen -> dadurch hier Abbruch unter Win2K
//	if ( lpavicompressoptions != NULL )
//		AVISaveOptionsFree(1,(LPAVICOMPRESSOPTIONS FAR *)&lpavicompressoptions);
//SVE 20.05.2001 AVIStreamRelease wurde oben schon aufgerufen
//	if ( m_pAVIstream_compressed != NULL )
//		AVIStreamRelease(m_pAVIstream_compressed); 
//SVE ENDE
	if ( m_pAVIstream != NULL )
		AVIStreamRelease(m_pAVIstream); 
	if ( m_pAVIfile != NULL )
		AVIFileRelease(m_pAVIfile);
	m_pAVIfile = NULL;
	m_pAVIstream = NULL;
	m_pAVIstream_compressed = NULL;
//SVE 20.05.2001 Da ich alles aus dem Destruktor entfernt habe, mache ich das auf hier
	AVIFileExit(); 	// v0.16B34	time( &finish_time );	/* Record the finish time */
//SVE ENDE

	time( &finish_time );	/* Record the finish time */

	/* time code copied from John Schlichther's AVI2MPG1 */
	puts("");
	el_time = finish_time - m_start_time;
	if(el_time <= 60)
		printf( "Elapsed time = %i seconds", el_time);
	else if(el_time < 3600)
		printf( "Elapsed time = %i:%02i minutes", (el_time/60)+1,
			el_time%60 );
	else
		printf( "Elapsed time = %i:%02i hours", el_time/3600, 
			(el_time%3600)/60);

	/* the key-frame data is only returned by ICSeqCompressFrame()...thus
	   RGB24-writing mode does not have access to key-frame info! */
	if ( m_fUseYUV ) 
		printf("\n'%s' AVI video statistics :\n\t(Key)/Frames = (%lu)/%lu, KBytes = %luKB",
			m_szFileName, m_dwKFCount, m_dwFrameCount, (m_cbWritten>>10) );
	else
		printf("\n'%s' AVI Statistics :\n\tFrames = %lu, KBytes = %luKB",
			m_szFileName, m_dwFrameCount, (m_cbWritten>>10));

	printf( "\n\tAverage AVI video bitrate : %.1f KBPS", (double)
		(m_cbWritten>>10) * ( m_AVIstreaminfo.dwRate / 
		m_AVIstreaminfo.dwScale ) / m_dwFrameCount );
	printf( "  ( @%.3f fps )", (double) m_AVIstreaminfo.dwRate / 
		m_AVIstreaminfo.dwScale );
/*
	if ( CHECKOPT( UserOptIVTC ) )
		printf("\nInverse-telecine : start-state = %d ", 
		  GETOPT( UserOptIVTC ) );
*/
	// reset some variables
	fInUse = FALSE; // mark that AVIwriter is now free
	if ( m_szFileName != NULL )
		delete m_szFileName;

	return AVWERR_OK;
} // cAVIwriter::avi_fileclose( void )



/* this function is called by store.c, the rest of the functions in this
   file are private  */
//SVE 20.05.2001 Neuer Parameter: Erzeungener Keyframe
DWORD
cAVIwriter::store_avi_one( const char aviFilename[], 
	unsigned char *source_frame, LPRECT CropRect, long FrameNumber, BOOL bKeyFrame )
//SVE ENDE
{
	if ( !fIsAVIOpen() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogMsg( LOG_NEW_ENTRY, "store_avi_one() : ");
		TextLogErr( AVWERR_FAIL, "store_avi_one() : AVI-file not open.");
#endif
		return AVWERR_FAIL;
	}

	if ( source_frame != NULL )	// have something to write? 
	{
		if ( m_fUseYUV )
//SVE 20.05.2001 Neuer Parameter: Out-Rect,Erzeungener Keyframe
			avi_store_yuv( source_frame, CropRect, bKeyFrame );  // write YUV frame
//SVE ENDE
		else
		{
			// convert YUV444 24bpp packed-pixel frame to RGB24 
			// yuv2rgb24( ivtc_frame, CropRect );
			avi_store_rgb24( source_frame );	// write RGB24 frame
		}
	}
	else
	{	// actually, IVTC is now performed inside the store.c
		// so store_avi_one() should never receive ivtc_frame == NULL
		printf("ODD !!!!!!!!!!!!!!!!!!!!!!!!                       ");
	}



//PX3	unsigned char *ivtc_frame = NULL ; /* output frame from IVTC algorithm */
//PX3	//int key;
//PX3	//BOOL fr;  /* boolean return code */
//PX3	DWORD dwPixFormat = 0; /* framebuffer pixel format, BI_RGB, YUV, etc. */

//PX3	//TextLogMsg( LOG_NEW_ENTRY, "store_avi_one() : ");

//PX3	if ( !fIsAVIOpen() )
//PX3	{
//PX3		TextLogMsg( LOG_NEW_ENTRY, "store_avi_one() : ");
//PX3		TextLogErr( AVWERR_FAIL, "store_avi_one() : AVI-file not open.");
//PX3		return AVWERR_FAIL;
//PX3	}

	/* storeavi.c assumes that the source_frame[] is already in the correct
	   format (dwPixFormat.)  This routine does not check the correctness
	   of the bitmap's format. Any conversion must take place *PRIOR* to
	   calling this function, store_avi_one() */
//PX3	ivtc_frame = source_frame; // already telecined in store.c
	//printf("\rMPEG frame %lu : ", FrameNumber );

//PX3	if ( ivtc_frame != NULL )	// have something to write? 
//PX3	{
//PX3		if ( m_fUseYUV )
//PX3			avi_store_yuv( ivtc_frame );  // write YUV frame
//PX3		else
//PX3		{
			// convert YUV444 24bpp packed-pixel frame to RGB24 
			// yuv2rgb24( ivtc_frame, CropRect );
//PX3			avi_store_rgb24( ivtc_frame );	// write RGB24 frame
//PX3		}
//PX3	}
//PX3	else
//PX3	{	// actually, IVTC is now performed inside the store.c
		// so store_avi_one() should never receive ivtc_frame == NULL
//PX3		printf("ODD !!!!!!!!!!!!!!!!!!!!!!!!                       ");
//PX3	}

	// v0.15B51, parse keyboard & previous QUIT command
/*
	if ( _kbhit() )	// recent keypress?  If not, don't _getch()
	{
		key = _getch();	// yes, read keypress
		if ( toupper( key ) == toupper( KEY_QUIT ) )
		{
			g_cmd_buttonStop = TRUE;	// set command to stop
		}
	}

	if ( g_cmd_buttonStop )
	{
		printf("\nDecoder stopped.");
		avi_fileclose();
		exit( ERROR );
	}
*/
	return AVWERR_OK;
}	// cAVIwriter::store_avi_one()


