📄 spu_decoder.cpp
字号:
/* vim:set ts=4 sw=4 et: */
/*****************************************************************************
******************************************************************************
** **
** Copyright (c) 2005 Videon Central, Inc. **
** All rights reserved. **
** **
** The computer program contained herein contains proprietary information **
** which is the property of Videon Central, Inc. The program may be used **
** and/or copied only with the written permission of Videon Central, Inc. **
** or in accordance with the terms and conditions stipulated in the **
** agreement/contract under which the programs have been supplied. **
** **
******************************************************************************
*****************************************************************************/
/**
* @file spu_decoder.cpp
*
* Private APIs for the DVD Software Subpicture Decoder
*
* $Id: spu_decoder.cpp,v 1.25 2006/10/27 14:14:10 rbehe Exp $
*/
#include "vdvd_types.h"
#include "osapi.h"
#include "cStream.h"
#include "spu_types.h"
#include "spu_app.h"
#include "spu_render.h"
#include "spu_decoder.h"
#include "utility.h"
#include "dbgprint.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#define DBG_SPU_DECODER DBG_ERROR
#define DBG_ON(x) (DBG_SPU_DECODER >= x)
/**
* Decodes complete SPUs received from the input cStream.
*
* @param hSPDecoder = The subpic decoder handle
*/
SPU_ERR SPUDecoderDecodeSPU(SPU_DECODER *pSPU)
{
BYTE *pbPtr = pSPU->pbSpuBuffer;
BYTE *pbSPU = pSPU->pbSpuBuffer;
BYTE *pbSPUEndPtr;
BYTE *pbDCSQEndPtr;
ULONG ulSPUSize;
BOOLEAN fUpdateBmp = FALSE;
BOOLEAN fDecodeBitmap = FALSE;
BYTE bSendCmd;
BYTE bCommand;
ULONG ulNextOffset;
ULONG ulLastOffset;
ULONG ulTemp;
TIME90k time90k_CurrSTC = 0;
TIME90k time90k_StartPTS;
ULONG ulSPUID;
USHORT usPreHead;
usPreHead = MAKE_WORD(&pbPtr[0]);
if (0 == usPreHead)
{
/* id of the stream */
ulSPUID = usPreHead;
/* size of the stream */
ulSPUSize = MAKE_DWORD(&pbPtr[2]);
pbPtr += 6;
}
else
{
ulSPUSize = usPreHead;
pbPtr += 2;
}
/* store spu end pointer */
pbSPUEndPtr = pbSPU + ulSPUSize;
/* Have a new SPU so invalidate the old color contrast info */
SPURenderSetPixelControlData(pSPU, NULL, 0);
if (0 == usPreHead)
{
/* get offset to the Control Sequence */
ulNextOffset = MAKE_DWORD(&pbPtr[0]);
pbPtr += 4;
}
else
{
/* get offset to the Control Sequence */
ulNextOffset = MAKE_WORD(&pbPtr[0]);
pbPtr += 2;
}
/* if the data is the same size then don't
* reset the spu variables. This way if nothing has changed
* we don't need to RLE expand the data again */
if ( (pSPU->ulCSOffset != ulNextOffset) || (pSPU->ulSPUSize != ulSPUSize) || (pSPU->fInserted == SP_NOT_INSERTED) )
{
/* initialize spu variables */
pSPU->ulCSOffset = ulNextOffset;
pSPU->ulSPUSize = ulSPUSize;
pSPU->ulBmpX = 0;
pSPU->ulBmpY = 0;
pSPU->ulBmpW = 0;
pSPU->ulBmpH = 0;
pSPU->ulFieldOffset[0] = 0;
pSPU->ulFieldOffset[1] = 0;
}
/* initialize so we don't send invalid dsp commands */
bSendCmd = CMD_END;
/* Loops through all of the SP_DCSQ (sub-picture decode control sequence) */
do
{
/* make sure we're not stopping */
if ( (pSPU->ulState == SPU_STATE_STOPPING) || (pSPU->ulState == SPU_STATE_FLUSHING) )
{
return (SPU_FAILURE);
}
ulLastOffset = ulNextOffset;
/* set data pointer to begin of the SP_DCSQ */
pbPtr = pbSPU + ulNextOffset;
/* start time is SPU PTS plus the SP_DCSQ_STM */
/* Need to multiply STM by 1024 to convert to 90kHz */
time90k_StartPTS = pSPU->ulPTS + (MAKE_WORD(&pbPtr[0]) * 1024);
/* get the offset to the next control sequence
* If no next SP_DCSQ exists this will equal the start address of this SP_DCSQ */
if (0 == usPreHead)
{
ulNextOffset = MAKE_DWORD(&pbPtr[2]);
pbPtr += 6;
}
else
{
ulNextOffset = MAKE_WORD(&pbPtr[2]);
pbPtr += 4;
}
if ( (ulNextOffset < ulLastOffset) || (ulNextOffset > ulSPUSize) )
{
DbgPrint(("SPUDecoderDecodeSPU(): BAD VALUE, ulNextOffset=%ld, ulLastOffset=%ld, ulSPUSize=%ld\n",
(long)ulNextOffset, (long)ulLastOffset, (long)ulSPUSize));
return (SPU_ERR_DECODE_FAIL);
}
/* if the previous DCSQ was skipped and we are going to block then render the previous DCSQ now */
if (fUpdateBmp == TRUE)
{
if (time90k_StartPTS > time90k_CurrSTC)
{
/* send FSTA_DSP, STA_DSP, and STP_DSP send commands to renderer */
if ( (bSendCmd == FSTA_DSP) || (bSendCmd == STA_DSP) )
{
/* take critical section */
OS_SemTake(pSPU->critical_section, OS_WAIT_FOREVER);
/* clear the flag */
fUpdateBmp = FALSE;
/* if the spu needs RLE decoded do it now */
if (TRUE == fDecodeBitmap)
{
fDecodeBitmap = FALSE;
if (pSPU->RLE8Bit == 0)
{
if (SPURenderRLEDecodePxd(pSPU) != SPU_SUCCESS)
{
/* give critical section */
OS_SemGive(pSPU->critical_section);
return (SPU_ERR_DECODE_FAIL);
}
}
else
{
if (SPURenderRLEDecodePxd8Bit(pSPU) != SPU_SUCCESS)
{
/* give critical section */
OS_SemGive(pSPU->critical_section);
return (SPU_ERR_DECODE_FAIL);
}
}
}
SPUDecoderProcessData(pSPU, bSendCmd);
/* give critical section */
OS_SemGive(pSPU->critical_section);
}
}
}
#ifndef __DISABLE_SYNC
/* wait for the SP_DCSQT execution time
* This is a callback that is attached by the module that will perform
* the avsync algorithm. Typically this would be the PE. */
((SPU_SYNC_CALLBACK)(pSPU->pSyncCallback))(pSPU->pSyncContext, time90k_StartPTS, &time90k_CurrSTC);
#endif
/* make sure we're not stopping */
if ( (pSPU->ulState == SPU_STATE_STOPPING) || (pSPU->ulState == SPU_STATE_FLUSHING) )
{
return (SPU_FAILURE);
}
if (ulNextOffset == ulLastOffset)
{
pbDCSQEndPtr = pbSPUEndPtr;
}
else
{
pbDCSQEndPtr = pbSPU + ulNextOffset;
}
/* take critical section */
OS_SemTake(pSPU->critical_section, OS_WAIT_FOREVER);
/* Loop through the current SP_DCSQ */
while (1)
{
bCommand = pbPtr[0];
pbPtr += 1;
/* if we hit CMD_END were done with this DCSQ */
if ( (bCommand == CMD_END) || (pbPtr >= pbDCSQEndPtr) )
{
break;
}
switch (bCommand)
{
case FSTA_DSP: /* force display */
case STA_DSP: /* start display */
case STP_DSP: /* stop display */
bSendCmd = bCommand;
break;
case SET_COLOR: /* set colors */
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_COLOR\n"));
#endif
SPURenderSetColor(pSPU, MAKE_WORD(pbPtr));
pbPtr += 2;
fUpdateBmp = TRUE;
pSPU->RLE8Bit = 0;
break;
case SET_COLOR2: /* set colors 8 bit */
SPURenderSetColor8bit(pSPU, pbPtr);
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_COLOR2\n"));
#endif
pbPtr += 256 * 3; /* 256 colors each is 24 bit */
pSPU->RLE8Bit = 1;
break;
case SET_CONTR: /* set alpha */
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_CONTR\n"));
#endif
SPURenderSetContrast(pSPU, MAKE_WORD(pbPtr));
pbPtr += 2;
fUpdateBmp = TRUE;
pSPU->RLE8Bit = 0;
break;
case SET_CONTR2:
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SET_CONTR2\n"));
#endif
SPURenderSetContrast8bit(pSPU, pbPtr);
pbPtr += 256;
pSPU->RLE8Bit = 1;
break;
case SET_DAREA:
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_DAREA\n"));
#endif
/* set screen position and dimension */
ulTemp = (MAKE_WORD(&pbPtr[0]) & 0x7ff0) >> 4;
if (ulTemp != pSPU->ulBmpX)
{
pSPU->ulBmpX = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = ((MAKE_WORD(&pbPtr[1]) & 0x7ff) - pSPU->ulBmpX) + 1;
if (ulTemp != pSPU->ulBmpW)
{
pSPU->ulBmpW = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = (MAKE_WORD(&pbPtr[3]) & 0x7ff0) >> 4;
if (ulTemp != pSPU->ulBmpY)
{
pSPU->ulBmpY = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = ((MAKE_WORD(&pbPtr[4]) & 0x7ff) - pSPU->ulBmpY) + 1;
if (ulTemp != pSPU->ulBmpH)
{
pSPU->ulBmpH = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
pbPtr += 6;
pSPU->RLE8Bit = 0;
break;
case SET_DAREA2:
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_DAREA2\n"));
#endif
/* set screen position and dimension */
ulTemp = (MAKE_WORD(&pbPtr[0]) & 0x7ff0) >> 4;
if (ulTemp != pSPU->ulBmpX)
{
pSPU->ulBmpX = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = ((MAKE_WORD(&pbPtr[1]) & 0x7ff) - pSPU->ulBmpX) + 1;
if (ulTemp != pSPU->ulBmpW)
{
pSPU->ulBmpW = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = (MAKE_WORD(&pbPtr[3]) & 0x7ff0) >> 4;
if (ulTemp != pSPU->ulBmpY)
{
pSPU->ulBmpY = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = ((MAKE_WORD(&pbPtr[4]) & 0x7ff) - pSPU->ulBmpY) + 1;
if (ulTemp != pSPU->ulBmpH)
{
pSPU->ulBmpH = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
pbPtr += 6;
pSPU->RLE8Bit = 1;
break;
case SET_DSPXA:
#if DBG_ON(DBG_VERBOSE)
DbgPrint(("SPUDecoderDecodeSPU() -- SET_DSPXA\n"));
#endif
/* set offset of fields */
ulTemp = MAKE_WORD(&pbPtr[0]);
if (ulTemp != pSPU->ulFieldOffset[0])
{
pSPU->ulFieldOffset[0] = ulTemp;
fUpdateBmp = TRUE;
fDecodeBitmap = TRUE;
}
ulTemp = MAKE_WORD(&pbPtr[2]);
if (ulTemp != pSPU->ulFieldOffset[1])
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -