//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
// 	MODULE		:	STi3520A.C
// 	PURPOSE		:  STi3520A Control functions
// 	AUTHOR 		:  JBS Yadawa
// 	CREATED		:	12-26-96
//
//	Copyright (C) 1996-1997 SGS-THOMSON microelectronics
//
//
//
//	REVISION HISTORY:
//	-----------------
//
// 	DATE 			: 	COMMENTS
//	----			: 	--------
//
//	12-28-96 	: 	added different way of handling BufABC
//	1-1-97		: 	Added suport of PTS in s/w
//	1-3-97		: 	Implemeted 3:2 Pulldown
//	1-7-97		: 	AVSYNC Re-implemented
//	1-10-97		: 	Still picture support done
//	1-15-97		: 	Programming to 16/9 and 4/3 added - JBS
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#include "strmini.h"
#include "stdefs.h"
#include "board.h"
#include "sti3520a.h"
#include "ptsfifo.h"
#include "zac3.h"
#include "trace.h"
//#include "subpic2.h"
#include "mpaudio.h"
#include "ksmedia.h"
#include "mpinit.h"

extern PHW_STREAM_OBJECT pVideoStream;
extern HANDLE hClk;
extern HANDLE hMaster;
extern ULONG VidRate;

extern KS_MPEGVIDEOINFO2 VidFmt;
extern KS_AMVPDATAINFO VPFmt;

ULONG VidRate = 1000;

static VIDEO Video;
PVIDEO pVideo;

PSP_STRM_EX pSPstrmex = NULL;
extern PHW_DEVICE_EXTENSION pDevEx;

BOOL VideoProgramDisplayBuffer(void);
#define MINVBL	4
//Default Matrix

extern PAC3 pAc3;

BYTE slowmode=1;

static BYTE	defIntraQuantMatrix[QMSIZE] = {
		0x08, 0x10, 0x10, 0x13, 0x10, 0x13, 0x16, 0x16,
		0x16, 0x16, 0x16, 0x16, 0x1A, 0x18, 0x1A, 0x1B,
		0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B,
		0x1B, 0x1D, 0x1D, 0x1D, 0x22, 0x22, 0x22, 0x1D,
		0x1D, 0x1D, 0x1B, 0x1B, 0x1D, 0x1D, 0x20, 0x20,
		0x22, 0x22, 0x25, 0x26, 0x25, 0x23, 0x23, 0x22,
		0x23, 0x26, 0x26, 0x28, 0x28, 0x28, 0x30, 0x30,
		0x2E, 0x2E, 0x38, 0x38, 0x3A, 0x45, 0x45, 0x53
};



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoOpen
//	PARAMS	: None
//	RETURNS	: Pointer to Video Structure
//
//	PURPOSE	: One time initialization of Video
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

PVIDEO VideoOpen(void)
{
	pVideo											= &Video;
	pVideo->pSequence								= &pVideo->sequence;
 	pVideo->pGop									= &pVideo->gop;
	pVideo->pPicture								= &pVideo->picture;
	pVideo->pSequenceExtension					= &pVideo->sequenceExtension;
	pVideo->pSequenceDisplayExtension		= &pVideo->sequenceDisplayExtension;
	pVideo->pPictureCodingExtension			= &pVideo->pictureCodingExtension;
	pVideo->pQuantMatrixExtension				= &pVideo->quantMatrixExtension;
	pVideo->pHeaderParser						= &pVideo->headerParser;
	pVideo->pPictureDisplayExtension			= &pVideo->pictureDisplayExtension;
	pVideo->pDecodedFrame = &pVideo->bufABC[0];
	pVideo->pDisplayedFrame = &pVideo->bufABC[2];

	return	pVideo;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoInitDecoder
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Initialse Video Decoder Registers
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoInitDecoder(void)
{
	int i;
	for(i=0; i<QMSIZE; i++)
	{
		pVideo->pSequence->intraQuantiserMatrix[i] = defIntraQuantMatrix[i];
		pVideo->pSequence->nonIntraQuantiserMatrix[i] = 16;
	}

	VideoInitialize();
	pVideo->dcf = 0;
	pVideo->tis = 0;
	pVideo->itm = 0;
	pVideo->displayEnabled = FALSE;
	for(i=0; i<3; i++)
	{
		pVideo->bufABC[i].firstField = TOP;
		pVideo->bufABC[i].nTimesDisplayed = 1;
		pVideo->bufABC[i].nTimesToDisplay = 2;
		pVideo->bufABC[i].pts = 0;
	}

	pVideo->state = videoPowerUp;
	VideoInitPLL(); // Initialize different Clocks
	VideoInitPLL(); // Initialize different Clocks
	VideoEnableDramInterface();
	VideoSetBufferSize();
	VideoSoftReset();
	
	HostDisableIT();
	VideoMaskInterrupt();
	HostEnableIT();
	
	BoardReadVideo(VID_ITS0);
	BoardReadVideo(VID_ITS1);
	BoardReadVideo(VID_ITS2);
	
	
	BoardWriteVideo(PES_CF1, 0x00);
	BoardWriteVideo(PES_CF2, 0x00);

	BoardWriteVideo(VID_TIS, 0);
	BoardWriteVideo(VID_CTL, CTL_EDC | CTL_ERP | CTL_ERS | CTL_ERU);
	pVideo->ctl = CTL_EDC | CTL_ERP | CTL_ERS | CTL_ERU;
	pVideo->dcf |= DCF0_PXD;
	pVideo->dcf |= DCF0_DSR;
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf&0xFF));
	BoardWriteVideo(VID_DCF1, (BYTE)(pVideo->dcf>>8));
	for(i=0; i<20; i++)
	{
		if(!VideoTestReg())
		{
			DbgPrint("*****ERROR IN VIDEO REG TEST ");
			break;
		}
	}
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPause
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Pause the video decoder
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoPause(void)
{
	DPF(("Video Pause Called!!"));
 //	pVideo->command = cmdPause;
  pVideo->state = videoPaused;
	
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPlay
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Play video
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoPlay(void)
{
	DPF(("Video Play Called!!"));
	if(pVideo->state == videoPowerUp)
	{
		HostDisableIT();
		pVideo->itm = ITM_VSB | ITM_VST | ITM_PSD | ITM_SCH;
		BoardWriteVideo(VID_ITM0, (BYTE)pVideo->itm);
		BoardWriteVideo(VID_ITM1, 0);
		BoardWriteVideo(VID_ITM2, 0);
		HostEnableIT();
		pVideo->command = cmdPlay;
	}
	else if(pVideo->state == videoPaused)
	{
		pVideo->state = videoPlaying;		

	}

	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoStop
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Stop video
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoStop(void)
{
	DPF(("Video Stop Called!!"));
	pVideo->command = cmdStop;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoFinishDecoding
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Wait for bit buffer to go empty to decode all pictures
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoFinishDecoding(void)
{
	pVideo->command = cmdEOS;
	DPF(("Video Finish Decoding Called!!"));
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSeek
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: initialize the decoder to restart decoding
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSeek(void)
{
	DPF(("Video Seek Called!!"));
	BoardWriteVideo(VID_ITM0, 0);
	BoardWriteVideo(VID_ITM1, 0);
	BoardWriteVideo(VID_TIS, 0);
	pVideo->itm = 0;

	BoardWriteVideo(VID_CSO, 0);
	pVideo->dcf = DCF0_PXD | DCF0_DSR | DCF0_EVD;
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf&0xFF));
	BoardWriteVideo(VID_DCF1, (BYTE)(pVideo->dcf>>8));
	pVideo->tis = 0;
	BoardWriteVideo(VID_TIS, 0);
	BoardWriteVideo(VID_HDS, 0);
	BoardWriteVideo(VID_LSO, 0);
	BoardWriteVideo(VID_LSR1, 0);
	BoardWriteVideo(VID_LSR0, 0);
	BoardWriteVideo(VID_PAN1, 0);
	BoardWriteVideo(VID_PAN0, 0);
	BoardWriteVideo(VID_PFH, 0);
	BoardWriteVideo(VID_PFV, 0);
	BoardWriteVideo(VID_PPR1, 0);
	BoardWriteVideo(VID_PPR2, 0);
	BoardWriteVideo(VID_SCN1, 0);
	BoardWriteVideo(VID_SCN0, 0);

	VideoSoftReset();
	VideoInitialize();
	VideoResetPSV();
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoInitialize
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Initialze all the variables to their default state
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoInitialize(VOID)
{
	int i;
	pVideo->state = videoPowerUp;
	pVideo->nVsyncsWithoutDsyncs = 0;
	pVideo->codingStandard = MPEG1; // Mpeg1 by default
	pVideo->errorCode	= errNoError;
	pVideo->nDecodedFrames	= 0;
	pVideo->nDisplayedFrames = 0;
	pVideo->command = cmdNone;
	pVideo->firstPPictureFound = FALSE;
	pVideo->skipRequest = FALSE;
	pVideo->skipMode = skipNone;
	pVideo->repeatRequest = FALSE;
	pVideo->starving = FALSE;
	pVideo->scdCount = 0;
	pVideo->prevScdCount = 0;
	pVideo->validPTS = FALSE;
	pVideo->displayEnabled = FALSE;
	pVideo->prevBuf				= 1;
	pVideo->sync		= FALSE;
	pVideo->instructionComputed = FALSE;
	pVideo->pPictureDisplayExtension->horOffset = 0;
	pVideo->pPictureDisplayExtension->verOffset = 0;
	pVideo->nTimesDisplayed = 1;
	pVideo->nTimesToDisplay = 2;
	for(i=0; i<3; i++)
	{
		pVideo->bufABC[i].firstField = TOP;
		pVideo->bufABC[i].nTimesDisplayed = 1;
		pVideo->bufABC[i].nTimesToDisplay = 2;
		pVideo->bufABC[i].pts = 0;
	}

	pVideo->firstField = TOP;
	pVideo->curImage = FRM;
	pVideo->panScan = FALSE;
	pVideo->prevPTS = 0;
	pVideo->firstPtsFound = FALSE;
	pVideo->firstFramePTS = 0;
	pVideo->lastFrameDecoded	= FALSE;
	pVideo->resetAndRestart = FALSE;
	pVideo->prevVsyncTop = FALSE;
	TraceReset();
	FifoOpen();
	FifoReset();

	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoEnableDramInterface
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Enable the clocks and memory refresh
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoEnableDramInterface(void)
{
	BoardWriteVideo(CFG_MCF, MCF_REFRESH);
	// Bus width is 64 bits, enable all interfaces
	BoardWriteVideo(CFG_CCF, (BYTE)( CCF_PBO | CCF_EC3 | CCF_EC2 | CCF_ECK | CCF_EDI | CCF_EVI) );
	BoardWriteVideo(CFG_DRC, 0x00);
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSetBufferSize
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Partition the Bit buffer for Audio/Video/OSD/PICT Buffers
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSetBufferSize (void)
{
	DWORD abg, abs, vbg, vbs, abt, vbt;
	
	pVideo->audioBufferSize = 0x120;
	pVideo->spBufferSize	= 0x152;
	pVideo->videoBufferSize = MEM_SIZE - 3 * PSZ_NTSC -
					pVideo->audioBufferSize - 2 - pVideo->spBufferSize;
	pVideo->bufABC[0].adr = MEM_SIZE - 3*PSZ_NTSC;
	pVideo->bufABC[1].adr = MEM_SIZE - 2*PSZ_NTSC;
	pVideo->bufABC[2].adr = MEM_SIZE - PSZ_NTSC;
	
	vbt = pVideo->videoBufferSize;
	abt = pVideo->audioBufferSize;
	vbg = 0;
	vbs = vbt;
	abg = vbs+1+pVideo->spBufferSize;
	abs = abg+abt;
	
	BoardWriteVideo(VID_ABG1, (BYTE)(abg>>8));
	BoardWriteVideo(VID_ABG0, (BYTE)(abg));
	BoardWriteVideo(VID_ABS1, (BYTE)(abs >> 8));
	BoardWriteVideo(VID_ABS0, (BYTE)(abs));
	BoardWriteVideo(VID_ABT1, (BYTE)(abt >> 8));
	BoardWriteVideo(VID_ABT0, (BYTE)(abt));

	BoardWriteVideo(VID_VBG1, 0);
	BoardWriteVideo(VID_VBG0, 0);
	BoardWriteVideo(VID_VBS1, (BYTE)(vbs >> 8));
	BoardWriteVideo(VID_VBS0, (BYTE)(vbs));
	BoardWriteVideo(VID_VBT1, (BYTE)(vbt >> 8));
	BoardWriteVideo(VID_VBT0, (BYTE)(vbt));
	
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoInitPLL
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program the PLL for different clocks
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoInitPLL(void)
{
	// Program the PLL

	// Select PixClock as refence clock and generate other clocks
 	// from PIXCLK
	BoardWriteVideo(CKG_PLL, PLL_SELECT_PIXCLK | PLL_DEVIDE_BY_N | PLL_MULT_FACTOR);

	// Program video clock
	BoardWriteVideo(CKG_VID, 0x22);
	BoardWriteVideo(CKG_VID, 0x08);
	BoardWriteVideo(CKG_VID, 0x5f);
	BoardWriteVideo(CKG_VID, 0x0f);

	//Program audio clock
	BoardWriteVideo(CKG_AUD, 0x2b);
	BoardWriteVideo(CKG_AUD, 0x02);
	BoardWriteVideo(CKG_AUD, 0x5f);
	BoardWriteVideo(CKG_AUD, 0x5f);


	// Select directions for different clocks
	BoardWriteVideo(CKG_CFG,
				CFG_INTERNAL_AUDCLK |
				CFG_INTERNAL_CLK 	  |
				CFG_PIXCLK_INPUT 	  |
				CFG_PCMCLK_INPUT 	  |
				CFG_MEMCLK_INPUT 	  |
				CFG_AUDCLK_OUTPUT	);
	
	return TRUE;
}



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoWaitTillHDFNotEmpty
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Wait for HDF to have some bytes for decoding
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoWaitTillHDFNotEmpty (void)
{
	BYTE	b;
	DWORD	cnt = 0;
	// Make sure that HDF is not empty for header processing
	// this could be a problem in case of PIO
	do {
		b = BoardReadVideo(VID_STA1);
		b = BoardReadVideo(VID_STA0);
		cnt++;
		if(cnt > 0xFFFF)
		{
			TRAP
			pVideo->errorCode = errHeaderFifoEmpty;
			return FALSE;
		}
	} while (b & ITM_HFE);

	return TRUE;
}



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoInitHeaderParser
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Initialise HDF related stuff to do header parsing
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

	BOOL	VideoInitHeaderParser (void)
{
	PHEADERPARSER pHdf;

	if(!VideoWaitTillHDFNotEmpty())
		return FALSE; // Header Fifo is empty
	pHdf = pVideo->pHeaderParser;

	pHdf->b 		= BoardReadVideo(VID_HDF); // First Byte
	pHdf->next 	= BoardReadVideo(VID_HDF); // Next Byte

	pHdf->first = TRUE;
	pHdf->second = (pHdf->b != 0x01);
	// If first byte is not 0x01, then it must be the start
	// code itself.
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Video Interrupt handling
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoInterrupt(void)
{
	VideoMaskInterrupt();
	do {
		BoardReadVideo(VID_ITS2);
		pVideo->its = (WORD)BoardReadVideo(VID_ITS1) << 8;
		pVideo->its |= BoardReadVideo(VID_ITS0);
		pVideo->its &= pVideo->itm;



		if(pVideo->its & ITM_PSD)
		{
			TraceIntr(dsync, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoDsyncInterrupt();
		}

		if(pVideo->its & ITM_SCH)
		{
			VideoHeaderHit();
		}

		if(pVideo->its & ITM_VSB)
		{
//			TraceIntr(vsb, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoVsyncInterrupt(FALSE); // Bot Vsync
		}

		if(pVideo->its & ITM_VST)
		{
			SubPicIRQ(pSPstrmex);
//			TraceIntr(vst, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoVsyncInterrupt(TRUE); // Top Vsync

			//
			// update any clock activity.
			//
		
			ClockEvents(pDevEx);
		}

		// Error Handling is done here
		if(pVideo->its & ITM_PER)
		{
			DPF(("PIPELINE Error!!!!!!"));
			pVideo->errorCode	= errPipeline;
			pVideo->state = videoErrorRecover;
			TraceIntr(error, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		}
		
		if(pVideo->its & ITM_SER)
		{
			DPF(("SERIOUS Error!!!!!!"));
			pVideo->errorCode	= errSerious;
			BoardWriteVideo(VID_CTL, CTL_PRS);
			Delay(1000);
			BoardWriteVideo(VID_CTL, (BYTE)(pVideo->ctl));
			pVideo->state = videoErrorRecover;
			TraceIntr(error, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		}


	} while(pVideo->its);


	VideoUnmaskInterrupt();
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoDsyncInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: DSYNC is done here
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoDsyncInterrupt(void)
{
static ULONG cSkip = 0;
static ULONG cHold = 0;

	pVideo->nVsyncsWithoutDsyncs = 0;

	if ((pVideo->nDecodedFrames >= 3) &&
		(pVideo->firstPPictureFound))
	{
//		BoardWriteVideo(VID_TIS, 0); // Wait mode
		VideoGetBBL();
		if ((pVideo->bbl < pVideo->videoBufferSize/4) &&
				(pVideo->state == videoPlaying))
		{
			pVideo->starving = TRUE;
			BoardWriteVideo(VID_CTL, 0);
		}
		
//		VideoProgramPanScanVectors();

		if(pVideo->nDecodedFrames>3)
		{
			VideoProgramDisplayBuffer();
			TraceTref(pVideo->pDisplayedFrame->tref, pVideo->pDisplayedFrame->frameType);
		}

		if(pVideo->pDisplayedFrame->pts)
		{
		
			pVideo->validPTS = TRUE;
			pVideo->framePTS = pVideo->pDisplayedFrame->pts;
			pVideo->pDisplayedFrame->pts = 0;
		}
		else
		{
			pVideo->validPTS = FALSE;
			if(pVideo->pDisplayedFrame->curField == FRM)
			{
				pVideo->framePTS = pVideo->prevPTS + FRAME_PERIOD;
			}
			else
			{
				pVideo->framePTS = pVideo->prevPTS + FIELD_PERIOD;
			}
		}		

		pVideo->prevPTS = pVideo->framePTS;
  /* rate changes */
		//if(pVideo->validPTS && pVideo->sync && (slowmode == 1) && hClk)
		if (pVideo->validPTS && hClk && slowmode ==1)
 /* end rate changes */
		{
			DWORD stc;

  			VideoGetBBL();
			VideoGetABL();

			/* rate changes */
	  		stc = (ULONG)((ULONGLONG)GetStreamPTS(pVideoStream) * (ULONGLONG)VidRate / (ULONGLONG)1000);
			/* end rate changes */

			if((pVideo->nDecodedFrames > 20) &&
				(!pVideo->skipRequest) &&
					(!pVideo->repeatRequest))
			{
				if(pVideo->framePTS > stc + 7000)
				{
			 		// Video is Leading
					// Next picture will be repeated
					pVideo->repeatRequest = TRUE;
					cSkip ++;

				}
				else if(stc > pVideo->framePTS + 7000)
				{
				 	// Video is Lagging
					// Next picture will be skipped
					pVideo->skipRequest = TRUE;

					cHold ++;

				}
				else
				{
					cSkip = cHold = 0;
				}
			}
	
 		}
	}
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoVsyncInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: VSYNC is done here
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoVsyncInterrupt(BOOL Top)
{

	pVideo->nVsyncsWithoutDsyncs++;
	if(Top)
	{
		pVideo->curField = TOP;
	}
	else
	{
		pVideo->curField = BOT;
	}

	switch(pVideo->state)
	{
		case videoPowerUp :
			if(pVideo->command == cmdPlay)
			{
				VideoGetBBL();
				if( pVideo->bbl > MINVBL)
				{
					pVideo->tis = TIS_EXE;
					BoardWriteVideo(VID_TIS, (BYTE)pVideo->tis);
					pVideo->state = videoStartUp;
					pVideo->command = cmdNone;
				}
			}
		break;

		case videoErrorRecover:
	case videoPlaying:
	
			if(Top&pVideo->prevVsyncTop)
				pVideo->pDisplayedFrame->nTimesDisplayed+=2; // missed one
			else
				pVideo->pDisplayedFrame->nTimesDisplayed++;

			if(pVideo->starving)
			{
				VideoGetBBL();
				if(pVideo->bbl > pVideo->videoBufferSize*3/4)
				{
					pVideo->starving = FALSE;
					BoardWriteVideo(VID_CTL, CTL_EDC | CTL_ERP | CTL_ERS | CTL_ERU);
					if((pVideo->pDisplayedFrame->nTimesDisplayed >=pVideo->pDisplayedFrame
						->nTimesToDisplay) && (pVideo->instructionComputed))
					{
						
							TraceIntr(storevs, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
							VideoStoreInstruction();
					}

				}
				else
				{
				}
			}
			else
			{
				if((pVideo->pDisplayedFrame->nTimesDisplayed >=pVideo->pDisplayedFrame
					->nTimesToDisplay) && (pVideo->instructionComputed))

				{
					
//					if((pVideo->pDisplayedFrame->firstField == pVideo->curField)
//						|| (pVideo->pDisplayedFrame->curField == FRM))
					{
						VideoStoreInstruction();
					}
				}

			}
			switch(pVideo->command)
			{
				 case cmdPause:
					pVideo->state = videoPaused;
					pVideo->command = cmdNone;
				 break;
				
				 case cmdEOS:
				 	DPF(("End of Stream Encountered!!\n"));
					pVideo->state = videoEOS;
					pVideo->command = cmdNone;

				 break;
				 case cmdNone:
				 default:
				 break;
			
			 }
		break;

		case videoPaused:
		break;

		case videoEOS :
			VideoGetBBL();
			if(pVideo->bbl < 2)
			{
				pVideo->state = videoPaused;
				BoardWriteVideo(VID_TIS, 0);
			 	DPF(("Pausing after EOS!!!\r\n"));
			}
		break;
		
		case videoInit:

				if(pVideo->curField == pVideo->pDecodedFrame->firstField)
				{
					if(pVideo->instructionComputed)
					{
						pVideo->state = videoFirstFrameDecoded;
						// Start Decoding the next Picture
						VideoSetReconstructionBuffer(pVideo->frameType);
						VideoSetDisplayBuffer(pVideo->frameType);
						VideoStoreInstruction();	
						BoardWriteVideo(VID_DFP0, 	(BYTE)(pVideo->pDecodedFrame->adr));
						BoardWriteVideo(VID_DFP1, 	(BYTE)(pVideo->pDecodedFrame->adr >> 8));
						pVideo->displayEnabled = TRUE;
						VideoForceBKC(FALSE);
						Delay(2000);
					}
					else
					{
						TRAP
					}
				}
				break;

		case videoFirstFrameDecoded:
				VideoGetBBL();
				if((pVideo->bbl+ 5 > pVideo->videoBufferSize)
					&& (pVideo->instructionComputed))
				{		
					if(pVideo->curField == pVideo->pDecodedFrame->firstField)
					{
						pVideo->state = videoPlaying;
						// Start Decoding the next Picture
						VideoComputePictureBuffers();
						VideoStoreInstruction();	
						pVideo->itm |= (ITM_PER | ITM_SER);
						if(pAc3->ac3Data)
							Ac3Play();
					}
				}
			break;


	}
	
	VideoDisplaySingleField(Top);
	pVideo->prevVsyncTop = Top;

	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoErrorInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Error Handling
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoErrorInterrupt(void)
{
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoHeaderHit
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Header analysis is done here
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoHeaderHit (void)
{
	BYTE sc;

	if(!VideoInitHeaderParser())
		return FALSE; // Header Fifo is empty
	VideoNextHeaderByte();
	// Now pVideo->pHeaderParser->b contains the start Code

	sc = pVideo->pHeaderParser->b;

	if ((sc >= SLICESTART_SC) && (sc <= SLICEEND_SC))
		sc = SLICE_SC;

	switch(sc)
	{
		case SEQUENCE_SC 			:
			TraceIntr(seq, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoSequenceHeader();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;

		case GOP_SC		  			:
			TraceIntr(gop, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoGopHeader();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;

		case PICTURE_SC 			:
			TraceIntr(pict, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoPictureHeader();
			if((pVideo->skipMode == skipOneFrame) ||
			(pVideo->skipMode == skipTwoFields) ||
			(pVideo->skipMode == skipSecondField))
			{
				BoardWriteVideo(VID_HDS, HDS_HDS);
			}
		break;

		case EXTENSION_SC			:
			TraceIntr(ext, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoExtensionHeader();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;

		case SEQUENCE_END_SC		:
			TraceIntr(seqend, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoSequenceEnd();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;

		case SEQUENCE_ERROR_SC	:
			VideoSequenceError();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;

		case USER_SC				 :
			VideoUserData();
			BoardWriteVideo(VID_HDS, HDS_HDS);
		break;
		
		case SLICE_SC				:
		break;

		case HACKED_SC				:
			pVideo->lastFrameDecoded = TRUE;
		break;
	}
	
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoNextHeaderByte
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Read the next byte off hdf and put in b
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoNextHeaderByte (void)
{
	PHEADERPARSER pHdf;
	pHdf = pVideo->pHeaderParser;

	if(pHdf->second)
	{
		pHdf->second = FALSE;
	}
	else if (pHdf->first)
	{
		pHdf->first = FALSE;
		pHdf->b = pHdf->next;
	}
	else  // Read next HDF word
	{
		pHdf->b 		= BoardReadVideo(VID_HDF); // First Byte
		pHdf->next 	= BoardReadVideo(VID_HDF); // Next Byte
		pHdf->first = TRUE;
	}
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//	FUNCTION : VideoNextSC
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Search the next startCode in the stream
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoNextSC (void)
{
	PHEADERPARSER pHdf;
	int i = 0, j, k;
	pHdf = pVideo->pHeaderParser;
	
    for (j = 1; j < 1000; j++) {

	    for (k = 1; k < 10000; k++)  {

    		if(pHdf->b)
	    		i = 0;
    		else
	    		i++;
		     VideoNextHeaderByte();

             if ((i >= 2) && (pHdf->b == 0x01)) return TRUE;
        }


        KeStallExecutionProcessor(100);

    }

    // bugbug - what do we return in this case??

	return TRUE;
}



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Sequence header handling
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceHeader (void)
{
	PSEQUENCEHEADER	pSeq;
	PHEADERPARSER		pHdf;
	BYTE					b;
	int					i;
    pSeq = pVideo->pSequence;
	pHdf = pVideo->pHeaderParser;
	
//	DPF(("SEQ_SC"));

	VideoNextHeaderByte();
	pSeq->horSize = (DWORD)((DWORD)pHdf->b << 4);
	VideoNextHeaderByte();
	pSeq->horSize |= (DWORD)(pHdf->b >> 4);
	pSeq->verSize = ((DWORD)(pHdf->b << 8) & 0xF00);
	VideoNextHeaderByte();
	pSeq->verSize |= pHdf->b;
	VideoNextHeaderByte();
	pSeq->aspectRatio	= pHdf->b >> 4;
	pSeq->frameRate  	= pHdf->b & 0x0F;
	VideoNextHeaderByte();
	pSeq->bitRate  	= (DWORD)pHdf->b << 10;
	VideoNextHeaderByte();
	pSeq->bitRate  	|= (DWORD)pHdf->b << 2;
	VideoNextHeaderByte();
	pSeq->bitRate  	|= (DWORD)pHdf->b >> 6;
	pSeq->vbvBufferSize = ((DWORD)pHdf->b & 0x01F) << 5;
	VideoNextHeaderByte();
	pSeq->vbvBufferSize |= (DWORD)(pHdf->b >> 3);
	pSeq->constrainedFlag = (DWORD)(pHdf->b >> 2) & 0x01;
	pSeq->loadIntra = (pHdf->b >> 1) & 0x01;
	if(pSeq->loadIntra)
	{
		for(i=0; i<QMSIZE; i++)
		{
			b = pHdf->b;
			VideoNextHeaderByte();
			pSeq->intraQuantiserMatrix[i] = ((b&0x01) << 7) | (pHdf->b >> 1);
		}
		VideoLoadQuantMatrix(TRUE);
	}
	pSeq->loadNonIntra = pHdf->b & 0x01;

	if(pSeq->loadNonIntra)
	{
		for(i=0; i<QMSIZE; i++)
		{
			VideoNextHeaderByte();
			pSeq->nonIntraQuantiserMatrix[i] = pHdf->b;
		}
		VideoLoadQuantMatrix(FALSE);
	}		
/*	if(pVideo->state == videoStartUp)
	{*/
		VideoProgramDisplayWindow();
	//}
	
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoGopHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Handle the GOP header
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoGopHeader (void)
{
	PGOPHEADER			pGop;
	PHEADERPARSER		pHdf;
	
//	DPF(("GOP_SC"));
 	pGop = pVideo->pGop;
	pHdf = pVideo->pHeaderParser;

	VideoNextHeaderByte();
	pGop->timeCode = ((DWORD)pHdf->b << 17);
	VideoNextHeaderByte();
	pGop->timeCode |= ((DWORD)pHdf->b << 9);
	VideoNextHeaderByte();
	pGop->timeCode |= ((DWORD)pHdf->b << 1);
	VideoNextHeaderByte();
	pGop->timeCode |= (pHdf->b >> 7);
	pGop->closedGOP = ((pHdf->b >> 6) & 0x01);
	pGop->brokenLink = ((pHdf->b >> 5) & 0x01);
	
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPictureHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Handle PCTURE header
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL  VideoPictureHeader (void)
{
	BYTE sc;
//	DPF(("PICT"));
	VideoAssociatePTS();
	VideoParsePictureHeader();
	VideoNextSC();
	VideoNextHeaderByte();
	sc = pVideo->pHeaderParser->b;
	if ((sc >= SLICESTART_SC) && (sc <= SLICEEND_SC))
	{
		sc = SLICE_SC;
	}
	while (sc != SLICE_SC)
	{
		switch(sc)
		{
			case EXTENSION_SC			:
			TraceIntr(ext, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
				VideoExtensionHeader();
			break;

			case USER_SC				 :
			TraceIntr(usr, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
				VideoUserData();
			break;
			default :
			TraceIntr(unknown, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			pVideo->errorCode = errStartCode;
			break;
		}
		VideoNextSC();
		VideoNextHeaderByte();
		sc = pVideo->pHeaderParser->b;
		if ((sc >= SLICESTART_SC) && (sc <= SLICEEND_SC))
		{
			sc = SLICE_SC;
		}
	}

	BoardReadVideo(VID_ITS2);
	pVideo->its = (WORD)BoardReadVideo(VID_ITS1) << 8;
	pVideo->its |= (BoardReadVideo(VID_ITS0) &0xFE);
	pVideo->its &= pVideo->itm;

	pVideo->nDecodedFrames++;

	switch(pVideo->state)
	{
		case videoStartUp:
			pVideo->state = videoInit;
			VideoProgramDisplayWindow();
		  	VideoComputeInstruction();
		break;

		case videoFirstFrameDecoded:
		  	VideoComputeInstruction();
		break;
		
		case videoPlaying :		
		case videoPaused 	:		
		case videoEOS 		:		
		case videoStopped :
		
		if ((pVideo->frameType == BFrame) &&
		((pVideo->curImage == FRM) ||
		(pVideo->curImage == pVideo->firstField)) &&
		(pVideo->skipMode == skipNone) &&
		(pVideo->skipRequest))
		{
			// Frame or First Field
			pVideo->skipRequest = FALSE;
			TraceIntr(skips, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			if(pVideo->curImage == FRM)	
				pVideo->skipMode = skipOneFrame;
			else
				pVideo->skipMode = skipTwoFields;
		}					
		else
		{
			VideoSkipOrDecode();
		}
		break;
	}		

	return TRUE;

}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSkipOrDecode
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Skip one or two pictures
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSkipOrDecode(void)
{
	switch(pVideo->skipMode)
	{
		case skipNone :
			VideoComputePictureBuffers();
		  	VideoComputeInstruction();
			TraceIntr(skipn, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
  	    break;
				
		case skipOneFrame:
			VideoComputePictureBuffers();
		  	VideoComputeInstruction();
			pVideo->skipMode = skipNone;	
			pVideo->tis |= (TIS_SKIP1P);
			pVideo->nTimesToDisplay = 2;
			TraceIntr(skipf, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		break;
				
		case skipTwoFields:
			pVideo->skipMode = skipSecondField;	
			TraceIntr(skip1, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		break;
		
		case skipSecondField:
			VideoComputePictureBuffers();
		  	VideoComputeInstruction();
			pVideo->skipMode = skipNone;	
			pVideo->tis |= TIS_SKIP2P;
			TraceIntr(skip2, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
			VideoStoreInstruction();
		break;
				
		case skipDone:
			// last picture was skipped
			pVideo->skipMode = skipNone;
			VideoComputePictureBuffers();
	  		VideoComputeInstruction();
			TraceIntr(skipd, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		break;
	}

	if(pVideo->repeatRequest)
	{
		pVideo->pDecodedFrame->nTimesToDisplay += 2;
		pVideo->repeatRequest = FALSE;
	}

	pVideo->pDecodedFrame->nTimesToDisplay *= slowmode;

	if((pVideo->pDisplayedFrame->nTimesDisplayed >=
		pVideo->pDisplayedFrame->nTimesToDisplay) &&
		(pVideo->instructionComputed))
	{
		TraceIntr(storepi, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
		VideoStoreInstruction();
	}

	return TRUE;
}
	
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoComputePictureBuffers
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program RFP,BFP,FFP,DFP
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoComputePictureBuffers(void)
{
//	if((pVideo->curImage == FRM) || (pVideo->curImage == pVideo->firstField))
	{
		VideoSetReconstructionBuffer(pVideo->frameType);
		VideoSetDisplayBuffer(pVideo->frameType);
	}
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoParsePictureHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract parameters off picture header
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoParsePictureHeader (void)
{
	PPICTUREHEADER pPict = pVideo->pPicture;
	PHEADERPARSER pHdf = pVideo->pHeaderParser;
	int i;
	BYTE nextBit;

	VideoNextHeaderByte();
	pPict->temporalReference = ((DWORD)pHdf->b << 2);
	VideoNextHeaderByte();
	pPict->temporalReference |= ((DWORD)pHdf->b >> 6);
	i = (pHdf->b >> 3) & 0x07;

	pPict->pictureCodingType = i;
	switch(i)
	{
		case 1:
			pVideo->frameType = IFrame;
		break;

		case 2:
			if(!pVideo->firstPPictureFound)
				pVideo->firstPPictureFound = TRUE;
			pVideo->frameType = PFrame;
		break;

		case 3:
			pVideo->frameType = BFrame;
		break;

		default:
			pVideo->errorCode = errInvalidPictureType;
		break;
	}
	pPict->vbvDelay = (DWORD)((DWORD)pHdf->b & 0x07) << 13;
	VideoNextHeaderByte();
	pPict->vbvDelay |= ((DWORD)pHdf->b << 5);
	VideoNextHeaderByte();
	pPict->vbvDelay |= ((DWORD)pHdf->b >> 3);
	i = 3; // 3 bits remaining
	if (pVideo->frameType != IFrame)
	{
		pPict->fFcode = (pHdf->b <<1 ) &0x0F;
		VideoNextHeaderByte();
		pPict->fFcode |= (pHdf->b >>7 );
		i = 7; // 7 bits remaining
		if (pVideo->frameType == BFrame)
		{
			pPict->bFcode = (pHdf->b >> 3)&0x0F;
			i = 3; // 3 bits remaining
		}
	}

	nextBit = 0x01 << (i-1);
	while(pHdf->b & nextBit)
	{
		VideoNextHeaderByte();
		i = i-1;
		if(i==0)
			i = 8;
		nextBit = 0x01 << (i-1);
	}

	if( (nextBit-1) & pHdf->b)
	{
		pVideo->errorCode = errStartCode;
		TRAP
		DPF(("ERROR!!!! i=%x ", i));
		DPF(("ERROR!! b=%x ", pHdf->b));
	}

	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program the extension header
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoExtensionHeader (void)
{
	pVideo->codingStandard = MPEG2;
	VideoNextHeaderByte();

	// first 4 bits are ID
//	DPF(("EXT_SC"));

	switch(pVideo->pHeaderParser->b >> 4)
	{
		case SEQUENCE_EXTENSION_ID :
			VideoSequenceExtensionHeader();
		break;

		case SEQUENCE_DISPLAY_EXTENSION_ID :
			VideoSequenceDisplayExtensionHeader();
		break;
		
		case QUANT_MATRIX_EXTENSION_ID :
			VideoQuantMatrixExtensionHeader();
		break;

		case COPYRIGHT_EXTENSION_ID :
			VideoCopyrightExtensionHeader();
		break;

		case SEQUENCE_SCALABLE_EXTENSION_ID :
			VideoSequenceScalableExtensionHeader();
		break;

		case PICTURE_DISPLAY_EXTENSION_ID :
			VideoPictureDisplayExtensionHeader();
		break;

		case PICTURE_CODING_EXTENSION_ID :
			VideoPictureCodingExtensionHeader();
		break;

		case PICTURE_SPATIAL_SCALABLE_EXTENSION_ID :
			VideoPictureSpatialScalableExtensionHeader();
		break;

		case PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID :
			VideoPictureTemporalScalableExtensionHeader();
		break;
	}
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceEnd
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: End of sequence Processing
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceEnd(void)
{
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceError
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Error Concealment
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceError(void)
{
	return TRUE;
}


/*
** GetCCTime ()
**
**    find the time for the next cc request
**
** Arguments:}
**
**
**
** Returns:
**
** Side Effects:
*/


ULONGLONG GetCCTime()
{

	if (pVideo->pts)
	{
		return (ConvertPTStoStrm(pVideo->pts));
	}

	return(ConvertPTStoStrm(GetStreamPTS(pVideoStream)));
}

/*
** CCSendDiscontinuity ()
**
**	  Send a DataDiscontinuity to the close caption decoder
**
** Arguments:
**
**
**
** Returns:
**
** Side Effects:
*/


VOID CCSendDiscontinuity(void)
{
PHW_STREAM_REQUEST_BLOCK pSrb;
PKSSTREAM_HEADER   pPacket;

	if (pDevEx->pstroCC && ((PSTREAMEX)(pDevEx->pstroCC->HwStreamExtension))->state
					== KSSTATE_RUN )
	{
		if (pSrb = CCDequeue())
		{
			//
			// we have a request, send a discontinuity
			//

			pSrb->Status = STATUS_SUCCESS;
			pPacket = pSrb->CommandData.DataBufferArray;

			pPacket->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY |
			KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
			pPacket->DataUsed = 0;
			pSrb->NumberOfBuffers = 0;

			pPacket->PresentationTime.Time = GetCCTime();
			pPacket->Duration = 1000;

			StreamClassStreamNotification(StreamRequestComplete,
					pSrb->StreamObject,
					pSrb);

		}
		else
		{
			TRAP
		}
	}

}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoUserData
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract User Data
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoUserData(void)
{
	ULONG cCCData;
	PBYTE pDest;
	PHW_STREAM_REQUEST_BLOCK pSrb;
	PHEADERPARSER		pHdf;
PKSSTREAM_HEADER   pPacket;
	pHdf = pVideo->pHeaderParser;

	//
	// check if the close caption pin is open and running, and that
	// we have a data packet avaiable
	//

	if (pDevEx->pstroCC && ((PSTREAMEX)(pDevEx->pstroCC->HwStreamExtension))->state
					== KSSTATE_RUN )
	{
		if (pSrb = CCDequeue())
		{

			//
			// check the SRB to ensure it can take at least the header
			// information from the GOP packet
			//

			if (pSrb->CommandData.DataBufferArray->FrameExtent < sizeof(KSGOP_USERDATA))
			{
				TRAP

				pSrb->Status = STATUS_INVALID_BUFFER_SIZE;

				pSrb->ActualBytesTransferred = 0;

				StreamClassStreamNotification(StreamRequestComplete,
						pSrb->StreamObject,
						pSrb);

				return TRUE;
		
			}

			//
			// fill in the header
			//

			pDest = pSrb->CommandData.DataBufferArray->Data;

			//
			// fill in the start code
			//

			*(PULONG)pDest = 0xB2010000;
			pDest += 4;

			//
			// pick up the next two header bytes
			//

			VideoNextHeaderByte();
			*pDest++= pHdf->b;

			VideoNextHeaderByte();
			*pDest++= pHdf->b;

			VideoNextHeaderByte();
			*pDest++= pHdf->b;
		
			VideoNextHeaderByte();
			*pDest++= pHdf->b;


			//
			// pick up the count field
			//

			VideoNextHeaderByte();
			*pDest++= pHdf->b;

			cCCData = (ULONG)pHdf->b & 0x3f;

			if (pSrb->CommandData.DataBufferArray->FrameExtent <
					(cCCData -1) * 3 + sizeof (KSGOP_USERDATA))
			{
				TRAP

				pSrb->Status = STATUS_INVALID_BUFFER_SIZE;

				pSrb->ActualBytesTransferred = 0;

				StreamClassStreamNotification(StreamRequestComplete,
						pSrb->StreamObject,
						pSrb);

				return TRUE;
		
			}

			//
			// indicate the amount of data transferred
			//

			pSrb->CommandData.DataBufferArray->DataUsed =
				pSrb->ActualBytesTransferred =
					(cCCData -1 ) * 3 + sizeof (KSGOP_USERDATA);

			//
			// copy the bits
			//

			for (;cCCData; cCCData--)
			{
				VideoNextHeaderByte();
				*pDest++= pHdf->b;
	
				VideoNextHeaderByte();
				*pDest++= pHdf->b;
	
				VideoNextHeaderByte();
				*pDest++= pHdf->b;

			}

			pSrb->Status = STATUS_SUCCESS;

			pPacket = pSrb->CommandData.DataBufferArray;

			pPacket->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
						KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
			pSrb->NumberOfBuffers = 1;

			pPacket->PresentationTime.Time = GetCCTime();
			pPacket->Duration = 1000;

			StreamClassStreamNotification(StreamRequestComplete,
					pSrb->StreamObject,
					pSrb);

			return TRUE;

		}
		else // no SRB!
		{
			TRAP
		}
	}

	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract Sequence Extension Parameters
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceExtensionHeader (void)
{
	PSEQUENCEEXTENSION pExt = pVideo->pSequenceExtension;
	PHEADERPARSER 						 pHdf = pVideo->pHeaderParser;

	pExt->profileAndLevel = ((DWORD)pHdf->b&0x0F) << 4;
	VideoNextHeaderByte();
	pExt->profileAndLevel |= ((DWORD)pHdf->b) >> 4;
	pExt->progressiveSequence = (pHdf->b >> 3) & 0x01;
	pExt->chromaFormat = (pHdf->b >> 1) & 0x03;
	pExt->horSizeExtension = (pHdf->b&0x01 ) << 1;
	VideoNextHeaderByte();
	pExt->horSizeExtension |= (pHdf->b >> 7);
	pVideo->pSequence->horSize |= (pExt->horSizeExtension << 12);
	pExt->verSizeExtension = (pHdf->b >> 5) & 0x03;
	pVideo->pSequence->verSize |= (pExt->verSizeExtension << 12);
	pExt->bitRateExtension = ((DWORD)pHdf->b&0x1F) << 7 ;
	VideoNextHeaderByte();
	pExt->bitRateExtension |= ((DWORD)pHdf->b >> 1);
	pVideo->pSequence->bitRate |= (pExt->bitRateExtension << 18);
	VideoNextHeaderByte();
	pExt->vbvBufSizeExtension = pHdf->b;
	pVideo->pSequence->vbvBufferSize |= (pExt->vbvBufSizeExtension << 10);
	VideoNextHeaderByte();
	pExt->frameRateExtensionN = (pHdf->b >> 5)&0x03;
	pExt->frameRateExtensionD = pHdf->b & 0x1F;
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceDisplayExtension
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract sequence display extension parameters
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceDisplayExtensionHeader(void)
{
	PSEQUENCEDISPLAYEXTENSION	pDispExt = pVideo->pSequenceDisplayExtension;
	PHEADERPARSER 						 pHdf = pVideo->pHeaderParser;

	pDispExt->videoFormat = (pHdf->b >> 1) & 0x07;
	pDispExt->colorDescription = (pHdf->b ) & 0x01;
	if(pDispExt->colorDescription)
	{
		VideoNextHeaderByte();
		pDispExt->colorPrimaries = pHdf->b;
		VideoNextHeaderByte();
		pDispExt->transferCharacteristic = pHdf->b;
		VideoNextHeaderByte();
		pDispExt->matrixCoefficients = pHdf->b;
	}


	//
	// check sizes here
	//

	VideoNextHeaderByte();
	pDispExt->displayHorSize = (DWORD)pHdf->b << 6;
	VideoNextHeaderByte();
	pDispExt->displayHorSize |= ((DWORD)pHdf->b >> 2);
	pDispExt->displayVerSize = ((DWORD)(pHdf->b&0x01) << 13);
	VideoNextHeaderByte();
	pDispExt->displayVerSize |= ((DWORD)pHdf->b << 5);
	VideoNextHeaderByte();
	pDispExt->displayVerSize |= ((DWORD)pHdf->b >> 3);
	//pVideo->panScan = TRUE;
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSequenceScalableExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract the sequence Scalable parameters
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSequenceScalableExtensionHeader(void)
{
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoCopyrightExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract copyright extension
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoCopyrightExtensionHeader(void)
{
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoQuantMatrixExtension
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract Quant Matrices
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoQuantMatrixExtensionHeader(void)
{
	PQUANTMATRIXEXTENSION pQuant = pVideo->pQuantMatrixExtension;
	PSEQUENCEHEADER			 pSeq	  = pVideo->pSequence;
	PHEADERPARSER			 pHdf	  = pVideo->pHeaderParser;
	BYTE b;
	int i;
	
	if(pHdf->b & 0x08)
	{
		for(i=0; i<QMSIZE; i++)
		{
			b = pHdf->b;
			VideoNextHeaderByte();
			pQuant->intraQuantMatrix[i] = pSeq->intraQuantiserMatrix[i] = ((b&0x07) << 5) | (pHdf->b >> 3);
		}
		VideoLoadQuantMatrix(TRUE);
	}

	if(pHdf->b & 0x04)
	{
		for(i=0; i<QMSIZE; i++)
		{
			b = pHdf->b;
			VideoNextHeaderByte();
			pQuant->nonIntraQuantMatrix[i] = pSeq->nonIntraQuantiserMatrix[i] = ((b&0x03) << 6) | (pHdf->b >> 2);
		}
		VideoLoadQuantMatrix(FALSE);
	}
	if(pHdf->b & 0x02)
	{
		for(i=0; i<QMSIZE; i++)
		{
			b = pHdf->b;
			VideoNextHeaderByte();
			pQuant->chromaIntraQuantMatrix[i] = ((b&0x01) << 7) | (pHdf->b >> 1);
		}
	}

	if(pHdf->b & 0x02)
	{
		for(i=0; i<QMSIZE; i++)
		{
			VideoNextHeaderByte();
			pQuant->chromaNonIntraQuantMatrix[i] = pHdf->b;
		}
	}
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPictureCodingExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract picture coding parameters
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoPictureCodingExtensionHeader(void)
{
	PPICTURECODINGEXTENSION pCodingExt =
					pVideo->pPictureCodingExtension;
	PHEADERPARSER			 pHdf	  = pVideo->pHeaderParser;

	pCodingExt->fCode[0][0] = (pHdf->b & 0x0F);
	VideoNextHeaderByte();
	pCodingExt->fCode[0][1] = (pHdf->b >> 4);
	pCodingExt->fCode[1][0] = (pHdf->b & 0x0F);
	VideoNextHeaderByte();
	pCodingExt->fCode[1][1] = (pHdf->b >> 4);
	pCodingExt->intraDCPrecision = (pHdf->b&0xF)>>2;		
	pCodingExt->pictureStructure = (pHdf->b &0x03);		
	VideoNextHeaderByte();
	pCodingExt->topFieldFirst = (pHdf->b >> 7);
	pCodingExt->framePredFrameDCT = (pHdf->b >> 6)&0x01;
	pCodingExt->concealmentMotionVectors = (pHdf->b >> 5)&0x01;
	pCodingExt->qScaleType = (pHdf->b >> 4)&0x01;
	pCodingExt->intraVLCFormat = (pHdf->b >> 3)&0x01;
	pCodingExt->alternateScan = (pHdf->b >> 2)&0x01;
	pCodingExt->repeatFirstField = (pHdf->b >> 1)&0x01;
	pCodingExt->chroma420Type = (pHdf->b)&0x01;
	VideoNextHeaderByte();
	pCodingExt->progressiveFrame = (pHdf->b >> 7)&0x01;
	pCodingExt->compositeDisplayFlag = (pHdf->b >> 6)&0x01;
	if(pCodingExt->compositeDisplayFlag)
	{
		pCodingExt->vAxis = (pHdf->b >> 5)&0x01;
		pCodingExt->fieldSequence = (pHdf->b >> 2)&0x07;
		pCodingExt->subCarrier = (pHdf->b >> 1)&0x01;
		pCodingExt->burstAmplitude = (pHdf->b &0x01 ) << 7;
		VideoNextHeaderByte();
		pCodingExt->burstAmplitude |= (pHdf->b >> 1);
		pCodingExt->subCarrierPhase = (pHdf->b &0x01 );
	}


		// Set to one field by default
	pVideo->nTimesToDisplay = 1;
	pVideo->firstField = TOP;

	if(!pVideo->pSequenceExtension->progressiveSequence)
	{
		if(pVideo->pPictureCodingExtension->pictureStructure == FRAME)
		{
			if(pVideo->pPictureCodingExtension->topFieldFirst)
				pVideo->firstField = TOP;
			else
				pVideo->firstField = BOT;

			if(pVideo->pPictureCodingExtension->repeatFirstField)
				pVideo->nTimesToDisplay = 3;
			else
				pVideo->nTimesToDisplay = 2;
		}
	}

	if(pVideo->pSequenceExtension->progressiveSequence)
	{
		if((!pVideo->pPictureCodingExtension->repeatFirstField) &&
			(!pVideo->pPictureCodingExtension->topFieldFirst))
		{
			pVideo->nTimesToDisplay = 1;
		}
 		else if((pVideo->pPictureCodingExtension->repeatFirstField) &&
			(!pVideo->pPictureCodingExtension->topFieldFirst))
		{
			pVideo->nTimesToDisplay = 2;
				
		}
	 	else if((pVideo->pPictureCodingExtension->repeatFirstField) &&
			(pVideo->pPictureCodingExtension->topFieldFirst))
		{
			pVideo->nTimesToDisplay = 3;
			
		}
		
	}
	//DPF(("Decoded:disp = %ld, todisp = %ld\r\n",pVideo->pDecodedFrame->nTimesDisplayed,pVideo->pDecodedFrame->nTimesToDisplay));

	switch(pVideo->pPictureCodingExtension->pictureStructure)
	{
		case FRAME:
			pVideo->curImage = FRM;
		break;

		case TOP_FIELD :
			pVideo->curImage = TOP;
		break;

		case BOT_FIELD :
			pVideo->curImage = BOT;
		break;
							
	}
			
	TracePictExt((BYTE)pVideo->nTimesToDisplay, (BYTE)pCodingExt->topFieldFirst, (BYTE)pCodingExt->repeatFirstField, (BYTE)pCodingExt->progressiveFrame, (BYTE)pCodingExt->pictureStructure);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPictureDisplayExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract pan and scan vectors
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoPictureDisplayExtensionHeader(void)
{
	PPICTUREDISPLAYEXTENSION pDisp =
					pVideo->pPictureDisplayExtension;
	PHEADERPARSER			 pHdf	  = pVideo->pHeaderParser;

	pDisp->horOffset = ((DWORD)(pHdf->b)&0x0F)<<12;
	VideoNextHeaderByte();
	pDisp->horOffset |= (((DWORD)pHdf->b)<<4);
	VideoNextHeaderByte();
	pDisp->horOffset |= (((DWORD)pHdf->b)>>4);

	pDisp->verOffset = (((DWORD)pHdf->b & 0x07)<<13);
	VideoNextHeaderByte();
	pDisp->verOffset |= (((DWORD)pHdf->b )<<5);
	VideoNextHeaderByte();
	pDisp->verOffset |= (((DWORD)pHdf->b )>>3);

	//
	// if pan / scan is enabled, set the new vectors here
	//

	if (VidFmt.dwFlags & KS_MPEG2_DoPanScan)
	{
		VideoConvertSixteenByNineToFourByThree();
	}
	else
	{
		VideoResetPSV();
	}

	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPictureSpatialScalableExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoPictureSpatialScalableExtensionHeader(void)
{
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoPictureTemporalScalableExtensionHeader
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoPictureTemporalScalableExtensionHeader(void)
{
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoLoadQuantMatrix
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Load quant matrices
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoLoadQuantMatrix(BOOL intra)
{
	int i;
	if(intra)
	{
		// Load Intra
		BoardWriteVideo(VID_HDS, HDS_QMI_INTRA);
		for(i=0; i<QMSIZE; i++)
			BoardWriteVideo(VID_QMW, pVideo->pSequence->intraQuantiserMatrix[i]);
	}
	else
	{
		// Load nonIntra
		BoardWriteVideo(VID_HDS, HDS_QMI_NON_INTRA);
		for(i=0; i<QMSIZE; i++)
			BoardWriteVideo(VID_QMW, pVideo->pSequence->nonIntraQuantiserMatrix[i]);
	}
	BoardWriteVideo(VID_HDS, 0);
	return TRUE;
}



//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSetReconstructionBuffer
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program RFP
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSetReconstructionBuffer (FRAMETYPE frame)
{

		switch(frame)
		{
			case IFrame :
			case PFrame :
				pVideo->rfp = 1 - pVideo->prevBuf;
				pVideo->bfp = pVideo->prevBuf;
				pVideo->ffp = pVideo->prevBuf;
			break;
	
			case BFrame :
				pVideo->rfp = 2; // B picture always uses BUFF_C
				pVideo->bfp = pVideo->prevBuf;
				pVideo->ffp = 1-pVideo->prevBuf;
			break;
	
			default :
				TRAP
			break;
		}
	
		pVideo->pDecodedFrame = &pVideo->bufABC[pVideo->rfp];
		BoardWriteVideo(VID_RFP1, 	(BYTE)(pVideo->pDecodedFrame->adr >> 8));
		BoardWriteVideo(VID_RFP0, 	(BYTE)(pVideo->pDecodedFrame->adr));
	
		BoardWriteVideo(VID_BFP1, 	(BYTE)(pVideo->bufABC[pVideo->bfp].adr >> 8));
		BoardWriteVideo(VID_BFP0, 	(BYTE)(pVideo->bufABC[pVideo->bfp].adr));
		
		BoardWriteVideo(VID_FFP1, 	(BYTE)(pVideo->bufABC[pVideo->ffp].adr >> 8));
		BoardWriteVideo(VID_FFP0, 	(BYTE)(pVideo->bufABC[pVideo->ffp].adr));

		pVideo->pDecodedFrame->pts = pVideo->pts;

		pVideo->pDecodedFrame->panHor =
					pVideo->pPictureDisplayExtension->horOffset;

		pVideo->pDecodedFrame->panVer =
					pVideo->pPictureDisplayExtension->verOffset;

		if(pVideo->rfp != 2)
			pVideo->prevBuf =  pVideo->rfp;

	pVideo->pDecodedFrame->tref = pVideo->pPicture->temporalReference;
	pVideo->pDecodedFrame->frameType = pVideo->frameType;

	// rr - JBS attempt to fix 3:2 problem
	pVideo->pDecodedFrame->nTimesToDisplay = pVideo->nTimesToDisplay;
	pVideo->pDecodedFrame->nTimesDisplayed = 1;
	pVideo->pDecodedFrame->curField = pVideo->curImage;
	pVideo->pDecodedFrame->firstField = pVideo->firstField;
	// end rr
		
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSetDisplayBuffer
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Calculate DFP
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSetDisplayBuffer (FRAMETYPE frame)
{
	switch(frame)
	{
		case IFrame :
		case PFrame :
				pVideo->dfp = 1 - pVideo->prevBuf;
		break;

		case BFrame :
				pVideo->dfp = 2; // B picture always uses BUFF_C
		break;

		default :
			TRAP
		break;
	}
	pVideo->pDisplayedFrame = &pVideo->bufABC[pVideo->dfp];
	pVideo->nDisplayedFrames++;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoProgramDisplayBuffer
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program DFP
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoProgramDisplayBuffer(void)
{
	BoardWriteVideo(VID_DFP0, 	(BYTE)(pVideo->pDisplayedFrame->adr));
	BoardWriteVideo(VID_DFP1, 	(BYTE)(pVideo->pDisplayedFrame->adr >> 8));
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSoftReset
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Soft reset sti3520A
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

extern BOOL fInitSP;

BOOL VideoSoftReset(void)
{

	BoardWriteVideo(VID_CTL, CTL_SRS);
	Delay(1000);
	BoardWriteVideo(VID_CTL, 0);
	BoardWriteVideo(VID_CTL, CTL_PRS);
	Delay(1000);
	BoardWriteVideo(VID_CTL, (BYTE)pVideo->ctl);

	Ac3Stop();
	BoardWriteAudio(AUD_RES, 0x01);
	Delay(1000);
	Ac3Stop();
	BoardWriteAudio(AUD_BBE, 0x01);
	BoardWriteAudio(AUD_DEM, 0x00);
	BoardWriteAudio(AUD_DIF, 0x01);
	BoardWriteAudio(AUD_DIV, 0x02);
	BoardWriteAudio(AUD_EXT, 0x00);
	BoardWriteAudio(AUD_FOR, 0x00);
	BoardWriteAudio(AUD_ISS, 0x03);
	BoardWriteAudio(AUD_LCA, 0x00);
	BoardWriteAudio(AUD_RCA, 0x00);
	BoardWriteAudio(AUD_LRP, 0x00);
	BoardWriteAudio(AUD_ORD, 0x00);
	BoardWriteAudio(AUD_P18, 0x01);
	BoardWriteAudio(AUD_SCP, 0x00);
	BoardWriteAudio(AUD_SEM, 0x00);
	BoardWriteAudio(AUD_SFR, 0x00);
	BoardWriteAudio(AUD_RST, 0x01);
	BoardWriteVideo(VID_CTL, CTL_SRS);
	Delay(1000);
	BoardWriteVideo(VID_CTL, 0);
	BoardWriteVideo(VID_CTL, CTL_PRS);
	Delay(1000);
	pVideo->ctl = CTL_EDC | CTL_ERP | CTL_ERS | CTL_ERU;
	BoardWriteVideo(VID_CTL, (BYTE)pVideo->ctl);
	Ac3Stop();

	Delay(1000);


	BoardWriteVideo(VID_OBP, (BYTE)((pVideo->videoBufferSize + 1) >> 8));
	BoardWriteVideo(VID_OBP, (BYTE)((pVideo->videoBufferSize + 1) & 0xFF));

	Delay(1000);

	BoardWriteVideo(VID_OTP, (BYTE)((pVideo->videoBufferSize + 1) >> 8));
	BoardWriteVideo(VID_OTP, (BYTE)((pVideo->videoBufferSize + 1) & 0xFF));

	fInitSP = FALSE;


	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSetSRC
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Set SRC
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSetSRC(DWORD srcSize, DWORD dstSize)
{
	DWORD lsr;
	
	lsr = 256L * (srcSize-4)/(dstSize-1);
	BoardWriteVideo(VID_LSO, 0);
	BoardWriteVideo(VID_LSR0, (BYTE)lsr);
	if(lsr > 255)
		BoardWriteVideo(VID_LSR1, 0x01);
	BoardWriteVideo(VID_CSO, 0x00);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoSwitchSRC
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Set src on or off
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoSwitchSRC(BOOL on)
{
	if(on)
		pVideo->dcf &= (~DCF0_DSR);
	else
		pVideo->dcf |= DCF0_DSR;
		
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf));
	BoardWriteVideo(VID_DCF1, 0);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoProgramDisplayWindow
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program the display window
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoProgramDisplayWindow(void)
{
	// Program XDO, YDO, XDS,YDS
	BYTE b;
	WORD w;

	BoardWriteVideo(VID_XDO0, (BYTE)(XOFFSET&0xFF));
	BoardWriteVideo(VID_XDO1, (BYTE)(XOFFSET>>8));

	BoardWriteVideo(VID_YDO, (BYTE)(YOFFSET&0xFF));

	BoardWriteVideo(VID_XDS0,  (BYTE)((XOFFSET+VPFmt.amvpDimInfo.dwFieldWidth - 63)&0xFF));
	BoardWriteVideo(VID_XDS1,  (BYTE)((XOFFSET+VPFmt.amvpDimInfo.dwFieldWidth - 63)>>8));


	switch(pVideo->codingStandard)
	{
		case MPEG1:
			BoardWriteVideo(VID_YDS,  (BYTE)((pVideo->pSequence->verSize+YOFFSET-YDS_CONST)&0xFF));
		   pVideo->dcf &= 0xF8;	 // Clear the VCF bits
			pVideo->dcf |= DCF0_VCFHALFRESCI;
			if(pVideo->pSequence->horSize < 720)
			{
				DPF(("Setting SRC!!"));
				VideoSetSRC(pVideo->pSequence->horSize, 720);
				VideoSwitchSRC(TRUE);
			}
		break;

		case MPEG2:
			BoardWriteVideo(VID_YDS,  (BYTE)(((pVideo->pSequence->verSize>>1)+YOFFSET-YDS_CONST)&0xFF));
		   pVideo->dcf &= 0xF8;	 // Clear the VCF bits
			pVideo->dcf |= DCF0_VCFFULLRESLRWI;
/*
	// Commenting it out for debugging
			if(pVideo->pSequence->aspectRatio == 0x03)
			{
				pVideo->panScan = TRUE;
				VideoSetSRC(544, 720);
				VideoSwitchSRC(TRUE);
				VideoConvertSixteenByNineToFourByThree();
			}
			else
*/
				//VideoSwitchSRC(FALSE);
		break;

	}
	
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf));
	BoardWriteVideo(VID_DCF1, 0);

	// Program DFW and DFS
	b = (BYTE)((pVideo->pSequence->horSize+15)>>4);
	BoardWriteVideo(VID_DFW, b);
	w = (WORD)((pVideo->pSequence->verSize+15)>>4)*(WORD)b;
	BoardWriteVideo(VID_DFS, (BYTE) ((w>>8) & 0x3F));
	BoardWriteVideo(VID_DFS, (BYTE) (w & 0xFF));

	BoardWriteVideo(VID_DFA, 0);
	BoardWriteVideo(VID_DFA, 0);
	
	BoardWriteVideo(VID_XFW, b);

	BoardWriteVideo(VID_XFS, (BYTE) ((w>>8) & 0x3F));
	BoardWriteVideo(VID_XFS, (BYTE) (w & 0xFF));
	
	BoardWriteVideo(VID_XFA, 0);
	BoardWriteVideo(VID_XFA, 0);
	VideoLoadQuantMatrix(TRUE);
	VideoLoadQuantMatrix(FALSE);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoMaskInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Mask the interrupt
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoMaskInterrupt(void)
{
	BoardWriteVideo(VID_ITM0, 0);
	BoardWriteVideo(VID_ITM1, 0);
	BoardWriteVideo(VID_ITM2, 0);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoUnmaskInterrupt
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Unmask the interrupts
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoUnmaskInterrupt(void)
{
	BoardWriteVideo(VID_ITM0, (BYTE)(pVideo->itm&0xFF));
	BoardWriteVideo(VID_ITM1, (BYTE)(pVideo->itm>>8));
	BoardWriteVideo(VID_ITM2, 0);
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : Compute the next instruction
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Extract it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoComputeInstruction(void)
{

	pVideo->tis = TIS_EXE;
	switch(pVideo->codingStandard)
	{
		case MPEG1:
				// Set to one field by default
			pVideo->nTimesToDisplay = 2;
			pVideo->firstField = TOP;

			pVideo->pfh = (pVideo->pPicture->fFcode) | (pVideo->pPicture->bFcode << 4);
			pVideo->pfv = 0;
			pVideo->ppr1 = (pVideo->pPicture->pictureCodingType << 4) & 0x30;
			pVideo->ppr2 = 0;
		break;

	case MPEG2:
			pVideo->pfh =
				(pVideo->pPictureCodingExtension->fCode[1][0] << 4) |
				(pVideo->pPictureCodingExtension->fCode[0][0] );

			pVideo->pfv =
				(pVideo->pPictureCodingExtension->fCode[1][1] << 4) |
				(pVideo->pPictureCodingExtension->fCode[0][1] );

			pVideo->ppr1 =
				((pVideo->pPicture->pictureCodingType << 4) & 0x30) |
				((pVideo->pPictureCodingExtension->intraDCPrecision << 2) & 0x0C) |
				((pVideo->pPictureCodingExtension->pictureStructure ) & 0x03);

			pVideo->ppr2 =
				(pVideo->pPictureCodingExtension->topFieldFirst << 5) |
				(pVideo->pPictureCodingExtension->framePredFrameDCT << 4) |
				(pVideo->pPictureCodingExtension->concealmentMotionVectors << 3) |
				(pVideo->pPictureCodingExtension->qScaleType << 2) |
				(pVideo->pPictureCodingExtension->intraVLCFormat << 1) |
				(pVideo->pPictureCodingExtension->alternateScan);
				pVideo->tis |=  TIS_MP2;
	
		break;
	}

	if(pVideo->frameType == BFrame)
	{
				pVideo->tis |= TIS_OVW;
	}
	
	TraceIntr(comp, (BYTE)pVideo->tis, (BYTE)pVideo->frameType);
  	pVideo->instructionComputed = TRUE;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoStoreInstruction
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Store it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoStoreInstruction(void)
{
	BoardWriteVideo(VID_PFV, (BYTE)(pVideo->pfv));
	BoardWriteVideo(VID_PFH, (BYTE)(pVideo->pfh));
	BoardWriteVideo(VID_PPR1, (BYTE)(pVideo->ppr1));
	BoardWriteVideo(VID_PPR2, (BYTE)(pVideo->ppr2));
	BoardWriteVideo(VID_TIS, (BYTE)(pVideo->tis));
	pVideo->instructionComputed = FALSE;
	pVideo->tis = 0;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoGetBBL
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Read BBL and put in pVideo->BBL
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoGetBBL(void)
{
	pVideo->bbl = BoardReadVideo(VID_VBL1) << 8;
	pVideo->bbl |= BoardReadVideo(VID_VBL0);
	pVideo->bbl &= 0x3FFF;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoReadABL
//	PARAMS	: None
//	RETURNS	: Read abl and put it in pVideo->abl
//
//	PURPOSE	: Extract it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoGetABL(void)
{
	pVideo->abl = BoardReadVideo(VID_ABL1) << 8;
	pVideo->abl |= BoardReadVideo(VID_ABL0);
	pVideo->abl &= 0x3FFF;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoReadSCD
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Get the SCD value
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoReadSCD(void)
{
	DWORD scd, diff;

	scd = ((DWORD)BoardReadVideo(VID_SCD)) << 16;
	scd |= ((DWORD)BoardReadVideo(VID_SCD)) << 8;
	scd |= (DWORD)BoardReadVideo(VID_SCD);
	if(scd < pVideo->prevScdCount)
		diff = 0x1000000 - pVideo->prevScdCount + scd;
	else
		diff = scd - pVideo->prevScdCount;
	pVideo->scdCount += diff;
	pVideo->prevScdCount = scd;
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoAssociatePTS
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Read the next PTS off the fifo and associate it
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL	VideoAssociatePTS(void)
{
	DWORD cdcount, pts;
	VideoReadSCD();

	if(FifoGetPTS(&cdcount, &pts))
	{
		// Hacking for still picture decode.
		if(!pVideo->firstPtsFound)
		{
		 	pVideo->firstPtsFound = TRUE;
			pVideo->firstFramePTS = pts;
		}

		if(pVideo->scdCount*2L > cdcount)
		{
			
			FifoReadPTS(&cdcount, &pts);
			pVideo->pts = pts;
			// Pts belongs to this frame
		}
		else
		{
			pVideo->pts = 0;
			// Pts does not belong to this frame
		}
	}
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoProgramPanScanVectors
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Program the pan scan vectors
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoConvertSixteenByNineToFourByThree(void)
{
	DWORD pan, scan, d1, d2;

	d1 = (pVideo->pSequence->verSize -
			pVideo->pSequenceDisplayExtension->displayVerSize) >> 1;
	d1 = d1 + (pVideo->pDisplayedFrame->panVer >> 4);
	d1 = (d1>>2) &0x1FF;
	scan = d1;

	d1 = (pVideo->pSequence->horSize -
			pVideo->pSequenceDisplayExtension->displayHorSize) >> 1;
	d1 = d1 + (pVideo->pDisplayedFrame->panHor >> 4);

	pan = (d1 >> 2) & 0xFFF;
	// Program the integer part into PSV reg
	BoardWriteVideo(VID_PAN1, (BYTE)(pan>>8));
	BoardWriteVideo(VID_PAN0, (BYTE)(pan));

//		BoardWriteVideo(VID_SCN1, (BYTE)(scan>>8));
//		BoardWriteVideo(VID_SCN0, (BYTE)(scan));

	// Fractional Part in LSO, CSO
	d2 = (d1&0x0F) << 4;
	BoardReadVideo(VID_LSO);
	d1 = BoardReadVideo(VID_LSR1);
	BoardWriteVideo(VID_LSO, (BYTE)d2);
	BoardWriteVideo(VID_LSR1, (BYTE)d1);
	BoardWriteVideo(VID_CSO, (BYTE)(d2>>1));
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoGetPTS
//	PARAMS	: None
//	RETURNS	: Return the next pts
//
//	PURPOSE	: Get the next video pts
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

DWORD VideoGetPTS(void)
{
	if(pVideo->nDecodedFrames < 5)
		return pVideo->firstFramePTS;
	else
 		return pVideo->framePTS;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
//
//	FUNCTION : VideoClose
//	PARAMS	: None
//	RETURNS	: TRUE on success, FALSE otherwise
//
//	PURPOSE	: Close Video
//
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoClose(void)
{
	TraceDump();
	return TRUE;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoForceBKC
//	PARAMS	: BOOL
//	RETURNS	: None
//	
//	PURPOSE	: Force the border color
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoForceBKC(BOOL on)
{
	if(!on)
		pVideo->dcf |= DCF0_EVD;
	else
		pVideo->dcf &= (~DCF0_EVD);
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf&0xFF));
	BoardWriteVideo(VID_DCF1, (BYTE)(pVideo->dcf>>8));
	return TRUE;

}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoResetPSV
//	PARAMS	: BOOL
//	RETURNS	: None
//	
//	PURPOSE	: Reset the value programmed in PSV
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoResetPSV(void)
{
	// Program the integer part into PSV reg
	BoardWriteVideo(VID_PAN1, 0);
	BoardWriteVideo(VID_PAN0, 0);
	BoardWriteVideo(VID_LSR0, 0);
	BoardWriteVideo(VID_LSR1, 0);
	BoardWriteVideo(VID_CSO, 0);
	BoardWriteVideo(VID_LSO, 0);
	return TRUE;
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoFreeze
//	PARAMS	: TOP or BOT
//	RETURNS	: None
//	
//	PURPOSE	: Force to display a field
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void VideoFreeze(BOOL Top)
{
	BYTE dcf1, dcf0;

	dcf1 = (BYTE)((pVideo->dcf >> 8) & 0xFF);
	if(Top)
		dcf1 |= 1;
		
	dcf0 = (BYTE)(pVideo->dcf);
	dcf0 |= DCF0_USR;
	BoardWriteVideo(VID_DCF0, dcf0);
	BoardWriteVideo(VID_DCF1,dcf1);
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoUnFreeze
//	PARAMS	: TOP or BOT
//	RETURNS	: None
//	
//	PURPOSE	: UnForce to display a field
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void VideoUnFreeze(void)
{
	BoardWriteVideo(VID_DCF0, (BYTE)(pVideo->dcf & 0xFF));
	BoardWriteVideo(VID_DCF1, (BYTE)((pVideo->dcf >>8) & 0xFF));
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoDisplaySingleField
//	PARAMS	: TOP or BOT
//	RETURNS	: None
//	
//	PURPOSE	: display a field
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void VideoDisplaySingleField(BOOL Top)
{
	BYTE dcf1, dcf0;

	dcf0 = (BYTE)(pVideo->dcf&0xFF);
	if((pVideo->state == videoPaused) ||
	(pVideo->state == videoFirstFrameDecoded))
	{

 		dcf1 = 4;
		dcf0 |= DCF0_USR;
		BoardWriteVideo(VID_DCF1,dcf1);
	}
	BoardWriteVideo(VID_DCF0, dcf0);
}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//	
//
//	FUNCTION	: VideoTestReg
//	PARAMS	: TOP or BOT
//	RETURNS	: None
//	
//	PURPOSE	: Test Video Access
//
//
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

BOOL VideoTestReg(void)
{
	BoardWriteVideo(CFG_MWP, 0x05);
	BoardWriteVideo(CFG_MWP, 0x55);
	BoardWriteVideo(CFG_MWP, 0xAA);

  if ((BoardReadVideo(CFG_MWP) & 0x1F)  != 0x05)
		return FALSE;
  if (BoardReadVideo(CFG_MWP)  != 0x55)
		return FALSE;
  if ((BoardReadVideo(CFG_MWP) & 0xFC) != 0xA8)
		return FALSE;
	return TRUE;									
}

void VideoTraceDumpReg()
{
		BYTE bh, bl;
		WORD w;
		int i;
		bh = BoardReadVideo(VID_DFP1)&0x3F;
		bl = BoardReadVideo(VID_DFP0);

		w = (WORD)bh<<8 | bl;

		DbgPrint("DFP = %x\n", w);

		for(i=0; i<3; i++)
		{
			 BoardWriteVideo(VID_DFP0, 	(BYTE)(pVideo->bufABC[i].adr));
			 BoardWriteVideo(VID_DFP1, 	(BYTE)(pVideo->bufABC[i].adr >> 8));
			 TRAP
		}

}