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

2748 lines
53 KiB
C
Raw 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.

#include "strmini.h"
#include "stdefs.h"
#include "mpinit.h"
#include "sti3520a.h"
#include "mpvideo.h"
#include "board.h"
#include "trace.h"
#include "hwcodec.h"
#include "copyprot.h"
void SPVideoOSDOn();
void SPVideoOSDOff();
static ULONG cSPBytes = 0;
extern PVIDEO pVideo;
extern PSP_STRM_EX pSPstrmex;
static ULONG ulRemain = 0;
/*
** DecodeRLE ()
**
** - decodes a DVD encoded RLE compressed bitmap region into an
** uncompressed 4 bit per pixel bitmap
**
** Arguments:
**
**
**
** Returns:
**
** Side Effects:
*/
#define GetCurNibble(foo) (((foo) % 2) ? (*((PBYTE)pspstrmex->pdecctl.pData + ((foo) >> 1))\
& 0x0f) : (((*((PBYTE)pspstrmex->pdecctl.pData + ((foo) >> 1)))) >> 4))
BOOL DecodeRLE(PBYTE pdest, ULONG cStart, PSP_STRM_EX pspstrmex)
{
ULONG pOffs; // current position in the packet in nibbles
USHORT cX;
USHORT cY;
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
ULONG cDestOffs; // current pixel in the destination bitmap
USHORT cPix;
USHORT cBlt;
USHORT yBlt;
UCHAR bPix;
UCHAR bPltPix; // current pallette pixel to draw
ULONG dbgWord;
BOOLEAN fLine = FALSE;
ULONG ulTmp;
//
// color pallette locals
//
PPXCTLY ppxcd = pdecctl->ppxcd;
SMYCOLCON linechg[11]; // color control structure
PSMYCOLCON pchg;
ULONG cChgs, cTmp; // number of color changes in the line
//
// clear the pallette mapping
//
for (ulTmp = 0; ulTmp < 16; ulTmp++)
{
pdecctl->mappal.palFlags[ulTmp] = 0;
}
pdecctl->minCon = 0xf;
pdecctl->decFlags &= ~SPDECFL_USE_STRAIGHT_PAL;
//
// find the offset in the packet (in nibbles)
//
RESTART_DECODE:
pOffs = cStart << 1;
//
// Source bitmap is as follow:
//
// (note: this whole thing is based on nibbles)
//
// format 1: xxPD - 2 bit count, plus 2 bit PD
// format 2: 00xxxxPD - 2 bit 0 marker, 4 bit count
// format 3: 0000xxxxxxPD - 4 bit 0 marker, 6 bit count
// format 4: 000000xxxxxxxxPD - 6 x 0, 8 bit count,
// format 5: 00000000000000PD - 14 x0, no count -> end of line
//
cY = 0;
cDestOffs = 0;
do {
//
// set up the default pallette
//
linechg[0].chgsppal = pdecctl->sppPal;
linechg[0].stopx = (pdecctl->ulDSAw);
cChgs = 1;
if (pOffs >> 1 >= pdecctl->pSPCmds)
{
TRAP
return(FALSE);
}
fLine = (ppxcd && ((*((PDWORD)ppxcd) != SP_LCTL_TERM)));
if ( fLine || pdecctl->HLI.fActive)
{
//
// we have line control information, OR highlight info
// let's use it to find the relevant color control information
//
//
// if the current cY < current line control number, and
// it's less than the highlight information
// we use standard info, and go to the start of line control
// or highlight, whichever is first
//
// if the current cY = current line control number, or highlight
// we use current change info, and go to termination
// line number or highlight, or
//
//
if ( (fLine && ((cY << 1) < ((((USHORT)ppxcd->chglinhi) << 8) +
((USHORT)ppxcd->chglin))))
|| (pdecctl->HLI.fActive && (cY <
(pdecctl->HLI.hli.StartY >> 1))))
{
if (fLine)
{
yBlt = ((ppxcd->chglinhi << 8) + ppxcd->chglin) >> 1;
}
else
{
yBlt = pdecctl->HLI.hli.StartY >> 1;
}
if (pdecctl->HLI.fActive && (yBlt << 1) > pdecctl->HLI.hli.StartY)
{
yBlt = pdecctl->HLI.hli.StartY >> 1;
}
pdecctl->numchg = 0;
}
else if (ppxcd)
{
TRAP
pdecctl->numchg = ppxcd->numchg;
if (!pdecctl->numchg)
{
TRAP
return(FALSE);
}
yBlt = ((ppxcd->chgstophi << 8) + ppxcd->chgstop) >> 1;
if (yBlt < cY)
{
TRAP
return (FALSE);
}
//
// define the x changes
//
if (ppxcd->numchg > 8)
{
TRAP
return(FALSE);
}
for (cChgs = 0; cChgs < pdecctl->numchg; cChgs++)
{
linechg[cChgs].stopx =
(ppxcd->xchg[cChgs].chgpixhi << 8) +
ppxcd->xchg[cChgs].chgpix;
linechg[cChgs+1].chgsppal.color[0]=
ppxcd->xchg[cChgs].colcon.backcol;
linechg[cChgs+1].chgsppal.color[1]=
ppxcd->xchg[cChgs].colcon.patcol;
linechg[cChgs+1].chgsppal.color[2]=
ppxcd->xchg[cChgs].colcon.emph1col;
linechg[cChgs+1].chgsppal.color[3]=
ppxcd->xchg[cChgs].colcon.emph2col;
}
linechg[cChgs].stopx = pdecctl->ulDSAw;
} // end else we have change information for this line
if (pdecctl->HLI.fActive)
{
if ((cY < (pdecctl->HLI.hli.StartY >> 1)))
{
yBlt = pdecctl->HLI.hli.StartY >> 1;
}
else if (cY < (pdecctl->HLI.hli.StopY) >> 1)
{
//
// we have highlight information for this period
// we need to override any change control information, and
// set the end lines appropriately
//
if (pdecctl->HLI.hli.StopX > pdecctl->ulDSAw)
{
TRAP
}
//
// find the change control that stops after the start of the
// Highlight info
//
for (cChgs = 0;
cChgs < pdecctl->numchg &&
linechg[cChgs].stopx < pdecctl->HLI.hli.StopX;
cChgs++)
{
}
//
// move over to the end after this change
//
for (cTmp = pdecctl->numchg +1;
cTmp > cChgs;
cTmp--)
{
linechg[cTmp] = linechg[cTmp - 1];
}
pdecctl->numchg++;
linechg[cChgs].stopx = pdecctl->HLI.hli.StartX;
//
// if the highlight is in the middle of a change, go ahead
// and create another change, starting at the end of the
// highlight
//
if (linechg[cChgs + 1].stopx > pdecctl->HLI.hli.StopX)
{
for (cTmp = pdecctl->numchg +1;
cTmp > cChgs + 1;
cTmp--)
{
linechg[cTmp] = linechg[cTmp - 1];
}
pdecctl->numchg++;
}
//
// now set up the highlight change
//
linechg[cChgs + 1].stopx = pdecctl->HLI.hli.StopX;
linechg[cChgs+1].chgsppal.color[0]=
pdecctl->HLI.hli.ColCon.backcol;
linechg[cChgs+1].chgsppal.color[1]=
pdecctl->HLI.hli.ColCon.patcol;
linechg[cChgs+1].chgsppal.color[2]=
pdecctl->HLI.hli.ColCon.emph1col;
linechg[cChgs+1].chgsppal.color[3]=
pdecctl->HLI.hli.ColCon.emph2col;
linechg[cChgs+1].chgsppal.mix[0]=
pdecctl->HLI.hli.ColCon.backcon;
linechg[cChgs+1].chgsppal.mix[1]=
pdecctl->HLI.hli.ColCon.patcon;
linechg[cChgs+1].chgsppal.mix[2]=
pdecctl->HLI.hli.ColCon.emph1con;
linechg[cChgs+1].chgsppal.mix[3]=
pdecctl->HLI.hli.ColCon.emph2con;
//
// now search the change information and
//
//
// check if the highlight information ends before the end
// of the current lines
//
yBlt = pdecctl->HLI.hli.StopY >> 1;
}
else
{
yBlt = (USHORT)(pdecctl->ulDSAh / 2);
}
} // end if highlight information
} // end if we have change information
else // no change information or end of change info
{
yBlt = (USHORT)(pdecctl->ulDSAh / 2);
ppxcd = NULL;
}
for (; cY < yBlt; cY++)
{
//
// the start of a line must always be on an even nibble!
//
if (pOffs & 1)
{
pOffs++;
}
for (cX = 0, pchg = &linechg[0]; cX < (pdecctl->ulDSAw);)
{
if (GetCurNibble(pOffs) > 0x3)
{
//
// smallest RLE encoding, must have 0-3 pixels
//
cPix = GetCurNibble(pOffs) >> 2;
}
else if (GetCurNibble(pOffs))
{
//
// must have a 2 bit 00 indicator code with 4 bit
// count
//
cPix = ((GetCurNibble(pOffs)) << 2)
+ (GetCurNibble(pOffs +1) >> 2);
dbgWord = (GetCurNibble(pOffs) << 4) +
(GetCurNibble(pOffs + 1));
pOffs += 1;
}
else if (GetCurNibble(pOffs + 1) > 3)
{
//
// 4 leading 00s, 6 bit count
//
cPix = (GetCurNibble(pOffs + 1) << 2) +
((GetCurNibble(pOffs + 2)) >> 2);
dbgWord = (GetCurNibble(pOffs) << 8) +
((GetCurNibble(pOffs + 1)) << 4) +
((GetCurNibble(pOffs + 2)));
pOffs += 2;
}
else if (GetCurNibble(pOffs + 1))
{
//
// 6 leading 0s, 8 bit count
//
cPix = (GetCurNibble(pOffs + 1) << 6) +
(GetCurNibble(pOffs + 2) << 2) +
(GetCurNibble(pOffs + 3) >> 2);
dbgWord = (GetCurNibble(pOffs) << 12) +
((GetCurNibble(pOffs + 1)) << 8) +
((GetCurNibble(pOffs + 2)) << 4);
((GetCurNibble(pOffs + 3)));
pOffs += 3;
}
else if (GetCurNibble(pOffs + 2) ||
(GetCurNibble(pOffs + 3) & 0xc0))
{
//
// for the 4 nibble case, we must have a count of
// at least 64 (nibble 1, bit 1 or 2 is set), or
// nibbles 1, 2, and top half of 3 must all be 0
//
// in this case, nibble 1 is clear and some other
// part of the count is not. This is illegal, so
// error out
//
TRAP
return(FALSE);
}
else
{
//
// this must be the end of the line case
//
cPix = (USHORT)(pdecctl->ulDSAw) - cX;
dbgWord = (GetCurNibble(pOffs) << 12) +
((GetCurNibble(pOffs + 1)) << 8) +
((GetCurNibble(pOffs + 2)) << 4);
((GetCurNibble(pOffs + 3)));
pOffs += 3;
}
bPix = GetCurNibble(pOffs) & 0x3;
pOffs++;
if ((cPix + cX > (USHORT)pdecctl->ulDSAw) || !cPix)
{
//
// Uh oh! Overruning the line, something is wrong!
//
TRAP
cPix = (USHORT)pdecctl->ulDSAw - cX;
// return(FALSE);
}
//
// set up the starting palette for this line
//
for (;cPix>0;)
{
//
// if the current change stop x < cx, we need
// to move on to the next color
//
if (pchg->stopx <= cX)
{
pchg++;
}
//
// blt for how many pixels we have, or until
// the next change
//
cBlt = (cPix < ((USHORT)pchg->stopx - cX)) ?
cPix : ((USHORT)pchg->stopx - cX);
cPix -= cBlt;
cX += cBlt;
bPltPix = pchg->chgsppal.color[bPix];
if (!(pdecctl->decFlags & SPDECFL_USE_STRAIGHT_PAL))
{
if (!SPChooseMap(pdecctl, &bPltPix, pchg->chgsppal.mix[bPix]))
{
TRAP
pdecctl->decFlags |= SPDECFL_USE_STRAIGHT_PAL;
goto RESTART_DECODE;
}
}
//
// if we are currently working on an odd pixel, (low
// nibble) go ahead and re-align on even ...
//
if (cDestOffs % 2)
{
(*(pdest + (cDestOffs >> 1))) &= 0xf0;
(*(pdest + (cDestOffs >> 1))) |= bPltPix;
cDestOffs++;
cBlt--;
}
//
// fill in the byte aligned bytes
//
bPltPix |= bPltPix << 4;
for (;cBlt > 1; cBlt -= 2, cDestOffs += 2)
{
*(pdest + (cDestOffs >> 1)) = bPltPix;
}
//
// if we have a nibble left, store it
//
if (cBlt)
{
*(pdest + (cDestOffs >> 1)) = bPltPix;
cDestOffs++;
}
// end for pixels until next change
} // end for number of pixels in this run
} // end of this horizontal line
if (pdecctl->ulDSAw & 1)
{
cDestOffs--;
}
} // end of this vertical line
} while (cY < (pdecctl->ulDSAh / 2)); // end of this vertical line change region
return(TRUE);
}
/*
** SPChooseMap ()
**
** Choose the pallette
**
** Arguments:
**
**
**
** Returns:
**
** Side Effects:
*/
BOOL SPChooseMap (PSP_DECODE_CTL pdecctl, PUCHAR pcol, UCHAR con)
{
ULONG ulTmp;
//
// check if this is the 0 color
//
if ((con == 0) || (pdecctl->spYUV.ucY[*pcol] == 0))
{
pdecctl->mappal.palFlags[0] = fInUse;
*pcol = 0;
return (TRUE);
}
//
// see if there is already a contrast less than this one
//
if (pdecctl->minCon < con)
{
con = 0xf;
}
//
// check if this color is already mapped correctly
//
if (((pdecctl->mappal.palFlags[*pcol]) & (fInUse)) &&
(pdecctl->mappal.yuvMap[*pcol] == *pcol) &&
((pdecctl->mappal.ucAlpha[*pcol] == con) ||
((pdecctl->mappal.ucAlpha[*pcol] > pdecctl->minCon) &&
(con > pdecctl->minCon))))
{
return (TRUE);
}
//
// see if there is already a color / con pair that maps to this
//
for (ulTmp = 1;ulTmp < 16; ulTmp++)
{
if (!(pdecctl->mappal.palFlags[ulTmp] & fInUse))
{
}
else if ((pdecctl->mappal.yuvMap[ulTmp] == *pcol) && (pdecctl->mappal.ucAlpha[ulTmp] == con))
{
*pcol = (UCHAR)ulTmp;
return (TRUE);
}
}
if (con < pdecctl->minCon)
{
pdecctl->minCon = con;
}
//
// this color does not map to any available colors, try and see if the
// direct mapping is available
//
if ((*pcol) && !(pdecctl->mappal.palFlags[*pcol] & fInUse))
{
pdecctl->mappal.palFlags[*pcol] = fInUse;
pdecctl->mappal.yuvMap[*pcol] = *pcol;
pdecctl->mappal.ucAlpha[*pcol] = con;
if (con != 0xf)
{
pdecctl->mappal.palFlags[*pcol] |= fUseAlpha;
}
return (TRUE);
}
//
// direct mapping is not available, start from 1 and work up
//
for (ulTmp = 1; ulTmp < 16; ulTmp++)
{
if (!(pdecctl->mappal.palFlags[ulTmp] & fInUse))
{
pdecctl->mappal.palFlags[ulTmp] = fInUse;
pdecctl->mappal.yuvMap[ulTmp] = *pcol;
pdecctl->mappal.ucAlpha[ulTmp] = con;
*pcol = (UCHAR)ulTmp;
if (con != 0xf)
{
pdecctl->mappal.palFlags[ulTmp] |= fUseAlpha;
}
return (TRUE);
}
}
return (FALSE);
}
/*
** StartSPDecode ()
**
** initialize subpicture decoding for this subpicture unit
**
** Arguments:
**
**
**
** Returns:
**
** Side Effects:
*/
void StartSPDecode (PSP_STRM_EX pspstrmex)
{
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
do {
pdecctl->decFlags &= ~SPDECFL_RESTART;
if (!BuildSPFields(pspstrmex))
{
//
// something is horribly wrong. Just ask for the next packet
//
pdecctl->decFlags &= ~SPDECFL_BUF_IN_USE;
pdecctl->decFlags |= SPDECFL_LAST_FRAME;
pdecctl->curData = 0;
pdecctl->stsPic = 0;
return;
}
} while (pdecctl->decFlags & SPDECFL_RESTART);
pdecctl->stsNextUpd =
*((WORD *)(pdecctl->pData + pdecctl->pSPCmds));
pdecctl->stsNextUpd = ((pdecctl->stsNextUpd & 0xFF00) << 2) |
((pdecctl->stsNextUpd & 0xFF) << 18);
//SetupSPBuffer(pspstrmex);
cSPBytes = 0;
pdecctl->decFlags &= ~SPDECFL_DECODING;
pdecctl->decFlags |= SPDECFL_SUBP_DECODED;
}
/*
** BuildSPFields ()
**
** Build new SPFields
**
** Arguments:
**
**
**
** Returns:
**
** Side Effects:
*/
BOOL BuildSPFields (PSP_STRM_EX pspstrmex)
{
//
// parse the current command set for this time
//
if (!UpdateSPConsts(pspstrmex))
{
return(FALSE);
}
//
// decode the RLE into the display buffers
//
if (!DecodeRLE(
pspstrmex->pdecctl.pTopWork,
pspstrmex->pdecctl.cTopDisp,
pspstrmex))
{
return(FALSE);
}
/*
if (!DecodeRLE(
pspstrmex->pdecctl.pBottomWork,
pspstrmex->pdecctl.cBottomDisp,
pspstrmex))
{
return(FALSE);
}
*/
return(TRUE);
}
/*
** UpdateSPConsts() -
**
** Update the subpicture decode constants
**
** Arguments:
**
** pSPCmds - pointer to a subpicture command(s) buffer
** cMax - counter to the max size of this subpicture command block
**
** Returns:
**
** Side Effects:
**
*/
UCHAR cSpcmd[] = {1, 1, 1, 3, 3, 7, 5, 0};
BOOL UpdateSPConsts(PSP_STRM_EX pspstrmex)
{
BOOL fDecode = TRUE;
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
//
// skip the start time, and the next command
//
ULONG cSPCmds = pdecctl->pSPCmds + 4;
UCHAR bTmp;
UCHAR bCmd;
ULONG oldX;
ULONG oldY;
ULONG oldW;
ULONG oldH;
//
// loop through until we see the end code
//
while (fDecode)
{
bCmd = *((PBYTE)pdecctl->pData + cSPCmds);
if (bCmd >= CMD_END)
{
//
// we hit the end of the command stream, we're done!
//
return(TRUE);
}
if (cSPCmds + cSpcmd[bCmd] > pdecctl->cData)
{
return(FALSE);
}
pdecctl->nextDispFlags = pdecctl->decFlags & (SPDECFL_DISP_OFF | SPDECFL_DISP_FORCED);
//
// check the function code
//
switch (bCmd)
{
case FSTA_DSP:
pdecctl->nextDispFlags |= SPDECFL_DISP_FORCED;
break;
case STA_DSP:
pdecctl->nextDispFlags &= ~SPDECFL_DISP_OFF;
break;
case STP_DSP:
pdecctl->nextDispFlags |= SPDECFL_DISP_OFF;
break;
case SET_COLOR:
bTmp = *((PBYTE)pdecctl->pData + cSPCmds + 1);
//
// pick up the emphasis colors
//
pdecctl->sppPal.color[3] = (bTmp & 0xf0) >> 4;
pdecctl->sppPal.color[2] = (bTmp & 0x0f);
//
// pick up the background and foreground colors
//
bTmp = *(pdecctl->pData + cSPCmds + 2);
pdecctl->sppPal.color[1] = (bTmp & 0xf0) >> 4;
pdecctl->sppPal.color[0] = (bTmp & 0x0f);
break;
case SET_CONTR:
bTmp = *((PBYTE)pdecctl->pData + cSPCmds + 1);
//
// pick up the emphasis mixs
//
pdecctl->sppPal.mix[3] = (bTmp & 0xf0) >> 4;
pdecctl->sppPal.mix[2] = (bTmp & 0x0f);
//
// pick up the background and foreground mixs
//
bTmp = *(pdecctl->pData + cSPCmds + 2);
pdecctl->sppPal.mix[1] = (bTmp & 0xf0) >> 4;
pdecctl->sppPal.mix[0] = (bTmp & 0x0f);
break;
case SET_DAREA:
//
// grap the x and y coordinates from the bit soup that defines
// the display area
//
oldX = pdecctl->ulDSAx;
oldY = pdecctl->ulDSAy;
oldH = pdecctl->ulDSAh;
oldW = pdecctl->ulDSAw;
pdecctl->ulDSAx = ((*(pdecctl->pData + cSPCmds +1)
& DAREA_START_UB_MASK) << DAREA_START_UB_SHIFT)
+ (*(pdecctl->pData + cSPCmds + 2) >> DAREA_START_UB_SHIFT);
pdecctl->ulDSAw = ((*(pdecctl->pData + cSPCmds + 2)
& DAREA_END_UB_MASK) << DAREA_END_UB_SHIFT) +
(*(pdecctl->pData + cSPCmds + 3)) -
pdecctl->ulDSAx + 1;
pdecctl->ulDSAy = ((*(pdecctl->pData + cSPCmds + 4)
& DAREA_START_UB_MASK) << DAREA_START_UB_SHIFT)
+ (*(pdecctl->pData + cSPCmds + 5) >> DAREA_START_UB_SHIFT);
pdecctl->ulDSAh = ((*(pdecctl->pData + cSPCmds + 5)
& DAREA_END_UB_MASK) << DAREA_END_UB_SHIFT) +
(*(pdecctl->pData + cSPCmds + 6)) -
pdecctl->ulDSAy + 1;
if (oldW != pdecctl->ulDSAw || oldH != pdecctl->ulDSAh)
{
pdecctl->decFlags |= SPDECFL_NEW_PIC;
}
//
// if the new bitmap requires more memory than the previous, we
// need to allocate one here
//
if (pdecctl->ulDSAh * pdecctl->ulDSAw / 2 > pdecctl->cDecod)
{
pdecctl->cDecod = pdecctl->ulDSAh * pdecctl->ulDSAw / 2;
if (!(pdecctl->cDecod))
{
TRAP
}
AllocateSPBufs(pdecctl);
}
break;
case SET_DSPSTRT:
{
//
// pick up the offsets of the top and bottom fields in the
// compressed data
//
pdecctl->cTopDisp =
(*(pdecctl->pData + cSPCmds + 1) << 8) +
*(pdecctl->pData + cSPCmds + 2);
pdecctl->cBottomDisp =
(*(pdecctl->pData + cSPCmds + 3) << 8) +
*(pdecctl->pData + cSPCmds + 4);
break;
}
case CHG_COLCON:
TRAP
pdecctl->ppxcd = (PPXCTLY)(pdecctl->pData + cSPCmds + 3);
//
// pick up the next command code
//
cSPCmds += (*(pdecctl->pData + cSPCmds + 1) << 8)
+ *(pdecctl->pData + cSPCmds + 2);
break;
default:
TRAP
//
// ACK! Couldn't handle this subpicture command stream, just bail!
//
return(FALSE);
} // end switch on command code
//
// go pick up the next command code
//
cSPCmds += cSpcmd[bCmd];
} // end while something to decode
return(FALSE);
}
VOID SPReceiveDataPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PSP_STRM_EX pspstrmex =
&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
PKSSTREAM_HEADER pPacket;
ULONG cPack;
MPTrace(mTraceSP);
MPTrace(mTraceRdySub);
StreamClassStreamNotification(ReadyForNextStreamDataRequest,
pSrb ->StreamObject);
switch (pSrb->Command)
{
case SRB_WRITE_DATA:
//
// search the packet for discontinuity bits. If it has any, we need
// to dump all current subpicture data, and stop the display.
//
pPacket = pSrb->CommandData.DataBufferArray;
for (cPack =0;
cPack < pSrb->NumberOfBuffers;
cPack++, pPacket++)
{
if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
{
AbortSP(pspstrmex);
break;
}
else if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY &&
pSrb->NumberOfBuffers <= 1)
{
CallBackError(pSrb);
return;
}// end if discontinuity bit is set
} // end loop on packets
break;
default:
CallBackError(pSrb);
return;
}
SPEnqueue(pSrb, pspstrmex);
if (!(pspstrmex->pdecctl.decFlags & SPDECFL_BUF_IN_USE))
{
DumpPacket(pspstrmex);
}
}
void AbortSP(PSP_STRM_EX pspstrmex)
{
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
pdecctl->curData = 0;
pspstrmex->pdecctl.decFlags = 0;
SPVideoOSDOff();
CleanSPQueue(pspstrmex);
}
void DumpPacket(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrb;
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
PKSSTREAM_HEADER pPacket;
ULONG dataOffset;
ULONG cPacket;
ULONG StartTime;
ULONG ulTmp;
ULONG cPack;
ULONG cMove;
PHW_STREAM_OBJECT phstrmo;
ULONG cSkipped = 0;
WORD wTmp;
PVOID Data = (PVOID) - 1;
do
{
RESTART_QUEUE:
if (pSrb = SPDequeue(pspstrmex))
{
pPacket = pSrb->CommandData.DataBufferArray;
RESTART_COPY:
while (((pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)
|| (!pPacket->Data) || (pPacket->DataUsed <
sizeof (SPPCKHDR) + PACK_HEADER_SIZE)))
{
pPacket++;
cSkipped++;
if (cSkipped >= pSrb->NumberOfBuffers)
{
//
// call back this packet
//
pSrb->Status = STATUS_SUCCESS;
phstrmo = pSrb->StreamObject;
MPTrace(mTraceSPDone);
StreamClassStreamNotification(StreamRequestComplete,
phstrmo,
pSrb);
goto RESTART_QUEUE;
}
}
//
// is this the first packet?
//
if (!pdecctl->curData)
{
//
// do we have a valid SP_PCK PES header?
//
Data = (PVOID) ((ULONG_PTR) pPacket->Data + PACK_HEADER_SIZE);
if ((*((PDWORD) Data) & 0xFFFFFF)
!= 0x010000)
{
CallBackError(pSrb);
return;
}
//
// find the subpicture start
//
dataOffset = ((PSPPCKHDR)Data)->
phdr_hdr_length + sizeof(SPPCKHDR) - 4;
if ((((PSPPCKHDR)Data)->
phdr_flags[1] & 0xC0) != 0x80)
{
//
// PTS is invalid on the first start code!
//
CallBackError(pSrb);
return;
}
//
// find the start time
//
StartTime = (((PSPPCKHDR)Data)->phdr_PTS[0]
& 0xE) << 26;
StartTime |= (((PSPPCKHDR)Data)->phdr_PTS[1])
<< 22;
StartTime |= (((PSPPCKHDR)Data)->phdr_PTS[2]
& 0xFE) << 14;
StartTime |= ((PSPPCKHDR)Data)->phdr_PTS[3] << 7;
StartTime |= ((PSPPCKHDR)Data)->phdr_PTS[4] >> 1;
if (!StartTime)
{
TRAP
StartTime++;
}
pdecctl->stsPic = StartTime;
pdecctl->lastTime = StartTime;
//
// y: pick up the size of the subpicture unit
//
pdecctl->cData = *((PWORD)((PBYTE) Data
+ dataOffset));
pdecctl->cData = (pdecctl->cData >> 8)
| ((pdecctl->cData & 0xff) <<8);
if (pdecctl->cData > SP_MAX_INPUT_BUF)
{
TRAP
CallBackError(pSrb);
return;
pSrb = NULL;
}
else
{
ulTmp = *((PWORD) ((PBYTE) Data +
dataOffset + 2));
ulTmp = (ulTmp >> 8) | ((ulTmp & 0xff) << 8);
if (ulTmp < pdecctl->cData >> 1)
{
//
// this is an illegal packet, the command
// stream is more than half the data
//
CallBackError(pSrb);
return;
pSrb = NULL;
}
}
}
if (pSrb)
{
//
// go ahead and start moving the data
//
for (cPack = cSkipped;
cPack < pSrb->NumberOfBuffers;
cPack++, pPacket++)
{
if (pPacket->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY ||
pPacket->DataUsed < 4)
{
//
// yikes! We have a discontinuity! Dump all data
// up to this point, and start again!
//
pdecctl->curData = 0;
pPacket++;
cSkipped = cPack + 1;
goto RESTART_COPY;
}
Data = (PVOID) ((ULONG_PTR) pPacket->Data + PACK_HEADER_SIZE);
if ((*((PDWORD) Data) & 0xFFFFFF) != 0x010000)
{
CallBackError(pSrb);
return;
}
//
// find the subpicture start
//
dataOffset = ((PSPPCKHDR)Data)->
phdr_hdr_length + sizeof(SPPCKHDR) - 4;
//
// the count of data bytes in the PES packet is
// the count of bytes following the packet_length
// field, so add 6 to the total (the offset)
//
cPacket = ((PSPPCKHDR)(Data))->
phdr_packet_length;
cPacket = (((cPacket & 0xff) << 8) | (cPacket >> 8)) -
dataOffset + 6 ;
if (cPacket > pPacket->DataUsed - PACK_HEADER_SIZE)
{
TRAP
CallBackError(pSrb);
return;
}
if (pdecctl->curData + cPacket > pdecctl->cData)
{
cMove = pdecctl->cData - pdecctl->curData;
}
else
{
cMove = cPacket;
}
//
// move the data
//
RtlCopyMemory(pdecctl->pData + pdecctl->curData,
(PBYTE)Data + dataOffset,
cMove);
//
// have we reached the end of the subpicture unit?
//
pdecctl->curData += cMove;
if (pdecctl->curData == pdecctl->cData)
{
cPack= 0xFFFFFFFE;
}
}
//
// call back this packet, if we don't have leftover
//
pSrb->Status = STATUS_SUCCESS;
phstrmo = pSrb->StreamObject;
MPTrace(mTraceSPDone);
StreamClassStreamNotification(StreamRequestComplete,
phstrmo,
pSrb);
if (pdecctl->curData == pdecctl->cData)
{
//
// y: indicate that we have a full buffer, and start
// the initial decoding process
//
pdecctl->decFlags |= SPDECFL_BUF_IN_USE | SPDECFL_NEW_PIC;
pdecctl->ulFrameCnt = 0;
pdecctl->pSPCmds = *((WORD *)(pdecctl->pData + 2));
pdecctl->pSPCmds = ((pdecctl->pSPCmds & 0xff) << 8) |
(pdecctl->pSPCmds) >> 8;
pdecctl->lastSPCmds = pdecctl->pSPCmds;
wTmp = *((WORD *)(pdecctl->pData + pdecctl->pSPCmds + 2));
wTmp = ((wTmp & 0xff) << 8) | (wTmp >> 8);
if (wTmp == pdecctl->pSPCmds)
{
pdecctl->decFlags |= SPDECFL_ONE_UNIT;
}
pdecctl->decFlags |= SPDECFL_DECODING;
// StartSPDecode(pspstrmex);
StreamClassCallAtNewPriority(phstrmo,
pspstrmex->phwdevex,
Low,
(PHW_PRIORITY_ROUTINE)StartSPDecode,
pspstrmex);
return;
}
}
}
else
{
return;
}
} while(TRUE);
}
void CallBackError(PHW_STREAM_REQUEST_BLOCK pSrb)
{
pSrb->Status = STATUS_SUCCESS;
if (pSPstrmex)
{
pSPstrmex->pdecctl.curData = 0;
pSPstrmex->pdecctl.decFlags = 0;
}
MPTrace(mTraceSPDone);
StreamClassStreamNotification(StreamRequestComplete,
pSrb->StreamObject,
pSrb);
}
void SPEnqueue(PHW_STREAM_REQUEST_BLOCK pSrb, PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrbTmp;
ULONG cSrb;
//
// enqueue the given SRB on the device extension queue
//
for (cSrb =0,
pSrbTmp = CONTAINING_RECORD((&(pspstrmex->pSrbQ)),
HW_STREAM_REQUEST_BLOCK, NextSRB);
pSrbTmp->NextSRB;
pSrbTmp = pSrbTmp->NextSRB, cSrb++);
pSrbTmp->NextSRB = pSrb;
pSrb->NextSRB = NULL;
}
PHW_STREAM_REQUEST_BLOCK SPDequeue(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pRet = NULL;
if (pspstrmex->pSrbQ)
{
pRet = pspstrmex->pSrbQ;
pspstrmex->pSrbQ = pRet->NextSRB;
}
return(pRet);
}
void SubPicIRQ(PSP_STRM_EX pspstrmex)
{
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
ULONG StartTime;
ULONG ulTmp;
LONG deltaT;
BOOLEAN fRemoveHLI = FALSE;
BOOLEAN fNewHLI = FALSE;
static ULONG cFrames = 0;
if (pdecctl->spState == KSSTATE_STOP)
{
SPVideoOSDOff();
pdecctl->curData = 0;
pdecctl->decFlags &= ~SPDECFL_BUF_IN_USE;
pdecctl->HLI.fValid = FALSE;
pdecctl->HLI.fActive = FALSE;
pdecctl->HLI.fProcessed = TRUE;
cSPBytes = 0;
cFrames = 0;
return;
}
//
// if HLI is not processed
//
if (!pdecctl->HLI.fProcessed)
{
if (!pdecctl->HLI.fValid)
{
fRemoveHLI = TRUE;
pdecctl->HLI.fValid = pdecctl->HLI.fActive = FALSE;
pdecctl->HLI.fProcessed = TRUE;
} // end if HLI invalid
else // HLI is valid
{
//
// if the HLI is valid, we need to check the timestamp, if
// it's time, we need to start using it
//
deltaT = (LONG)(VideoGetPTS() - pdecctl->HLI.hli.StartPTM);
if (pdecctl->HLI.hli.StartPTM == 0xFFFFFFFF ||
(deltaT > (-3* 3003)))
// DbgPrint("'HLI deltaT: %X \n", deltaT);
//pdecctl->HLI.hli.StartPTM <= VideoGetPTS())
{
pdecctl->HLI.fProcessed = TRUE;
pdecctl->HLI.fActive = TRUE;
fNewHLI = TRUE;
}
}
}
if (pdecctl->HLI.fActive && (pdecctl->HLI.hli.EndPTM != 0xFFFFFFFF) &&
(pdecctl->HLI.hli.EndPTM >= VideoGetPTS()))
{
pdecctl->HLI.fValid = pdecctl->HLI.fActive = FALSE;
pdecctl->HLI.fProcessed = TRUE;
//
// HLI is ending, so we need to see if the subpicture is also
// ending
//
fRemoveHLI = TRUE;
}
if ((pdecctl->decFlags & SPDECFL_LAST_FRAME) &&
(pdecctl->spState != KSSTATE_PAUSE))
{
pdecctl->decFlags &= ~(SPDECFL_LAST_FRAME | SPDECFL_SUBP_ON_DISPLAY |
SPDECFL_DISP_LIVE);
cFrames = 0;
SPVideoOSDOff();
return;
}
//
// if we do not have subpicture data, deal with the HLI here
//
if (!(pdecctl->decFlags & SPDECFL_BUF_IN_USE))
{
if (fRemoveHLI)
{
pdecctl->decFlags |= SPDECFL_LAST_FRAME;
}
if (fNewHLI)
{
SPVideoOSDOff();
DumpHLI(pspstrmex);
SPVideoOSDOn();
}
return;
}
//
// check to see if we need to change the existing subpicture
//
if (fNewHLI || fRemoveHLI)
{
pdecctl->pSPCmds = pdecctl->lastSPCmds;
pdecctl->stsNextUpd = pdecctl->lastTime;
pdecctl->decFlags &= ~(SPDECFL_SUBP_DECODED);
SPSchedDecode(pspstrmex);
return;
}
//
// have we started this subpicture yet?
//
if (!(pdecctl->decFlags & SPDECFL_SUBP_ON_DISPLAY))
{
//
// is videotimestamp >= starting time stamp of subpicture?
//
deltaT = (LONG)(VideoGetPTS() - pdecctl->stsPic + 7 * 3003);
DbgPrint("'Video PTS: %X \n", VideoGetPTS());
if (deltaT >= 0)
//pdecctl->stsPic <= VideoGetPTS())
{
//
// y: start the ticks at current frame count
//
pdecctl->decFlags |= SPDECFL_SUBP_ON_DISPLAY;
pdecctl->cFrames = 0;
}
else
{
if (cFrames > 120)
{
//
// this picture is taking too long. Let's assume
// we missed the timestamp, and dump it.
//
cFrames = 0;
pdecctl->decFlags &= ~(SPDECFL_BUF_IN_USE | SPDECFL_SUBP_ON_DISPLAY);
pdecctl->decFlags |= SPDECFL_LAST_FRAME;
pdecctl->curData = 0;
CleanSPQueue(pspstrmex);
DumpPacket(pspstrmex);
return;
}
if (pdecctl->spState == KSSTATE_RUN)
{
cFrames++;
}
//
// n: don't do anything!
//
return;
}
}
else if (pdecctl->spState == KSSTATE_RUN)
{
//
// increment the field counter
//
pdecctl->cFrames++;
}
if (!(pdecctl->decFlags & (SPDECFL_SUBP_DECODED)))
{
//
// we don't have any data! (so, don't check time stamps)
//
//
return;
}
//
// is current time stamp one behind next update?
//
if ((pdecctl->cFrames + 7) * 3003 <= pdecctl->stsNextUpd)
{
//
// we're still too far from the next update, don't do anything
//
return;
}
//
// we need to get busy. Go off and copy the bitmap to the
// hardware, and then start the next decode
//
ulTmp = *((PWORD)(pdecctl->pData + pdecctl->pSPCmds + 2));
ulTmp = (ulTmp >> 8) | ((ulTmp & 0xff) << 8);
if ((pdecctl->decFlags & SPDECFL_ONE_UNIT) || ulTmp != pdecctl->pSPCmds)
{
if (pdecctl->decFlags & SPDECFL_NEW_PIC)
{
pdecctl->decFlags &=~SPDECFL_DISP_LIVE;
SPVideoOSDOff();
}
//SetupSPBuffer(pspstrmex);
if (!WriteBMP(pspstrmex))
{
return;
}
pdecctl->decFlags &= ~(SPDECFL_DISP_OFF | SPDECFL_DISP_FORCED);
pdecctl->decFlags |= pdecctl->nextDispFlags;
if (pdecctl->decFlags & SPDECFL_NEW_PIC)
{
pdecctl->decFlags |= SPDECFL_DISP_LIVE;
SPVideoOSDOn();
}
pdecctl->decFlags &= ~(SPDECFL_SUBP_DECODED | SPDECFL_NEW_PIC);
}
if (pdecctl->decFlags & SPDECFL_ONE_UNIT)
{
return;
}
//
// find the next start time and start address
//
ulTmp = pdecctl->pSPCmds;
pdecctl->pSPCmds = *((PWORD)(pdecctl->pData + pdecctl->pSPCmds + 2));
pdecctl->pSPCmds = (pdecctl->pSPCmds >> 8) | ((pdecctl->pSPCmds & 0xff) << 8);
StartTime = *((WORD *)(pdecctl->pData + pdecctl->pSPCmds));
StartTime = ((StartTime & 0xFF00) << 2) | ((StartTime & 0xFF) << 18);
if (ulTmp == pdecctl->pSPCmds)
{
//
// we're done with this subpicture! Flag it and start the
// next packet
//
pdecctl->decFlags &= ~(SPDECFL_BUF_IN_USE | SPDECFL_SUBP_ON_DISPLAY);
pdecctl->decFlags |= SPDECFL_LAST_FRAME;
pdecctl->curData = 0;
DumpPacket(pspstrmex);
return;
}
pdecctl->lastTime = pdecctl->stsNextUpd;
pdecctl->stsNextUpd = StartTime;
SPSchedDecode(pspstrmex);
}
void SPSchedDecode(PSP_STRM_EX pspstrmex)
{
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
if (pdecctl->decFlags & SPDECFL_DECODING)
{
pdecctl->decFlags |= SPDECFL_RESTART;
}
else
{
pdecctl->decFlags |= SPDECFL_DECODING;
StreamClassCallAtNewPriority(pspstrmex->phstrmo,
pspstrmex->phwdevex,
Low,
(PHW_PRIORITY_ROUTINE)StartSPDecode,
pspstrmex);
}
}
BOOL fInitSP = FALSE;
void InitSP()
{
UCHAR EndOsd[]= {0xc1, 0xff, 0xff, 0xff};
ULONG ulTmp;
ulTmp = (pVideo->videoBufferSize + pVideo->spBufferSize) * 256;
BoardWriteVideo(CFG_MWP, (BYTE)(ulTmp >> 17));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 9 ) & 0xFF));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 1) & 0xFF));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[0])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[1])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[2])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[3])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[1])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[1])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[1])));
BoardWriteVideo(CFG_MWF, (UCHAR)((EndOsd[1])));
fInitSP = TRUE;
}
void DumpHLI(PSP_STRM_EX pspstrmex)
{
OSDHEAD Header;
ULONG ulTmp;
PBYTE foo;
BYTE bTmp;
ULONG spBytes;
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
if (!fInitSP)
{
InitSP();
}
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp++)
{
*foo++ = 0;
}
//
// space is open, so set the memory pointer to the top of
// the video buffer
//
ulTmp = (pVideo->videoBufferSize + 1) * 256;
BoardWriteVideo(CFG_MWP, (BYTE)(ulTmp >> 17));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 9 ) & 0xFF));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 1) & 0xFF));
//
// set the OSD top and bottom displays
//
ulTmp = (pVideo->videoBufferSize + pVideo->spBufferSize) * 32;
Header.osdhres1 = (USHORT)(ulTmp & 0x00008);
Header.osdhres2 = (USHORT)(ulTmp & 0x00070) >> 4;
Header.osdhres3 = (USHORT)(ulTmp & 0x01f80) >> 7;
Header.osdhres4 = (USHORT)(ulTmp & 0x7e000) >> 13;
Header.osdhStarty = (USHORT)pdecctl->HLI.hli.StartY /2 + 0x1f;
Header.osdhStartx = (USHORT)pdecctl->HLI.hli.StartX + XOFFSET + 16;
Header.osdhStopy = (USHORT)pdecctl->HLI.hli.StopY / 2 + 0x20;
Header.osdhStopx = (USHORT)pdecctl->HLI.hli.StopX + (1 -((pdecctl->HLI.hli.StopX -
pdecctl->HLI.hli.StartX) & 1)) + XOFFSET + 16;
spBytes =(((ULONG) Header.osdhStopy - (ULONG)Header.osdhStarty +1) *
(pdecctl->HLI.hli.StopX - pdecctl->HLI.hli.StartX + 1) / 2);
if (FALSE && Header.osdhStopy > 239)
{
Header.osdhStopy = 239;
}
if (Header.osdhStopx > 720)
{
Header.osdhStopx = 720;
if (!(Header.osdhStartx & 1))
{
Header.osdhStopx = 719;
}
}
Header.osdhMQ = 2; // set up 4 bpp bitmap
for (ulTmp =0; ulTmp < 16
; ulTmp ++)
{
Header.osdhYUV[ulTmp].osdY = pdecctl->spYUV.ucY[pdecctl->HLI.hli.ColCon.emph1col];
Header.osdhYUV[ulTmp].osdV = pdecctl->spYUV.ucV[pdecctl->HLI.hli.ColCon.emph1col];
Header.osdhYUV[ulTmp].osdU = pdecctl->spYUV.ucU[pdecctl->HLI.hli.ColCon.emph1col];
Header.osdhYUV[ulTmp].osdT = 1;
Header.osdhYUV[ulTmp].osdres = 0;
}
Header.osdhMix = pdecctl->HLI.hli.ColCon.emph1con;
//
// write over the header
//
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
WriteSPBuffer((PBYTE)&Header, sizeof(Header));
for (;spBytes >= 4; spBytes -=4)
{
WriteSPData(0);
}
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
ulTmp = 0;
//
// put down the end header (indicate a line beyond the display
// region
//
Header.osdhStarty = 0x1ff;
Header.osdhStopy = 0x1ff;
Header.osdhMQ = 3; // set up 4 bpp bitmap
ulTmp = 0;
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
//
// write over the header
//
WriteSPBuffer((PBYTE)&Header, sizeof (Header));
return;
}
BOOL WriteBMP(PSP_STRM_EX pspstrmex)
{
OSDHEAD Header;
ULONG ulTmp;
PBYTE foo;
BYTE bTmp;
ULONG spBytes;
ULONG cBytes = 256;
ULONG ulActualWidth;
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
if (!fInitSP)
{
InitSP();
}
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp++)
{
*foo++ = 0;
}
//
// figure out if we have enough place for the bitmap yet
//
/*
if (VideoGetBBL() > pVideo->videoBufferSize)
{
return (FALSE);
}
*/
//
// space is open, so set the memory pointer to the top of
// the video buffer
//
if (cSPBytes)
{
ulTmp = (pVideo->videoBufferSize + 1) * 256 +cSPBytes + sizeof(Header);
}
else
{
ulTmp = (pVideo->videoBufferSize + 1) * 256;
}
BoardWriteVideo(CFG_MWP, (BYTE)(ulTmp >> 17));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 9 ) & 0xFF));
BoardWriteVideo(CFG_MWP, (BYTE)((ulTmp >> 1) & 0xFF));
//
// set the OSD top and bottom displays
//
if (!cSPBytes)
{
/*
ulTmp = BoardReadVideo(VID_OBP) << 8;
ulTmp |= BoardReadVideo(VID_OBP);
ulTmp &= 0x3fff;
DbgPrint("'OBP: %lx \n", ulTmp);
ulTmp = BoardReadVideo(VID_OTP) << 8;
ulTmp |= BoardReadVideo(VID_OTP);
ulTmp &= 0x3fff;
DbgPrint("'OTP: %lx \n", ulTmp);
DbgPrint("'vidbufsize: %lx \n", pVideo->videoBufferSize + 1);
BoardWriteVideo(VID_OBP, (BYTE)((pVideo->videoBufferSize +1) >> 8));
BoardWriteVideo(VID_OBP, (BYTE)((pVideo->videoBufferSize +1) & 0xFF));
BoardWriteVideo(VID_OTP, (BYTE)((pVideo->videoBufferSize +1) >> 8));
BoardWriteVideo(VID_OTP, (BYTE)((pVideo->videoBufferSize +1) & 0xFF));
*/
}
ulTmp = (pVideo->videoBufferSize + pVideo->spBufferSize) * 32;
Header.osdhres1 = (USHORT)(ulTmp & 0x00008);
Header.osdhres2 = (USHORT)(ulTmp & 0x00070) >> 4;
Header.osdhres3 = (USHORT)(ulTmp & 0x01f80) >> 7;
Header.osdhres4 = (USHORT)(ulTmp & 0x7e000) >> 13;
Header.osdhStarty = (USHORT)pdecctl->ulDSAy /2 +0x1f;
Header.osdhStartx = (USHORT)pdecctl->ulDSAx + XOFFSET + 16;
Header.osdhStopy = Header.osdhStarty + ((USHORT)pdecctl->ulDSAh - 1) /2 -1;
if (Header.osdhStopy > 249)
{
Header.osdhStopy = 249;
}
Header.osdhStopx = Header.osdhStartx + (((USHORT)pdecctl->ulDSAw) & 0xFFFE) - 1;
if (!(Header.osdhStartx & 1))
{
Header.osdhStartx++;
Header.osdhStopx++;
}
if (FALSE && Header.osdhStopx > 720)
{
Header.osdhStopx = 720;
if (!(Header.osdhStartx & 1))
{
Header.osdhStopx = 719;
}
}
ulActualWidth = ((ULONG)Header.osdhStopx - (ULONG)Header.osdhStartx + 1) /2;
spBytes =((ULONG) Header.osdhStopy - (ULONG)Header.osdhStarty +1) * ulActualWidth;
while (spBytes / cBytes > 6)
{
cBytes = cBytes << 1;
}
if (pdecctl->ulDSAw >= 719 && pdecctl->ulDSAh >= 440)
{
cBytes = spBytes;
}
DbgPrint("'width %d, height %d, actual width %d\n", pdecctl->ulDSAw, pdecctl->ulDSAh,
ulActualWidth);
Header.osdhMQ = 2; // set up 4 bpp bitmap
if (pdecctl->decFlags & SPDECFL_USE_STRAIGHT_PAL)
{
for (ulTmp =0; ulTmp < 16
; ulTmp ++)
{
Header.osdhYUV[ulTmp].osdY = pdecctl->spYUV.ucY[ulTmp];
Header.osdhYUV[ulTmp].osdV = pdecctl->spYUV.ucV[ulTmp];
Header.osdhYUV[ulTmp].osdU = pdecctl->spYUV.ucU[ulTmp];
Header.osdhYUV[ulTmp].osdT = 0;
Header.osdhYUV[ulTmp].osdres = 0;
}
Header.osdhMix = 0xf;
Header.osdhYUV[0].osdT = 1;
}
else
{
Header.osdhYUV[0].osdT = 1;
Header.osdhYUV[0].osdY = 0;
Header.osdhYUV[0].osdV = 0;
Header.osdhYUV[0].osdU = 0;
for (ulTmp =1; ulTmp < 16 ; ulTmp ++)
{
Header.osdhYUV[ulTmp].osdY = pdecctl->spYUV.ucY[pdecctl->mappal.yuvMap[ulTmp]];
Header.osdhYUV[ulTmp].osdV = pdecctl->spYUV.ucV[pdecctl->mappal.yuvMap[ulTmp]];
Header.osdhYUV[ulTmp].osdU = pdecctl->spYUV.ucU[pdecctl->mappal.yuvMap[ulTmp]];
if (pdecctl->mappal.ucAlpha[ulTmp] != pdecctl->minCon ||
(pdecctl->mappal.ucAlpha[ulTmp] == 0xf))
{
Header.osdhYUV[ulTmp].osdT = 0;
}
else
{
Header.osdhYUV[ulTmp].osdT = 1;
}
if (pdecctl)
Header.osdhYUV[ulTmp].osdres = 0;
}
Header.osdhMix = pdecctl->minCon;
}
//
// write over the header
//
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
if (!cSPBytes)
{
ulRemain = 0;
WriteSPBuffer((PBYTE)&Header, sizeof(Header));
cBytes -= sizeof(Header);
}
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
//
// now copy the data
//
if (spBytes - cSPBytes > cBytes)
{
if (ulActualWidth == (pdecctl->ulDSAw / 2))
{
DbgPrint("'Writing equal length %X, %u\n", pdecctl->pTopWork +cSPBytes,
cBytes);
WriteSPBuffer(pdecctl->pTopWork + cSPBytes, cBytes);
cSPBytes += cBytes;
}
else
{
if (cBytes >= (cSPBytes % ulActualWidth) && (cSPBytes % ulActualWidth))
{
TRAP
DbgPrint("'Writing start %X, %u\n", pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) + (cSPBytes % ulActualWidth), ulActualWidth -
(cSPBytes % ulActualWidth));
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) + (cSPBytes % ulActualWidth), ulActualWidth -
(cSPBytes % ulActualWidth));
cBytes -= ulActualWidth - (cSPBytes % ulActualWidth);
cSPBytes += ulActualWidth - (cSPBytes % ulActualWidth);
}
while (cBytes >= ulActualWidth)
{
TRAP
DbgPrint("'Writing even rows %X, %u\n",pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) , ulActualWidth );
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) , ulActualWidth );
cSPBytes += ulActualWidth;
cBytes -= ulActualWidth;
}
if (cBytes)
{
TRAP
DbgPrint("'writing tail section %ux, %ul\n",pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) , cBytes);
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
((pdecctl->ulDSAw + 1)/2)) , cBytes);
cSPBytes += cBytes;
}
}
return(FALSE);
}
else
{
if (ulActualWidth == (pdecctl->ulDSAw)/2)
{
WriteSPBuffer(pdecctl->pTopWork + cSPBytes, spBytes - cSPBytes);
}
else
{
cBytes = spBytes - cSPBytes;
if ((cSPBytes % ulActualWidth) && (cBytes >= (cSPBytes % ulActualWidth)))
{
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
(((pdecctl->ulDSAw + 1)/2))) + (cSPBytes % ulActualWidth), ulActualWidth -
(cSPBytes % ulActualWidth));
cBytes -= ulActualWidth - (cSPBytes % ulActualWidth);
cSPBytes += ulActualWidth - (cSPBytes % ulActualWidth);
}
while (cBytes >= ulActualWidth)
{
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
(((pdecctl->ulDSAw + 1)/2))) , ulActualWidth );
cBytes -= ulActualWidth;
cSPBytes += ulActualWidth;
}
if (cBytes)
{
WriteSPBuffer(pdecctl->pTopWork + ((cSPBytes / ulActualWidth) *
(((pdecctl->ulDSAw + 1)/2))) , cBytes);
cSPBytes += cBytes;
}
}
cSPBytes = 0;
}
// WriteSPBuffer(pdecctl->pTopWork, 719 * 115);
ulTmp = 0;
//
// put down the end header (indicate a line beyond the display
// region
//
Header.osdhStarty = 0x1ff;
Header.osdhStopy = 0x1ff;
Header.osdhMQ = 3; // set up 4 bpp bitmap
ulTmp = 0;
for (foo = (PBYTE)(&Header),ulTmp = 0; ulTmp < sizeof (Header); ulTmp+=2)
{
bTmp = *foo;
*foo = *(foo +1);
*(foo + 1) = bTmp;
foo+=2;
}
//
// write over the header
//
WriteSPBuffer((PBYTE)&Header, sizeof (Header));
return(TRUE);
}
void WriteSPBuffer(PBYTE pBuf, ULONG cnt)
{
static ULONG ulTmp = 0;
if (ulRemain && (cnt + ulRemain >= 4))
{
for ( ;ulRemain < 4; ulRemain++)
{
((PUCHAR)&ulTmp)[ulRemain] = *pBuf++;
cnt--;
}
WriteSPData(ulTmp);
ulRemain = 0;
}
while (cnt >= 4)
{
WriteSPData(*((PULONG)pBuf));
cnt -= 4;
pBuf += 4;
}
if (cnt)
{
for (;cnt > 0;cnt--, ulRemain++)
{
((PUCHAR)&ulTmp)[ulRemain] = *pBuf++;
}
}
}
void WriteSPData(ULONG ulData)
{
ULONG bTmp;
do {
BoardReadVideo(VID_STA0);
bTmp = BoardReadVideo(VID_STA1) << 8;
BoardReadVideo(VID_STA2);
} while (!(bTmp & ITM_WFE));
BoardWriteVideo(CFG_MWF, (UCHAR)((ulData & 0xFF)));
ulData = ulData >> 8;
BoardWriteVideo(CFG_MWF, (UCHAR)((ulData & 0xFF)));
ulData = ulData >> 8;
BoardWriteVideo(CFG_MWF, (UCHAR)((ulData & 0xFF)));
ulData = ulData >> 8;
BoardWriteVideo(CFG_MWF, (UCHAR)((ulData & 0xFF)));
}
BOOL AllocateSPBufs(PSP_DECODE_CTL pdecctl)
{
if (pdecctl->pTopWork)
{
ExFreePool(pdecctl->pTopWork);
pdecctl->pTopWork = NULL;
}
if (pdecctl->pTopWork = ExAllocatePool( NonPagedPool, pdecctl->cDecod))
{
pdecctl->pBottomWork = pdecctl->pTopWork + pdecctl->cDecod / 2;
return(TRUE);
}
TRAP
pdecctl->cDecod = 0;
return(FALSE);
}
void CleanSPQueue(PSP_STRM_EX pspstrmex)
{
PHW_STREAM_REQUEST_BLOCK pSrb;
pspstrmex->pdecctl.curData = 0;
ulRemain = 0;
while (pSrb = SPDequeue(pspstrmex))
{
CallBackError(pSrb);
}
}
void SPSetState (PHW_STREAM_REQUEST_BLOCK pSrb)
{
PHW_DEVICE_EXTENSION phwdevext =
((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
PSP_STRM_EX pspstrmex =
&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);
pspstrmex->pdecctl.spState = pSrb->CommandData.StreamState;
switch (pSrb->CommandData.StreamState)
{
case KSSTATE_STOP:
/*
pVideo->videoBufferSize += pVideo->spBufferSize;
pVideo->spBufferSize = 0;*/
pspstrmex->pdecctl.decFlags = 0;
pspstrmex->pdecctl.HLI.fValid = FALSE;
pspstrmex->pdecctl.HLI.fProcessed = TRUE;
SPVideoOSDOff();
CleanSPQueue(pspstrmex);
break;
case KSSTATE_PAUSE:
case KSSTATE_RUN:
pspstrmex->pdecctl.decFlags |= SPDECFL_NEW_PIC;
HwCodecEnableIRQ();
DumpPacket(pspstrmex);
break;
default:
break;
}
pSrb->Status = STATUS_SUCCESS;
}
void SPSetProp (PHW_STREAM_REQUEST_BLOCK pSrb)
{
PSP_STRM_EX pspstrmex =
&(((PSTREAMEX)pSrb->StreamObject->HwStreamExtension)->spstrmex);
PSP_DECODE_CTL pdecctl = &(pspstrmex->pdecctl);
PKSPROPERTY_SPPAL ppal;
USHORT cPal;
//
// make sure it is a valid property set
//
if (pSrb->CommandData.PropertyInfo->PropertySetID)
{
//
// invalid property
//
pSrb->Status = STATUS_SUCCESS;
return;
}
switch (pSrb->CommandData.PropertyInfo->Property->Id )
{
//
// look for the pallette property
//
case KSPROPERTY_DVDSUBPIC_PALETTE:
ppal = (PKSPROPERTY_SPPAL)pSrb->CommandData.PropertyInfo->PropertyInfo;
for (cPal = 0;cPal < 16; cPal++)
{
pdecctl->spYUV.ucY[cPal] = ppal->sppal[cPal].Y >> 2;
pdecctl->spYUV.ucU[cPal] = ppal->sppal[cPal].U >> 4;
pdecctl->spYUV.ucV[cPal] = ppal->sppal[cPal].V >> 4;
}
pSrb->Status = STATUS_SUCCESS;
break;
//
// look for HLI property
//
case KSPROPERTY_DVDSUBPIC_HLI:
//
// copy the HLI over
//
pdecctl->HLI.hli = *((PKSPROPERTY_SPHLI)pSrb->CommandData.PropertyInfo->PropertyInfo);
pdecctl->HLI.fProcessed = FALSE;
if (pdecctl->HLI.hli.HLISS)
{
pdecctl->HLI.fValid = TRUE;
}
else
{
if (!pdecctl->HLI.fActive)
{
pdecctl->HLI.fProcessed = TRUE;
}
pdecctl->HLI.fValid = FALSE;
}
//
// indicate that this HLI has not been processed yet
//
pdecctl->HLI.fActive = FALSE;
pSrb->Status = STATUS_SUCCESS;
break;
case KSPROPERTY_DVDSUBPIC_COMPOSIT_ON:
if (*((PKSPROPERTY_COMPOSIT_ON)pSrb->CommandData.PropertyInfo->PropertyInfo))
{
SPSetSPEnable();
}
else
{
SPSetSPDisable();
}
pSrb->Status = STATUS_SUCCESS;
break;
default:
pSrb->Status = STATUS_NOT_IMPLEMENTED;
break;
}
}
void SPGetProp (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;
}
}
//----------------------------------------------------------------------------
// Enable OSD
//----------------------------------------------------------------------------
void SPSetSPEnable()
{
PSP_DECODE_CTL pdecctl = &(pSPstrmex->pdecctl);
pdecctl->decFlags &= ~SPDECFL_USER_DISABLED;
//
// check if we currently have video in the card. If so, enable it
//
if (pdecctl->decFlags & SPDECFL_DISP_LIVE)
{
SPVideoOSDOn();
}
}
//----------------------------------------------------------------------------
// Disable OSD
//----------------------------------------------------------------------------
void SPSetSPDisable()
{
PSP_DECODE_CTL pdecctl = &(pSPstrmex->pdecctl);
pdecctl->decFlags |= SPDECFL_USER_DISABLED;
//
// check if we currently have video in the card that we can disable
//
if (!(pdecctl->decFlags & SPDECFL_DISP_FORCED))
{
SPVideoOSDOff();
}
}
//----------------------------------------------------------------------------
// Enable OSD
//----------------------------------------------------------------------------
void SPVideoOSDOn()
{
PSP_DECODE_CTL pdecctl = &(pSPstrmex->pdecctl);
//
// check to see if we should enable the display
//
if ((pdecctl->decFlags & SPDECFL_DISP_FORCED) ||
!(pdecctl->decFlags & (SPDECFL_DISP_OFF | SPDECFL_USER_DISABLED)))
{
pVideo->dcf = pVideo->dcf | 0x10;
BoardWriteVideo(VID_DCF1, (BYTE)(pVideo->dcf >> 8));
BoardWriteVideo(VID_DCF0, (BYTE)pVideo->dcf);
}
}
//----------------------------------------------------------------------------
// Disable OSD
//----------------------------------------------------------------------------
void SPVideoOSDOff ()
{
pVideo->dcf = pVideo->dcf & (~0x10);
BoardWriteVideo(VID_DCF1, (BYTE)(pVideo->dcf >> 8));
BoardWriteVideo(VID_DCF0,(BYTE) pVideo->dcf);
}