⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spu_decoder.cpp

📁 这是DVD中伺服部分的核心代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* 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 + -