📄 smlparse.cpp
字号:
}
#else
// Don't QI core for IID_IHXXMLParser; use our own instance.
HXXMLParser* parser = new HXXMLParser();
if (parser)
{
parser->AddRef();
}
else
{
rc = HXR_OUTOFMEMORY;
}
if (SUCCEEDED(rc))
{
m_pResponse = new CSmil1ParserResponse(this);
m_pResponse->AddRef();
rc = parser->Init(m_pResponse, NULL, TRUE); // strict parser
}
if (m_bStoreErrors && parser)
{
parser->InitErrorNotifier(m_pResponse);
}
m_pParser = (IHXXMLParser*)parser;
#endif
return rc;
}
HX_RESULT
CSmil1Parser::parse(IHXBuffer* pBuffer, BOOL bIsFinal)
{
HX_RESULT rc = HXR_OK;
rc = m_pParser->Parse(pBuffer, bIsFinal);
if(HXR_OK != rc)
{
m_pParser->GetCurrentLineNumber(m_ulErrorLineNumber);
m_pParser->GetCurrentColumnNumber(m_ulErrorColumnNumber);
HX_RELEASE(m_pErrorText);
m_pParser->GetCurrentErrorText(m_pErrorText);
}
return rc;
}
HX_RESULT
CSmil1Parser::durationResolved(const char* pID, UINT32 ulDuration)
{
SMIL1Node* pNode = NULL;
IHXBuffer* pBuf = NULL;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
if (pNode->m_pElement->m_bIndefiniteDuration)
{
goto cleanup;
}
// add duration to parent element
if(pNode &&
pNode->m_pElement &&
pNode->m_pElement->m_pTimelineElement)
{
pNode->m_pElement->m_pTimelineElement->setDuration(ulDuration);
}
}
cleanup:
HX_RELEASE(pBuf);
return HXR_OK;
}
BOOL AncestorEventsAreResolved(SMIL1Node* pNode)
{
if (!pNode || !pNode->m_pElement ||
!pNode->m_pElement->m_pTimelineElement || pNode->m_tag == SMILBody)
{
return TRUE;
}
//Now, look to see if its duration and delay events, if any, are
// resolved:
if ( ( (pNode->m_pElement->m_pTimelineElement->durationEvent() &&
!pNode->m_pElement->m_pTimelineElement->durationSet()) ||
(pNode->m_pElement->m_pTimelineElement->delayEvent() &&
!pNode->m_pElement->m_pTimelineElement->initialDelaySet()) ) &&
//[SMIL 1.0 compliance] Helps fix PR 32578:
//However, if we have a duration event and it's based on a child's
// timing (as can happen via endsync="id(child)", then we want to
// avoid this element waiting for its parent to be resolved while
// the parent is waiting for this element to be resolved:
(!pNode->m_pElement->m_pTimelineElement->durationEvent() ||
SMILEventSourceID != pNode->m_pElement->m_nEndsyncEventSourceTag) )
{
return FALSE; //We still need to await event resolution.
}
//pNode is ok but its dependency ancestors may still be unresolved and
// thus pNode may still have timing constraints from its dependency
// ancestors due to their unresolved event(s):
return AncestorEventsAreResolved(pNode->m_pParent);
}
void
CSmil1Parser::insertTimelineElement(const char* pID, UINT32 ulDelay)
{
SMIL1Node* pNode = 0;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
if(pNode &&
pNode->m_pElement &&
!pNode->m_pElement->m_bInsertedIntoTimeline &&
//[SMIL 1.0 compliance] Helps fix PR 16629:
// We don't want to insert a node into the timeline if
// its begin or end is dependent on another (not-yet-
// resolved) element:
( (!pNode->m_pElement->m_pTimelineElement->durationEvent() ||
pNode->m_pElement->m_pTimelineElement->durationSet()) &&
(!pNode->m_pElement->m_pTimelineElement->delayEvent() ||
pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )
//[SMIL 1.0 compliance] Helps fix 14420:
// First, we need to look all the way up the tree of ancestors
// to see if any of them have event-based delays or durations
// and to make sure the appropriate time(s) are resolved. If
// not, we'll have to await those event resolutions before
// inserting this element into the timeline:
&& AncestorEventsAreResolved(pNode)
)
{
// /[SMIL 1.0 Compliance] Fixes PR 27644:
// if our begin offset is same or greater than our parent's
// end offset, then we should be ignored:
if ( pNode->m_pParent && pNode->m_pParent->m_pElement &&
pNode->m_pElement->m_ulBeginOffset != ((UINT32)-1) &&
pNode->m_pParent->m_pElement->m_ulEndOffset !=
((UINT32)-1) &&
(pNode->m_pElement->m_ulBeginOffset >
pNode->m_pParent->m_pElement->m_ulEndOffset) )
{
return; //Don't insert this because it can't ever play.
}
// skip the element if its duration == 0
if (0 == pNode->m_pElement->m_ulDuration)
{
durationResolved(pNode->m_id, 0);
}
else
{
pNode->m_pElement->m_ulDelay = ulDelay;
pNode->m_pElement->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
pNode->m_pElement->m_bInsertedIntoTimeline = TRUE;
insertElementByTimestamp(pNode->m_pElement);
}
}
}
}
void
CSmil1Parser::resetTimelineElementDuration(const char* pID,
UINT32 ulDuration)
{
SMIL1Node* pNode = NULL;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
CSmil1SourceUpdate* pUpdate = new CSmil1SourceUpdate;
pUpdate->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
pUpdate->m_srcID = pID;
pUpdate->m_ulUpdatedDuration = ulDuration;
if(!m_pSourceUpdateList)
{
m_pSourceUpdateList = new CHXSimpleList;
}
m_pSourceUpdateList->AddTail(pUpdate);
insertElementByTimestamp(pUpdate);
}
}
CSmil1Element*
CSmil1Parser::findElement(const char* pID)
{
SMIL1Node* pNode = NULL;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
return pNode->m_pElement;
}
return NULL;
}
const char*
CSmil1Parser::assignID(const char* pPrefix)
{
SafeSprintf(m_pVarName, 256, "%s_%ld", pPrefix, GetUniqueNumber());
return m_pVarName;
}
UINT16
CSmil1Parser::getFragmentGroup(const char* pFragment)
{
if(pFragment)
{
SMIL1Node* pNode = 0;
if(m_pIDMap->Lookup(pFragment, (void*&)pNode))
{
if(!pNode->m_bDelete)
{
if(pNode->m_tag == SMILAAnchor ||
pNode->m_tag == SMILSwitch)
{
SMIL1Node* pChildNode = getTimelineDescendent(pNode, NULL);
while(pChildNode)
{
if(!pChildNode->m_bDelete)
{
return pChildNode->m_nGroup;
}
pChildNode = getTimelineDescendent(pNode, pChildNode);
}
}
else if(pNode->m_tag == SMILAnchor)
{
SMIL1Node* pParentNode = pNode->m_pParent;
if(pParentNode &&
!pParentNode->m_bDelete)
{
return pParentNode->m_nGroup;
}
}
else
{
return pNode->m_nGroup;
}
}
}
}
return 0;
}
UINT32
CSmil1Parser::getFragmentOffset(const char* pFragment,
//This BOOL will be set to FALSE if the fragment
// does not exist or does not yet have a resolved
// begin time. This was necessary to fix PR 22655:
BOOL& bFragFoundAndResolved)
{
bFragFoundAndResolved = FALSE;
if(pFragment)
{
UINT32 ulAnchorBegin = 0;
SMIL1Node* pNode = NULL;
CSmil1Element* pElement = NULL;
CSmil1Element* pActualElement = NULL;
if(m_pIDMap->Lookup(pFragment, (void*&)pNode) &&
pNode->m_pElement)
{
pElement = pNode->m_pElement;
if(pNode->m_tag == SMILSwitch ||
pNode->m_tag == SMILAAnchor)
{
SMIL1Node* pChildNode = getTimelineDescendent(
pNode, NULL);
while(pChildNode)
{
if(!pChildNode->m_bDelete)
{
pActualElement = pChildNode->m_pElement;
break;
}
pChildNode = getTimelineDescendent(
pNode, pChildNode);
}
}
else if(pNode->m_tag == SMILAnchor)
{
if(pElement->m_ulBeginOffset != (UINT32)-1)
{
ulAnchorBegin = pElement->m_ulBeginOffset;
}
SMIL1Node* pParent = pNode->m_pParent;
if(pParent)
{
pActualElement = pParent->m_pElement;
}
}
else
{
pActualElement = pElement;
}
if(pActualElement)
{
//[SMIL 1.0 Compliance] Fixes PR 26464:
// Use delay (which already includes begin offset)
// if it's a valid value, else use begin offset
// without delay added (see comment below):
if(pActualElement->m_ulDelay != (UINT32)-1)
{
bFragFoundAndResolved = TRUE;
return pActualElement->m_ulDelay +
ulAnchorBegin;
}
else if(pActualElement->m_ulBeginOffset != (UINT32)-1)
{
bFragFoundAndResolved = TRUE;
//Changed this while fixing PR 26464:
// This used to return pActualElement->m_ulDelay +
// pActualElement->m_ulBeginOffset + ulAnchorBegin but
// the delay can already account for the begin if both
// are set so we'd end up seeking past where we were
// supposed to go by the amount of the begin offset.
// Also, we weren't even checking to see
// if delay was valid before using it (and now we're
// sure it is invalid per check above):
return pActualElement->m_ulBeginOffset +
ulAnchorBegin;
}
else
{
return 0;
}
}
}
}
return 0;
}
SMIL1Node*
CSmil1Parser::findFirstNode(SMIL1NodeList* pNodeList, SMIL1NodeTag tag)
{
if(!pNodeList)
{
return 0;
}
SMIL1Node* pFoundNode = 0;
CHXSimpleList::Iterator i;
for(i=pNodeList->Begin();i!=pNodeList->End();++i)
{
SMIL1Node* pNode = (SMIL1Node*)(*i);
if(pNode->m_tag == tag)
{
pFoundNode = pNode;
}
else
{
pFoundNode = findFirstNode(pNode->m_pNodeList, tag);
}
if(pFoundNode)
{
break;
}
}
return pFoundNode;
}
SMIL1Node*
CSmil1Parser::findFirstNode(SMIL1NodeTag tag)
{
return findFirstNode(m_pNodeList, tag);
}
SMIL1Node*
CSmil1Parser::getFirstNodeChild(SMIL1Node* pNode)
{
m_pCurNode = pNode;
if(!m_pCurNode)
{
return 0;
}
return m_pCurNode->getFirstChild();
}
SMIL1Node*
CSmil1Parser::getNextNodeChild()
{
if(!m_pCurNode)
{
return 0;
}
return m_pCurNode->getNextChild();
}
HX_RESULT
CSmil1Parser::parseClockValue(const char* pValue, UINT32& ulTimeValue)
{
// try npt
char* pPtr = (char *)strstr(pValue, "npt=");
if(pPtr)
{
pPtr += 4; // point to beginning of clock value
//[SMIL 1.0 compliance] fixes PR 26445: if "npt=4h" is specified,
// we need to convert to "14400s" otherwise the 4 is treated as
// seconds:
char* pHourChar = strchr(pPtr, 'h');
if (pHourChar && !strchr(pPtr, ':')) //then it's hours without ':'
{
IHXBuffer* pBuf = new CHXBuffer;
if (pBuf)
{
pBuf->AddRef();
*pHourChar = '\0'; //get rid of the 'h' in pPtr.
pBuf->Set((const unsigned char *)pPtr,
strlen(pPtr) + strlen(":00:00") + 1);
char* pTmp = (char*)pBuf->GetBuffer();
strcat(pTmp, ":00:00"); /* Flawfinder: ignore */
NPTime clockTime((const char*)pTmp);
ulTimeValue = (UINT32)clockTime;
pBuf->Release();
}
else
{
return HXR_OUTOFMEMORY;
}
}
//END fix for PR 26445.
else
{
NPTime clockTime(pPtr);
ulTimeValue = (UINT32)clockTime;
}
return HXR_OK;
}
// try smpte
pPtr = (char *)strstr(pValue, "smpte=");
if(pPtr)
{
pPtr += 6; // point to beginning of clock value
SMPTETimeCode clockTime(pPtr);
ulTimeValue = (UINT32)clockTime;
return HXR_OK;
}
pPtr = (char *)strstr(pValue, "smpte-30-drop=");
if(pPtr)
{
pPtr += 14; // point to beginning of clock value
SMPTETimeCode clockTime(pPtr);
ulTimeValue = (UINT32)clockTime;
return HXR_OK;
}
pPtr = (char *)strstr(pValue, "smpte-25=");
if(pPtr)
{
pPtr += 9; // point to beginning of clock value
SMPTETimeCode clockTime;
clockTime.m_framesPerSec = SMPTETimeCode::FPS_25;
clockTime.fromString(pPtr);
ulTimeValue = (UINT32)clockTime;
return HXR_OK;
}
else if(strchr(pValue, ':')) // try just hh:mm:ss with no prefix/suffix
{
NPTime clockTime(pValue);
ulTimeValue = (UINT32)clockTime;
return HXR_OK;
}
// ok, try h/min/s/ms
char* pEndPtr = 0;
double dVal = strtod(pValue, &pEndPtr);
if(strcmp(pEndPtr, "h") == 0)
{
ulTimeValue = (UINT32)(dVal * 60.0 * 60.0 * 1000.0);
return HXR_OK;
}
else if(strcmp(pEndPtr, "min") == 0)
{
ulTimeValue = (UINT32)(dVal * 60.0 * 1000.0);
return HXR_OK;
}
else if(strcmp(pEndPtr, "s") == 0 ||
//[SMIL 1.0 compliance] Fixes PR 22673: the SMIL doc says that we
// need to default to seconds if no unit-type is given:
// Timecount-val ::= Timecount ("." Fraction)?
// ("h" | "min" | "s" | "ms")? ; default is "s"
(!strlen(pEndPtr)) )
{
ulTimeValue = (UINT32)(dVal * 1000.0);
return HXR_OK;
}
else if(strcmp(pEndPtr, "ms") == 0)
{
ulTimeValue = (UINT32)(dVal);
return HXR_OK;
}
//else something other than "h", "min", "s", "", or "ms" was specified:
else
{
return HXR_FAIL;
}
}
HX_RESULT
CSmil1Parser::parseAnchorCoords(const char* pCoords, CSmil1AnchorElement* pAnchor)
{
HX_RESULT rc = HXR_OK;
double coordArray[4];
BOOL percentArray[4];
int i = 0;
for(i=0; i<4; ++i)
{
coordArray[i] = 0.0;
percentArray[i] = FALSE;
}
char* pCoordCopy = new_string(pCoords);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -