/* store.cpp, picture output routines                                         */

/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */

/*
 * Disclaimer of Warranty
 *
 * These software programs are available to the user without any license fee or
 * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
 * any and all warranties, whether express, implied, or statuary, including any
 * implied warranties or merchantability or of fitness for a particular
 * purpose.  In no event shall the copyright-holder be liable for any
 * incidental, punitive, or consequential damages of any kind whatsoever
 * arising from the use of these programs.
 *
 * This disclaimer of warranty extends to the user of these programs and user's
 * customers, employees, agents, transferees, successors, and assigns.
 *
 * The MPEG Software Simulation Group does not represent or warrant that the
 * programs furnished hereunder are free of infringement of any third-party
 * patents.
 *
 * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
 * are subject to royalty fees to patent holders.  Many of these patents are
 * general enough such that they are unavoidable regardless of implementation
 * design.
 *
 *
 * MPEG2AVI
 * --------
 * v0.16B35 corrected memset() bug in store_avi_gdi() which didn't
 *    clear the entire framebuffer workspaces
 *    increased memory padding on all calloc() calls
 * v0.16B34 converted malloc() calls to calloc() calls
 * v0.16B33 for '-*', a square-block is printed for each I-frame
 * v0.16B32 for '-*', a correct upper-left justification is applied so the
 *    the mpeg-header info is always in the UL corner, regardless of cropping
 * v0.16B30 update_mpeginfo() called in Write_Frame(), this updates the LBA,
 *          temporal_reference, pictref, etc. variables
 * 
 * v0.16B23 if (UserOptIDCT == _IDCT_MMX_AAN), disallow AVI-writing!
 *         moved the planar->packed conversion to yuv2yuv.c.  mildly changed
 *          the calling parameters (now uses a ConvBlock struct)
 *         in store_avi_gdi(), fb_yuv is malloc'd to a 32bpp space (instead of 24bpp)
 * 
 * v0.16B22 __asm emms to the end of Write_Frame() & middle of store_avi_gdi()
 *         MMX optimizations to YV12, YUY2 buffer generation.
 *         added EXTRA_MEM_PAD to extend frame-buffer stores.
 * v0.16B2 added watermarking feature to frames,
 *           1st Decoded frame counter (always starts from 0)
 *           2nd line gop_timecode (from GOP header)
 *           3rd line temporal reference (from MPEG picture header)
 *           4th line VOB LBA address of last good MPEG SYSTEM HEADER
 * v0.16B1 ++g_cbMPEGpicture moved to Write_Frame(), so it doesn't double-count
 *       interlaced (two fields) video
 *       moved keyboard parsing to here
 *       added m_cbSkipFrame to store_avi_one() to implement UserOptAVISkipFrame
 *        the skip-feature applies to GDI/AVI output, but it occurs after the
 *        frame is sent through the IVTC (so as to not disturb its operatino)
 * v0.15B51 the UserOptFRangeEnd triggers -> g_cmd_buttonStop 
 * v0.15B5 restructured post-processing operations, fixed malloc() bug in
 *       store_avi_gdi()
 *
 *       | MPEG2V12 | -> | VRESIZE.C | -> | YUV2YUV | -> | CROP&CSC | -> OUTPUT
 *       MPEG decoder    -3X, -3Y resize   pixFormat     crop viewport
 *                                         conversion
 *
 * v0.15B4 direct-YUV AVI mode.  The decoded-MPEG frames are transferred
 *       to storeavi.c in the native YCbCr420 color-format
 *       half-resolution mode now works for all CHROMA formats (420/422/444)
 * v0.15 added frame-counter, g_FrameCount.  This counts the #frames received
 *       from the MPEG-decoder, and is not 100% reliable.  It's a useful
 *       statistic for the GDI and AVI functions, though.
 *       
 *       added process_filter_cmd( void ) to proces g_cmd_filter
 *
 * v0.14
 *    Clear all memory-spaces, 
 *    Created a new function store_avi_gdi() ... 
 *    half-resolution output mode (currently only supports CHROMA420 foramt.)
 *    The 1/2-res mode only supports YUV420 planar, MPEG's most popular
 *    color format.
 *
 *     Cropping & 1/2-resolution implementation
 *     ----------------------------------------
 *
 *     1)  decoder-output <src[0],src[1],src[2]>
 *     2)  Half-resolution?  if yes, downsample
 *     3)  build YUV888 24bpp packed bitmap from <Resized image, YUV444 planar)
 *         (crop & convert image simultaneously)
 *     4)  call output functions (pass YUV888 24bpp packed image)
 *     5)  (display_dib or store_avi_one), convert color space with yuv2rgb24() 
 *         yuv2rgb24()...
 *     6)  done
 *
 *     only store_avi_gdi() implement cropping/downsampling...the other
 *     functions ignore these operations.
 *
 *    When 1/2-res mode is in use, store_avi_gdi() *directly* calls 
 *    ivtc_half_8bpp() [ telecine.c ], then sends the processed frame to
 *    the appropriate output-routine ( store_avi() or display_dib() )
 *
 *    By handling the telecine-conversion in native YUV420 planar, the
 *    upscaling/downscaling (YUV420->422->444) filters are bypassed entirely,
 *    increasing both performance and precision.
 *
 *    Overall data-flow from MPEG-decoder's output to file
 *
 *    1)  store_one()  -> src[0],src[1],src[2] -> store_avi()
 *    2)  src[0]... -> src[0] (y_half), src[1] ->u444, src[2] -> v444 )
 *    3)     fb_yuv -> ivtc_half_8bpp() -> (display_dib or store_avi_one) -> yuv2rgb24()
 *
 * v0.11
 * Most modifications are to store_ppm_tga() ... in addition to its previous
 * PPM/TGA output, this function now handles GDI and AVI.
 *
 * store_ppm_tga() redirects GDI output to display_dib() [windisp.c]
 *					 and AVI to store_avi_one() [storeavi.c]
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <io.h>
#include <conio.h>

#include "config.h"
#include "global.h"
#include <windows.h> /* used only to get type declaration BOOL */
#include <wingdi.h> /* used for BITMAPINFO */


//SVE 20.05.2001 Deklaration neuer Funktionen
#include "sve.h"
//SVE ENDE

void yuv444torgb32( tImageOpBlock *pConvBlock );



/* private prototypes */
static void store_one _ANSI_ARGS_((char *outname, unsigned char *src[],
  int offset, int incr, int height));
//static void store_yuv _ANSI_ARGS_((char *outname, unsigned char *src[],
//  int offset, int incr, int height));
//static void store_sif _ANSI_ARGS_((char *outname, unsigned char *src[],
//  int offset, int incr, int height));
//static void store_ppm_tga _ANSI_ARGS_((char *outname, unsigned char *src[],
//  int offset, int incr, int height, int tgaflag));
static void store_avi_gdi _ANSI_ARGS_((char *outname, unsigned char *src[],
  int offset, int incr, int height, int tgaflag));
//static void store_yuv1 _ANSI_ARGS_((char *name, unsigned char *src,
//  int offset, int incr, int width, int height));
//static void putbyte _ANSI_ARGS_((int c));
//static void putword _ANSI_ARGS_((int w));
BOOL process_filter_cmd( void ); /* process command-variable g_cmd_filter */

	/* private variables */

static RECT srcRect; /* resolution of MPEG-video */
static BITMAPINFO g_bmi;
#define OBFRSIZE 4096
static unsigned char obfr[OBFRSIZE];
static unsigned char *optr;
static int outfile;

#define EXTRA_MEM_PAD 16	// extra bytes to pad each framebuffer
	// 0.16B22  EXTRA_MEM_PAD allows MMX-operations to read beyond the
	// logical end of a video-frame (for example, an MMX-loop might
	// right up to 7 bytes beyond the end of the frame, for DWORD/QWORD
	// alignment purposes.)


int
rstrcmpi( const char a[], const char b[] )
{
	long counter = 0;
	long result = 0;
	long len_a = 0, len_b = 0;
	long minab = 0;
	
	if ( a != NULL )
		len_a = strlen( a );

	if ( b != NULL )
		len_b = strlen( b );

	if ( len_a == 0 && len_b == 0 )
		return 0;	/* equal ?!? */

	if ( len_a == 0 )
		return -1; /* left < right */

	if ( len_b == 0 )
		return 1; /* left > right */

	minab = ( len_a > len_b ) ? len_b : len_a;

	for ( counter = 0; counter < minab && result == 0; ++counter )
	{
		if ( toupper( a[ len_a - counter ] ) !=
			toupper( b[ len_b - counter ] ) )
			result = toupper( a[ len_a - counter ] ) >
				toupper( b[ len_b - counter ] ) ? 1 : -1 ;
	}

	return result;
}

/*
 * store a picture as either one frame or two fields
 */
void Write_Frame(src,frame)
unsigned char *src[];
int frame;
{
  char outname[FILENAME_LENGTH];

  update_mpeginfo();	// update LBA, goptimecode, temporalref, v0.16B3

  if (progressive_sequence || progressive_frame || Frame_Store_Flag)
  {
    /* progressive */
    sprintf(outname,Output_Picture_Filename,frame,'f');
    store_one(outname,src,0,Coded_Picture_Width,vertical_size);
  }
  else
  {
    /* interlaced */
    sprintf(outname,Output_Picture_Filename,frame,'a');
    store_one(outname,src,0,Coded_Picture_Width<<1,vertical_size>>1);

    sprintf(outname,Output_Picture_Filename,frame,'b');
    store_one(outname,src,
      Coded_Picture_Width,Coded_Picture_Width<<1,vertical_size>>1);
  }
  ++g_cbMPEGPicture; /* update decoded picture counter */
  //g_cbMPEGPicture = frame;

 // __asm emms;
}

/*
 * store one frame or one field
 */
static void store_one(outname,src,offset,incr,height)
char *outname;
unsigned char *src[];
int offset, incr, height;
{
  static int first_iteration = 1;
  int keyp; // keypress
  if ( first_iteration )
  {
	  first_iteration = 0;
	  //g_FrameCount = 0;  /* initialize frame counter */
//SVE 20.05.2001	  printf("\nMPEG-%d video resolution : <%d x %d>, coded format = ",
//SVE 20.05.2001		  (1+base.MPEG2_Flag), Coded_Picture_Width,Coded_Picture_Height );
//SVE 20.05.2001	  switch( chroma_format )
//SVE 20.05.2001	  {
//SVE 20.05.2001	    case CHROMA420 :
//SVE 20.05.2001		  printf("YUV420");
//SVE 20.05.2001		  break;
//SVE 20.05.2001	    case CHROMA422 :
//SVE 20.05.2001		  printf("YUV422");
//SVE 20.05.2001		  break;
//SVE 20.05.2001	    case CHROMA444 :
//SVE 20.05.2001		  printf("YUV444");
//SVE 20.05.2001		  break;
//SVE 20.05.2001	    default:
//SVE 20.05.2001		  printf("unknown!");
//SVE 20.05.2001	  } /* endswitch */

	  /* setup rectangle for store.c */
	  srcRect.left = 0; 
	  srcRect.top = 0;
	  srcRect.right = Coded_Picture_Width;
	  srcRect.bottom = Coded_Picture_Height;
//SVE 20.05.2001	  printf("\n");
  } /* endif ( first_iteration ) */
  
  switch (Output_Type)
  {
  case T_YUV:
//    store_yuv(outname,src,offset,incr,height);
    break;
  case T_SIF:
//    store_sif(outname,src,offset,incr,height);
    break;
  case T_TGA:
//    store_ppm_tga(outname,src,offset,incr,height,1);
    break;
  case T_PPM:
//    store_ppm_tga(outname,src,offset,incr,height,0);
    break;
#ifdef DISPLAY
  case T_X11:
    dither(src);
    break;
#endif
  case T_GDI:
	store_avi_gdi(outname,src,offset,incr,height,T_GDI);
	break;
  case T_AVI:
	store_avi_gdi(outname,src,offset,incr,height,T_AVI);
	break;
  case T_AVI_YV12:  // quick hack for 0.15B4
	store_avi_gdi(outname,src,offset,incr,height,T_AVI_YV12);
	break;
  case T_AVI_YUY2:  // quick hack for 0.15B5
	store_avi_gdi(outname,src,offset,incr,height,T_AVI_YUY2);
	break;
  default:
	  fprintf(stderr, "\nstore_one() : Unknown output mode -o%d", Output_Type );
	  exit(ERROR);
    break;
  }

  if ( Output_Type != T_GDI )
  { // scan keyboard
  	if ( _kbhit() )	// recent keypress?  If not, don't _getch()
	{
		keyp = _getch();	// yes, read keypress
		if ( toupper( keyp ) == toupper( KEY_QUIT ) )
		{
			g_cmd_buttonStop = TRUE;	// set command to stop
		}
	}

	if ( g_cmd_buttonStop )
	{
//SVE 20.05.2001		printf("\nDecoder stopped.");
		avi_fileclose();
		exit( ERROR );
	}
  }
}

/* separate headerless files for y, u and v */
/*
static void store_yuv(outname,src,offset,incr,height)
char *outname;
unsigned char *src[];
int offset,incr,height;
{
  int hsize;
  char tmpname[FILENAME_LENGTH];

  hsize = horizontal_size;

  sprintf(tmpname,"%s.Y",outname);
  store_yuv1(tmpname,src[0],offset,incr,hsize,height);

  if (chroma_format!=CHROMA444)
  {
    offset>>=1; incr>>=1; hsize>>=1;
  }

  if (chroma_format==CHROMA420)
  {
    height>>=1;
  }

  sprintf(tmpname,"%s.U",outname);
  store_yuv1(tmpname,src[1],offset,incr,hsize,height);

  sprintf(tmpname,"%s.V",outname);
  store_yuv1(tmpname,src[2],offset,incr,hsize,height);
}
*/
/* auxiliary routine 
static void store_yuv1(name,src,offset,incr,width,height)
char *name;
unsigned char *src;
int offset,incr,width,height;
{
  int i, j;
  unsigned char *p;

  if (!Quiet_Flag)
    fprintf(stderr,"saving %s\n",name);

  if ((outfile = _open(name,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1)
  {
    sprintf(Error_Text,"Couldn't create %s\n",name);
    Error(Error_Text);
  }

  optr=obfr;

  for (i=0; i<height; i++)
  {
    p = src + offset + incr*i;
    for (j=0; j<width; j++)
      putbyte(*p++);
  }

  if (optr!=obfr)
    _write(outfile,obfr,optr-obfr);

  _close(outfile);
}*/

/*
 * store as headerless file in U,Y,V,Y format
 *
static void store_sif (outname,src,offset,incr,height)
char *outname;
unsigned char *src[];
int offset, incr, height;
{
  int i,j;
  unsigned char *py, *pu, *pv;
  static unsigned char *u422, *v422;

  if (chroma_format==CHROMA444)
    Error("4:4:4 not supported for SIF format");

  if (chroma_format==CHROMA422)
  {
    u422 = src[1];
    v422 = src[2];
  }
  else
  {
    if (!u422)
    {
      if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                           *Coded_Picture_Height)))
        Error("malloc failed");
      if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                           *Coded_Picture_Height)))
        Error("malloc failed");
    }
  
    conv420to422(src[1],src[2],u422,v422, Coded_Picture_Width,
		Coded_Picture_Height );
  }

  strcat(outname,".SIF");

  if (!Quiet_Flag)
    fprintf(stderr,"saving %s\n",outname);

  if ((outfile = _open(outname,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1)
  {
    sprintf(Error_Text,"Couldn't create %s\n",outname);
    Error(Error_Text);
  }

  optr = obfr;

  for (i=0; i<height; i++)
  {
    py = src[0] + offset + incr*i;
    pu = u422 + (offset>>1) + (incr>>1)*i;
    pv = v422 + (offset>>1) + (incr>>1)*i;

    for (j=0; j<horizontal_size; j+=2)
    {
      putbyte(*pu++);
      putbyte(*py++);
      putbyte(*pv++);
      putbyte(*py++);
    }
  }

  if (optr!=obfr)
    _write(outfile,obfr,optr-obfr);

  _close(outfile);
}*/

/*
 * store as PPM (PBMPLUS) or uncompressed Truevision TGA ('Targa') file
 *
static void store_ppm_tga(outname,src,offset,incr,height,tgaflag)
char *outname;
unsigned char *src[];
int offset, incr, height;
int tgaflag;
{
  int i, j;
  int y, u, v, r, g, b;
  int crv, cbu, cgu, cgv;
  unsigned char *py, *pu, *pv;
  static unsigned char tga24[14] = {0,0,2,0,0,0,0, 0,0,0,0,0,24,32};
  char header[FILENAME_LENGTH];
  unsigned char *pixelxy_addr = NULL;
  static unsigned char *u422, *v422, *u444, *v444;
  
  
  if (chroma_format==CHROMA444)
  {
    u444 = src[1];
    v444 = src[2];
  }
  else
  {
    if (!u444)
    {
      if (chroma_format==CHROMA420)
      {
        if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                             *Coded_Picture_Height)))
          Error("malloc failed");
        if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                             *Coded_Picture_Height)))
          Error("malloc failed");
      }

      if (!(u444 = (unsigned char *)malloc(Coded_Picture_Width
                                           *Coded_Picture_Height)))
        Error("malloc failed");

      if (!(v444 = (unsigned char *)malloc(Coded_Picture_Width
                                           *Coded_Picture_Height)))
        Error("malloc failed");
    }

    if (chroma_format==CHROMA420)
    {
      conv420to422(src[1],src[2],u422,v422, Coded_Picture_Width, 
		  Coded_Picture_Height );
      conv422to444(u422,v422,u444,v444,Coded_Picture_Width, 
		  Coded_Picture_Height );
    }
    else
    {
      conv422to444(src[1],src[2],u444,v444,Coded_Picture_Width, 
		  Coded_Picture_Height );
    }
  }

  //strcat(outname,tgaflag ? ".tga" : ".ppm");
  switch ( tgaflag )
  {
	case 0 : if ( rstrcmpi( outname, ".ppm" ) != 0 )
				 strcat( outname, ".ppm" );
		break;
	case 1 : if ( rstrcmpi( outname, ".tga" ) != 0 )
				 strcat( outname, ".tga" );
		break;
	default :
		;
  }
  

  if ( tgaflag )
  {
  if (!Quiet_Flag)
    fprintf(stderr,"saving %s\n",outname);

  if ((outfile = _open(outname,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1)
  {
    sprintf(Error_Text,"Couldn't create %s\n",outname);
    Error(Error_Text);
  }
  }

  optr = obfr;

  if (tgaflag)
  {
    // TGA header 
    for (i=0; i<12; i++)
      putbyte(tga24[i]);

    putword(horizontal_size); putword(height);
    putbyte(tga24[12]); putbyte(tga24[13]);
  }
  else
  {
    // PPM header 
    sprintf(header,"P6\n%d %d\n255\n",horizontal_size,height);

    for (i=0; header[i]!=0; i++)
      putbyte(header[i]);
  }

  // matrix coefficients 
  crv = Inverse_Table_6_9[matrix_coefficients][0];
  cbu = Inverse_Table_6_9[matrix_coefficients][1];
  cgu = Inverse_Table_6_9[matrix_coefficients][2];
  cgv = Inverse_Table_6_9[matrix_coefficients][3];
  
  for (i=0; i<height; i++)
  {
    py = src[0] + offset + incr*i;
    pu = u444 + offset + incr*i;
    pv = v444 + offset + incr*i;

    for (j=0; j<horizontal_size; j++)
    {
      u = *pu++ - 128;
      v = *pv++ - 128;
      y = 76309 * (*py++ - 16); // (255/219)*65536 
      r = Clip[(y + crv*v + 32768)>>16];
      g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
      b = Clip[(y + cbu*u + 32786)>>16];
	  
	  if (tgaflag)
	  {
	        putbyte(b); putbyte(g); putbyte(r);
	  }
	  else
	  {
	        putbyte(r); putbyte(g); putbyte(b);
	  }
    }
  }

  if (optr!=obfr)
  {
    _write(outfile,obfr,optr-obfr); // write image to file 
    _close(outfile);
  }
}*/

/*
 * store as AVI (Windows) or display to Windows GDI
 */
static void store_avi_gdi(outname,src,offset,incr,height,tgaflag)
char *outname;
unsigned char *src[];
int offset, incr, height;
int tgaflag;
{
  char szText[256], szName[256]; // avi description string
  /*int y, u, v, r, g, b;*/
  DWORD y_src_addr=0, uv_src_addr=0, dest_addr=0;
  RECT dstRect;
  BITMAPINFOHEADER bmih;
  DWORD dwPixFormat = 0;	/* needed for avi_fileopen() */
  DWORD dwXpos, dwYpos; /* v0.16B32 justification (in #chars) for vtitler */
  DWORD psize;

//SVE 05.06.2001  static unsigned char *u422 = NULL, *v422= NULL, *u444=NULL, *v444=NULL,*y_full=NULL, 
  static unsigned char *u_extra = NULL, *v_extra = NULL, *y_extra = NULL;
  
  static int first_iteration = 1;
  static unsigned char *fb_yuv = NULL, *y_ptr = NULL , *u_ptr = NULL,
	  *v_ptr = NULL;
  static long m_OutputHeight, m_OutputWidth; 
	/* dimensions of DISPLAYED (final) frames, after cropping */
  static long m_cbSkipFrame = 0;
    /* v0.16B1 AVISkipFrame counter */

  static RECT CropRect; /* cropping rectangle, passed to -o6 and -o7 */


//SVE 20.05.2001 Neue Variablen
  long ltmp;
  static long cpw,cph,rpw,rph;
  static BOOL bConvert;
  BOOL bKeyFrame;
  static unsigned char *y1,*u1,*v1,*y2,*u2,*v2;
  unsigned char *yin,*uin,*vin,*yout,*uout,*vout;
  DWORD dwCF;
//SVE ENDE




  /* the cropping rectangle is with respect to Resized_Picture_xxx
     yuv2rgb24 ultimately handles the cropping. */
  tImageOpBlock convBlock; /* conversion information for yuv2yuv() */

  
  if ( first_iteration )
  {

	first_iteration = 0;	/* disable this flag */
	psize = (Coded_Picture_Width * Coded_Picture_Height) >> 5;
  	/* allocate memory and clear it */
	fb_yuv = (unsigned char *)calloc( (psize*4)+2, 32 ); 
//SVE 05.06.2001	y_full = (unsigned char *)calloc(  psize + 2, 32 );
	/* y, u and v extra are for the resizer */
	y_extra = (unsigned char *)calloc( psize + 2, 32);
	u_extra = (unsigned char *)calloc( psize + 2, 32);
	v_extra = (unsigned char *)calloc( psize + 2, 32);
//SVE 05.06.2001	u422 = (unsigned char *)calloc( psize + 2, 32);
//SVE 05.06.2001	v422 = (unsigned char *)calloc( psize + 2, 32);
//SVE 05.06.2001	u444 = (unsigned char *)calloc( psize + 2, 32);
//SVE 05.06.2001	v444 = (unsigned char *)calloc( psize + 2, 32 );

	/* vresizer.c */
	if ( CHECKOPT( UserOptResizeX ) && UserOptResizeX.data < 32 
		 || CHECKOPT( UserOptResizeY ) && UserOptResizeY.data < 32 )
	{
		fprintf( stderr, "\nshrink_frame() : minimum size requirement (32x32) not met!");
		exit( ERROR );
	}


//SVE 05.06.2001	if ( !( fb_yuv && y_full && y_extra && u_extra && v_extra &&
//SVE 05.06.2001		u422 && v422 && u444 && v444 ) )
	if ( !( fb_yuv && y_extra && u_extra && v_extra))
	{
		fprintf( stderr, 
			"\nstore_avi_gdi() : could not allocate temp framebuffers!");
		exit( ERROR );
	}
	else
	{
		/* clear the framebuffers! */
		psize = ( psize +2 ) << 5;	// convert back to #bytes
		memset((LPVOID)fb_yuv,0,psize*4);
//SVE 05.06.2001		memset((LPVOID)y_full,0,psize );
		memset((LPVOID)y_extra,0,psize );
		memset((LPVOID)u_extra,128,psize );
		memset((LPVOID)v_extra,128,psize );
//SVE 05.06.2001		memset((LPVOID)u422,128,psize );
//SVE 05.06.2001		memset((LPVOID)v422,128,psize );
//SVE 05.06.2001		memset((LPVOID)u444,128,psize );
//SVE 05.06.2001	  	memset((LPVOID)v444,128,psize );
	}  /* endif */

	// v0.16B23, if (UserOptIDCT == _IDCT_MMX_AAN), disallow AVI-writing!
	if ( tgaflag != T_GDI )
	{
		if ( rstrcmpi( outname, ".avi" ) != 0 )
			strcat( outname, ".avi" );

		if ( GETOPT( UserOptIDCT ) == _IDCT_MMX_AAN )
		{
			fprintf( stderr, "\nCommandOption '-r%d' : You have chosen a fast (inaccurate) IDCT algorithm.",
				GETOPT( UserOptIDCT ) );
			fprintf( stderr, "\nAVI-writing is not permitted with low-precision IDCT.");
			fprintf( stderr, "\n(try '-r0', '-r1', or '-r2' instead!)\n");
			exit( ERROR );
		}
	}

	/* check chroma format if ( g_vHalfResFlag == TRUE )
	   currently we only support CHROMA420 for half-resolution mode */
	//if ( g_vHalfResFlag && chroma_format != CHROMA420 )
	//{
	//	fprintf( stderr, "\nstore.c - half-resolution requires color-format of input bitstream to be CHROMA420." );
	//	  Error("Color format incompatible");
	  //}

	/* load valid co-ordinates into Resized_Picture_Width/Height */
	// setup variables for DIB/AVI output routines 
	Resized_Picture_Width= g_vHalfResFlag ? (Coded_Picture_Width >> 1 ):
		Coded_Picture_Width;
	Resized_Picture_Height = g_vHalfResFlag ? (Coded_Picture_Height >> 1):
		Coded_Picture_Height;

	/* check if g_AVIcrop already has valid co-ordinates, if not set
	   them to current image-height/width...i.e. effectively disables cropping */
    /* m_OutputWidth, m_OutputHeight replace g_AVIcrop... */
	m_OutputWidth = Resized_Picture_Width;
	m_OutputHeight = Resized_Picture_Height;

	if ( CHECKOPT( UserOptCropX ) )
		m_OutputWidth = GETOPT( UserOptCropX );

	if ( CHECKOPT( UserOptCropY ) )
		m_OutputHeight = GETOPT( UserOptCropY );

	/* validate g_AVIcrop & Resized_Picture ... are parameters legal? */
	/* Make sure cropped sized is smaller than resized-image */
	if ( m_OutputWidth > Resized_Picture_Width || 
		m_OutputHeight > Resized_Picture_Height )
	{
		fprintf( stderr, "\nstore_avi_gdi() : Viewport dimensions (\"-1\" %ld X %ld)",
			m_OutputWidth , m_OutputHeight );
		fprintf( stderr, " exceed\n\tresized-output's dimensions (%ld X %ld) !",
			Resized_Picture_Width, Resized_Picture_Height );
		exit (ERROR );
	}

	/* v0.16B22, crop window must be divisible by 8 for MMX-crop functions! */

	if ( (m_OutputWidth & 0x07) || (m_OutputHeight & 0x03 ) )
	{
		fprintf( stderr, "\nstore_avi_gdi() : Viewport dimensions (\"-1\" %ld X %ld)",
			m_OutputWidth , m_OutputHeight );			
		fprintf( stderr, " are\n\tnot divisible by 8!" );
		exit( ERROR );
	}

	CropRect.top = ( Resized_Picture_Height - m_OutputHeight  ) >> 1;
	CropRect.bottom = Resized_Picture_Height - 
		(( Resized_Picture_Height - m_OutputHeight ) >> 1);
	CropRect.left = ( Resized_Picture_Width - m_OutputWidth ) >> 1;
	CropRect.right = Resized_Picture_Width -
		(( Resized_Picture_Width - m_OutputWidth ) >> 1 );


  	// create stream header text
    strcpy( szName, Version ); // Version = "mpeg2avi ..." 
	// v0.16B22, updated IDCT-type reporting
	switch( GETOPT( UserOptIDCT ) )
	{
		case _IDCT_INT32 :
			sprintf( szText, " {IDCT32INT} " ); // 32-bit integer
			break;
		case _IDCT_MMX32 :
			sprintf( szText, " {IDCT32MMX} " ); // 32-bit MMX
			break;
		case _IDCT_FPU64 :
			sprintf( szText, " {IDCT64FPU} " ); // 64-bit double float
			break;		
		case _IDCT_MMX_CHEN1 :
			sprintf( szText, " {IDCT16MMXChen} " ); // 16-bit MMX Chen
			break;
		case _IDCT_MMX_AAN :	// this output mode is no longer allowed
			sprintf( szText, " {IDCT16MMXAAN} " ); // 16-bit MMX AAN
			break;
		default :
			sprintf( szText, " {IDCT ???} " ); // unknown IDCT
	}
	strcat( szName, szText );
	sprintf( szText, "%s", g_fastfilter ? "'-q1'" : "'-q0'" );
	strcat( szName, szText );
	if ( CHECKOPT( UserOptIVTC ) ) // is IVTC in use?
	{
		sprintf( szText, ", -s%d IVTC(%d)", GETOPT( UserOptIVTC ), 
			GETOPTAUX( UserOptIVTC )  ); // extended IVTC config info 
		strcat( szName, szText );
	}

	if ( tgaflag != T_GDI )
	{
		// construct bitmapinfo
		bmih.biSize = sizeof(BITMAPINFOHEADER); 
		bmih.biWidth = m_OutputWidth;
		bmih.biHeight = m_OutputHeight;
		// some codecs *require* valid Height/Width params to avoid ICERR_BADFORMAT
		bmih.biPlanes = 1;			// must be 1
		//m_bmih.biSizeImage = 0;			// okay to be 0 for BI_RGB
		bmih.biXPelsPerMeter = bmih.biYPelsPerMeter = 0;
		bmih.biClrUsed = bmih.biClrImportant = 0;
		bmih.biSizeImage = bmih.biWidth * bmih.biHeight; 

		switch ( Output_Type )
		{
		case T_AVI_YV12 :
//			fUseYUV = TRUE;
			dwPixFormat = mmioFOURCC( 'Y','V','1','2');
			bmih.biBitCount = 12;
			bmih.biSizeImage = ( bmih.biSizeImage * 3 ) >> 1;
			break;
		case T_AVI_YUY2 :
//			fUseYUV = TRUE;
			dwPixFormat = mmioFOURCC( 'Y','U','Y','2');
			bmih.biBitCount = 16;
			bmih.biSizeImage = ( bmih.biSizeImage ) << 1;
			break;
		default :
			dwPixFormat = BI_RGB;
			bmih.biBitCount = 24;
			bmih.biSizeImage = ( bmih.biSizeImage * 3 );
//			fUseYUV = FALSE;
		} /* endswitch ( Output_Type ) */

		bmih.biCompression = dwPixFormat;	// standard RGB bitmap
		g_bmi.bmiHeader = bmih;

//PX3		__asm emms;	// 0.16B22, to deal with MMX

		avi_fileopen( outname, szName, &CropRect, g_bmi, UserOptAVIrate, 
			UserOptAVISplitLength, TRUE );
		// the TRUE requests a codec-selection dialog-box
	}

	m_cbSkipFrame = 0;

//SVE 20.05.2001 Neue Variablen initialisieren
	rpw=cpw=Coded_Picture_Width;
	rph=cph=Coded_Picture_Height;
	if(CHECKOPT(UserOptResizeX)) rpw = UserOptResizeX.data;
	if(CHECKOPT(UserOptResizeY)) rph = UserOptResizeY.data;
	y1 = (unsigned char *)malloc(cpw * cph);
	u1 = (unsigned char *)malloc(cpw * cph);
	v1 = (unsigned char *)malloc(cpw * cph);
	y2 = (unsigned char *)malloc(cpw * cph);
	u2 = (unsigned char *)malloc(cpw * cph);
	v2 = (unsigned char *)malloc(cpw * cph);
	// Merker, ob in CHROMA444 konvertiert werden muß
	bConvert=((m_iDeinterlace && m_iDeinterlace!=3) || m_iSharpen>3);
//SVE ENDE

  } /* endif ---- if ( first_iteration ) */


  // Added if by PX3 .. no need for keycheck if we're in
  // AVI-Output.. 
//SVE 05.06.2001  if ( tgaflag == T_GDI )
//SVE 05.06.2001  {
//SVE 05.06.2001	process_filter_cmd( );  /* process commands to filter routines */
//SVE 05.06.2001	process_resize_cmd( );  /* process commands to resize routines */
//SVE 05.06.2001  }
	
  /* check UserOptFRangeStart & UserOptFRangeEnd */

  /* gethdr.c skips B-frames, but we still need to skip I/P frame processing
     we can't simply skip I/P frames entirely, because we might start
	 displaying on a B-frame which depends on previous I/P frames! */
  /* the inequalities imply that <a> ... <b> are INCLUDED in the range! */
  if ( CHECKOPT( UserOptFRangeStart ) )
  {
	  if ( GETOPT( UserOptFRangeStart ) >= g_cbMPEGPicture)
	  {
		  return;
	  }
  }

  if ( CHECKOPT( UserOptFRangeEnd ) )
  {
     if ( g_cbMPEGPicture > GETOPT( UserOptFRangeEnd ) )
	 {
		 printf("\r< FRangeEnd > = MPEG-FrameCount (%ld)>", g_cbMPEGPicture );
		 g_cmd_buttonStop = TRUE;  /* stop after current frame */
	 }
  }

  y_ptr = src[0];
  u_ptr = src[1];
  v_ptr = src[2];

//  if ( !g_vHalfResFlag ) /* no 1/2 downsampling, FULL resolution */
//  {
	//y_ptr = ivtc_full_8bpp( src[ 0 ], g_FrameCount );
  
    y_ptr = ivtc_full_8bpp( src[ 0 ], g_cbMPEGPicture );


//SVE 20.05.2001 Filter verarbeitem
	bKeyFrame=FALSE;
//	lAkt=g_cbMPEGPicture-1;

	yin=y_ptr;
	uin=u_ptr;
	vin=v_ptr;

	// Wenns sein muß, konvertieren
	if(bConvert)
	{
		// Umsetzen nach CHROMA444
		switch(chroma_format)
		{
		case CHROMA420:
//SVE 04.06.2001 Beim "normalen" Deinterlacen reicht jede 2.Zeile
			memcpy(y1,y_ptr,cpw*cph);
			if(m_iDeinterlace==1)
				SVEfast420to422(u_ptr,v_ptr,u2,v2, cpw, cph);
			else
				SVEconv420to422(u_ptr,v_ptr,u2,v2, cpw, cph);
			SVEconv422to444(u2,v2,u1,v1, cpw, cph);
			yin=y1;
			uin=u1;
			vin=v1;
			break;
		case CHROMA422:
			memcpy(y1,y_ptr,cpw*cph);
			SVEconv422to444(u_ptr,v_ptr,u1,v1, cpw, cph);
			yin=y1;
			uin=u1;
			vin=v1;
			break;
		case CHROMA444:
			memcpy(y1,y_ptr,cpw*cph);
			memcpy(u1,u_ptr,cpw*cph);
			memcpy(v1,v_ptr,cpw*cph);
			yin=y1;
			uin=u1;
			vin=v1;
			break;
		}
		dwCF=CHROMA444;
	}
	else
	{
		if(m_iDeinterlace)
		{
			memcpy(y1,y_ptr,cpw*cph);
			yin=y1;
		}
		else yin=y_ptr;
		uin=u_ptr;
		vin=v_ptr;
		dwCF=chroma_format;
	}

	switch(m_iDeinterlace)
	{
	case 1:	// Deinterlacer 1 -> Normaler Deinterlacer
		SVEdeinterlace1(yin,uin,vin,cpw,cph);
		break;
	case 2:	// Deinterlacer 2 -> Motion-based Deinterlacer
		SVEdeinterlace2(yin,uin,vin,cpw,cph);
		break;
	case 3: // Deinterlacer 3 -> Schneller Deinterlacer
		SVEdeinterlace3(yin,cpw,cph);
		break;
	}

	// Resizen ?
	if (cpw!=rpw || cph!=rph)
	{
		yout=(yin==y1)?y2:y1;
		uout=(uin==u1)?u2:u1;
		vout=(vin==v1)?v2:v1;
		dstRect.top = 0;
		dstRect.left = 0;
		dstRect.right = rpw;
		dstRect.bottom = rph;
		shrink_frame( yout, uout, vout, yin, uin, vin, &srcRect, &dstRect, dwCF);
		yin=yout;
		uin=uout;
		vin=vout;
	}

	switch(m_iSharpen)
	{
	case 1:	// 1 - 3 Schärfen des Y-Layers
	case 2:
	case 3:
		yout=(yin==y1)?y2:y1;
		SVEsharpen(m_iSharpen,yin,NULL,NULL,yout,NULL,NULL,cpw,cph,rpw,rph);
		yin=yout;
		break;
	case 4:	// 4 - 6 Schärfen aller Layer
	case 5:
	case 6:
		yout=(yin==y1)?y2:y1;
		uout=(uin==u1)?u2:u1;
		vout=(vin==v1)?v2:v1;
		SVEsharpen(m_iSharpen,yin,uin,vin,yout,uout,vout,cpw,cph,rpw,rph);
		yin=yout;
		uin=uout;
		vin=vout;
		break;
	}

	// Umsetzen ins benötigte Chroma-Format
	switch(tgaflag)
	{
	case T_AVI_YV12:	// Benötigt wird CHROMA420
		switch(dwCF)
		{
		case CHROMA444:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEfast444to420(uin,vin,uout,vout, cpw, cph);
			uin=uout;
			vin=vout;
			break;
		case CHROMA422:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEconv422to420(uin,vin,uout,vout, cpw, cph);
			uin=uout;
			vin=vout;
			break;
		}
		break;
	case T_AVI_YUY2:	// Benötigt wird CHROMA422
		switch(dwCF)
		{
		case CHROMA444:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEconv444to422(uin,vin,uout,vout, cpw, cph);
			uin=uout;
			vin=vout;
			break;
		case CHROMA420:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEconv420to422(uin,vin,uout,vout, cpw, cph);
			uin=uout;
			vin=vout;
			break;
		}
		break;
	default:	// Benötigt wird CHROMA444
		switch(dwCF)
		{
		case CHROMA422:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEconv422to444(uin,vin,uout,vout, cpw, cph);
			uin=uout;
			vin=vout;
			break;
		case CHROMA420:
			uout=(uin==u1)?u2:u1;
			vout=(vin==v1)?v2:v1;
			SVEconv420to422(uin,vin,uout,vout, cpw, cph);
			SVEconv422to444(uout,vout,uin,vin, cpw, cph);
			break;
		}
		break;
	}

//SVE 05.06.2001
//SVE 05.06.2001	/* Resize the output image */
//SVE 05.06.2001	if ( y_ptr != NULL )  /* did ivtc delete current frame? */
//SVE 05.06.2001	{ /* current frame wasn't deleted, resize the output! */
//SVE 05.06.2001		if ( CHECKOPT( UserOptResizeX ) || CHECKOPT( UserOptResizeY ) )
//SVE 05.06.2001		{
//SVE 05.06.2001			dstRect.top = 0;
//SVE 05.06.2001			dstRect.left = 0;
//SVE 05.06.2001			dstRect.right = CHECKOPT( UserOptResizeX ) ? UserOptResizeX.data :
//SVE 05.06.2001				srcRect.right;
//SVE 05.06.2001			dstRect.bottom = CHECKOPT( UserOptResizeY ) ? UserOptResizeY.data :
//SVE 05.06.2001				srcRect.bottom;
//SVE 05.06.2001
//SVE 05.06.2001			shrink_frame( y_extra, u_extra, v_extra, y_ptr, u_ptr, v_ptr,
//SVE 05.06.2001			&srcRect, &dstRect, chroma_format);
//SVE 05.06.2001
//SVE 05.06.2001
//SVE 05.06.2001			  /* don't forget that RGB24 requires CHROMA444 to function */
//SVE 05.06.2001
//SVE 05.06.2001			y_ptr = y_extra;
//SVE 05.06.2001			u_ptr = u_extra;
//SVE 05.06.2001			v_ptr = v_extra;
//SVE 05.06.2001		}
//SVE 05.06.2001	} /* endif ( y_ptr != NULL ) */
//SVE 05.06.2001
//SVE 05.06.2001	/* at this point, the framebuffer y_ptr, u_ptr, v_ptr holds a resized
//SVE 05.06.2001	   bitmap, whose format == chroma_format (specified by MPEG-bistream) */
//SVE 05.06.2001
//SVE 05.06.2001  if ( y_ptr != NULL )  /* did ivtc delete current frame? */
//SVE 05.06.2001  { /* current frame wasn't deleted, convert ouput format */
//SVE 05.06.2001
//SVE 05.06.2001	/* Should we skip this frame? */
//SVE 05.06.2001	if (  CHECKOPT( UserOptAVISkipEvery ) )
//SVE 05.06.2001	{
//SVE 05.06.2001	  if ( m_cbSkipFrame >= GETOPT( UserOptAVISkipEvery ) )
//SVE 05.06.2001	  {  /* don't write this frame, skip it! */
//SVE 05.06.2001		  m_cbSkipFrame = 0;
//SVE 05.06.2001		  printf( "skipping! ('-!')                              " );
//SVE 05.06.2001		  y_ptr = NULL;
//SVE 05.06.2001		  return;
//SVE 05.06.2001	  }
//SVE 05.06.2001	  else
//SVE 05.06.2001		  ++m_cbSkipFrame;	// don't skip current, so increment skip-counter
//SVE 05.06.2001	}
//SVE 05.06.2001
//SVE 05.06.2001	convBlock.srcRect = srcRect;
//SVE 05.06.2001	// convBlock.destRect = not used
//SVE 05.06.2001	convBlock.dwSrcFormat = chroma_format;
//SVE 05.06.2001
//SVE 05.06.2001	switch ( tgaflag )
//SVE 05.06.2001	{
//SVE 05.06.2001		case T_AVI_YV12 :
//SVE 05.06.2001			convBlock.dwDstFormat = CHROMA420;
//SVE 05.06.2001			break;
//SVE 05.06.2001		case T_AVI_YUY2 :
//SVE 05.06.2001			convBlock.dwDstFormat = CHROMA422;
//SVE 05.06.2001			break;
//SVE 05.06.2001		default : /* RGb24 */
//SVE 05.06.2001			convBlock.dwDstFormat = CHROMA444;
//SVE 05.06.2001			break;
//SVE 05.06.2001	} /* endswitch */
//SVE 05.06.2001		
//SVE 05.06.2001	/* specify input buffers */
//SVE 05.06.2001	convBlock.src1 = y_ptr;
//SVE 05.06.2001	convBlock.src2 = u_ptr;
//SVE 05.06.2001	convBlock.src3 = v_ptr;
//SVE 05.06.2001	/* supply allocated buffer space for operation output*/
//SVE 05.06.2001	convBlock.dst1 = y_full;
//SVE 05.06.2001	convBlock.dst2 = u444;
//SVE 05.06.2001	convBlock.dst3 = v444;
//SVE 05.06.2001		
//SVE 05.06.2001	yuv2yuv( &convBlock );	// convert YUV(input) -> YUV(output)
//SVE 05.06.2001	// input = MPEG-coded chroma format, always PLANAR
//SVE 05.06.2001	// output= user selected output-mode, still PLANAR
//SVE 05.06.2001	//
//SVE 05.06.2001	// USER's CHOICE   | yuv2yuv() operation
//SVE 05.06.2001	// -------------     -------------------
//SVE 05.06.2001	//   "YV12"        =  output YUV420
//SVE 05.06.2001	//   "YUY2"        =  output YUV422
//SVE 05.06.2001	//   "RGB24"       =  output YUV444
//SVE 05.06.2001		
//SVE 05.06.2001	y_ptr = convBlock.outdst1; // get new y_ptr[]
//SVE 05.06.2001	u_ptr = convBlock.outdst2; // get new u_ptr[]
//SVE 05.06.2001	v_ptr = convBlock.outdst3; // get new v_ptr[]
//SVE 05.06.2001
//SVE 05.06.2001	/* v0.16B2 print MPEG-frame code and GOP time codes, if requested */
//SVE 05.06.2001	// note, under certain circumstances, the vtitler causes
//SVE 05.06.2001	// visual 'side-effects.'  If y_ptr is a pointer to the *ORIGINAL* 
//SVE 05.06.2001	// y_buffer, then vtitler() will actually modify the MPEG-decoder's
//SVE 05.06.2001	// internal framebuffer state.  If the current-frame happens to be
//SVE 05.06.2001	// an I/P frame, the watermarked-video is "carried forward" to
//SVE 05.06.2001	// all dependent frames.  In essence, vtitler() can soil the video.
//SVE 05.06.2001		
//SVE 05.06.2001	// This only happens if the user plays the video without any
//SVE 05.06.2001	// modification (resizing, 1/2 resolution)
//SVE 05.06.2001	if ( CHECKOPT( UserOptPrintFrameCode ) )
//SVE 05.06.2001	{
//SVE 05.06.2001		// calculcate left-justification (in #chars) for titler
//SVE 05.06.2001		dwXpos = ( CropRect.left >> 2 ) + 1; 
//SVE 05.06.2001		dwYpos = ( CropRect.top >> 3 );
//SVE 05.06.2001
//SVE 05.06.2001		// print decoded MPEG frame# on 1st line
//SVE 05.06.2001		vt_printnum( (LPDWORD) y_ptr, g_cbMPEGPicture, dwXpos, dwYpos+1,
//SVE 05.06.2001			( Resized_Picture_Width >>2 ) );
//SVE 05.06.2001
//SVE 05.06.2001		// print GOP timecode on 2nd line, last char indicates "I" frame
//SVE 05.06.2001		sprintf( szText, "%d:%02d:%02d:%02d%s%s",g_dtimecode.hour, 
//SVE 05.06.2001			g_dtimecode.minute, g_dtimecode.second, g_dtimecode.frame,
//SVE 05.06.2001			g_mpvpcur.pty == I_TYPE ? "I" : "",
//SVE 05.06.2001			drop_flag ? "DROP":""  );
//SVE 05.06.2001		vt_printstr( (LPDWORD) y_ptr, szText, dwXpos, dwYpos+2, 
//SVE 05.06.2001			(Resized_Picture_Width>>2) );
//SVE 05.06.2001
//SVE 05.06.2001		// print picture temporal reference on 3rd line
//SVE 05.06.2001		vt_printnum( (LPDWORD) y_ptr, g_mpvpcur.tref, dwXpos, dwYpos+3, 
//SVE 05.06.2001			(Resized_Picture_Width>>2) );
//SVE 05.06.2001
//SVE 05.06.2001		// the one-frame delay mechanism accounts for the temporal
//SVE 05.06.2001		// difference between the demuxer and MPEG-decoder states.
//SVE 05.06.2001		if ( g_vobflag )
//SVE 05.06.2001			vt_printnum( (LPDWORD) y_ptr, g_dwLBApack, dwXpos, dwYpos+4,
//SVE 05.06.2001				( Resized_Picture_Width >>2 ) );
//SVE 05.06.2001		//m_dwSystemPackLBAlast = g_dwSystemPackLBA;
//SVE 05.06.2001	} // endif ( CHECKOPT( UserOptPrintFrameCode ) )

	/* prepare convBlock structure for yplanar2fb() function */

	// specify input buffers 
//SVE 05.06.2001	convBlock.src1 = y_ptr;
//SVE 05.06.2001	convBlock.src2 = u_ptr;
//SVE 05.06.2001	convBlock.src3 = v_ptr;

	convBlock.src1 = yin;
	convBlock.src2 = uin;
	convBlock.src3 = vin;

	// supply allocated buffer space for operation output
	convBlock.dst1 = fb_yuv;
	convBlock.dst2 = NULL;
	convBlock.dst3 = NULL;

	convBlock.srcRect.left = CropRect.left; // specify top-left corner (src)
	convBlock.srcRect.top = CropRect.top;	// of viewport window

	convBlock.srcRect.right = Resized_Picture_Width; // src bitmap
	convBlock.srcRect.bottom = Resized_Picture_Height;	// dimensions

	convBlock.dstRect.right = m_OutputWidth; // specify viewport
	convBlock.dstRect.bottom = m_OutputHeight;	// dimensions

	/////////////////////////////////////////////////////////////////
	// Color-format conversion functions,
	// convert planar YUV to a single contiguous output-bitmap YUV
	//
	// planar :                  one_bitmap
	//   y_ptr[]                 
	//   u_ptr[] -> yuv2yuv.c -> fb_yuv[]
	//   v_ptr[]
	///////////////////////////////////////////////////////////////////

	switch ( tgaflag )
	{
	  case T_AVI_YV12 : /* convert YUV420 planar -> "YV12" planar 12bpp */
		yuv420toyv12( &convBlock );
		break;

	  case T_AVI_YUY2 : /* convert YUV422 planar -> "YUY2" packed 16bpp */
		yuv422toyuy2( &convBlock );
		break;

	  default: /* RGB24 */
		/* starting with version 0.16B22, the default case does not
		   perform any action.  yuv2rgb24() has been modified to
		   operate directly on the planar data y_ptr[], u_ptr[], v_ptr[].
		   This eliminates an wasteful repacking to 24bpp.  */

		/* (used to convert & crop YUV4:4:4 planar to YUV 24bpp packed pixel */
		/* note we do *NOT* perform color-space conversion just yet! */
		/* framebuffer[] = YUV 24bpp packed pixel image */
		/* invert image at the same time ) */
		 ;
		/* integer crop code no longer in use, has been combined with the
		   y444torgb24() function 
		for (j=0; j<m_OutputHeight ; j++)
		{
			for (i=0; i<m_OutputWidth ; i++)
			{
				y_src_addr = (j+CropRect.top)*Resized_Picture_Width +
					(i+CropRect.left);
				// the "-1" is necessary for proper alignment
				dest_addr = ( m_OutputHeight - j -1 ) * m_OutputWidth + i;
				*( fb_yuv + 3*dest_addr + 0 ) = *(y_ptr + y_src_addr );
				*( fb_yuv + 3*dest_addr + 1 ) = *(u_ptr + y_src_addr );
				*( fb_yuv + 3*dest_addr + 2 ) = *(v_ptr + y_src_addr );
			}
		}  // endfor 
		*/
	} // endswitch ( tgaflag )

	/////////////////////////////////////////////////////////////////
	// Final output stage
	// Perform 1 of 2 actions :
	//  1) display to WinGDI ( tgaflag == T_GDI)
	//
	//      or
	//
	//  2) write to AVI file (tgaflag != T_GDI)
	///////////////////////////////////////////////////////////////////

	if ( tgaflag == T_GDI )
	{
		yuv444torgb24( &convBlock ); // convert color y444 -> RGB24
		// display current frame to WinGDI
		display_dib( fb_yuv, &CropRect, g_cbMPEGPicture ); 
	}
	else if ( tgaflag == T_AVI || tgaflag == T_AVI_YV12 || tgaflag==T_AVI_YUY2 )
	{
		
		if ( tgaflag == T_AVI ) // RGB24 mode?
			yuv444torgb24( &convBlock ); // convert color y444 -> RGB24

		// emms resets FPU-stack state (necessary due to use of MMX 
//PX3		__asm emms; // emms *MUST* be called prior to calling avi-function
		// REMOVED BY PX3 .. no need to call it here
		// all asm routines had been fixed an call emms after 
		// function executed
		
		// store current frame to AVI writer
//SVE 20.05.2001 Neuer Parameter: Erzwungener Keyframe
//		store_avi_one( outname, fb_yuv, &CropRect, g_cbMPEGPicture ); 
		store_avi_one( outname, fb_yuv, &CropRect, g_cbMPEGPicture,bKeyFrame); 
//SVE ENDE


	} // end if ( tgaflag == T_GDI )

//SVE 05.06.2001  } // endif - if ( y_ptr != NULL ) 
  y_ptr = NULL;
}
/*
static void putbyte(c)
int c;
{
  *optr++ = c;

  if (optr == obfr+OBFRSIZE)
  {
    _write(outfile,obfr,OBFRSIZE);
    optr = obfr;
  }
}

static void putword(w)
int w;
{
  putbyte(w); putbyte(w>>8);
}

*/
