2025-04-27 07:49:33 -04:00

636 lines
14 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*******************************************************************
*
* MPVIDEO.C
*
* Copyright (C) 1995 SGS-THOMSON Microelectronics.
*
*
* PORT/MINIPORT Interface Video Routines
*
*******************************************************************/
#include "strmini.h"
#include "mpinit.h"
#include <wingdi.h>
#include "ksmedia.h"
#include "mpvideo.h"
#include "hwcodec.h"
#include "ptsfifo.h"
#include "trace.h"
#include "copyprot.h"
extern PVIDEO pVideo;
extern GUID MY_KSEVENTSETID_VPNOTIFY;
KS_MPEGVIDEOINFO2 VidFmt;
KS_AMVPDATAINFO VPFmt;
void mpstCommandComplete(PHW_STREAM_REQUEST_BLOCK pSrb);
VOID AudioTimerCallBack(PHW_STREAM_OBJECT pstrm);
ULONG mpstVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb);
void AudioPacketStub(PHW_STREAM_OBJECT pstrm);
void VideoPacketStub(PHW_STREAM_OBJECT pstrm)
{
VideoTimerCallBack(pstrm);
}
ULONG miniPortVideoPause(PHW_STREAM_REQUEST_BLOCK pSrb, PHW_DEVICE_EXTENSION pHwDevExt)
{
ULONG dwErrCode = NO_ERROR;
pSrb = pSrb; // Remove Warning
HwCodecPause();
pHwDevExt->VideoDeviceExt.DeviceState = KSSTATE_PAUSE;
return dwErrCode;
}
VOID miniPortVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
ULONG dwErrCode = NO_ERROR;
ULONG uSent=0;
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.
//
pvidex->cPacket = 0;
pvidex->cOffs = PACK_HEADER_SIZE;
pvidex->pPacket = pSrb->CommandData.DataBufferArray;
if (!pvidex->pPacket)
{
TRAP
}
pvidex->pCurrentSRB = pSrb;
pHwDevExt->VideoDeviceExt.videoSTC =
pvidex->pPacket->PresentationTime.Time;
MPTrace(mTraceVideo);
VideoPacketStub(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
//
CopyProtGetProp(pSrb);
break;
default:
break;
}
}
VOID miniPortSetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext =
((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
DbgPrint("'miniPortSetState:StreamState=%x\n",pSrb->CommandData.StreamState);
switch (pSrb->CommandData.StreamState)
{
case KSSTATE_STOP:
MPTrace(mTraceStop);
if(phwdevext->VideoDeviceExt.pCurrentSRB != NULL)
{
MPTrace(mTraceLastVideoDone);
phwdevext->VideoDeviceExt.pCurrentSRB->Status = STATUS_SUCCESS;
mpstCommandComplete(phwdevext->VideoDeviceExt.pCurrentSRB);
phwdevext->VideoDeviceExt.pCurrentSRB = NULL;
StreamClassScheduleTimer(pSrb->StreamObject, phwdevext,
0, VideoPacketStub, pSrb->StreamObject);
}
if(phwdevext->AudioDeviceExt.pCurrentSRB != NULL)
{
MPTrace(mTraceLastAudioDone);
phwdevext->AudioDeviceExt.pCurrentSRB->Status = STATUS_SUCCESS;
mpstCommandComplete(phwdevext->AudioDeviceExt.pCurrentSRB);
phwdevext->AudioDeviceExt.pCurrentSRB = NULL;
StreamClassScheduleTimer(pSrb->StreamObject, phwdevext,
0, AudioPacketStub, pSrb->StreamObject);
}
// miniPortVideoStop(pSrb, phwdevext);//pause for now should be stop
HwCodecStop();
phwdevext->VideoDeviceExt.DeviceState = KSSTATE_STOP;
break;
case KSSTATE_PAUSE:
MPTrace(mTracePause);
// miniPortVideoPause(pSrb, phwdevext);
HwCodecPause();
phwdevext->VideoDeviceExt.DeviceState = KSSTATE_PAUSE;
break;
case KSSTATE_RUN:
MPTrace(mTracePlay);
HwCodecPlay();
phwdevext->VideoDeviceExt.DeviceState = KSSTATE_RUN;
break;
}
pSrb->Status = STATUS_SUCCESS;
}
ULONG miniPortVideoReset(PHW_STREAM_REQUEST_BLOCK pSrb, PHW_DEVICE_EXTENSION pHwDevExt)
{
ULONG dwErrCode = NO_ERROR;
TRAP
// TBC
// mpstVideoReset();
HwCodecSeek();
pHwDevExt->VideoDeviceExt.DeviceState = KSSTATE_PAUSE;
pSrb->Status = STATUS_SUCCESS;
return dwErrCode;
}
ULONG miniPortVideoSetStc(PHW_STREAM_REQUEST_BLOCK pSrb, PHW_DEVICE_EXTENSION pHwDevExt)
{
ULONG dwErrCode = NO_ERROR;
pHwDevExt = pHwDevExt; // Remove Warning
pSrb = pSrb; // Remove Warning
return dwErrCode;
}
ULONG miniPortVideoStop (PHW_STREAM_REQUEST_BLOCK pSrb, PHW_DEVICE_EXTENSION pHwDevExt)
{
ULONG dwErrCode = NO_ERROR;
// TBC
if(pHwDevExt->VideoDeviceExt.pCurrentSRB != NULL)
{
// Still to send a packet
pHwDevExt->VideoDeviceExt.pCurrentSRB->Status = STATUS_SUCCESS;
MPTrace(mTraceRdyVid);
StreamClassStreamNotification(ReadyForNextStreamDataRequest,
pHwDevExt->VideoDeviceExt.pCurrentSRB->StreamObject);
StreamClassStreamNotification(StreamRequestComplete,
pHwDevExt->VideoDeviceExt.pCurrentSRB->StreamObject,
pHwDevExt->VideoDeviceExt.pCurrentSRB);
//
// request a timer callback
//
StreamClassScheduleTimer(pSrb->StreamObject, pSrb->HwDeviceExtension,
0, VideoPacketStub, pSrb->StreamObject);
pHwDevExt->VideoDeviceExt.pCurrentSRB =
pHwDevExt->pCurSrb = NULL;
}
DbgPrint("'miniPortVideoStop\n");
//HwCodecVideoPause();//should be stop use pause for now
HwCodecStop();
pSrb->Status = STATUS_SUCCESS;
return dwErrCode;
}
BYTE BogusPacket[8192] = {0};
VOID VideoTimerCallBack(PHW_STREAM_OBJECT pstrm)
{
PHW_DEVICE_EXTENSION pdevext = pstrm->HwDeviceExtension;
PHW_STREAM_REQUEST_BLOCK pSrb;
ULONG uSent;
BOOL fNotVideo;
PVIDEO_DEVICE_EXTENSION pvidex = &(pdevext->VideoDeviceExt);
static BOOL fNewVid = FALSE;
ULONG ExtraBytes;
PUCHAR SizePtr;
pSrb = pvidex->pCurrentSRB;
if (!pSrb)
{
return;
}
do
{
fNotVideo = FALSE;
if (pvidex->pPacket->OptionsFlags &
KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
{
HwCodecProcessDiscontinuity();
}
if (pvidex->pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
{
if (pvidex->pPacket->DataUsed >= sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
{
ProcessVideoFormat((PKSDATAFORMAT)pvidex->pPacket->Data, pdevext);
uSent = pvidex->pPacket->DataUsed + 1;
}
else
{
TRAP
}
fNotVideo = TRUE;
}
else if (pvidex->pPacket->DataUsed)
{
uSent = mpstVideoPacket(pSrb);
fNewVid= FALSE;
}
else
{
DbgPrint("'Video Discontinuity\n");
fNewVid = TRUE;
uSent = 1;
fNotVideo = TRUE;
}
pvidex->cOffs += uSent;
//
// check if we finished this packet. If so, go on to the
// next packet
//
if (pvidex->cOffs >=
pvidex->pPacket->DataUsed)
{
if (pvidex->pPacket->DataUsed >= 4 && !fNotVideo)
{
SizePtr = (PUCHAR) ((ULONG_PTR) pvidex->pPacket->Data +
PACK_HEADER_SIZE + 4);
ExtraBytes = pvidex->pPacket->DataUsed - PACK_HEADER_SIZE -
((ULONG) (SizePtr[0] << 8) + (ULONG) SizePtr[1] + 4 + 2);
if (*((PULONG)((PBYTE)pvidex->pPacket->Data + pvidex->pPacket->DataUsed - 4 - ExtraBytes)) ==
0xb7010000)
{
//
// found an end of sequence header
//
// Flush the buffer
HwCodecFlushBuffer();
}
}
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);
MPTrace(mTraceVideoDone);
pvidex->pCurrentSRB = 0;
return;
}
}
} while (uSent);
StreamClassScheduleTimer(pstrm, pstrm->HwDeviceExtension,
1, (PHW_PRIORITY_ROUTINE)VideoTimerCallBack, pstrm);
}
void StubMpegEnableIRQ(PHW_STREAM_OBJECT pstrm)
{
HwCodecEnableIRQ();
}
ULONG mpstVideoPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
BOOL bPts = FALSE;
BOOL bLatchPts = FALSE;
DWORD vPts;
PVIDEO_DEVICE_EXTENSION pvidex =
&(((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension)->VideoDeviceExt);
ULONG uLen;
ULONG cPacket;
PUCHAR p;
PUCHAR SizePtr;
ULONG ExtraBytes;
#define MAX_SIZE 8192
//
// find out how many bytes we can squeeze in
//
uLen = MAX_SIZE; //(BUF_FULL - VideoGetBBL()) * 256;
if(pvidex->pPacket->OptionsFlags &
KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
{
TRAP
}
if(pvidex -> cOffs == PACK_HEADER_SIZE)
{
p = (PUCHAR)((ULONG_PTR) pvidex->pPacket->Data + PACK_HEADER_SIZE);
if ((p!=NULL) && (pvidex->pPacket->DataUsed > 8 + PACK_HEADER_SIZE))
{
int ptsf;
ptsf = (p[7] >> 6)&0x03;
pvidex->cOffs = p[8]+9 + PACK_HEADER_SIZE;
bLatchPts = TRUE;
if(ptsf)
{
bPts = TRUE;
vPts =((DWORD)(p[9]&0x0E)>>1) << 30 |
((DWORD)(p[10])) << 22 |
((DWORD)(p[11])>>1) << 15 |
((DWORD)(p[12])) << 7 |
((DWORD)(p[13])>>1) ;
}
else
{
vPts = 0x0;
}
}
else
{
TRAP
}
}
SizePtr = (PUCHAR) ((ULONG_PTR) pvidex->pPacket->Data + PACK_HEADER_SIZE + 4);
ExtraBytes = pvidex->pPacket->DataUsed - PACK_HEADER_SIZE -
((ULONG) (SizePtr[0] << 8) + (ULONG) SizePtr[1] + 4 + 2);
cPacket = pvidex->pPacket->DataUsed - pvidex->cOffs - ExtraBytes;
uLen = uLen > cPacket ? cPacket : uLen;
if(uLen > MAX_SIZE)
uLen = MAX_SIZE;
if (uLen)
{
ULONG retval;
retval = HwCodecSendVideo((BYTE *)(((ULONG_PTR)pvidex->pPacket->Data) + pvidex->cOffs), uLen);
if(bLatchPts)
{
FifoPutPTS(vPts, pvidex->pPacket->DataUsed-pvidex->cOffs, bPts);
}
if (uLen == retval) {
return retval + ExtraBytes;
} else {
return retval;
}
}
return uLen;
}
/////////////////////////////////////////////////////////////////////////
//
// Function : mpstCommandComplete
// Args : SRB
// Returns : none
//
// Purpose:
// Performs a completion callback on a given request,
// and then dequeues any outstanding requests
//
// Last Modified 10.1.96 by JBS
//
/////////////////////////////////////////////////////////////////////////
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
//
MPTrace(mTraceRdyVid);
StreamClassStreamNotification(ReadyForNextStreamDataRequest,
pSrb->StreamObject);
StreamClassStreamNotification(StreamRequestComplete,
pSrb->StreamObject,
pSrb);
}
void ProcessVideoFormat(PKSDATAFORMAT pfmt, PHW_DEVICE_EXTENSION pdevex)
{
KS_MPEGVIDEOINFO2 * pblock = (KS_MPEGVIDEOINFO2 *)((ULONG_PTR)pfmt + sizeof (KSDATAFORMAT));
ULONG cXOut;
if (pfmt->FormatSize != sizeof(KSDATAFORMAT) + sizeof(KS_MPEGVIDEOINFO2))
{
TRAP
return;
}
//
// copy the format block
//
VidFmt = *pblock;
//
// copy the picture aspect ratio for now
//
VPFmt.dwPictAspectRatioX = VidFmt.hdr.dwPictAspectRatioX;
VPFmt.dwPictAspectRatioY = VidFmt.hdr.dwPictAspectRatioY;
//
// 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;
//
// set up the X dimensions
//
cXOut = 540;
}
else // pan scan disabled, just check the format, and use it
{
cXOut = VidFmt.hdr.bmiHeader.biWidth;
}
//
// set up the valid regions.
//
DbgPrint("CYCLO: FieldX = %d\n", cXOut);
DbgPrint("CYCLO: FieldY = %d\n", VidFmt.hdr.bmiHeader.biHeight);
VPFmt.amvpDimInfo.dwFieldWidth = cXOut + 63;
VPFmt.amvpDimInfo.dwFieldHeight = (VidFmt.hdr.bmiHeader.biHeight /2 )+18;
VPFmt.amvpDimInfo.dwVBIWidth = cXOut+63;
VPFmt.amvpDimInfo.dwVBIHeight = 0;
VPFmt.amvpDimInfo.rcValidRegion.left = 63;
VPFmt.amvpDimInfo.rcValidRegion.top = 18;
VPFmt.amvpDimInfo.rcValidRegion.right = cXOut + 63;
VPFmt.amvpDimInfo.rcValidRegion.bottom = 258;
VideoSwitchSRC(FALSE);
//
// call the IVPConfig interface here
//
if (pdevex->pstroYUV &&
((PSTREAMEX)(pdevex->pstroYUV->HwStreamExtension))->EventCount)
{
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_PTR)pfmt + sizeof (KSDATAFORMAT));
//
// 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))
{
return;
}
pSrb->Status = STATUS_SUCCESS;
}