
/* mpeg2dec.c, main(), initialization, option processing                    */

/* 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 REVISION HISTORY
 * -------------------------
 *   0.16B35 increased memory padding on calloc() calls
 *      allow IVTC to be initialized to ODD polarity.
 *      -s0 through -s4 are even polarity, -s5 through -s9 are odd
 *      the ivtc routine converts s5-s9 back to s0-s4
 *   0.16B34 declared unsigned char g_scan[2][64], which the MPEG-decoder uses
 *      to scan macroblock coefficiens.  g_scan[] is initialized during
 *      run-time, so the decoder can run with both transposing and 
 *      non-transposing iDCT functions efficiently.
 *      fixed bug with default iDCT mode : now it really is _IDCT_MMX32 (doh!)
 *      converted malloc() calls to calloc() calls
 *      removed int32_idct entirely
 *   0.16B33 more mmx optimization to downsizer, restructuring of vresizer.c
 *      all motino-compensation PEL cases use aligned reads (recon.c)
 *      modified MMX AAN IDCT - transpose is now integrated
 *      Chen MMX IDCT hand-scheduled for better performance on Pentium/MMX
 *      replaced INT32-iDCT ('-r1') with MXM32-IDCT (IEEE-1180 compliant)
 *       (note, due to my error, 0.16B33 defaults to INT32-iDCT!)
 *      removed the demux_queue from MPEG2AVI
 *      changed INT32 iDCT to ('-r4'), still available to user
 *   0.16B32 mmx optimizations to the resizers CHROMA420 Y-downsizers.  
 *      Scaling in the Y-direction should not be somewhat faster.  The resizer
 *      now imposes a minimum source/destination pixel-size of 32, to make
 *      sure the internal scaling coefficients fit inside a 15-bit magnitude.
 *   0.16B31 resizer functions shrink() [vresizer.c] minor optimization
 *      force user to specify '-f' option, to fix AVI-encoding problems with
 *      coded interlaced sequences (no repeat-first field),
 *      some further optimizations to recon.c (read alignment for reads)
 *  10/15/99
 *   0.16B3  changed default for UserOptVOBStartLBA to 0, to always engage
 *      seek mode
 *      made the printed-information from '-*' more accurate, hopefully
 *       frame-accurate
 *      replaced getchar(), _getch() calls with scanf().
 *      encapsulated the streamlist feature into a C++ object cStreamlist
 *  10/10/99
 *   0.16B24 added my_open(), my_read(), and my_close() to mpv_read.cpp
 *      all low-level IO accesses are routed through the my_xxx() functions
 *      this allows continuous-stream reading
 *
 *  10/08/99
 *   0.16B23 more MMX-optimizations (DWORD aligned -> Add_Block() getpic.c)
 *          MMX color-space conversion (very slightly less accurate than int)
 *          moved yuv444torgb24() to new file, yuv2rgb.c
 *          moved yuv(planar) -> yuv(packed) to yuv2yuv.c
 *           (these functions were integrated into a switch() in store.c )
 *          store.c - prevent user from writing-AVI with _IDCT_MMX_AAN 

 *  10/6/99
 *   0.16B22 MMX optimizations, added test_cpu() function to test for MMX.
 *          recon.c is fully MMX-optimized (all motion-compensation cases
 *          run MMX asm code.  Not necessarily the most efficient code...)
 *          getpic.c 's Add_Block() and Clear_Block() are MMX-optimized
 *          most frequently used fast-filters (downsample_half(), yuv2yuv)
 *           are MMX-optimized
 *          changed default filter-mode to '-q1' (fast-filter), since most
 *           fast-filters are MMX-optimized
 *          Initialize all IDCT algorithms
 *          changed meaning of '-r', now user chooses IDCT-function with
 *           '-r<n>', where <n> is chosen from a table (in global.h)
 *           If the table is modified, store.c and mpeg2dec.c must be changed

 *
 *   0.16B2 added UserOptPrintFrameCode, prints <MPEG frame#> in upper-left 
 *          corner of the output frame.  option '-*' for video watermarking
 *          '-@ <lba>' VOB LBA seek, target must be SYSTEM HEADER packet!
 *          enhanced input option '-b' with '-b filename [stream_id]',
 *           [stream_id] = optional StreamID (hex) parameter
 *          example '-b input.vob 0xE1'
 *          BBDMUX has been upgraded to v1.2 and converted to C++ (cDemuxer)
 *  09/20/99
 *   0.16B1 moved the AVI-backend to C++,
 *          added '-$ <MB>' UserOptAVISplitLength to support auto AVI-splitting
 *          added '-! <n>' UserOptAVISkipEvery to drop 1 MPEG-frame per <n> 
 *            MPEG-frames, the frame-drop is done at the last possible second
 *            (to not disturb IVTC)
 *      
 *  09/14/99
 *   0.15B51(finally) fixed AVI-YUV modes and video-codec setup, see
 *          storeavi.c for details
 *          also removed "2X pixel-granularity" restrictions on shrink420()
 *          and shrink422() functions.  The restriction was totally 
 *          unnecessary, due to a mathematical misperception on my part.
 *          Added -# option for frame-start/end points,
 *          g_cmd_buttonStop, g_cbMPEGPicture (gethdr.c) vars added
 *           -# is implemented in two places, gethdr.c and store.c
 *           the FRangeStart is implemented in gethdr.c

 *  09/11/99
 *   0.15ß5 restructured the AVI/GDI output dataflow.  Now, the output images
 *          are resized, then (optionally) halved, and finally converted to
 *          the final image format.
 *          | MPEG decoder | -> | resizer | -> | half-res | -> | Crop & CSC |
 *               store.c     ->  shrink_frame()-> yuv2yuv() ->  | yuv2rgb24()
 *          added YUY2 output mode
 *          
 *  09/04/99  
 *   0.15ß4 corrected bug with fast-filter (-q1) when decoding MPEG-1 video
 *          reduced #references to  global variables in vidfilt.c, vresizer.c
 *          +converted g_AVIcrop -> UserOptCrop
 *
 *  08/15/99  v0.15ß3
 *   0.15ß3 further performance tweaks to resizer.c, vidfilt.c
 *          +auto-disable IVTC feature (gethdr.c, telecine.c)
 *          +converted g_ivtc_start_state -> struct UserOptIVTC
 *   0.15ß2 moved resizer functions shrink888() to vresize.c, added
 *          shrink888xy() for faster downsampling when both X/Y are adjusted.
 *
 *   0.15ß added fast/Hi-Q filter control '-q<n>', fast-upscaling for YUV420->YUV444
 *        deafult is Hi-Q filter ( -q0 )
 *        changed all references from open()/close()/write() to 
 *        _open(), _write(), _close()
 *        (low-pass) downsampling filter for half-resolution mode
 *        new file : vidfilt.c (upsample/downsample filters moved here)
 *        created new type ( struct tUserOption ) to manage/transport user options
 *		  between the main-parser (mpeg2dec.c) and decoder/output routines.
 *        (see useropt.h)
 *
 *  08/11/99  v0.14
 *   0.14 added 1/2-resolution support and cropping to output modes -o6, -o7
 *        added necessary variables g_AVIcropX, g_AVIcropY, g_vHalfResFlag
 *              Resized_Picture_Width, Resized_Picture_Height
 *        removed automatic "-r" (FP-IDCT) with "-o7" usage
 *        tweaked ivtc algorithms, fixed "color bleed" problem in full
 *        resolution mode.
 *
 *  08/09/99  v0.13
 *   0.13 preliminary support for VOB files using BBDMUX,
 *        abort key 'Q' to terminate AVI encoding (while preserving AVI file)
 *        BBDMUX is the work of Brent Beyeler (http://members.home.net/beyeler)
 *
 *  08/06/99  v0.12
 *   0.12 user-selected frame-rate code
 *   0.11 corrected AVI [uncompressed] write mode, incorrect header size 
 *   0.10 first public release
 *  modifications by Royce Shih-Wea Liao (liaor@iname.com) 
 *
 ***************************************************************
 *  mpeg2dec.c (modified)
 *		added option to display images (as 24bpp RGB) to Windows GDI
 *		added option to perform inverse-telecine (inverse 3:2 pulldown)
 *  
 *  aviwrite.c (C++ object)
 *      starting with v0.16B1, the AVI-writer is now encapsulated as a C++ 
 *      object.  There is an additional file "aviinit.c" that acts like
 *      "glue logic", to stitch store_avi_gdi() [store.c] to the C++
 *      object.  Not very elegant, but simplifies future updates to
 *      the AVIwriter.
 *
 *  windisp.c (new file)
 *		draw_dib() routine
 *      implements -o6
 *
 *  telecine.c (new file)
 *		inverse_telecine() routine
 *      ivtc_full_8bpp()
 *      ivtc_half_8bpp()
 *      get_ivtc_cmd()
 *
 *  store.c (modified)
 *      rstrcmpi()
 *      store_avi_gdi() -  handles -o6 and -o7 functions
 *      supports inverse_telecine() for -o6 and -o7 only!
 *
 *  storeavi.c (new file)
 *      implements -o7
 *
 *  useropt.h (new file)
 *		implements <struct tUserOption>
 *      this structure encapsulates "UserOptions", i.e. command-line parameters
 *      It's gradual phase-in will hopefully limit the # "free floating" global 
 *      variables
 *		CLEAROPT( tUserOption );  // quick-macro : clears tUserOption
 *		if ( CHECKOPT( tUserOption ) ) // quick-macro 
 *
 *
 *  vidfilt.c (new file)
 *      all u420to422, u422to444, u444to422, u422to420, 
 *      The command-var (g_cmd_filter)
 *      is processed in here.  Color-space convertors are stored here 
 *      as well.
 *
 *  vresizer.c (new file )   aspect-ratio (downsizing) functions 
 *      shrink888x(), shrink888y(), shrink888xy() 
 *      downsample_half(), half420to420()
 *
 *  vtitler.c (new file)  print text onto the video (very primitive, #s only)
 *
 *  yuv2yuv.c (new file) convert MPEG-format planar pixel format (420/422/444)
 *      to a different format (420/422/444.)  Any input-type can be convertrd
 *      to any output-type.  Additionaly, "half-resolution" option auto
 *      downsamples the input in an optimal manner (both performance-wise and
 *      quality-wise.)
 *
 *  demuxbuf.cpp - a C++ queue that sits between the cDemuxer [bbdmux12.h]
 *      and s_read.c [ fread() emulator for MPEG2Decoder ]
 *  bbdmux12.cpp, bbdbits.cpp (.h), demuxbuf.cpp (.h), s_read.cpp
 *      together, these files implement stream-demuxing through BBDMUX
 *      MPEG-2 video (stream 0xE0 only) can be extracted from VOB files
 *      s_read.cpp is a "wrapper" for getbits.c's ( _read() )
 *      demuxbuf.cpp is a C++ class-definition which implements a queue
 *      to connect BBDMUX's mpeg2_demux() and MPEG2V12's _read() 
 *  idct_aan.c, idctchen.c
 *      16-bit MMX implementations of the IDCT operation.  Neither MMX IDCT
 *      is IEEE-1180 compliant.
 */

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

#define GLOBAL
#include "config.h"
#include "global.h"
#include "asm.h"
#include <math.h>

#include <windows.h>

//SVE TEST
#include "process.h"
void  __cdecl
DispThread( void *lpArgs );


#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.)


// v0.16B24, these functions are located in mpv_read.cpp
// they are manually declared in this file, as extern, because the
// functions are located in a C++ file.  I cannot include the
// function definition in the global.h file because the global.h
// is used by both the C++ files and C files.  The linker becomes
// confused and thinks mpv_open(), mpv_close() are C++ functions 
extern int mpv_open( const char *filename, int oflag, const char* outDir);
extern int mpv_close( int handle );
//extern long mpv_lseek( int handle, long offset, int origin );


/* private function prototypes, and private variables */
static int  video_sequence _ANSI_ARGS_((int *framenum));
static int Decode_Bitstream _ANSI_ARGS_((void));
static int  Headers _ANSI_ARGS_((void));
static void Initialize_Sequence _ANSI_ARGS_((void));
static void Initialize_Decoder _ANSI_ARGS_((void));
static void Deinitialize_Sequence _ANSI_ARGS_((void));
//PX3 static void Process_Options _ANSI_ARGS_((int argc, char *argv[]));
	// test CPU for MMX-capability
static void test_cpu( BOOL *p_fMMX, BOOL *p_f3DNOW );	
	// v0.16b34 initialize scan order matrix g_scan[2][64]
static void init_scan_matrix( int type );

// for init_scan_matrix()
#define SCAN_ORDER_TRANSPOSE 1
#define SCAN_ORDER_NORMAL    0

#if OLD
static int  Get_Val _ANSI_ARGS_((char *argv[]));
#endif

/* #define DEBUG */

static void Clear_Options();
#ifdef DEBUG
static void Print_Options();
#endif 



BOOL m_fMMX , m_f3DNOW; /* flags for CPU capabilities */


void InitEngine( void )
{
	DWORD dwrc = 0; /* dword return code */

	m_fMMX = FALSE;
	m_f3DNOW = FALSE; /* flags for CPU capabilities */
	
	Clear_Options();

	/* 0.16B22 check for MMX capability */
	test_cpu( &m_fMMX, &m_f3DNOW );

	if ( m_fMMX == FALSE )
	{
		fprintf( stderr, "\nmain() : Your CPU does *NOT* support MMX instructions!");
		fprintf( stderr, "\n\tThis version of <%s> requires MMX support!", Version );
		exit( ERROR );
	}
}


/* Main entry point for encoding via lib */
int EncodeMpeg2Avi( void )
{

	int ret, code;


	/* v0.16B31 enforce '-f' */
	if ( !Frame_Store_Flag )
	{
		fprintf( stderr, "\nFrame_Store_Flag is not specified." );
		fprintf( stderr, "\nYou must include '-f' in your command line!" );
		exit( ERROR );
	}
	
	// the input file is a streamlist, automatically engage BBDMUX
	
	if ( rstrcmpi( Main_Bitstream_Filename, ".vob" ) == 0 ||
		rstrcmpi( Main_Bitstream_Filename, ".lst" ) == 0  )
		g_vobflag = 1; /* DVD vob file, use BBDMUX */
	else
		g_vobflag = 0; /* M2V file, don't use BBDMUX */
	
	
	ld = &base; /* select base layer context */
	
	/* open MPEG base layer bitstream file(s) */
	/* NOTE: this is either a base layer stream or a spatial enhancement stream */
	
	/* if g_vobflag is set, then the routines in s_read.cpp will automatically
	"connect" to BBDMUX, and BBDMUX will perform an fopen() on the filename */
	
	//  if ( !g_vobflag )
	//  {  
    if ((base.bs_Infile=mpv_open(Main_Bitstream_Filename,O_RDONLY|O_BINARY, Output_Directory))<0)
	{
		fprintf(stderr,"\nBase layer input file '%s' not found", Main_Bitstream_Filename);
		exit(1);
	}
	
	//  if ( g_vobflag )
	if ( !g_vobflag )
	{
	/*	  printf("\nUsing BBDMUX to decode bitstream 0xE0 from %s", 
		  Main_Bitstream_Filename );
		  
			if ( Frame_Store_Flag == 0 )
			{
			fprintf(stderr,"Warning : -f option was not specified!");
			fprintf(stderr,"\n        (Post-processing functions may fail!)");
			}
	}*/
		
		
		if(base.bs_Infile != 0)
		{
			Initialize_Buffer(); 
			
			if(Show_Bits(8)==0x47)
			{
				sprintf(Error_Text,"Decoder currently does not parse transport streams\n");
				Error(Error_Text);
			}
			
			next_start_code();
			code = Show_Bits(32);
			
			switch(code)
			{
			case SEQUENCE_HEADER_CODE:
				break;
			case PACK_START_CODE:
				System_Stream_Flag = 1;
			case VIDEO_ELEMENTARY_STREAM:
				System_Stream_Flag = 1;
				break;
			default:
				sprintf(Error_Text,"Unable to recognize stream type\n");
				Error(Error_Text);
				break;
			}
			
			// v0.16B35 instead of using mpv_lseek(), close and re-open the file
			mpv_close(base.bs_Infile);
			
			if ((base.bs_Infile=mpv_open(Main_Bitstream_Filename,O_RDONLY|O_BINARY, Output_Directory))<0)
			{
				fprintf(stderr,"\nBase layer input file '%s' could not be re-opened", Main_Bitstream_Filename);
				exit(1);
			}
			
			//  mpv_lseek(base.bs_Infile, 0l, SEEK_SET); 
		} /* endif ( base.bs_Infile != 0) */
	} /* endif -- if ( !g_vobflag ) */
	
	Initialize_Buffer(); 
	
	/* disable two_streams support
	if(Two_Streams)
	{
    ld = &enhan;  select enhancement layer context 
	
	  if ((enhan.Infile = _open(Enhancement_Layer_Bitstream_Filename,O_RDONLY|O_BINARY))<0)
	  {
      sprintf(Error_Text,"enhancment layer bitstream file %s not found\n",
	  Enhancement_Layer_Bitstream_Filename);
	  
		Error(Error_Text);
		}
		
		  Initialize_Buffer();
		  ld = &base;
		  }
	*/
	
	Initialize_Decoder();
	if ( Output_Type == T_AVI || Output_Type == T_AVI_YV12 ||
		Output_Type == T_AVI_YUY2 )
	{
		;
	} // endif
	
	ret = Decode_Bitstream();
	mpv_close(base.bs_Infile);
	
	
	/*if (Two_Streams)
    _close(enhan.Infile);*/
	
	/* rsl */
	if ( Output_Type == T_AVI || Output_Type == T_AVI_YV12 
		|| Output_Type == T_AVI_YUY2 )
	{
		if ( Output_Picture_Filename != NULL )
		{
			printf( "\nClosing output (AVI) file %s", Output_Picture_Filename );
			avi_fileclose();
		}
	}
	
	if ( Output_Type == T_GDI )
	{
		printf("\r<Done.>");
		_getch();
	}


	return 0;
}


//PX3int main(int argc, char *argv[])
//PX3{
//PX3	int ret, code;
//PX3	BOOL m_fMMX = FALSE, m_f3DNOW = FALSE; /* flags for CPU capabilities */
//PX3	DWORD dwrc = 0; /* dword return code */
	
//PX3	Clear_Options();
	
	/* decode command line arguments */
//PX3	Process_Options(argc,argv);
	
	/* v0.16B31 enforce '-f' */
//PX3	if ( !Frame_Store_Flag )
//PX3	{
//PX3		fprintf( stderr, "\nFrame_Store_Flag is not specified." );
//PX3		fprintf( stderr, "\nYou must include '-f' in your command line!" );
//PX3		exit( ERROR );
//PX3	}
	
	/* 0.16B22 check for MMX capability */
//PX3	test_cpu( &m_fMMX, &m_f3DNOW );
	
//PX3	if ( m_fMMX == FALSE )
//PX3	{
//PX3		fprintf( stderr, "\nmain() : Your CPU does *NOT* support MMX instructions!");
//PX3		fprintf( stderr, "\n\tThis version of <%s> requires MMX support!", Version );
//PX3		exit( ERROR );
//PX3	}
	
	// printf( "\nmain() : m_fMMX = %d, m_f3DNOW = %d", m_fMMX, m_f3DNOW );
	
//PX3#ifdef DEBUG
//PX3	Print_Options();
//PX3#endif
	
	// the input file is a streamlist, automatically engage BBDMUX
	
//PX3	if ( rstrcmpi( Main_Bitstream_Filename, ".vob" ) == 0 ||
//PX3		rstrcmpi( Main_Bitstream_Filename, ".lst" ) == 0  )
//PX3		g_vobflag = 1; /* DVD vob file, use BBDMUX */
//PX3	else
//PX3		g_vobflag = 0; /* M2V file, don't use BBDMUX */
	
	
//PX3	ld = &base; /* select base layer context */
	
	/* open MPEG base layer bitstream file(s) */
	/* NOTE: this is either a base layer stream or a spatial enhancement stream */
	
	/* if g_vobflag is set, then the routines in s_read.cpp will automatically
	"connect" to BBDMUX, and BBDMUX will perform an fopen() on the filename */
	
	//  if ( !g_vobflag )
	//  {  
//PX3    if ((base.bs_Infile=mpv_open(Main_Bitstream_Filename,O_RDONLY|O_BINARY, Output_Directory))<0)
//PX3	{
//PX3		fprintf(stderr,"\nBase layer input file '%s' not found", Main_Bitstream_Filename);
//PX3		exit(1);
//PX3	}
	
	//  if ( g_vobflag )
//PX3	if ( !g_vobflag )
//PX3	{
	/*	  printf("\nUsing BBDMUX to decode bitstream 0xE0 from %s", 
		  Main_Bitstream_Filename );
		  
			if ( Frame_Store_Flag == 0 )
			{
			fprintf(stderr,"Warning : -f option was not specified!");
			fprintf(stderr,"\n        (Post-processing functions may fail!)");
			}
	}*/
		
		
//PX3		if(base.bs_Infile != 0)
//PX3		{
//PX3			Initialize_Buffer(); 
			
//PX3			if(Show_Bits(8)==0x47)
//PX3			{
//PX3				sprintf(Error_Text,"Decoder currently does not parse transport streams\n");
//PX3				Error(Error_Text);
//PX3			}
			
//PX3			next_start_code();
//PX3			code = Show_Bits(32);
			
//PX3			switch(code)
//PX3			{
//PX3			case SEQUENCE_HEADER_CODE:
//PX3				break;
//PX3			case PACK_START_CODE:
//PX3				System_Stream_Flag = 1;
//PX3			case VIDEO_ELEMENTARY_STREAM:
//PX3				System_Stream_Flag = 1;
//PX3				break;
//PX3			default:
//PX3				sprintf(Error_Text,"Unable to recognize stream type\n");
//PX3				Error(Error_Text);
//PX3				break;
//PX3			}
			
			// v0.16B35 instead of using mpv_lseek(), close and re-open the file
//PX3			mpv_close(base.bs_Infile);
			
//PX3			if ((base.bs_Infile=mpv_open(Main_Bitstream_Filename,O_RDONLY|O_BINARY, Output_Directory))<0)
//PX3			{
//PX3				fprintf(stderr,"\nBase layer input file '%s' could not be re-opened", Main_Bitstream_Filename);
//PX3				exit(1);
//PX3			}
			
			//  mpv_lseek(base.bs_Infile, 0l, SEEK_SET); 
//PX3		} /* endif ( base.bs_Infile != 0) */
//PX3	} /* endif -- if ( !g_vobflag ) */
	
//PX3	Initialize_Buffer(); 
	
	/* disable two_streams support
	if(Two_Streams)
	{
    ld = &enhan;  select enhancement layer context 
	
	  if ((enhan.Infile = _open(Enhancement_Layer_Bitstream_Filename,O_RDONLY|O_BINARY))<0)
	  {
      sprintf(Error_Text,"enhancment layer bitstream file %s not found\n",
	  Enhancement_Layer_Bitstream_Filename);
	  
		Error(Error_Text);
		}
		
		  Initialize_Buffer();
		  ld = &base;
		  }
	*/
	
//PX3	Initialize_Decoder();
//PX3	if ( Output_Type == T_AVI || Output_Type == T_AVI_YV12 ||
//PX3		Output_Type == T_AVI_YUY2 )
//PX3	{
//PX3		;
//PX3	} // endif
	
//PX3	ret = Decode_Bitstream();
//PX3	mpv_close(base.bs_Infile);
	
	
	/*if (Two_Streams)
    _close(enhan.Infile);*/
	
	/* rsl */
//PX3	if ( Output_Type == T_AVI || Output_Type == T_AVI_YV12 
//PX3		|| Output_Type == T_AVI_YUY2 )
//PX3	{
//PX3		if ( Output_Picture_Filename != NULL )
//PX3		{
//PX3			printf( "\nClosing output (AVI) file %s", Output_Picture_Filename );
//PX3			avi_fileclose();
//PX3		}
//PX3	}
	
//PX3	if ( Output_Type == T_GDI )
//PX3	{
//PX3		printf("\r<Done.>");
//PX3		_getch();
//PX3	}
	
//PX3	return 0;
//PX3}

/* IMPLEMENTAION specific rouintes */
static void Initialize_Decoder()
{
  int i;

  /* Clip table */
  //if (!(Clip=(unsigned char *)malloc(1024)))
  if (!(Clip=(unsigned char *)calloc(32, 32)))
    Error("Clip[] malloc failed\n");

  Clip += 384;

  for (i=-384; i<640; i++)
    Clip[i] = (i<0) ? 0 : ((i>255) ? 255 : i);

  /* IDCT */
  /* v0.16B22 initialize all IDCTs */
//  if (Reference_IDCT_Flag)
    init_idct_ref64();
//  else
//  init_idct_int32(); 

	// v0.16B22 set (*p_idctFunction)() to an IDCT-function.
	// The switch statement parses the user's IDCT-selection
	//
	// The idct-function is called with this statement :
	//  short *block; // IDCT block data (8x8 elements)
	//
	//   (*p_idctFunction)( block );

	switch ( GETOPT( UserOptIDCT ) )
	{
		case _IDCT_FPU64 :
			p_idctFunction = idct_ref64;
			init_scan_matrix( SCAN_ORDER_NORMAL );
			break;		
		case _IDCT_MMX32 :
			// idct8x8_mmx; do not use idct8x8_mmx at the moment
			// it's still not working.. PX3
			p_idctFunction = idct_mmx32; 
			init_scan_matrix( SCAN_ORDER_TRANSPOSE );
			break;
//		case _IDCT_INT32 :
//			p_idctFunction = idct_int32;
//			init_scan_matrix( SCAN_ORDER_NORMAL );
//			break;
		case _IDCT_MMX_CHEN1 :
			p_idctFunction = idct_mmx_chen1;
			init_scan_matrix( SCAN_ORDER_NORMAL );
			break;
		case _IDCT_MMX_AAN :
			p_idctFunction = idct_mmx_aan;
			init_scan_matrix( SCAN_ORDER_TRANSPOSE );
			break;
		default :
			p_idctFunction = idct_mmx32; // v0.16B33 default is now MMX32
			init_scan_matrix( SCAN_ORDER_TRANSPOSE );
	}
}

/* mostly IMPLEMENTAION specific rouintes */
static void Initialize_Sequence()
{
  int cc, size;
  static int Table_6_20[3] = {6,8,12};

  /* check scalability mode of enhancement layer */
  if (Two_Streams && (enhan.scalable_mode!=SC_SNR) && (base.scalable_mode!=SC_DP))
    Error("unsupported scalability mode\n");

  /* force MPEG-1 parameters for proper decoder behavior */
  /* see ISO/IEC 13818-2 section D.9.14 */
  if (!base.MPEG2_Flag)
  {
    progressive_sequence = 1;
    progressive_frame = 1;
    picture_structure = FRAME_PICTURE;
    frame_pred_frame_dct = 1;
    chroma_format = CHROMA420;
    matrix_coefficients = 5;
  }

  /* round to nearest multiple of coded macroblocks */
  /* ISO/IEC 13818-2 section 6.3.3 sequence_header() */
  mb_width = (horizontal_size+15)/16;
  mb_height = (base.MPEG2_Flag && !progressive_sequence) ? 2*((vertical_size+31)/32)
                                        : (vertical_size+15)/16;

  Coded_Picture_Width = 16*mb_width;
  Coded_Picture_Height = 16*mb_height;

  /* ISO/IEC 13818-2 sections 6.1.1.8, 6.1.1.9, and 6.1.1.10 */
  Chroma_Width = (chroma_format==CHROMA444) ? Coded_Picture_Width
                                           : Coded_Picture_Width>>1;
  Chroma_Height = (chroma_format!=CHROMA420) ? Coded_Picture_Height
                                            : Coded_Picture_Height>>1;
  
  /* derived based on Table 6-20 in ISO/IEC 13818-2 section 6.3.17 */
  block_count = Table_6_20[chroma_format-1];

  // v0.16B23, to support aligned qword reading in Add_Block() [getpic.c],
  // the framebuffer sizes must be extended an extra few bytes (EXTRA_MEM_PAD.)
  // This allows the MMX-code to read past the end of the frame, without 
  // causing a protection-fault

  for (cc=0; cc<3; cc++)
  {
    if (cc==0)
      size = (Coded_Picture_Width*Coded_Picture_Height) + EXTRA_MEM_PAD;
    else
      size = Chroma_Width*Chroma_Height + EXTRA_MEM_PAD;

	if (!(backward_reference_frame[cc] = (unsigned char *)calloc( (size>>5)+2,32)))
      Error("backward_reference_frame[] malloc failed\n");

    if (!(forward_reference_frame[cc] = (unsigned char *)calloc( (size>>5)+2,32)))
      Error("forward_reference_frame[] malloc failed\n");

    if (!(auxframe[cc] = (unsigned char *)calloc( (size>>5)+2,32)))
      Error("auxframe[] malloc failed\n");

    if(Ersatz_Flag)
      if (!(substitute_frame[cc] = (unsigned char *)calloc( (size>>5)+2,32)))
        Error("substitute_frame[] malloc failed\n");


//snr    if (base.scalable_mode==SC_SPAT)
//snr    {
//snr      /* this assumes lower layer is 4:2:0 */
//snr      if (!(llframe0[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1))))
//snr        Error("llframe0 malloc failed\n");
//snr      if (!(llframe1[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1))))
//snr        Error("llframe1 malloc failed\n");
//snr    }
  }

  /* SCALABILITY: Spatial */
//snr  if (base.scalable_mode==SC_SPAT)
//snr  {
//snr    if (!(lltmp = (short *)malloc(lower_layer_prediction_horizontal_size*((lower_layer_prediction_vertical_size*vertical_subsampling_factor_n)/vertical_subsampling_factor_m)*sizeof(short))))
//snr      Error("lltmp malloc failed\n");
//snr  }

#ifdef DISPLAY
  if (Output_Type==T_X11)
  {
    Initialize_Display_Process("");
    Initialize_Dither_Matrix();
  }
#endif /* DISPLAY */

}

void Error(char* text)
{
  fprintf(stderr,text);
  exit(1);
}

/* Trace_Flag output */
void Print_Bits(int code, int bits, int len)
{
  int i;
  for (i=0; i<len; i++)
    printf("%d",(code>>(bits-1-i))&1);
}



/* option processing */
//PX3 static void Process_Options(int argc, char *argv[])
//PX3 {
//PX3   int i, LastArg, NextArg;
//PX3   int temp;
//PX3   int dirSize;

  /* at least one argument should be present */
//PX3   if (argc<2)
//PX3   {
//PX3     printf("%s(MMX) [original code %s]\n",Version,Author);
//PX3     printf("Usage:  mpeg2avi  {options}\n\
//PX3 Options: -b <file>  input bitstream-file <or> 'streamlist.lst' (see readme) \n\
//PX3          -b <file> 0xID [optional] ('ID' = desired stream ID, default=0xE0)\n\
//PX3          -f         store/display interlaced video in frame format\n\
//PX3                      (if MPEG-2 input & output-mode -o7, -f is REQUIRED)\n\
//PX3          -o<n> directory output ( 6:WinGDI 7:AVI(RGB24) 8:AVI(YV12) 9:AVI(YUY2) )\n\
//PX3          -q<n>      postfilter quality, -q1 = fast(default), -q0 = HiQ\n\
//PX3          -r<n>      Select IDCT function (default='-r1' <32-bit MMX>)\n\
//PX3          -@ <lba>   Start DEMUXER at logical block address (VOB input only!)\n\
//PX3          -# <a> <b> declare decoding range [#a .. #b] (inclusive)\n\
//PX3          -*         print data timestamp (video watermark)\n\
//PX3       <options below only affect GDI and AVI output modes (-o6 ... -o9)>\n\
//PX3          -s<n>      Use Inverse-Telecine algorithm with frame offset (0..9)\n\
//PX3                     (-s0, -s1, -s2, -s3, ..., default is OFF)\n\
//PX3          -1 X Y     crop output to <X> * <Y> (crop window is centered)\n\
//PX3          -2         downsample output to half-resolution (if both -1 and -2,\n\
//PX3                      decoder 1st downsamples frame, then crops it)\n\
//PX3          -3X n, -3Y n  adjust aspect-ratio <X> or <Y> direction to n-pixels\n\
//PX3          -$ <nnn>   autosplit AVI file after <nnn> megabytes (1024KB chunks)\n\
//PX3          -! <nnn>   skip 1 decoded-frame per <nnn> decoded-frames (AVI-only)\n\
//PX3          -a         decode video only no audio\n\
//PX3 Examples:  mpeg2avi.exe -b clip04.vob -2 -1 352 240 -3X 320 -3Y 200 -f -o6\n\
//PX3            mpeg2avi.exe -b stuff.vob 0xE1 -2 -f0 -s3 -r -o7 output.avi");
//PX3     exit(0);
//PX3   }

/*         -e  file  enhancement layer bitstream (SNR or Data Partitioning)\n\
         -g         concatenated file format for substitution method (-x)\n\
         -i<n> file information & statistics report  (n: level)\n\

         -c<n> file conformance report (n: level)\n\
          -l  file  file name pattern for lower layer sequence\n\
         -o<n> file output (0:YUV 1:SIF 2:TGA 3:PPM 6:WinGDI 7:AVI 8:AVI*)\n\
         -q         disable warnings to stderr\n\
                   (for spatial scalability)\n\
           -t        enable low level tracing to stdout\n\
         -u  file   print user_data to stdio or file\n\
           -vn       verbose output (n: level)\n\
           -x  file  filename pattern of picture substitution sequence\n\n\
File patterns:  for sequential filenames, \"printf\" style, e.g. rec%%d\n\
                 or rec%%d%%c for fieldwise storage\n\
Levels:        0:none 1:sequence 2:picture 3:slice 4:macroblock 5:block\n\n\
 */

//PX3   Output_Type = -1;
//PX3   i = 1;

  /* command-line options are proceeded by '-' */

//PX3   while(i < argc)
//PX3   {
    /* check if this is the last argument */
//PX3     LastArg = ((argc-i)==1);

    /* parse ahead to see if another flag immediately follows current
       argument (this is used to tell if a filename is missing) */
//PX3     if(!LastArg)
//PX3       NextArg = (argv[i+1][0]=='-');
//PX3     else
//PX3       NextArg = 0;

    /* second character, [1], after '-' is the switch */
//PX3     if(argv[i][0]=='-')
//PX3     {
//PX3       switch(toupper(argv[i][1]))
//PX3       {
        /* third character. [2], is the value */

//PX3 	  case '#':  /* MPEG-decoder frame range limit */
//PX3 		if ( ( argc - i ) < 2 )
//PX3 		{
//PX3 			printf("ERROR: -# must be followed by two parameters [ -# <start> <end>");
//PX3 			printf("\n  <start> = # of starting frame (0 = first frame)");
//PX3 			printf("\n    <end> = # of last frame (inclusive)");
//PX3 			exit( ERROR );
//PX3 		}

//PX3 		SETOPT( UserOptFRangeStart, atoi( argv[++i] ) );
//PX3 		SETOPT( UserOptFRangeEnd, atoi( argv[++i] ) );

//PX3 		if ( GETOPT( UserOptFRangeStart )< 0 || GETOPT( UserOptFRangeEnd )< 0 
//PX3 			|| GETOPT( UserOptFRangeStart ) > GETOPT( UserOptFRangeEnd ) )
//PX3 		{
//PX3 			fprintf( stderr, "ERROR: FRangeStart(%ld) and FRangeEnd(%ld) value(s) invalid!\n",
//PX3 				GETOPT( UserOptFRangeStart ), GETOPT( UserOptFRangeEnd ) );
//PX3 			exit(ERROR);
//PX3 		}

//PX3 		break;

//PX3 	  case '@': /* AVI-writer file-length limit, autosplit */
//PX3 		if ( !LastArg )
//PX3 		{
//PX3 			SETOPT( UserOptVOBStartLBA, atoi( argv[++i] ) );
//PX3 			if ( GETOPT( UserOptVOBStartLBA ) < 0 )
//PX3 			{
//PX3 				fprintf( stderr, "ERROR : '-@ <lba>', lba must be positive!" );
//PX3 				exit( ERROR );
//PX3 			}
//PX3 		}
//PX3 		else
//PX3 		{
//PX3 			fprintf( stderr, "ERROR : '-@ <lba>' requires 1 parameter!" );
//PX3 			fprintf( stderr, "\n\t<lba> = logical block address (1 block=2048 bytes)");
//PX3 			fprintf( stderr, "\n\n\tThe demuxer starts decoding at the specified LBA.");
//PX3 			fprintf( stderr, "\n\tThe starting LBA must contain a SYSTEM HEADER!");
//PX3 			exit( ERROR );
//PX3 		}
//PX3 		break;

//PX3 	  case '$': /* AVI-writer file-length limit, autosplit */
//PX3 		if ( !LastArg )
//PX3 		{
//PX3 			if ( ( atoi( argv[i+1] ) < 0 ) || ( atoi( argv[i+1] ) > 2047 ) )
//PX3 			{
//PX3 				fprintf( stderr, "ERROR : '-$ <nnn>', <nnn> is outside legal range!" );
//PX3 				fprintf( stderr, "\n\t<nnn> is in units of megabytes (1024KB)" );
//PX3 				fprintf( stderr, "\n\t<nnn> = 1 ... 2047 ");
//PX3 				exit( ERROR );
//PX3 			}
			/* legal value, record it */
//PX3 			SETOPT(UserOptAVISplitLength, ( atoi( argv[ ++i ] ) << 20 ) );
//PX3 		}
//PX3 		else
//PX3 		{
//PX3 			fprintf( stderr, "ERROR: must specify a value <nnn> (megabytes) for '-$ <nnn>'");
//PX3 			fprintf( stderr, "\n\t<nnn> = 1 ... 2047 ");
//PX3 			exit( ERROR );
//PX3 		}
//PX3 		break;

//PX3 	  case '!': /* AVI/GDI output skip-1-frame per N */
//PX3 		if ( !LastArg && ( atoi( argv[i+1] ) > 0 ) )
//PX3 		{
//PX3 			SETOPT( UserOptAVISkipEvery, atoi( argv[ ++i ] ) );
//PX3 		}
//PX3 		else
//PX3 		{
//PX3 			fprintf( stderr, "ERROR: must specify a value <nnn> (interval in #frames) for ");
//PX3 			fprintf( stderr, "\n\t'-!' option.  Every <n>th frame is not written to AVI.");
//PX3 			fprintf( stderr, "\n\t(the frame is decoded, but not sent to output-routine.");
//PX3 		}
//PX3 		break;

//PX3 	  case '*': /* Print MPEG frame# in upper-left corner of frame */
//PX3 		SETOPT( UserOptPrintFrameCode, TRUE );
//PX3 		break;

//PX3       case '1': /* output picture cropping, does not adjust aspect-ratio */
		
		/* g_AVIcropX and g_AVIcropY are initialized with default values
		   of _DISABLE_CROP...this value is later converted to *valid*
		   picture co-ordinate(s) in store_avi_gdi() [store.c] */
//PX3 		if( ( argc - i ) < 2 )  
//PX3         {
//PX3           printf("ERROR: -1 must be followed by two parameters [ -1 x y ]\n");
//PX3           exit(ERROR);
//PX3         }

//PX3 		SETOPT( UserOptCropX, atoi(argv[++i]) );
//PX3 		SETOPT( UserOptCropY, atoi(argv[++i]) );
//PX3 		if ( GETOPT( UserOptCropX )<= 0 || GETOPT( UserOptCropY )<= 0 )
//PX3 		{
//PX3 			fprintf( stderr, "ERROR: crop value(s) must be positive!\n");
//PX3 			exit(ERROR);
//PX3 		}
//PX3 		break;

//PX3       case '2': /* half video resolution */
//PX3         g_vHalfResFlag = 1; 
//PX3 		break;
//PX3 	  case '3': /* arbitrary aspect-ratio control */
//PX3 		if ( !LastArg )
//PX3 		  switch ( toupper( argv[i][2] ) )
//PX3 		  {
//PX3 			case 'X' : /* horizontal resolution resizing */
//PX3 				if ( atoi( argv[ i+1 ] ) <= 0 )
//PX3 				{
//PX3 					fprintf( stderr, "\nERROR: downscale size is negative (%d)",
//PX3 						atoi( argv[ i+1 ] ) );
//PX3 					exit( ERROR );
//PX3 				}
//PX3 				SETOPT( UserOptResizeX,atoi(argv[++i]) );
//PX3 				break;
//PX3 			case 'Y' : /* vertical resolution resizing */
//PX3 				SETOPT( UserOptResizeY,atoi(argv[++i]) );
//PX3 				break;
//PX3 			default:
//PX3 				printf("ERROR: valid options are '-vX <n>' and '-vY <n>'\n");
//PX3 				printf("       <n>=(output size in pixels, n must be LESS THAN source's size)");
//PX3 				printf("\nexamples: (MPEG-2 720x480 input)");
//PX3 				printf("\n  mpeg2avi.exe -b input.vob -3Y 408  (16:9 film-> PC letterbox)");
//PX3 				printf("\n  mpeg2avi ... -3X 424 -3Y 240 -1 352 240 (16:9 film-> 1/2-res pans&scan)");
//PX3 				printf("\n  mpeg2avi ... -3X 640 -1 640 480 (4:3 NTSC TV -> PC/VGA 4:3)");
//PX3 				exit(ERROR);
//PX3 		} /* end switch */
//PX3 		else
//PX3         {
//PX3 		  printf("ERROR: valid options are '-vX <n>' and '-vY <n>'\n");
//PX3 		  printf("       <n>=(output size in pixels, n must be LESS THAN source's size)");
//PX3 		  printf("\nexamples: (MPEG-2 720x480 input)");
//PX3 		  printf("\n  mpeg2avi.exe -b input.vob -3Y 408  (16:9 film-> PC letterbox)");
//PX3 		  printf("\n  mpeg2avi ... -3X 424 -3Y 240 -1 352 240 (16:9 film-> 1/2-res pans&scan)");
//PX3 		  printf("\n  mpeg2avi ... -3X 640 -1 640 480 (4:3 NTSC TV -> PC/VGA 4:3)");
//PX3 		  exit(ERROR );
//PX3 		}

//PX3 		break;
//PX3       case 'B':
//PX3         Main_Bitstream_Flag = 1;

//PX3         if(NextArg || LastArg)
//PX3         {
//PX3           printf("ERROR: '-b' must be followed by input file (MPG/VOB), ");
//PX3 		  printf("or a 'streamlist'.\n\t(The streamlist's extension must == '*.lst')");
//PX3 		  printf("\n\nExamples : mpeg2avi -b movie_trailer.vob -f -2 -o6");
//PX3 		  printf("\n  <streamlist>  mpeg2avi -b filelist.lst -f -2 -o6");
//PX3 		  printf("\n\nSee the sample.lst & readme.txt for more info on streamlists.");
//PX3 		  exit( ERROR );
//PX3 		}
//PX3         else
//PX3 		{
//PX3           Main_Bitstream_Filename = argv[++i]; 
		  // check for additional parameter, Stream ID?
//PX3 		  if ( ( argc - i ) > 1 )
//PX3 		  {	// at least one more parameter!
//PX3 			  if ( argv[i+1][0] != '-' )
//PX3 			  {   // get VOBstreamID
//PX3 				  sscanf( argv[++i], "%X", &temp );
//PX3 				  if ( temp > 0 && temp < 256 )
//PX3 					  SETOPT( UserOptVOBStreamID, temp );
//PX3 			  }
//PX3 		  }
//PX3 		}


//PX3         break;


//PX3       case 'C':

//PX3 #ifdef VERIFY
//PX3         Verify_Flag = atoi(&argv[i][2]); 

//PX3         if((Verify_Flag < NO_LAYER) || (Verify_Flag > ALL_LAYERS))
//PX3         {
//PX3           printf("ERROR: -c level (%d) out of range [%d,%d]\n",
//PX3             Verify_Flag, NO_LAYER, ALL_LAYERS);
//PX3           exit(ERROR);
//PX3         }
//PX3 #else  /* VERIFY */
//PX3         printf("This program not compiled for Verify_Flag option\n");
//PX3 #endif /* VERIFY */
//PX3         break;

//PX3       case 'E':
//PX3         Two_Streams = 1; /* either Data Partitioning (DP) or SNR Scalability enhancment */
	                   
//PX3         if(NextArg || LastArg)
//PX3         {
//PX3           printf("ERROR: -e must be followed by filename\n");
//PX3           exit(ERROR);
//PX3         }
//PX3         else
//PX3           Enhancement_Layer_Bitstream_Filename = argv[++i]; 

//PX3         break;


//PX3       case 'F':
		/* record user's choice regarding frame-rate, overrides _ASK_USER */
//PX3 		if ( argv[ i ][ 2 ] != 0 ) /* user may not have entered a # */
//PX3 		{
//PX3 			SETOPT( UserOptAVIrate, atoi( &argv[i][2]) );
			// g_AVIrate = atoi( &argv[i][2]);
//PX3 		}
//PX3         Frame_Store_Flag = 1;
//PX3         break;

//PX3       case 'G':
//PX3         Big_Picture_Flag = 1;
//PX3         break;


//PX3       case 'I':
//PX3 #ifdef VERIFY
//PX3         Stats_Flag = atoi(&argv[i][2]); 
//PX3 #else /* VERIFY */
//PX3         printf("WARNING: This program not compiled for -i option\n");
//PX3 #endif /* VERIFY */     
//PX3         break;
    
//PX3       case 'L':  /* spatial scalability flag */
//PX3         Spatial_Flag = 1;

//PX3        if(NextArg || LastArg)
//PX3        {
//PX3          printf("ERROR: -l must be followed by filename\n");
//PX3          exit(ERROR);
//PX3        }
//PX3        else
//PX3          Lower_Layer_Picture_Filename = argv[++i]; 

//PX3         break;

//PX3       case 'O':
  
//PX3         Output_Type = atoi(&argv[i][2]); 
  
		/* AVI output now defaults to integer IDCT */
		/*if ( Output_Type == 7 )	
			Reference_IDCT_Flag = 1; */

//PX3         if((Output_Type==4) || (Output_Type==5) || (Output_Type==6) )
//PX3           Output_Picture_Filename[0] = 0; /* no need of filename */
//PX3         else if(NextArg || LastArg)  
//PX3         {
//PX3           printf("ERROR: -o%d must be followed by filename\n", Output_Type );
//PX3           exit(ERROR);
//PX3         }
//PX3         else
//PX3 		{
        /* filename is separated by space, so it becomes the next argument */
//PX3 		  strcpy(Output_Directory, argv[++i]);
//PX3 		  dirSize = strlen(Output_Directory);
//PX3 		  if (Output_Directory[dirSize - 1] != '\\')
//PX3 		  {
//PX3 			  Output_Directory[dirSize] = '\\';
//PX3 			  Output_Directory[dirSize + 1] = 0;
//PX3 		  }
//PX3           strcpy(Output_Picture_Filename, Output_Directory); //Output_Directory + "movie.avi"; 
//PX3 		  strcat(Output_Picture_Filename, "movie.avi");
//PX3 		}

//PX3 #ifdef DISPLAY
//PX3         if (Output_Type==T_X11HIQ)
//PX3         {
//PX3           hiQdither = 1;
//PX3           Output_Type=T_X11;
//PX3         }
//PX3 #endif /* DISPLAY */
//PX3         break;

/*      case 'Q':
        Quiet_Flag = 1;
        break;*/

//PX3       case 'Q': /* filter quality mode */
//PX3 		switch( argv[i][2] )
//PX3 		{
//PX3 			case '0' :
//PX3 				g_fastfilter = 0;
//PX3 				break;
//PX3 			case '1' :
//PX3 				g_fastfilter = 1;
//PX3 				break;
//PX3 			default:
//PX3 				fprintf(stderr, "\nERROR: Invalid value (%c) for option -q<n>",
//PX3 					argv[i][2] );
//PX3 				fprintf(stderr, "\n    -q0 HiQuality (YUV420 -> RGB24 U/V-pixel interpolation"); 
//PX3 				fprintf(stderr, "\n                  (for '-2', low-pass FIR filter");
//PX3 				fprintf(stderr, "\n    -q1 Fast*     (YUV420 -> RGB24 U/V-pixel duplication");
//PX3 				fprintf(stderr, "\n                  (for '-2', arithmetic average on Y-pixel");
//PX3 				fprintf(stderr, "\n\n * = DEFAULT, MMX-optimizations available");
//PX3 				fprintf(stderr, "\n\n     '-3' (aspect ratio) always uses arithmetic pixel averaging");
				
				//fprintf(stderr,   "\n     '-o8' (YV12 AVI mode) non-standard ");
//PX3 				exit( ERROR );
//PX3 		}
//PX3 		break;

//PX3       case 'R':	// v0.16B22 let user select from several IDCT functions
//PX3 		  if ( argv[i][2] != 0 )
//PX3 			  SETOPT( UserOptIDCT, atoi( &argv[i][2] ) );
//PX3 		  if ( argv[i][2] == 0 || ( GETOPT(UserOptIDCT) < 0 ) || 
//PX3 			  ( GETOPT(UserOptIDCT) > 3 ) )
//PX3 		  {
//PX3 			fprintf( stderr, "\nERROR: '-r<#>' requires a #!\nChoose an IDCT-function from the table:");
//PX3 			fprintf( stderr, "\n\n\t  -r0 64-bit D-FPU IDCT (IEEE-1180 compliant)      [ most-accurate ]");
//PX3 			fprintf( stderr, "\n\n\t* -r1 32-bit MMX32 IDCT (IEEE-1180 compliant)");
//PX3 			fprintf( stderr, "\n\n\t  -r2 16-bit MMX16 Chen IDCT (not compliant) ");
//PX3 			fprintf( stderr, "\n\n\t  -r3 16-bit MMX16 AAN IDCT (not compliant)        [ fastest       ]");
//			fprintf( stderr, "\n\n\t( -r4 32-bit INT32 Chen IDCT   *obsolete* ) ");
//PX3 			fprintf( stderr, "\n\n\t* = DEFAULT");
//PX3 			fprintf( stderr, "\nMost-accurate IDCT = (-r0)  : Fastest-IDCT = (-r3)" );

//PX3 			exit( ERROR );
//PX3 		  }
//          Reference_IDCT_Flag = 1;
//PX3         break;

//PX3       case 'S':  /* read the user's selection of IVTC start state */
//PX3 		switch ( argv[i][2] )
//PX3 		{
//PX3 		  case '0' :
//PX3 			SETOPT( UserOptIVTC, 0 );
//PX3 			break;
//PX3 		  case '1' :
//PX3 			SETOPT( UserOptIVTC, 1 );
//PX3 			break;
//PX3 		  case '2' :
//PX3 			SETOPT( UserOptIVTC, 2 );
//PX3 			break;
//PX3 		  case '3' :
//PX3 			SETOPT( UserOptIVTC, 3 );
//PX3 			break;
//PX3 		  case '4' :
//PX3 			SETOPT( UserOptIVTC, 4 );
//PX3 			break;
//PX3 		  case '5' :
//PX3 			SETOPT( UserOptIVTC, 5 );
//PX3 			break;
//PX3 		  case '6' :
//PX3 			SETOPT( UserOptIVTC, 6 );
//PX3 			break;
//PX3 		  case '7' :
//PX3 			SETOPT( UserOptIVTC, 7 );
//PX3 			break;
//PX3 		  case '8' :
//PX3 			SETOPT( UserOptIVTC, 8 );
//PX3 			break;
//PX3 		  case '9' :
//PX3 			SETOPT( UserOptIVTC, 9 );
//PX3 			break;
//PX3 		  default :
//PX3 			  fprintf( stderr, "\nERROR: Invalid IVTC-offset (%c) for option -s!", 
//PX3 				  argv[i][2] );
//PX3 			  fprintf( stderr, "  <n> must be between 0..9! (-s0, -s1, -s2, ...)" );
//PX3 			  fprintf( stderr, "\n  add 'D' for IVTC autoshutdown ( -s0D, -s1D, -s2D, etc.)");
//PX3 			  fprintf( stderr, "\nTo disable IVTC function, do not include -s<n>");
//PX3 			  exit( ERROR );
//PX3 		}

//PX3 		if ( argv[i][2] ) /* make sure this char isn't NULL, i.e. terminator */
//PX3 			if ( toupper( argv[i][3] ) == 'D' ) 
//PX3 				SETOPTAUX( UserOptIVTC, _IVTC_AUTODISABLE );
//PX3 		break;
//PX3       case 'T':
//PX3 #ifdef TRACE
//PX3         Trace_Flag = 1;
//PX3 #else /* TRACE */
//PX3         printf("WARNING: This program not compiled for -t option\n");
//PX3 #endif /* TRACE */
//PX3         break;

//PX3       case 'U':
//PX3         User_Data_Flag = 1;

//PX3       case 'V':
//PX3 #ifdef VERBOSE
//PX3         Verbose_Flag = atoi(&argv[i][2]); 
//PX3 #else /* VERBOSE */
//PX3         printf("This program not compiled for -v option\n");
//PX3 #endif /* VERBOSE */
//PX3         break;


//PX3       case 'X':
//PX3         Ersatz_Flag = 1;

//PX3        if(NextArg || LastArg)
//PX3        {
//PX3          printf("ERROR: -x must be followed by filename\n"); 
//PX3          exit(ERROR);
//PX3        }
//PX3        else
//PX3         Substitute_Picture_Filename = argv[++i]; 

//PX3         break;

//PX3 	  case 'A':
//PX3 		  SETOPT( UserOptNoAudioDecoding, 1 );
//PX3 		  break;


//PX3       default:
//PX3         fprintf(stderr,"undefined option -%c ignored. Exiting program\n", 
//PX3           argv[i][1]);

//PX3         exit(ERROR);
    
//PX3       } /* switch() */
//PX3     } /* if argv[i][0] == '-' */
    
//PX3     i++;

  	/* check for bitstream filename argument (there must always be one, at the very end
	   of the command line arguments */

//PX3   } /* while() */


  /* options sense checking */

//PX3   if(Main_Bitstream_Flag!=1)
//PX3   {
//PX3     printf("There must be a main bitstream specified (-b filename)\n");
//PX3   }

  /* force display process to show frame pictures */
//PX3   if((Output_Type==4 || Output_Type==5) && Frame_Store_Flag)
//PX3     Display_Progressive_Flag = 1;
//PX3   else
//PX3     Display_Progressive_Flag = 0;

//PX3 #ifdef VERIFY
  /* parse the bitstream, do not actually decode it completely */
  

//PX3 #if 0
//PX3   if(Output_Type==-1)
//PX3   {
//PX3     Decode_Layer = Verify_Flag;
//PX3     printf("FYI: Decoding bitstream elements up to: %s\n", 
//PX3       Layer_Table[Decode_Layer]);
//PX3   }
//PX3   else
//PX3 #endif
//PX3     Decode_Layer = ALL_LAYERS;

//PX3 #endif /* VERIFY */

  /* no output type specified */
//PX3   if(Output_Type==-1)
//PX3   {
//PX3     Output_Type = 9; 
//PX3     Output_Picture_Filename[0] = 0;;
//PX3   }


//PX3 #ifdef DISPLAY
//PX3   if (Output_Type==T_X11)
//PX3   {
//PX3     if(Frame_Store_Flag)
//PX3       Display_Progressive_Flag = 1;
//PX3     else
//PX3       Display_Progressive_Flag = 0;

//PX3     Frame_Store_Flag = 1; /* to avoid calling dither() twice */
//PX3   }
//PX3 #endif


//PX3 }


#ifdef OLD
/* 
   this is an old routine used to convert command line arguments
   into integers 
*/
static int Get_Val(argv)
char *argv[];
{
  int val;

  if (sscanf(argv[1]+2,"%d",&val)!=1)
    return 0;

  while (isdigit(argv[1][2]))
    argv[1]++;
 
  return val;
}
#endif



static int Headers()
{
  int ret;

  ld = &base;
  

  /* return when end of sequence (0) or picture
     header has been parsed (1) */

  ret = Get_Hdr();


  if (Two_Streams)
  {
    ld = &enhan;
    if (Get_Hdr()!=ret && !Quiet_Flag)
      fprintf(stderr,"streams out of sync\n");
    ld = &base;
  }

  return ret;
}



static int Decode_Bitstream()
{
  int ret;
  int Bitstream_Framenum;



  Bitstream_Framenum = 0;

  for(;;)
  {

#ifdef VERIFY
    Clear_Verify_Headers();
#endif /* VERIFY */

    ret = Headers();
    
    if(ret==1)
    {
      ret = video_sequence(&Bitstream_Framenum);
    }
    else
      return(ret);

  }

}


static void Deinitialize_Sequence()
{
  int i;

  /* clear flags */
  base.MPEG2_Flag=0;

  for(i=0;i<3;i++)
  {
    free(backward_reference_frame[i]);
    free(forward_reference_frame[i]);
    free(auxframe[i]);

    if (base.scalable_mode==SC_SPAT)
    {
     free(llframe0[i]);
     free(llframe1[i]);
    }
  }

  if (base.scalable_mode==SC_SPAT)
    free(lltmp);

#ifdef DISPLAY
  if (Output_Type==T_X11) 
    Terminate_Display_Process();
#endif
}

//SVE 03.06.2001 Routine komplett umgeschrieben, danach verworfen und durch den DispTread ersetzt

static void TimeCalc()
{
	__int64 iHE,iME,iSE;
	__int64 iHT,iMT,iST;
	float fFPS;

	if(st_RunState.diffTime)
		fFPS=(double)st_RunState.readFrames/(double)st_RunState.diffTime;
	else
		fFPS=0;

	iSE=st_RunState.diffTime;
	iME=iSE/60; iSE-=iME*60;
	iHE=iME/60; iME-=iHE*60;

	if(st_RunState.filePos)
		iST = st_RunState.fileSize * st_RunState.diffTime / st_RunState.filePos;
	else 
		iST=0;
	iMT=iST/60; iST-=iMT*60;
	iHT=iMT/60; iMT-=iHT*60;

	printf("\rFrame %lu (%lu KB) KF=%lu FPS=%.2f ET=%d:%02d:%02d TT=%d:%02d:%02d  ",
		st_RunState.readFrames,st_RunState.kbWritten,st_RunState.keyFrames,
		fFPS,(int)iHE,(int)iME,(int)iSE,(int)iHT,(int)iMT,(int)iST);
}

static int video_sequence(int *Bitstream_Framenumber)
{
  int Bitstream_Framenum;
  int Sequence_Framenum;
  int Return_Value;
  short dispout;
//SVE 03.06.2001
  long diffTime;

  Bitstream_Framenum = *Bitstream_Framenumber;
  Sequence_Framenum=0;

//SVE 03.06.2001 Neuer Thread für die Bildschirmausgabe
	SetThreadPriority(_beginthread( DispThread, 0, &st_RunState), THREAD_PRIORITY_IDLE);

  Initialize_Sequence();

  /* decode picture whose header has already been parsed in 
     Decode_Bitstream() */


  Decode_Picture(Bitstream_Framenum, Sequence_Framenum);

  /* update picture numbers */
  if (!Second_Field)
  {
    Bitstream_Framenum++;
    Sequence_Framenum++;
  }

  dispout = 0;

  /* loop through the rest of the pictures in the sequence */
  while ((Return_Value=Headers()))
  {

    Decode_Picture(Bitstream_Framenum, Sequence_Framenum);

    if (!Second_Field)
    {
      Bitstream_Framenum++;
      Sequence_Framenum++;
    }

//SVE 03.06.2001 Hier nur die Framenummer speichern
	st_RunState.readFrames=g_cbMPEGPicture;

/*
	time(&st_RunState.CurrentTime); 
	diffTime=(long)difftime(st_RunState.CurrentTime,st_RunState.StartTime);
	if(diffTime!=st_RunState.diffTime)
	{
		st_RunState.diffTime=diffTime;
		TimeCalc();
	}
*/
//SVE 03.06.2001 Die Ausgabe wird komplett von DispTread übernommen
	//if ( st_RunState.encFrames%4 == 1 )
//SVE 20.05.2001	TimeCalc();
//SVE 20.05.2001	printf("\rFrame#%lu : AVI (%.0f KB) #KF=%lu #FPS=%.2f #ET=%s #RT=%s",
//SVE 20.05.2001		st_RunState.encFrames,
//SVE 20.05.2001		st_RunState.kbWritten,
//SVE 20.05.2001		st_RunState.keyFrames,
//SVE 20.05.2001		st_RunState.FPS,
//SVE 20.05.2001		st_RunState.ElapsedTime,
//SVE 20.05.2001		st_RunState.RemainTime );
  }

  /* put last frame */
  if (Sequence_Framenum!=0)
  {
    Output_Last_Frame_of_Sequence(Bitstream_Framenum);
  }

  Deinitialize_Sequence();

//SVE Warten, Bis der Display-Tread beendet wurde
  st_RunState.Ende = 1;
  Sleep(2000);

#ifdef VERIFY
    Clear_Verify_Headers();
#endif /* VERIFY */

  *Bitstream_Framenumber = Bitstream_Framenum;
  return(Return_Value);
}



static void Clear_Options()
{
  Verbose_Flag = 0;
  Output_Type = -1;
  Output_Picture_Filename[0] = 0;
  Output_Directory[0] = 0;
  hiQdither  = 0;
  Output_Type = 0;
  Frame_Store_Flag = 0;
  Spatial_Flag = 0;
  Lower_Layer_Picture_Filename = " ";
  Reference_IDCT_Flag = 0;
  Trace_Flag = 0;
  Quiet_Flag = 0;
  Ersatz_Flag = 0;
  Substitute_Picture_Filename  = " ";
  Two_Streams = 0;
  Enhancement_Layer_Bitstream_Filename = " ";
  Big_Picture_Flag = 0;
  Main_Bitstream_Flag = 0;
  Main_Bitstream_Filename = " ";
  Verify_Flag = 0; 
  Stats_Flag  = 0;
  User_Data_Flag = 0; 
  g_vHalfResFlag = 0; /* output pictures are downsampled to 1/2 resolution */
  /*g_AVIcropX= _DISABLE_CROP;  for AVI/GDI output */
  /*g_AVIcropY= _DISABLE_CROP;  size of the encoded AVI frames */
  g_vobflag = 0; /* don't use BBDMUX, read-input bitstream directly  */
  Resized_Picture_Width = 0;
  Resized_Picture_Height = 0;
	/* will be set later by store.c, if -o6 or -o7 is active */
  g_cmd_ivtc = 0; /* command-variable for IVTC, see telecine.c */
  g_cmd_filter = 0; /* command-variable for up/down filtering, see store.c */
  g_cmd_buttonStop = 0; /* command-variable for stopping the decoder */

  g_fastfilter = 1; /* 0.16B22, now fast-filter is ON by default */
  g_cbMPEGPicture = 0; /* reset MPEG-picture counter to 0 */
  g_dwSystemPackLBA = -1; /* reset MPEG-System Header LBA position */

  CLEAROPT( UserOptIVTC );    /* clear user-option fields */
  CLEAROPT( UserOptResizeX );
  CLEAROPT( UserOptResizeY );
  CLEAROPT( UserOptCropX );
  CLEAROPT( UserOptCropY );
  CLEAROPT( UserOptFRangeStart );
  CLEAROPT( UserOptFRangeEnd );
  CLEAROPT( UserOptAVIrate );
  
  /* 0.16B1 AVI file splitting, AVIwriter automatically closes and opens new 
	file after #bytes specified by this option */
  CLEAROPT( UserOptAVISplitLength );
  /* if user does not specify, auto-splitting after ~2000MB */
  SETOPT( UserOptAVISplitLength, 1024*1024*2000 );

  CLEAROPT( UserOptAVISkipEvery ); /* 0.16B1 */
  CLEAROPT( UserOptPrintFrameCode ); /* 0.16B2 */
  CLEAROPT( UserOptVOBStartLBA ); /* 0.16B2 */
  SETOPT( UserOptVOBStartLBA, 0 ); /* 0.16B3, always scan VOB for sysheader */
  CLEAROPT( UserOptVOBStreamID ); /* 0.16B2 */

  CLEAROPT( UserOptIDCT ); /* 0.16B22 */
  SETOPT( UserOptIDCT, _IDCT_MMX32 ); /* v0.16B34 default IDCT = 32-bit MMX */

  CLEAROPT( UserOptNoAudioDecoding );
  SETOPT( UserOptNoAudioDecoding, 2 ); /* Default decode all audio */

  p_idctFunction = NULL; // reset IDCT function pointer to NULL

  st_RunState.fileCount = 0;
//SVE 03.06.2001  st_RunState.curFile[0] = '\0';
  st_RunState.curFile = -1;
  st_RunState.fileSize = 0;
  st_RunState.fileSizeComplete = 0;
  st_RunState.filePos = 0;
//SVE 03.06.2001  st_RunState.startTime = 0;
  st_RunState.diffTime = -1;
  st_RunState.encFrames = 0;
  st_RunState.kbWritten = 0;
  st_RunState.keyFrames = 0;
//SVE 03.06.2001
  st_RunState.Ende = 0;
//SVE 03.06.2001 st_RunState.FPS = 0;
//SVE 03.06.2001  st_RunState.lowestFPS = 0;
//SVE 03.06.2001  st_RunState.highestFPS = 0;

//SVE 03.06.2001  st_RunState.RemainTime[0] = '\0';
//SVE 03.06.2001  strcpy( st_RunState.RemainTime, "00:00:00" );

//SVE 03.06.2001  st_RunState.ElapsedTime[0] = '\0';
//SVE 03.06.2001  strcpy( st_RunState.ElapsedTime, "00:00:00" );

}



#ifdef DEBUG
static void Print_Options()
{
  
  printf("Verbose_Flag                         = %d\n", Verbose_Flag);
  printf("Output_Type                          = %d\n", Output_Type);
  printf("Output_Picture_Filename              = %s\n", Output_Picture_Filename);
  printf("hiQdither                            = %d\n", hiQdither);
  printf("Output_Type                          = %d\n", Output_Type);
  printf("Frame_Store_Flag                     = %d\n", Frame_Store_Flag);
  printf("Spatial_Flag                         = %d\n", Spatial_Flag);
  printf("Lower_Layer_Picture_Filename         = %s\n", Lower_Layer_Picture_Filename);
  printf("Reference_IDCT_Flag                  = %d\n", Reference_IDCT_Flag);
  printf("Trace_Flag                           = %d\n", Trace_Flag);
  printf("Quiet_Flag                           = %d\n", Quiet_Flag);
  printf("Ersatz_Flag                          = %d\n", Ersatz_Flag);
  printf("Substitute_Picture_Filename          = %s\n", Substitute_Picture_Filename);
  printf("Two_Streams                          = %d\n", Two_Streams);
  printf("Enhancement_Layer_Bitstream_Filename = %s\n", Enhancement_Layer_Bitstream_Filename);
  printf("Big_Picture_Flag                     = %d\n", Big_Picture_Flag);
  printf("Main_Bitstream_Flag                  = %d\n", Main_Bitstream_Flag);
  printf("Main_Bitstream_Filename              = %s\n", Main_Bitstream_Filename);
  printf("Verify_Flag                          = %d\n", Verify_Flag);
  printf("Stats_Flag                           = %d\n", Stats_Flag);
  printf("User_Data_Flag                       = %d\n", User_Data_Flag);

}
#endif


//
// Check CPU type for MMX extensions
//
// code from John Schlichter's AVI2MPG1 v1.7
//
static 
void test_cpu( BOOL *p_fMMX, BOOL *p_f3DNOW )
{
	BOOL m_fMMX = FALSE;
	BOOL m_f3DNOW = FALSE;

	if ( p_fMMX == NULL || p_f3DNOW == NULL )
	{
		fprintf( stderr, "\nTestCPU() : p_fMMX or p_f3DNOW == NULL!");
		exit( ERROR );
	}

	printf(" ");
	// based on code from www.amd.com 3dNow manual 21928e.pdf
	//
	// Added define because compiler did not like CPUID instruction
	//
//	#define cpuid __asm _emit 0x0F __asm _emit 0xA2
    __asm
    {
		pushfd                          ; // save EFLAGS
		pop   eax                       ; // store EFLAGS in EAX
		mov   ebx, eax                  ; // save EBX for later testing
		xor   eax, 0x00200000           ; // toggle bit 21
		push  eax                       ; // put to stack
		popfd                           ; // save changed EAX to EFLAGS
		pushfd                          ; // push EFLAGS to TOS
		pop   eax                       ; // store EFLAGS in EAX
		cmp   eax, ebx                  ; // see if bit 21 has changed
		jz    NO_CPUID                  ; // if no change, no CPUID

		mov   eax, 0x80000000           ; // query for AMD extended functions
        cpuid                           ; // get extended function limit
		cmp   eax, 0x80000000           ; // is 8000_0001h supported?
		jbe   NO_EXTENDEDMSR            ; // if not, 3DNow! tech. not supported

		mov   [m_fMMX], 1                ; // but 3DNow is!
		mov   eax, 0x80000001           ; // setup extended function 1
		cpuid                           ; // call the function
		test  edx, 0x80000000           ; // test bit 31
		jz    NO_3DNOW                  ; // 3DNow Not Detected
        mov   [m_f3DNOW], 1              ; // 3DNow detected!
		jmp   GOT_3DNow

NO_EXTENDEDMSR:
		mov   eax, 0x00000001           ; // query for standard INTEL
        cpuid   						; // cpu feature flags
		test  edx, 0x00800000           ; // is MMX supported?
		jz    NO_MMX                    ;
		mov   [m_fMMX], 1                ;
GOT_3DNow:
NO_MMX:
NO_3DNOW:
NO_CPUID:
	//	pop eax;
	}	// end __asm

	printf(" ");

	// reset flags to false
	(*p_fMMX) = m_fMMX;
	(*p_f3DNOW) = m_f3DNOW;
}


//initializes the g_scan[][] matrix
// type = 0   normal scan-order (non transpose)
// type = 1   transpose scan-order (for transposing iDCT functions)
static void
init_scan_matrix( int type )
{
	int i;

	for ( i = 0; i < 64; ++i )
	{
		if ( type != SCAN_ORDER_NORMAL )
		{	// transpose scan order
			g_scan[0][i] = scan_tr[0][i];
			g_scan[1][i] = scan_tr[1][i];
		}
		else
		{	// normal scan order (non-transpose)
			g_scan[0][i] = scan_no[0][i];
			g_scan[1][i] = scan_no[1][i];
		}
	}
}


//SVE 03.06.2001 Neuer Thread für die Bildschirmausgabe 
void  __cdecl DispThread( void *lpArgs )
{
	__int64 iHE,iME,iSE;
	__int64 iHT,iMT,iST;
	float fFPS;
	runstate* pRunState=(runstate*) lpArgs;
	while(!pRunState->Ende)
	{
		Sleep(2000);
		time(&pRunState->CurrentTime); 
		pRunState->diffTime=(long)difftime(pRunState->CurrentTime,pRunState->StartTime);

		if(pRunState->diffTime)
			fFPS=(double)pRunState->readFrames/(double)pRunState->diffTime;
		else
			fFPS=0;

		iSE=pRunState->diffTime;
		iME=iSE/60; iSE-=iME*60;
		iHE=iME/60; iME-=iHE*60;

		if(pRunState->filePos)
			iST = pRunState->fileSize * pRunState->diffTime / pRunState->filePos;
		else 
			iST=0;
		iMT=iST/60; iST-=iMT*60;
		iHT=iMT/60; iMT-=iHT*60;

		printf("\rFrame %lu (%lu KB) KF=%lu FPS=%.2f ET=%d:%02d:%02d TT=%d:%02d:%02d  ",
			pRunState->readFrames,pRunState->kbWritten,pRunState->keyFrames,
			fFPS,(int)iHE,(int)iME,(int)iSE,(int)iHT,(int)iMT,(int)iST);
	}
	_endthread();
}
