📄 pe_consumer_dvd.cpp
字号:
/*****************************************************************************
******************************************************************************
** **
** Copyright (c) 2006 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 pe_consumer_dvd.cpp
*
* $Revision: 1.27 $
*
* PE Consumer DVD Derived Class Definition
* The PE Consumer moves data from an input stream to a decoder or demux.
*
*/
#include <stdlib.h>
#include "decoder.h"
#include "vdvd_types.h"
#include "osapi.h"
#include "dbgprint.h"
#include "pe_app.h"
#include "pe_consumer.h"
#include "pe_consumer_dvd.h"
#include "pe_types.h"
#include "spu_app.h"
#include "css.h"
#include "utility.h"
#define DEBUG_PE_CONSUMER_DVD DBG_ERROR
#define DBG_NVPCK DBG_VERBOSE
#define DBG_SUBPIC DBG_VERBOSE
#define DBG_ON(x) (DEBUG_PE_CONSUMER_DVD >= x)
#define PE_CONSUMER_DVD_PROC_PRIORITY OS_TASK_NORMAL_PRIORITY
#define PE_CONSUMER_PROC_STACK_SIZE (16 * 1024)
/* number of messages accepted by the PSDemux before it blocks
* this is kept at a minimum because the prefetch buffer is maintained in the DR */
#define INPUT_STREAM_DEPTH 1
/* number of messages accepted by spu before it blocks
* the max bitrate for one stream is 3.36 Mbps, the SPU decoder does not buffer SPUs so the
* buffer is maintained in the cStream. The number of messages required is ((3.36Mbps / 8) / 2048)
* because each message holds 2048 of data. */
#define SUBPIC_NUM_MESSAGES 215
/* number of messages accepted by the bypass stream before it blocks
* this is one because the buffering is in the decoder */
#define BYPASS_NUM_MESSAGES 1
/* number of messages accepted by the navpack stream before it blocks
* PCI and DSI packets share the same message so this equates to 2 full navpacks
* This allows us to feed 3 VOBU to the decoder before the PSDemux blocks */
#define NVPACK_NUM_MESSAGES 2
const UCHAR PCI_STRT[] = {0x00, 0x00, 0x01, 0xBF, 0x03, 0xD4, 0x00};
const UCHAR DSI_STRT[] = {0x00, 0x00, 0x01, 0xBF, 0x03, 0xFA, 0x01};
/**
* peConsumerNavPackTaskCaller
*
* @return ULONG
*/
static ULONG peConsumerNavPackTaskCaller(PVOID pvParam)
{
PE_STATUS status = PE_SUCCESS;
if (NULL != pvParam)
{
status = ( (cPEConsumer_DVD*)pvParam )->NavPackTask(pvParam);
}
OS_TaskExit();
return (status);
}
/**
* peConsumerPlaybackTaskCaller
*
* @return ULONG
*/
static ULONG peConsumerPlaybackTaskCaller(PVOID pvParam)
{
PE_STATUS status = PE_SUCCESS;
if (NULL != pvParam)
{
status = ( (cPEConsumer_DVD*)pvParam )->PlaybackTask(pvParam);
}
OS_TaskExit();
return (status);
}
/**
* peConsumerDVDSubpicSyncCallback
*
* @return SPU_ERR
*/
static SPU_ERR peConsumerDVDSubpicSyncCallback(PVOID pContext, TIME90k time90k_TargPTS, TIME90k *ptime90k_CurrSTC)
{
if ( ((cPEConsumer_DVD*)(pContext))->SubpicSyncCallback(time90k_TargPTS, ptime90k_CurrSTC) == PE_SUCCESS)
{
return (SPU_SUCCESS);
}
else
{
return (SPU_FAILURE);
}
} /* end peConsumerDVDSubpicSyncCallback() */
/**
* cPEConsumer_DVD::Configure
*
* @return PE_STATUS
*/
PE_STATUS cPEConsumer_DVD::Configure(PE_CONSUMER_CONFIG_INFO *pConfigInfo)
{
PE_STATUS status;
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Configure()\n"));
/* base class does work required by all consumers */
status = cPEConsumer::Configure(pConfigInfo);
if (status == PE_SUCCESS)
{
/* Create and initialize cStreams */
DBGPRINT(DBG_ON(DBG_VERBOSE), ("cPEConsumer_DVD::Configure() - create cStreams\n"));
if (CreateStreams() != PE_SUCCESS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("cPEConsumer_DVD::Configure() - Could not create cStreams\n"));
goto error_out;
}
/* Create and initialize a program stream demux
* This will be used to demux the subpicture and navpack data */
DBGPRINT(DBG_ON(DBG_VERBOSE), ("cPEConsumer_DVD::Configure() - create PSDemux\n"));
if (CreatePSDemux() != PE_SUCCESS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("cPEConsumer_DVD::Configure() - Could not create PSDemux\n"));
goto error_out;
}
/* DVD needs to demux navpacks */
DBGPRINT(DBG_ON(DBG_VERBOSE), ("cPEConsumer_DVD::Configure() - Start navpack demux\n"));
if (pcDemux->AttachOutputStream(0xBF, 0, DEMUX_ANY, NVPCK, m_pNvPckStream) != DEMUX_PASS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("cPEConsumer_DVD::Configure() - Could not start Navpack Demux\n"));
goto error_out;
}
/* Create a task to read navpacks from psdemux and syncronize them to the scr */
task_navpack = OS_TaskSpawnParam("PENavPck", PE_CONSUMER_DVD_PROC_PRIORITY, PE_CONSUMER_PROC_STACK_SIZE,
peConsumerNavPackTaskCaller, this, NULL);
/* Create send date task */
task_playback = OS_TaskSpawnParam("PEPbcTsk", PE_CONSUMER_DVD_PROC_PRIORITY, PE_CONSUMER_PROC_STACK_SIZE,
peConsumerPlaybackTaskCaller, this, NULL);
}
return (status);
error_out:
return (PE_FAILURE);
}
/**
* cPEConsumer_DVD::Reset
*
* @return PE_STATUS
*/
PE_STATUS cPEConsumer_DVD::Reset(void)
{
PE_STATUS status;
DEMUXOUTPUTMESSAGE *pMessage = NULL;
if (m_ConsumerState == PE_CONSUMER_STATE_UNREALIZED)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("cPEConsumer_DVD::Reset() - PE_INVALID_STATE (%d)\n", m_ConsumerState));
return (PE_INVALID_STATE);
}
/* clear prefill since we are going to stop state */
m_fPrefill = FALSE;
m_fSuspend = FALSE;
m_fPauseAfterVOBU = FALSE;
/* start flushing */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - start flushing\n"));
m_fFlushNavPacks = TRUE;
m_fFlushPlayback = TRUE;
if ( (IS_PECONSUMER_STATE_RUNNING(m_ConsumerState) == TRUE) && (m_fStop == FALSE) )
{
PEINPUTMESSAGE *pInMessage = NULL;
m_fStop = TRUE;
m_fAbort = TRUE;
/* kick the dataProc so it won't wait */
pInMessage = (PEINPUTMESSAGE*)m_InputStream->GetMsg(OS_NO_WAIT);
if (pInMessage != NULL)
{
m_InputStream->Write(pInMessage);
}
/* stop the PSDemux */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - stop the PSDemux\n"));
pcDemux->Stop();
/* Flush the spu decoder
* NOTE: disable forced subpics so the the current spu doesn't get displayed during the flush */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - SPUStop\n"));
if (m_spu_decoder != NULL)
{
ULONG ulSPDStatus;
SPUGetStatus(m_spu_decoder, &ulSPDStatus);
if ((ulSPDStatus & SPU_STATE_MASK) != SPU_STATE_STOPPED)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("cPEConsumer_DVD::Reset() stop spu decoder, pids %d %d\n", m_spu_pesID, m_spu_subID));
SPUDisableForced(m_spu_decoder);
SPUStop(m_spu_decoder);
}
}
/* wait for transition to stopped state */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - Wait for stopped state\n"));
while (m_fStop == TRUE)
{
OS_TaskYield();
}
}
/* send termination messages to the PSDemux output streams */
pMessage = (DEMUXOUTPUTMESSAGE*)m_pNvPckStream->GetMsg(OS_WAIT_1S);
if (pMessage != NULL)
{
pMessage->fTerminate = TRUE;
m_pNvPckStream->Write(pMessage);
}
pMessage = (DEMUXOUTPUTMESSAGE*)m_pBypassStream->GetMsg(OS_WAIT_1S);
if (pMessage != NULL)
{
pMessage->fTerminate = TRUE;
m_pBypassStream->Write(pMessage);
}
/* use the base clase to terminate the main consumer task */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - base clase terminate\n"));
status = cPEConsumer::Reset();
/* wait until the dvd consumer tasks have terminated */
DBGPRINT(DBG_ON(DBG_TRACE), ("cPEConsumer_DVD::Reset() - wait until tasks have terminated\n"));
OS_TaskJoin(task_navpack);
OS_TaskJoin(task_playback);
OS_TaskDelete(task_navpack);
OS_TaskDelete(task_playback);
if (m_spu_decoder != NULL)
{
ULONG ulSPDStatus = 0;
/* if the subpic stop is still in progress wait for it to complete */
SPUGetStatus(m_spu_decoder, &ulSPDStatus);
while ((ulSPDStatus & SPU_STATE_MASK) == SPU_STATE_STOPPING)
{
OS_TaskDelayMsec(100);
SPUGetStatus(m_spu_decoder, &ulSPDStatus);
}
/* detach stream from spu before we delete it */
SPUDetachInputStream(m_spu_decoder);
m_spu_pesID = -1;
m_spu_subID = -1;
}
/* cleanup the ps demux */
if (pcDemux != NULL)
{
/* detach the navpack stream from the demux */
DBGPRINT(DBG_ON(DBG_TRACE), ("DeletePSDemux: detach the navpack stream from the demux\n"));
pcDemux->DetachOutputStream(m_pNvPckStream);
/* delete the ps demux */
DeletePSDemux();
}
/* delete any streams we've created */
DeleteStreams();
return (status);
} /* end cPEConsumer_DVD::Reset() */
/**
* Private function that creates a PSDemux class and the input stream used to feed it data.
*
* @param None
*
* @return PE_STATUS.
*/
PE_STATUS cPEConsumer_DVD::CreatePSDemux(void)
{
/* Create the program stream demux */
pcDemux = new cDemux;
if (NULL == pcDemux)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("%s: Could not create cDemux\n", __FUNCTION__));
goto error_out;
}
/* create semaphore used for message synchronization */
m_semPSDemxMsgSync = OS_SemBCreateNamed(OS_SEM_Q_FIFO, OS_SEM_EMPTY, "semDmxMsg");
if (m_semPSDemxMsgSync == 0)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("%s: Could not create semDmxMsg\n", __FUNCTION__));
goto error_out;
}
/* create semaphore used for message synchronization */
m_semNavPackState = OS_SemBCreateNamed(OS_SEM_Q_FIFO, OS_SEM_FULL, "semNVpckState");
if (m_semNavPackState == 0)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("%s: Could not create semNVpckState\n", __FUNCTION__));
goto error_out;
}
/* Attach the Demux input stream */
if (pcDemux->AttachInputStream(m_pDemuxInStream) != DEMUX_PASS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("%s: Could not attach input stream\n", __FUNCTION__));
goto error_out;
}
/* Create the demux task */
if (pcDemux->Create("PSDemux", DEMUX_MPEG2) != DEMUX_PASS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("%s: Could not create PSDemux\n", __FUNCTION__));
goto error_out;
}
/* attach a bypass output stream to feed the playback */
if (pcDemux->AttachOutputStream(0, 0, DEMUX_ANY, BYPASS, m_pBypassStream) != DEMUX_PASS)
{
DbgPrint(("%s, %d, FAILED TO ADD BYPASS DEMUX\n", __FILE__, __LINE__));
goto error_out;
}
return (PE_SUCCESS);
error_out:
DBGPRINT(DBG_ON(DBG_ERROR), ("CreatePSDemux: FAILED\n"));
return (PE_FAILURE);
}
/**
* Private function that deletes the PSDemux class and the input stream used to feed it data.
*
* @param None
*
* @return PE_STATUS
*/
PE_STATUS cPEConsumer_DVD::DeletePSDemux(void)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("DeletePSDemux: Delete the program stream demux\n"));
/* Delete the program stream demux */
if (NULL != pcDemux)
{
/* detach the bypass stream from the demux */
DBGPRINT(DBG_ON(DBG_TRACE), ("DeletePSDemux: detach the bypass stream from the demux\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -