📄 pg_parse.cpp
字号:
/*****************************************************************************
******************************************************************************
** **
** Copyright (c) 2005-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 pg_parse.cpp
*
* $Revision: 1.7 $
*
* Parse routines for the PG module
*
*/
#include "vdvd_types.h"
#include "pg_api.h"
#include "pg_parse.h"
#include "pg_render.h"
#include "pg_util.h"
#include "pg_defs.h"
#include "utility.h"
#include "pg_graphics.h"
#include <directfb.h>
#define DEBUG_PG_PARSE DBG_ERROR
#define DBG_ON(x) (DEBUG_PG_PARSE >= x)
/* data declarations */
extern OBJECT_DEFINITION_SEGMENT PGObjList[PG_MAX_ODS]; /* our array of Objects (images) */
extern PALETTE PGPalettes[PG_MAX_PALETTES];
extern PGINFO PGInfo;
extern PGSTATS PGStats;
int gPGParserWaiting;
static PG_WINDOW PGWindows[MAX_WINDOWS]; /* our windows for images */
/* the amount of time between frames in relation to the FrameRate in the Video Descriptor,
we use this to determine when to start a PCS rendering, these
are in terms of 90khz clock */
int FrameTimes[16] = {0, 3754, 3750, 3600,
3003, 0, 3600, 3003,
0, 0, 0, 0,
0, 0, 0, 0};
/* local proto's */
static PG_STATUS PGLoadPCSCompObjs(BYTE *DataStart, PRESENTATION_COMPOSITION_SEGMENT *Pcs, ULONG *MovedBytes);
static PG_STATUS PGLoadPCS(BYTE *DataStart, ULONG DataLength, ULONG PTS, BYTE PTS_DTS_Flags);
static PG_STATUS PGLoadPalette(BYTE *DataStart, ULONG DataLength);
static PG_STATUS PGLoadObject(BYTE *DataStart, ULONG DataLength);
static PG_STATUS PGLoadWindows(BYTE *DataStart, ULONG DataLength);
static PG_STATUS PGDecodeData(PG_PARSE_MSG *ParseData);
static PG_STATUS PGWaitForDTS(ULONG DTS);
/**
* PGParse - the parse task for the PG module
*
* @param PVOID pvParam - the parse queue we will use, this may change
*
* @return ULONG
*/
ULONG PGParse(PVOID pvParam)
{
ULONG status = PG_STATUS_SUCCESS;
PG_PARSE_MSG *pMessage = NULL;
/* loop:
read from queue
process data
*/
while (PG_FLAGS_EXIT != PGInfo.QuitFlags)
{
gPGParserWaiting = 1;
/* Get a stream message */
pMessage = (PG_PARSE_MSG *)PGInfo.PGParseQ->Read(OS_WAIT_FOREVER);
gPGParserWaiting = 0;
if (pMessage == NULL)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("Null message in PGParse\n"));
OS_TaskYield();
continue;
}
if (PG_STATE_RUNNING != PGInfo.CurrentState)
{
/* release the message */
PGInfo.PGParseQ->ReleaseMsg(pMessage);
pMessage = NULL;
continue;
}
/* decode the data */
PGDecodeData(pMessage);
/* release the message */
PGInfo.PGParseQ->ReleaseMsg(pMessage);
pMessage = NULL;
}
DBGPRINT(DBG_ON(DBG_TRACE), ("exit PGParse()\n"));
OS_TaskExit();
return (status);
}
/**
* PGDecodeData - decodes data from the PGParseBuffer into our object lists
*
* @param PG_PARSE_DATA *ParseData - info about what to parse and how much data is there
*
* @return PG_STATUS
*/
PG_STATUS PGDecodeData(PG_PARSE_MSG *ParseData)
{
ULONG SegmentLength;
/* set start and end ptrs */
BYTE *SegmentStart = ParseData->DataStart;
BYTE *DataEnd = ParseData->DataStart + ParseData->DataLength;
if (ParseData->DataStart < PGInfo.PGParseBuffer)
{
DbgPrint(("ERROR in parser, data start\n"));
return PG_STATUS_ERROR;
}
if (DataEnd > PGInfo.PGParseBuffer + SIZE_PG_CODED_DATA_BUFFER)
{
DbgPrint(("ERROR in parser, data end\n"));
return PG_STATUS_ERROR;
}
/*
when we are called, we scoop up data from the start given in ParseData
it gives a pointer and size and is assumed to be complete in that the
data will be full segments, if it was a multipes packet segment
the data will have been written to the queue such that no special handling is needed
*/
/* while we still have data to process */
while (SegmentStart < DataEnd)
{
/* look at the first byte in the sequence, if it is not a valid
segment start code, skip the rest of the packet and return */
/* check our quit flags */
if (PG_STATE_RUNNING != PGInfo.CurrentState)
{
DBGPRINT(DBG_ON(DBG_TRACE), ("Leaving PGDecodeData() via flags\n"));
/* update the read pointer */
PGInfo.ParseReadPtr = (ULONG)DataEnd - (ULONG)PGInfo.PGParseBuffer;
return PG_STATUS_SUCCESS;
}
/* the length of the segment is right after the first byte,
unless this is a multipes segment, then there is only one object
in this message it MUST be a ODS */
SegmentLength = MAKE_WORD(SegmentStart+1);
switch (*SegmentStart)
{
case PALETTE_DEFINITION:
DBGPRINT(DBG_ON(DBG_TRACE), ("PG Parse: PAL wait for 0x%x CurPTS = 0x%x\n", ParseData->DTS, PGInfo.CurPTS));
if (PGInfo.StreamAcquired)
{
PGWaitForDTS(ParseData->DTS); /* wait for the decode time we want */
PGLoadPalette(SegmentStart+3, SegmentLength); /* feed start ptr as first byte after segment descriptor */
}
SegmentStart += SIZE_SEGMENT_DESCRIPTOR + SegmentLength;
break;
case OBJECT_DEFINITION:
DBGPRINT(DBG_ON(DBG_TRACE), ("PG Parse: ODS, wait for 0x%x CurPTS 0x%x\n", ParseData->DTS, PGInfo.CurPTS));
if (PGInfo.StreamAcquired)
{
if (PGInfo.FrameDropping == 1)
{
/* if the display PTS has passed, we drop this */
if ((PGInfo.CurPTS <= PGInfo.ParserPCS->PTSDisplayTime) ||
(PGInfo.CurPTS < (ParseData->DTS + 3000)) )
{
PGWaitForDTS(ParseData->DTS); /* wait for it */
if (ParseData->MultiPES)
{
PGLoadObject(SegmentStart+3, ParseData->DataLength - 3);
}
else
{
PGLoadObject(SegmentStart+3, SegmentLength);
}
}
else
{
DBGPRINT(DBG_ON(DBG_ERROR), ("Dropping ODS: DTS: 0x%x PTS 0x%x PTSComp 0x%x, CurPTS 0x%x\n\n",
ParseData->DTS, ParseData->PTS, PGInfo.ParserPCS->PTSDisplayTime, PGInfo.CurPTS));
PGStats.PGTotalFrameDrops++;
}
}
else
{
/* not dropping frames, wait for time */
PGWaitForDTS(ParseData->DTS);
if (ParseData->MultiPES)
{
PGLoadObject(SegmentStart+3, ParseData->DataLength - 3);
}
else
{
PGLoadObject(SegmentStart+3, SegmentLength);
}
}
}
if (ParseData->MultiPES)
{
SegmentStart = DataEnd;
}
else
{
SegmentStart += SIZE_SEGMENT_DESCRIPTOR + SegmentLength;
}
break;
case PRESENTATION_COMPOSITION:
DBGPRINT(DBG_ON(DBG_TRACE), ("PG Parse: PCS, wait for 0x%x CurPTS is 0x%x\n", ParseData->DTS, PGInfo.CurPTS));
/* reset the drop data flag and wait */
PGWaitForDTS(ParseData->DTS);
PGLoadPCS(SegmentStart+3, SegmentLength, ParseData->PTS, ParseData->PTS_DTS_Flags);
SegmentStart += SIZE_SEGMENT_DESCRIPTOR + SegmentLength;
break;
case WINDOW_DEFINITION:
DBGPRINT(DBG_ON(DBG_TRACE), ("PG Parse: WDS wait for 0x%x CurPTS is 0x%x\n", ParseData->DTS, PGInfo.CurPTS));
if (PGInfo.StreamAcquired)
{
if (PGInfo.ParserPCS == NULL)
{
DbgPrint(("GOT WDS WITHOUT A PCS!!!\n\n"));
}
PGWaitForDTS(ParseData->DTS);
PGLoadWindows(SegmentStart+3, SegmentLength);
}
SegmentStart += SIZE_SEGMENT_DESCRIPTOR + SegmentLength;
break;
case END_OF_DISPLAY_SET:
DBGPRINT(DBG_ON(DBG_TRACE), ("PG Parse: EDS wait for 0x%x CurPTS is 0x%x\n", ParseData->DTS, PGInfo.CurPTS));
PGWaitForDTS(ParseData->DTS);
if (PGInfo.StreamAcquired)
{
if (PGInfo.ParserPCS && (PGInfo.CurrentState == PG_STATE_RUNNING))
{
/* render this pcs */
OS_SemTake(PGInfo.RenderLock, OS_WAIT_FOREVER);
OS_SemTake(PGInfo.BlitLock, OS_WAIT_FOREVER);
RenderPCS(PGInfo.ParserPCS);
OS_SemGive(PGInfo.BlitLock);
OS_TimerSet(PGInfo.PGFlipTimer, 1);
OS_TaskYield();
OS_SemGive(PGInfo.RenderLock);
/* the renderer will free the memory, we DON'T free it here, just mark it
as not in use by the parser (NULL) */
PGInfo.ParserPCS = NULL;
}
}
/* we aren't guaranteed to get one of these after a pcs i don't think
* need to verify, if so, it would make a good signal to attach to
* the pcs so we know it's ok to render */
SegmentStart += (SIZE_SEGMENT_DESCRIPTOR + SegmentLength);
break;
default:
DBGPRINT(DBG_ON(DBG_ERROR), ("\n###ERROR: unsupported type of segment, 0x%x, datalength %d\n", *SegmentStart, ParseData->DataLength));
PGStats.PGTotalParseMsgDrops++;
goto errout;
}
}
/* update the read pointer */
PGInfo.ParseReadPtr = (ULONG)DataEnd - (ULONG)PGInfo.PGParseBuffer;
return PG_STATUS_SUCCESS;
errout:
DBGPRINT(DBG_ON(DBG_ERROR), ("ERROR OUT OF PG_DECODE\n"));
/* update the read pointer */
PGInfo.ParseReadPtr = (ULONG)DataEnd - (ULONG)PGInfo.PGParseBuffer;
return PG_STATUS_ERROR;
}
/**
* PGLoadPCS - decodes data from the PGParseBuffer into our object lists
*
* @param BYTE *DataStart - pointer to the buffer with data in it for decode
* @param ULONG DataLength - the length of DataStart in bytes
* @param ULONG PTS - Presentation Time Stamp of the PES packet this PCS came in
* @param ULONG DTS - Decode Time Stamp of the PES packet this PCS came in
* @param BYTE PTS_DTS_Flags - the PTS/DTS flags from the pes header (shifted down) (PTS_ONLY/PTS_AND_DTS)
*
* @return PG_STATUS
*/
PG_STATUS PGLoadPCS(BYTE *DataStart, ULONG DataLength, ULONG PTS, BYTE PTS_DTS_Flags)
{
ULONG MovesBytes;
BYTE *SegmentIndex = DataStart;
if (PGInfo.CurrentState != PG_STATE_RUNNING)
{
return PG_STATUS_SUCCESS;
}
if (PGInfo.ParserPCS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("PGInfo.ParserPCS already exists\n"));
ReleasePCS(PGInfo.ParserPCS);
PGInfo.ParserPCS = NULL;
}
/* allocate space for a PCS */
PGInfo.ParserPCS = (PRESENTATION_COMPOSITION_SEGMENT *)OS_MemAlloc(sizeof(PRESENTATION_COMPOSITION_SEGMENT));
if (NULL == PGInfo.ParserPCS)
{
DBGPRINT(DBG_ON(DBG_ERROR), ("Not Enough Memory for PCS\n"));
return PG_STATUS_ERROR;
}
/* clear out the PCS object */
memset(PGInfo.ParserPCS, 0, sizeof(PRESENTATION_COMPOSITION_SEGMENT));
/* video descriptor */
PGInfo.ParserPCS->VideoDesc.Width = MAKE_WORD(SegmentIndex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -