#include "strmini.h"
#include "mpinit.h"
#include <wingdi.h>
#include "ksmedia.h"
#include "mpvideo.h"
#include "stdefs.h"
#include "copyprot.h"
#include "ls220.h"
#include "video.h"
#include "audio.h"
#include "dvhw32.h"

#ifdef WINDOWS2000
	#include "iic.h"
#endif

#include "luxksprop.h"

#ifndef LS240
	#define USE_STC
#endif


#define CHK_CNT	0x40

KS_MPEGVIDEOINFO2 VidFmt;
KS_AMVPDATAINFO VPFmt;

BOOL fClkPause;
ULONGLONG LastSysTime = 0;
ULONGLONG PauseTime = 0;
ULONGLONG LastStamp;
ULONGLONG LastSys;
BOOLEAN fValid;
DWORD dwSTCinPause=0;
BOOLEAN fProgrammed;
BOOLEAN fStarted;
ULONGLONG StartSys;
DWORD	vPts=0;		//declare as global so that USerData can use

BOOL   m_Pal = FALSE;	// Video Src
DWORD  m_Palcnt = 0;

extern DWORD	v_PTS;

extern GUID MY_KSEVENTSETID_VPNOTIFY;
extern PHW_STREAM_OBJECT pVideoStream;
extern KSDATAFORMAT hwfmtiMpeg2Vid;
extern KSDATAFORMAT hwfmtiMpeg2VidPES;
extern DWORD luxbase;
extern DWORD v_wptr;

extern BOOL	m_docopy;

extern BOOL m_resume;
extern BOOL b_first_pcm_data;

extern BYTE	eprom[]; 

extern BOOL	f_HLIActive;

void mpstCommandComplete(PHW_STREAM_REQUEST_BLOCK pSrb);
ULONG mpstVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb);
void SetRateChange(PHW_DEVICE_EXTENSION pHwDevExt, LONG strm);	//Rate Chnage Global Function
void CCSendDiscontinuity(PHW_DEVICE_EXTENSION);

void VideoLuxSetProp(PHW_STREAM_REQUEST_BLOCK pSrb);

void VideoLuxGetProp(PHW_STREAM_REQUEST_BLOCK pSrb);

extern WORD	GetWORD(BYTE *p);
extern DWORD GetDWORD(BYTE *p);
extern void AudioPacketStub(PHW_STREAM_OBJECT pstrm);
extern ULONGLONG GetSystemTime();
extern ULONGLONG ConvertPTStoStrm(ULONG pts);
extern ULONG GetStreamPTS(PHW_STREAM_OBJECT strm);
extern ULONGLONG ConvertVPTStoStrm(ULONGLONG vpts);
extern VOID STREAMAPI StreamTimeCB(IN PHW_TIME_CONTEXT tc);

BOOL	m_alwaysF = TRUE;
////////////////////////////////////////////////////////////////////////////////

void VideoPacketStub(PHW_STREAM_OBJECT pstrm)
{
	//VideoTimerCallBack(pstrm);
				
	//Call At Dispatch IRQL
	StreamClassCallAtNewPriority(pstrm,
								pstrm->HwDeviceExtension,
								Dispatch,
								VideoTimerCallBack,
								pstrm);
	
}

////////////////////////////////////////////////////////////////////////////////

ULONG miniPortVideoPause(PHW_STREAM_REQUEST_BLOCK pSrb, PHW_DEVICE_EXTENSION pHwDevExt)
{
ULONG dwErrCode = NO_ERROR;

	pSrb = pSrb; // Remove Warning 
	#ifdef DBG
		DbgPrint("luxdvd : miniPortVideoPause - calling LUXVideoPause, LUXAudioPause\n");
	#endif

	LUXVideoPause();
	LUXAudioPause();
	
	pHwDevExt->VideoDeviceExt.DeviceState = KSSTATE_PAUSE;
	return dwErrCode; 	
}

////////////////////////////////////////////////////////////////////////////////

VOID miniPortVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
PVIDEO_DEVICE_EXTENSION pvidex = &(((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension)->VideoDeviceExt);

	
	// set up for initial parsing of the scatter gather packet.
	if(!pSrb)
    {
		#ifdef DBG
			DbgPrint("luxdvd ERROR : miniPortVideoPacket - invalid SRB !!!!\n");
		#endif
		return;
	}
 
	pvidex->cPacket = 0;
    pvidex->cOffs = PACK_HEADER_SIZE;
	pvidex->pPacket = pSrb->CommandData.DataBufferArray;

	if(pvidex->pPacket->TypeSpecificFlags & KS_AM_UseNewCSSKey)
	{
		//should just return as it is an empty packet
		#ifdef DBG
			DbgPrint("luxdvd : miniPortVideoPacket - received KS_AM_UseNewCSSKey flag\n");
		#endif

		if(pHwDevExt->AudioType == AUDIO_PCM)	// only AC3 can do copyprot ?!
		{
			//change back to AC3
			LUXAudioStop();
			LUXAudioStopDSP();

			LUXVideoStop();

			LUXVideoCleanScreen();	//try not to show garbage whilst we reset chip

			DisableIT();
			LUXChngDSP(AUDIO_AC3,pHwDevExt->VideoPort);
			EnableIT();

			LUXVideoSetVPM(1,pHwDevExt->VideoPort);

			LUXVideoPlay(1000);
			LUXAudioPlay(1000);
		}
		
		pSrb->Status = STATUS_SUCCESS;
		StreamClassStreamNotification(ReadyForNextStreamDataRequest,pSrb->StreamObject);
		StreamClassStreamNotification(StreamRequestComplete,pSrb->StreamObject,pSrb);
        return;
		
	}

	if( pHwDevExt->AudioType != AUDIO_AC3 && m_resume )
	{
		m_resume = FALSE;

		LUXAudioStop();
		LUXAudioStopDSP();

		LUXVideoStop();

		LUXVideoCleanScreen();	//try not to show garbage whilst we reset chip

		DisableIT();
		LUXChngDSP(pHwDevExt->AudioType,pHwDevExt->VideoPort);
		EnableIT();

		LUXVideoSetVPM(1,pHwDevExt->VideoPort);

		LUXVideoPlay(1000);
		LUXAudioPlay(1000);
		b_first_pcm_data = TRUE;
	}
	
	pvidex->pCurrentSRB = pSrb;
	pHwDevExt->VideoDeviceExt.videoSTC = pvidex->pPacket->PresentationTime.Time;
		
	//VideoPacketStub(pSrb->StreamObject);

	
	//Call At Dispatch IRQL
	StreamClassCallAtNewPriority(pSrb->StreamObject,
								pSrb->StreamObject->HwDeviceExtension,
								Dispatch,
								VideoTimerCallBack,
								pSrb->StreamObject);
	
}

////////////////////////////////////////////////////////////////////////////////

VOID miniPortGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	pSrb->Status = STATUS_SUCCESS;

	switch (pSrb->CommandData.PropertyInfo->PropertySetID)
	{
		case 1:
			
			// this is a copy protection property go handle it there
			#ifdef DBG
				//DbgPrint("luxdvd : video calling CopyProtGetProp\n");
			#endif
			CopyProtGetProp(pSrb);
			break;

		case 2:

			#ifdef DBG
				DbgPrint("luxdvd : video calling VideoRateChangeGetProp\n");
			#endif
			VideoRateChangeGetProp(pSrb);
			break;

		case 3:
			VideoLuxGetProp(pSrb);
			break;

		default:
	        break;
	}

}

////////////////////////////////////////////////////////////////////////////////

VOID miniPortSetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext =
		((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	pSrb->Status = STATUS_SUCCESS;

	switch (pSrb->CommandData.PropertyInfo->PropertySetID)
	{
		case 1:

			// this is a copy protection property go handle it there
			#ifdef DBG
				//DbgPrint("luxdvd : video calling CopyProtSetProp\n");
			#endif
			CopyProtSetProp(pSrb);
			break;

		case 2:

			#ifdef DBG
				DbgPrint("luxdvd : video calling VideoRateChangeSetProp\n");
			#endif
			VideoRateChangeSetProp(pSrb);
			break;

		case 3:
			VideoLuxSetProp(pSrb);
			break;


		default:
	        break;
	}

}

////////////////////////////////////////////////////////////////////////////////

VOID miniPortSetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
    
	if(!pSrb)
    {
		#ifdef DBG
			DbgPrint("luxdvd ERROR : miniPortSetState - invalid SRB !!!!\n");
		#endif
		return;
	}

	switch (pSrb->CommandData.StreamState)  
	{

		case KSSTATE_STOP:
	 		

			#ifdef DBG
				DbgPrint("luxdvd : Video KSSTATE_STOP\n");
			#endif

			fProgrammed = fStarted = FALSE;
			fClkPause = FALSE;
						
			dwSTCinPause = LUXVideoGet_STC();
			
			LUXVideoCleanScreen();
			LUXVideoStop();
			LUXAudioStop();

			LUXVideoAfterSeek();
			LUXAudioAfterSeek();

			phwdevext->VideoDeviceExt.DeviceState = KSSTATE_STOP;
			
			InitVideoRate(phwdevext);	//initialise the video rate change params

			m_alwaysF = TRUE;

			break;


		case KSSTATE_PAUSE:
	 	
			#ifdef DBG
				DbgPrint("luxdvd : Video KSSTATE_PAUSE\n");
			#endif

			PauseTime = GetSystemTime();
			if( !fStarted ) 
			{
				fStarted = TRUE;
				LastStamp = 0;
				StartSys = LastSysTime = PauseTime;
			}
			fClkPause = TRUE;

			LUXVideoPause();
			LUXAudioPause();
			phwdevext->VideoDeviceExt.DeviceState = KSSTATE_PAUSE;
			
			m_alwaysF = TRUE;

			break;

		case KSSTATE_RUN:
	 	
			#ifdef DBG
				DbgPrint("luxdvd : Video KSSTATE_RUN\n");
			#endif

			if( !fStarted && !fProgrammed ) 
			{
				LastStamp = 0;
				StartSys = LastSysTime = GetSystemTime();
			}

			fProgrammed = TRUE;
			fStarted = TRUE;
			fClkPause = FALSE;

			LUXVideoPlay(1000);
			LUXAudioPlay(1000);

			phwdevext->VideoDeviceExt.DeviceState = KSSTATE_RUN;
			phwdevext->vid_speed = 1000;

			m_alwaysF = FALSE;
				
			break;
	}

	pSrb->Status = STATUS_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////

VOID miniPortGetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	#ifdef DBG
		DbgPrint("luxdvd : miniPortGetState\n");
	#endif

	pSrb->CommandData.StreamState = phwdevext->VideoDeviceExt.DeviceState;
	pSrb->Status = STATUS_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////

VOID VideoTimerCallBack(PHW_STREAM_OBJECT pstrm)
{
PHW_DEVICE_EXTENSION		pdevext = pstrm->HwDeviceExtension;
PHW_STREAM_REQUEST_BLOCK	pSrb;
ULONG						uSent;
PVIDEO_DEVICE_EXTENSION		pvidex = &(pdevext->VideoDeviceExt);

DWORD dwcnt = 0;

	pSrb = pvidex->pCurrentSRB;

	
	if (!pSrb)
	{
		//Always get here after a CancelPacket
		#ifdef DBG
			DbgPrint("luxdvd ERROR : VideoTimerCallBack -received invalid SRB !!!!!!\n");
		#endif
		return;
	}

	if ( m_docopy )
	{
		#ifdef DBG
			DbgPrint("luxdvd : VideoTimerCallBack - doing KeyExch, discard Packet\n");
		#endif

		
		pSrb->Status = STATUS_SUCCESS;
        mpstCommandComplete(pSrb);
		return;
	}

	do
	{
		if(pvidex->pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY)
		{
			#ifdef DBG
				DbgPrint("luxdvd : video KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY\n");
			#endif
			
			LUXVideoFlush();
			
			while ( DVReadReg(0x19c) )
			{
				KeStallExecutionProcessor(1);
				if ( dwcnt++ > 0xffffff )
				{
					#ifdef DBG
						DbgPrint("luxdvd ERROR : VideoTimerCallBack - Wait for 0x19c time out \n");
					#endif
					break;
				}
			}

			LUXVideoSeq_end();

			if( pdevext->TimeDisCount++ >= 2)
			{
				#ifdef DBG
					DbgPrint("luxdvd : received all 3 Stream TimeDisContinuties !!!\n");
				#endif
				pdevext->TimeDisCount = 0;
				LUXVideoSeq_end();

				//After A, V, SP have all received TimeDis, we are fairly certain that
				//a menu will appear. Here we turn off menu workaround
//				LUXVideoMenu(0);
			}
		}

		if (pvidex->pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
		{
			#ifdef DBG
				DbgPrint("luxdvd : video KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY\n");
			#endif

			CCSendDiscontinuity(pdevext);
		}
		
		if (pvidex->pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)			
		{
			#ifdef DBG
				DbgPrint("luxdvd : VideoTimerCallback - KSSTREAM_HEADER_OPTIONSF_TYPECHANGED\n");
			#endif
			if (pvidex->pPacket->DataUsed >= sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
			{
				#ifdef DBG
					DbgPrint("luxdvd : VideoTimerCallback - KSSTREAM_HEADER_OPTIONSF_TYPECHANGED calling ProcessVideoFormat\n");
				#endif
				ProcessVideoFormat((PKSDATAFORMAT)pvidex->pPacket->Data, pdevext);
				uSent = pvidex->pPacket->DataUsed + 1;
			}
		}
		else if (pvidex->pPacket->DataUsed)
		{
			if(pdevext->bVFlush)	//if we are flushing out video, we dont eat anymore data
				uSent = pvidex->pPacket->DataUsed;
			else
			{
				if ( m_Pal )
				{
					if ( pdevext->AudioType != AUDIO_AC3 || m_Palcnt++ > 0x50 )
						m_Pal = FALSE;

					uSent = 0;
				}
				else
					uSent = mpstVideoPacket(pSrb);
			}
		}
		else
		{
			#ifdef DBG
				DbgPrint("luxdvd : Video Discontinuity\n");
			#endif
			uSent = 0;
		}

		pvidex->cOffs += uSent;

		// check if we finished this packet.  If so, go on to the next packet
		if (pvidex->cOffs >= pvidex->pPacket->DataUsed)
		{
			pvidex->pPacket++;

			// reset the packet offset
			pvidex->cOffs = PACK_HEADER_SIZE;
			pvidex->cPacket++;

			// if we have finished all the packets, then we are done
			if (pvidex->cPacket >= pSrb->NumberOfBuffers)           
			{		
 				pSrb->Status = STATUS_SUCCESS;
	            mpstCommandComplete(pSrb);
				pvidex->pCurrentSRB = 0;
				return;
			}
		}

	} while (uSent);

	//This will call VideoPacketStub at HIGH IRQL
	StreamClassScheduleTimer(pstrm, 
							pstrm->HwDeviceExtension,
							50, 
							(PHW_PRIORITY_ROUTINE)VideoPacketStub, 
							pstrm);
}

////////////////////////////////////////////////////////////////////////////////

ULONG mpstVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PVIDEO_DEVICE_EXTENSION pvidex = &(((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension)->VideoDeviceExt);
	
PUCHAR  p=NULL;
BOOL	b_scramble;
int		len, pes_len;
PDWORD	pdw=NULL;

	if(!pSrb)
    {
		#ifdef DBG
			DbgPrint("luxdvd ERROR : mpstVideoPacket - invalid SRB !!!!\n");
		#endif
		return 0;
	}

	if(pvidex->pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
	{
		#ifdef DBG
			DbgPrint("luxdvd : video - KSSTREAM_HEADER_OPTIONSF_TYPECHANGED\n");
		#endif
	}

	pdw = (PDWORD)((ULONG) pvidex->pPacket->Data);

	if(*pdw == 0xBA010000)	//DVD PACK HEADER
	{
		p = (PUCHAR)((ULONG) pvidex->pPacket->Data + PACK_HEADER_SIZE + 4);
	}
	else	//MPEG2 PES Format
	{
		//MPEG2 PES Video seems to just have the video start code
		p = (PUCHAR)((ULONG) pvidex->pPacket->Data + 4);
	}

	len = (int)GetWORD(p);	//get the PES_packet_length

	b_scramble = (BOOL)(p[2] & 0x30);

	pes_len = (int)p[4];

	len = (int)(len - 3 - pes_len);

	vPts = 0;	//re-init this global here

	if( pes_len >= 5)
    {
		if( (p[5] & 0xf0) == 0x30 )
        {
			vPts = (DWORD)(GetWORD(&p[6]) >> 1);
            vPts = (DWORD)(vPts << 14 | GetWORD(&p[8]) >> 2);
            vPts |= (DWORD) ( p[5] & 0xe )  << 28;
		}
    }

	p += pes_len + 5;
		
	if( LUXSendData((BYTE *)((ULONG)pvidex->pPacket->Data),
							(BYTE *)p,len,vPts,b_scramble) )
	{
		return (pvidex->pPacket->DataUsed);
	}
	else
		return 0;
}


////////////////////////////////////////////////////////////////////////////////

void mpstCommandComplete(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION pHwDevExt = 
	 ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);

	 // see if there is a request outstanding on either queue.
	 // if there is, go ahead and start it.
	 //  Note: this code cannot be re-entered!

	 pHwDevExt ->pCurSrb = 0;

	 // now, go ahead and complete this request
	 	 
	 StreamClassStreamNotification(ReadyForNextStreamDataRequest,
			 pSrb->StreamObject);
 
	 StreamClassStreamNotification(StreamRequestComplete,
			 pSrb->StreamObject,
			 pSrb);

}

////////////////////////////////////////////////////////////////////////////////

void ProcessVideoFormat(PKSDATAFORMAT pfmt, PHW_DEVICE_EXTENSION pdevex)
{
KS_MPEGVIDEOINFO2 * pblock = (KS_MPEGVIDEOINFO2 *)((ULONG)pfmt + sizeof  (KSDATAFORMAT));
ULONG cXOut=0, cYOut=0;
   
	#ifdef DBG	
		DbgPrint("luxdvd : ProcessVideoFormat\n");
	#endif

	//if (pfmt->FormatSize != sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
	if (pfmt->FormatSize < sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : ProcessVideoFormat - invalid pfmt->FormatSize !!!\n");
		#endif
		return;
	}


	if( (IsEqualGUID2(&(pfmt->MajorFormat), &(hwfmtiMpeg2Vid.MajorFormat)) &&
		IsEqualGUID2(&(pfmt->SubFormat), &(hwfmtiMpeg2Vid.SubFormat))) ) 
	{
		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - DVD MPEG VIDEO format\n");
		#endif
	}
	else if( (IsEqualGUID2(&(pfmt->MajorFormat), &(hwfmtiMpeg2VidPES.MajorFormat)) &&
		IsEqualGUID2(&(pfmt->SubFormat), &(hwfmtiMpeg2VidPES.SubFormat))) ) 
	{
		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - PES MPEG VIDEO format\n");
		#endif
	}

	// copy the format block
	VidFmt = *pblock;

	// copy the picture aspect ratio for now
	VPFmt.dwPictAspectRatioX = VidFmt.hdr.dwPictAspectRatioX;
	VPFmt.dwPictAspectRatioY = VidFmt.hdr.dwPictAspectRatioY;

	LUXVideoSetXY(VidFmt.hdr.bmiHeader.biWidth,VidFmt.hdr.bmiHeader.biHeight);

	m_Palcnt = 0;

	if( VidFmt.hdr.bmiHeader.biHeight >= 576 )
	{
		m_Pal = TRUE;
		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - PAL format\n");
		#endif
	}
	else
	{
		m_Pal = FALSE;
		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - NTSC format\n");
		#endif
	}

	#ifdef DBG
		DbgPrint("luxdvd : ProcessVideoFormat - VPFmt.dwPictAspectRatioX=0x%lx, VPFmt.dwPictAspectRatioY=0x%lx\n",VPFmt.dwPictAspectRatioX,VPFmt.dwPictAspectRatioY);
	#endif

	// check for pan scan enabled
	if (VidFmt.dwFlags & KS_MPEG2_DoPanScan)
	{
		// under pan scan for DVD for NTSC, we must be going to a 540 by
		// 480 bit image, from a 720 x 480 (or 704 x 480)  We will
		// use this as the base starting dimensions.  If the Sequence
		// header provides other sizes, then those should be updated,
		// and the Video port connection should be updated when the
		// sequence header is received.
		//
		// change the picture aspect ratio.  Since we will be stretching
		// from 540 to 720 in the horizontal direction, our aspect ratio
		// will 
	
		VPFmt.dwPictAspectRatioX = (VidFmt.hdr.dwPictAspectRatioX * (54000 / 72));
		VPFmt.dwPictAspectRatioY = VidFmt.hdr.dwPictAspectRatioY * 1000;

		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - KS_MPEG2_DoPanScan !!!!!\n");
			DbgPrint("luxdvd : ProcessVideoFormat - VPFmt.dwPictAspectRatioX=0x%lx, VPFmt.dwPictAspectRatioY=0x%lx\n",VPFmt.dwPictAspectRatioX,VPFmt.dwPictAspectRatioY);
		#endif

		//new width
		cXOut = 540;

	}
	else if(VidFmt.dwFlags & KS_MPEG2_SourceIsLetterboxed)
	{
		VPFmt.dwPictAspectRatioX = VidFmt.hdr.dwPictAspectRatioX;
		VPFmt.dwPictAspectRatioY = VidFmt.hdr.dwPictAspectRatioY;

		//new width
		cXOut = VidFmt.hdr.bmiHeader.biWidth;

		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - KS_MPEG2_SourceIsLetterboxed !!!!!\n");
			DbgPrint("luxdvd : ProcessVideoFormat - VPFmt.dwPictAspectRatioX=0x%lx, VPFmt.dwPictAspectRatioY=0x%lx\n",VPFmt.dwPictAspectRatioX,VPFmt.dwPictAspectRatioY);
		#endif
	}
	else // pan scan disabled, just check the format, and use it
	{
		if( VidFmt.hdr.dwPictAspectRatioX == 4 )
		{
			#ifdef DBG
				DbgPrint("luxdvd : ProcessVideoFormat - 4:3 format\n");
			#endif
		}
		else
		{
			#ifdef DBG
				DbgPrint("luxdvd : ProcessVideoFormat - 16:9 format\n");
			#endif
		}

		cXOut = VidFmt.hdr.bmiHeader.biWidth;
		VPFmt.dwPictAspectRatioX = VidFmt.hdr.dwPictAspectRatioX;
		VPFmt.dwPictAspectRatioY = VidFmt.hdr.dwPictAspectRatioY;
	}

	//new height
	cYOut = VidFmt.hdr.bmiHeader.biHeight;

	#ifdef DBG
		DbgPrint("luxdvd : ProcessVideoFormat - Width = %d, height = %d\n",cXOut,cYOut);
	#endif

	//NEW
	VPFmt.amvpDimInfo.dwFieldWidth		= cXOut;
	VPFmt.amvpDimInfo.dwFieldHeight 	= cYOut/2;
	VPFmt.amvpDimInfo.dwVBIWidth		= 0;
	VPFmt.amvpDimInfo.dwVBIHeight		= 0;
		
	VPFmt.amvpDimInfo.rcValidRegion.left	= 0;
	VPFmt.amvpDimInfo.rcValidRegion.top		= 0;
	VPFmt.amvpDimInfo.rcValidRegion.right	= 720;
	VPFmt.amvpDimInfo.rcValidRegion.bottom	= 240;


	// call the IVPConfig interface here

	if (pdevex->pstroYUV &&	((PSTREAMEX)(pdevex->pstroYUV->HwStreamExtension))->EventCount)
	{
		#ifdef DBG
			DbgPrint("luxdvd : ProcessVideoFormat - KSEVENT_VPNOTIFY_FORMATCHANGE\n");
		#endif

		StreamClassStreamNotification(
	        SignalMultipleStreamEvents,
			pdevex->pstroYUV,
			&MY_KSEVENTSETID_VPNOTIFY,
			KSEVENT_VPNOTIFY_FORMATCHANGE
			);

	}
}

////////////////////////////////////////////////////////////////////////////////

void VideoQueryAccept(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PKSDATAFORMAT pfmt = pSrb->CommandData.OpenFormat;
KS_MPEGVIDEOINFO2 * pblock = (KS_MPEGVIDEOINFO2 *)((ULONG)pfmt + sizeof  (KSDATAFORMAT));

	#ifdef DBG
		DbgPrint("luxdvd : VideoQueryAccept\n");
	#endif

	if(!pSrb)
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : VideoQueryAccept - invalid SRB !!!!\n");
		#endif
		return;
	}

	// pick up the format block and examine it. Default to not implemented
	pSrb->Status = STATUS_NOT_IMPLEMENTED;

	//if (pfmt->FormatSize != sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
	if (pfmt->FormatSize < sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
	{
		#ifdef DBG
			DbgPrint("luxdvd ERROR : VideoQueryAccept - invalid pfmt->FormatSize !!!\n");
		#endif
		return;
	}

	pSrb->Status = STATUS_SUCCESS;

}

////////////////////////////////////////////////////////////////////////////////

//Rate change stuff

void InitVideoRate(PHW_DEVICE_EXTENSION pHwDevExt)
{
	#ifdef DBG
		DbgPrint("luxdvd : InitVideoRate\n");
	#endif
	pHwDevExt->VideoStartTime = 0;
	pHwDevExt->VideoInterceptTime = 0;
	pHwDevExt->VideoRate = 1 * 10000;
	pHwDevExt->StartTime = 0;
	pHwDevExt->InterceptTime = 0;
	pHwDevExt->Rate = 1 * 10000;
	pHwDevExt->ChangeFlag = 0;
	pHwDevExt->VideoMaxFullRate = 2 * 10000;
	//pHwDevExt->VideoMaxFullRate = 3 * 10000;

	pHwDevExt->vid_speed = 1000;
}

////////////////////////////////////////////////////////////////////////////////

void VideoRateChangeGetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension;
	
	switch( pSrb->CommandData.PropertyInfo->Property->Id ) 
	{
		case KS_AM_RATE_SimpleRateChange :
		{
		KS_AM_SimpleRateChange* pRateChange;

			#ifdef DBG
				DbgPrint("luxdvd : VideoRateChangeGetProp - KS_AM_RATE_SimpleRateChange\n");
			#endif
			pSrb->ActualBytesTransferred = sizeof (KS_AM_RATE_SimpleRateChange);
			pRateChange = (KS_AM_SimpleRateChange*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pRateChange->StartTime = pHwDevExt->VideoStartTime;
			pRateChange->Rate = pHwDevExt->VideoRate;
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case KS_AM_RATE_ExactRateChange :
		{
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
		}

		case KS_AM_RATE_MaxFullDataRate :
		{
		KS_AM_MaxFullDataRate* pMaxRate;
		
			#ifdef DBG
				DbgPrint("luxdvd : VideoRateChangeGetProp - KS_AM_RATE_MaxFullDataRate\n");
			#endif
			pSrb->ActualBytesTransferred = sizeof (KS_AM_RATE_MaxFullDataRate);
			pMaxRate = (KS_AM_MaxFullDataRate*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			*pMaxRate = pHwDevExt->VideoMaxFullRate;
			pSrb->Status = STATUS_SUCCESS;
			break;
		}

		case KS_AM_RATE_Step :
		{
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////

void VideoRateChangeSetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef DBG
		DbgPrint("luxdvd : VideoRateChangeSetProp\n");
	#endif

	switch(pSrb->CommandData.PropertyInfo->Property->Id) 
	{
		case KS_AM_RATE_SimpleRateChange :
		{
		KS_AM_SimpleRateChange* pRateChange;
		PHW_DEVICE_EXTENSION pHwDevExt;
		REFERENCE_TIME NewStartTime;
		LONG NewRate;

			#ifdef DBG
				DbgPrint("luxdvd : VideoRateChangeSetProp - KS_AM_RATE_SimpleRateChange\n");
			#endif

			pRateChange = (KS_AM_SimpleRateChange*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension;
			NewStartTime = pRateChange->StartTime;
			NewRate = ( pRateChange->Rate < 0 ) ? -pRateChange->Rate : pRateChange->Rate;

			#ifdef DBG
				DbgPrint("luxdvd : Received - StartTime = = 0x%08x\n", NewStartTime);
				DbgPrint("luxdvd : Received - Rate = = 0x%08x\n", NewRate);
				
				DbgPrint("luxdvd : Current - InterceptTime = 0x%08x\n",pHwDevExt->VideoInterceptTime);
				DbgPrint("luxdvd : Current - StartTime = 0x%08x\n",pHwDevExt->VideoStartTime);
				DbgPrint("luxdvd : Current - Rate = 0x%08x\n",pHwDevExt->VideoRate);
			#endif
			//				pHwDevExt->VideoInterceptTime
			//					= (pHwDevExt->VideoInterceptTime - NewStartTime)
			//					* pHwDevExt->VideoRate
			//					/ NewRate
			//					+ NewStartTime;
						

			if( NewRate == 10000 ) 
			{
				/*
				pHwDevExt->VideoInterceptTime = 0;
				pHwDevExt->VideoStartTime = 0;
				*/
			REFERENCE_TIME NewInterceptTime;

				NewInterceptTime = (REFERENCE_TIME) ( (pHwDevExt->VideoInterceptTime - NewStartTime)*(pHwDevExt->VideoRate/NewRate) 
									+ NewStartTime );
				pHwDevExt->VideoInterceptTime = NewInterceptTime;
				pHwDevExt->VideoStartTime = NewStartTime;

				#ifdef DBG
					DbgPrint("luxdvd : NORMAL RATE\n");
					DbgPrint("luxdvd : pHwDevExt->VideoInterceptTime = 0x%08x, NewStartTime = 0x%08x\n",pHwDevExt->VideoInterceptTime,NewStartTime);
					DbgPrint("luxdvd : pHwDevExt->VideoRate = 0x%08x, NewRate = 0x%08x\n",pHwDevExt->VideoRate,NewRate);
					DbgPrint("luxdvd : New InterceptTime = 0x%08x\n",NewInterceptTime);
				#endif

			}
			else 
			{
			//REFERENCE_TIME NewInterceptTime = 	(REFERENCE_TIME)((-NewStartTime) * 10000 / NewRate + NewStartTime);
			REFERENCE_TIME NewInterceptTime;

				NewInterceptTime = (REFERENCE_TIME) ( (pHwDevExt->VideoInterceptTime - NewStartTime)*(pHwDevExt->VideoRate/NewRate) 
									+ NewStartTime );
				pHwDevExt->VideoInterceptTime = NewInterceptTime;
				pHwDevExt->VideoStartTime = NewStartTime;

				#ifdef DBG
					DbgPrint("luxdvd : SPECIAL RATE\n");
					DbgPrint("luxdvd : pHwDevExt->VideoInterceptTime = 0x%08x, NewStartTime = 0x%08x\n",pHwDevExt->VideoInterceptTime,NewStartTime);
					DbgPrint("luxdvd : pHwDevExt->VideoRate = 0x%08x, NewRate = 0x%08x\n",pHwDevExt->VideoRate,NewRate);
					DbgPrint("luxdvd : New InterceptTime = 0x%08x\n",NewInterceptTime);
				#endif
			}

			pHwDevExt->VideoRate = NewRate;

			SetRateChange( pHwDevExt, 0x01 );
			pSrb->Status = STATUS_SUCCESS;
			break;
		}


		case KS_AM_RATE_ExactRateChange :
		{
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
		}

		case KS_AM_RATE_MaxFullDataRate :
		{
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
		}

		case KS_AM_RATE_Step :
		{
			LUXVideoStep();
			pSrb->Status = STATUS_SUCCESS;
//			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////

void SetRateChange(PHW_DEVICE_EXTENSION pHwDevExt, LONG strm)
{
// strm = 1:video, 2:audio, 4:subpic

	#ifdef DBG
		DbgPrint("luxdvd : SetRateChange for ");
		if(strm==1)
			DbgPrint("Video\n");
		else if(strm==2)
			DbgPrint("Audio\n");
		else if(strm==4)
			DbgPrint("SubPic\n");
	#endif
			
	pHwDevExt->ChangeFlag = strm;

	// When video stream rate is changed, rate change is enable... Is this OK?

	if( (pHwDevExt->ChangeFlag & 0x01)==0x01 )	//VIDEO
	{
		pHwDevExt->ChangeFlag = 0;

		// Maybe buggy? use video rate, start time and intercept time
		pHwDevExt->StartTime = pHwDevExt->VideoStartTime;
		pHwDevExt->InterceptTime = pHwDevExt->VideoInterceptTime;
		pHwDevExt->Rate = pHwDevExt->VideoRate;

		#ifdef DBG
			DbgPrint("luxdvd : SetRateChange - Calculated Data :\n");
			DbgPrint("\tInterceptTime = 0x%08x\n", pHwDevExt->VideoInterceptTime);
			DbgPrint("\tStartTime = 0x%08x\n", pHwDevExt->VideoStartTime);
			DbgPrint("\tRate = 0x%08x\n", pHwDevExt->VideoRate);
		#endif

		if( pHwDevExt->Rate == 10000 ) 
		{
			#ifdef ORIG
				SetPlayMode( pHwDevExt, PLAY_MODE_NORMAL );
			#endif

			#ifdef DBG
				DbgPrint("luxdvd : Video Rate == 10000, NORMAL_SPEED\n");
			#endif
						
			if ( pHwDevExt->vid_speed > 1000 )
			{
				LUXVideoStop();
				LUXAudioStop();
				LUXVideoAfterSeek();
				LUXAudioAfterSeek();

				LUXVideoCleanScreen();
			}

			LUXVideoPlay(1000);
			LUXAudioPlay(1000);

			pHwDevExt->vid_speed = 1000;
			pHwDevExt->bAudioFF = FALSE;

		}
		else
		{
			#ifdef ORIG
				SetPlayMode( pHwDevExt, PLAY_MODE_FAST );
			#endif

			pHwDevExt->bAudioFF = TRUE;

			if( pHwDevExt->Rate < 10000 ) 
			{
				pHwDevExt->vid_speed = 2000;
				#ifdef DBG
					DbgPrint("luxdvd : Video Rate < 10000, FAST_SPEED /w Rate = %d\n",pHwDevExt->Rate);
				#endif

				LUXAudioSetVolume(255);	//special method to perform real MUTE
				LUXVideoStop();
				LUXAudioStop();
				LUXVideoAfterSeek();
				LUXAudioAfterSeek();
			
				LUXVideoFFward();

			}
			else
			{
				pHwDevExt->vid_speed = 500;
				#ifdef DBG
					DbgPrint("luxdvd : Video Rate > 10000, Slow_SPEED /w Rate = %d\n",pHwDevExt->Rate);
				#endif
				
				LUXAudioMute();
				LUXAudioStop();
				LUXVideoSetSpeed(500);
				LUXAudioSetSpeed(500);
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////

void UserDataEvents(PHW_DEVICE_EXTENSION pdevex)
{
DWORD i,numb;
PBYTE pDest;
PHW_STREAM_REQUEST_BLOCK pSrb;
PKSSTREAM_HEADER   pPacket;
BYTE *pb;
PDWORD pdw;
ULONGLONG CCTime=0, StrmTime=0;


	pb = (BYTE*)LUXVideoUserData();
	pb -=0x10;
	for (i=0;i<CHK_CNT;i++)
	{
		pdw = (DWORD *)(pb+i);
		if ((*pdw== 0xb2010000) && ( *((WORD*)(pb+i+4)) == 0x4343 ))
		{
			pb += i;
			break;
		}
	}
	if (i == CHK_CNT) 
		return;
	
	// 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())
		{
			if(pSrb==NULL)
				return;

			//
			// 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))
			{
				pSrb->Status = STATUS_INVALID_BUFFER_SIZE;
				pSrb->ActualBytesTransferred = 0;
				StreamClassStreamNotification(StreamRequestComplete,
						pSrb->StreamObject,
						pSrb);
				return;
			}

			pDest = pSrb->CommandData.DataBufferArray->Data;

			// move pdw pointer to the size of CC
			pb = pb+8;

			numb = (DWORD)(*pb)&0x3f;
			numb = (numb-1)*3 + sizeof(KSGOP_USERDATA);

			if (pSrb->CommandData.DataBufferArray->FrameExtent < numb)
			{
				pSrb->Status = STATUS_INVALID_BUFFER_SIZE;
				pSrb->ActualBytesTransferred = 0;
				StreamClassStreamNotification(StreamRequestComplete,
						pSrb->StreamObject,
						pSrb);
				return;
			}
			
			pSrb->CommandData.DataBufferArray->DataUsed =
				pSrb->ActualBytesTransferred = numb;

			DVReadStr((DWORD)pDest,(DWORD)pdw-(DWORD)luxbase,numb);

			pSrb->Status = STATUS_SUCCESS;

			pPacket = pSrb->CommandData.DataBufferArray;

			pPacket->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
						KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
			pSrb->NumberOfBuffers = 1;

			#ifdef USE_STC
				pPacket->PresentationTime.Time = ConvertPTStoStrm((ULONG)LUXVideoGet_STC()/*-0x800*/) ;
			#else
				//pPacket->PresentationTime.Time = ConvertPTStoStrm(vPts<<1) ;
//				pPacket->PresentationTime.Time = ConvertVPTStoStrm((ULONGLONG)(vPts<<1));
				pPacket->PresentationTime.Time = ConvertVPTStoStrm(((ULONGLONG)(v_PTS))<<1);
			#endif
			
			CCTime = (ULONGLONG)pPacket->PresentationTime.Time;

			//Get the cuurent audio clock returned to StreamClass driver
			StreamClassQueryMasterClock(pSrb->StreamObject, hClk, TIME_GET_STREAM_TIME , StreamTimeCB);
			StrmTime = (ULONGLONG)(LastStamp + GetSystemTime() - LastSys);

			#ifdef DBG
				DbgPrint("luxdvd : CCTime = 0x%lx   ",CCTime);
				DbgPrint("StrmTime = 0x%lx   ",StrmTime);
				if( StrmTime > CCTime )
				{
					DbgPrint("CC behind, Adjusting\n");
					
				}
				else
					DbgPrint("\n");
			#endif

			//Make sure that the CCtime matches the Strmtime
			if( StrmTime > CCTime )
				pPacket->PresentationTime.Time = StrmTime;


			pPacket->Duration = 1000;	//Line21 decoder does not care about this

			StreamClassStreamNotification(StreamRequestComplete,
					pSrb->StreamObject,
					pSrb);

			return;

		}
	}

}

////////////////////////////////////////////////////////////////////////////////

void CCSendDiscontinuity(PHW_DEVICE_EXTENSION pdevex)
{
PHW_STREAM_REQUEST_BLOCK pSrb;
PKSSTREAM_HEADER   pPacket;

	if (pdevex->pstroCC && ((PSTREAMEX)(pdevex->pstroCC->HwStreamExtension))->state	== KSSTATE_RUN )
	{
		if (pSrb = CCDequeue())
		{
			if(pSrb==NULL)
				return;

			#ifdef DBG
				DbgPrint("luxdvd : CCSendDiscontinuity\n");
			#endif
				
			// we have a request, send a discontinuity
			pSrb->Status = STATUS_SUCCESS;
			pPacket = pSrb->CommandData.DataBufferArray;

			if(pPacket == NULL)
				return;
	
			pPacket->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY |
			KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;

			pPacket->DataUsed = 0;
			pSrb->NumberOfBuffers = 0;

			#ifdef USE_STC
			pPacket->PresentationTime.Time = ConvertPTStoStrm((ULONG)LUXVideoGet_STC());
			#else
			//pPacket->PresentationTime.Time = ConvertPTStoStrm(vPts<<1) ;
//			pPacket->PresentationTime.Time = ConvertVPTStoStrm((ULONGLONG)(vPts<<1));
			pPacket->PresentationTime.Time = ConvertVPTStoStrm(((ULONGLONG)(v_PTS))<<1);
			#endif

			pPacket->Duration = 1000;

			pSrb->ActualBytesTransferred = 0;

			StreamClassStreamNotification(StreamRequestComplete,
					pSrb->StreamObject,
					pSrb);

		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////

void VideoLuxSetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef DBG
		//DbgPrint("luxdvd : VideoLuxSetProp\n");
	#endif

	switch( pSrb->CommandData.PropertyInfo->Property->Id ) 
	{
		case LUXSONOR_AM_PROPERTY_VID_GAMMA :
		{
		LuxVidGamma* pGa;

			pGa = (LuxVidGamma*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			LUXVideoSetGamma(pGa->gamma);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}
		case LUXSONOR_AM_PROPERTY_VID_ZOOM :
		{
		LuxSetVidZoom* pZ;

			pZ = (LuxSetVidZoom*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			LUXVideoSetZoom(pZ->leftTop,pZ->rightBottom);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}
		case LUXSONOR_AM_PROPERTY_VID_CHROMA :
		{
		LuxVidChroma* pCa;

			pCa = (LuxVidChroma*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			LUXVideoSetChroma(pCa->chroma);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}
		case LUXSONOR_AM_PROPERTY_VID_EPROM :
		{
		LuxSetVidEprom* pEprom;

			pEprom = (LuxSetVidEprom*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			send_i2c(0xa0,pEprom->addr,pEprom->value);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}
		case LUXSONOR_AM_PROPERTY_VID_FULLSCR :
		{
		LuxSetVidFullScr* mfullscr;
			mfullscr = (LuxSetVidFullScr*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			LUXVideoSetFullScreen(mfullscr->onoff);
			pSrb->Status = STATUS_SUCCESS;
			break;
		}
		default:
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}
}

void VideoLuxGetProp(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	pSrb->Status = STATUS_SUCCESS;

	switch( pSrb->CommandData.PropertyInfo->Property->Id ) 
	{
		case LUXSONOR_AM_PROPERTY_VID_GAMMA :
		{
		LuxVidGamma* pGa;

			pGa = (LuxVidGamma*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pGa->gamma = LuxVideoGetGamma();
			pSrb->ActualBytesTransferred = sizeof(LuxVidGamma);
			break;
		}

		case LUXSONOR_AM_PROPERTY_VID_CHROMA :
		{
		LuxVidChroma* pCa;

			pCa = (LuxVidChroma*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pCa->chroma = LuxVideoGetChroma();
			pSrb->ActualBytesTransferred = sizeof(LuxVidChroma);
			break;
		}

		case LUXSONOR_AM_PROPERTY_VID_EPROM_SPDIF :
		{
		LuxGetVidEpromSPDIF* pEprom;

			pEprom = (LuxGetVidEpromSPDIF*)pSrb->CommandData.PropertyInfo->PropertyInfo;
			pEprom->eprom0a = eprom[0x0a];
			pEprom->eprom0b = eprom[0x0b];
			pSrb->ActualBytesTransferred = sizeof(LuxGetVidEpromSPDIF);
			break;
		}

		default:
			pSrb->Status = STATUS_NOT_IMPLEMENTED;
			break;
	}
}