📄 srcinfo.cpp
字号:
ulStreamStartTime, m_pPlayer); } else { m_pWallClock = (SharedWallClock*)pLookupResult; ulStreamStartTime = m_pWallClock->ResetStartTime(ulStreamStartTime); } m_pWallClock->AddUser(this); } HX_RELEASE(pValues); HX_RELEASE(pWallClockName); return ulStreamStartTime;}/* * -- LIVE SYNC SUPPORT -- * * Basic clean up support for wall clock object. Notice that after * calling RemoveUser, you can use the wall clock object since it * may get deleted... so we always reset our wall clock object * pointer to NULL. */voidSourceInfo::DoneWithWallClock(){ if (m_pWallClock) { m_pWallClock->RemoveUser(this); m_pWallClock = NULL; }}HX_RESULTSourceInfo::ProcessIdle(BOOL bIsFirst, ULONG32& ulNumStreamsToBeFilled, BOOL& bIsBuffering, UINT16& uLowestBuffering, BOOL bPersistent){ HX_RESULT theErr = HXR_OK; CHXEvent* pEvent = NULL; HXSource* pSource = NULL; IHXPendingStatus* pStatus = NULL; RendererInfo* pRendInfo = NULL; IHXValues* pHeader = NULL; HXStream* pStream = NULL; IHXRenderer* pRenderer = NULL; STREAM_INFO* pStreamInfo = NULL; IHXPacket* pPacket = NULL; UINT16 unStatusCode = 0; UINT16 unPercentDone = 0; UINT32 ulPacketTime = 0; INT64 llActualPacketTime = 0; INT64 llLastExpectedPacketTime = 0; IHXBuffer* pStatusDesc = NULL; BOOL bAtInterrupt = FALSE; bAtInterrupt = m_pPlayer->m_pEngine->AtInterruptTime(); if (m_bStopped) { return HXR_OK; } /* Check if a source has not been initialized. This will happen * ONLY when we start a new track in the mid of a presentation */ if (!m_bInitialized) { /* Do not initialize source at interrupt time */ if (bAtInterrupt) { ScheduleProcessCallback(); return HXR_OK; } theErr = InitializeAndSetupRendererSites(); if (theErr || !m_bInitialized) { return theErr; } } if (m_bSeekPending) { m_bSeekPending = FALSE; Pause(); Seek(m_ulSeekTime); m_pSource->DoSeek(m_ulSeekTime); Begin(); } pSource = m_pSource; pStatus = m_pStatus; // don't start getting events till the player setup has been // done if (!m_pPlayer->m_bInitialized || m_pPlayer->m_bSetupToBeDone || m_pPlayer->m_bPostSetupToBeDone) { return HXR_OK; } UINT16 uIndex = 0; BOOL bHandled = TRUE; llLastExpectedPacketTime = m_pSource->GetLastExpectedPacketTime(); LISTPOSITION posRend = m_pCurrentScheduleList->GetHeadPosition(); for (; uIndex < m_pCurrentScheduleList->GetCount(); uIndex++) { BOOL bSentMe = TRUE; BOOL bEndMe = FALSE; llActualPacketTime = 0; theErr = HXR_OK; if (uIndex > 0) { if (bHandled) { posRend = m_pCurrentScheduleList->RemoveAt(posRend); LISTPOSITION listRet = m_pCurrentScheduleList->AddTail(pRendInfo); // This check is critical for catching oom errors. XXXJHHB if( listRet == NULL ) { return HXR_OUTOFMEMORY; } } else { m_pCurrentScheduleList->GetNext(posRend); } } bHandled = TRUE; pRendInfo = (RendererInfo*) m_pCurrentScheduleList->GetAt(posRend); pStreamInfo = pRendInfo->m_pStreamInfo; if (pStreamInfo->m_bSrcInfoStreamDone) { // SPECIAL CASE: // the player received all the packets(m_bSrcStreamDone is TRUE) and // EndOfPacket() hasn't been sent to the renderer yet, // BUT the renderer still calls ReportRebufferStatus() if (!IsRebufferDone()) { bIsBuffering = TRUE; } else { CheckIfDone(); } continue; } if (bIsFirst) { pStreamInfo->m_bSrcInfoStreamFillingDone = FALSE; ulNumStreamsToBeFilled++; } BOOL bThisSourceBuffering = FALSE; if (!bPersistent) { // every HXSource has to implement IID_IHXPendingStatus HX_ASSERT(pStatus); HX_VERIFY(HXR_OK == pStatus->GetStatus(unStatusCode, pStatusDesc, unPercentDone)); HX_RELEASE(pStatusDesc); if ((HX_STATUS_BUFFERING == unStatusCode && unPercentDone < 100) || HX_STATUS_CONTACTING == unStatusCode) { bIsBuffering = TRUE; bThisSourceBuffering = TRUE; if (uLowestBuffering > unPercentDone) { uLowestBuffering = unPercentDone; } } } /* the event times are actual ts - preroll.. so we do not * need to add preroll in calculations here... */ UINT32 ulDeliveryTime = m_pPlayer->m_ulCurrentPlayTime + m_pPlayer->m_ulLowestGranularity;#ifdef _MACINTOSH#define ADDITIONAL_PREDELIVERY_TIME 4000 /* on Mac we try to be even farther ahead than the timeline in * packet delivery since the callbacks are not that smooth * and if we are really close to the wire, it results in * unnecccessary re-buffers. */ ulDeliveryTime += ADDITIONAL_PREDELIVERY_TIME;#endif if (pSource) { pSource->FillRecordControl(); } if (bPersistent || bThisSourceBuffering || (pRendInfo->m_ulLatestEventTime <= ulDeliveryTime)) { theErr = pSource->GetEvent(pStreamInfo->m_uStreamNumber, pEvent); if (!theErr) { pPacket = pEvent->GetPacket(); if (pEvent->IsPreSeekEvent()) { // associate the packet with its renderer.. pEvent->m_pRendererInfo = pRendInfo; if (!bAtInterrupt || pRendInfo->m_bInterruptSafe) { theErr = m_pPlayer->SendPacket(pEvent); delete pEvent; } else { // insert event in the common packet/event list... theErr = m_pPlayer->m_EventList.InsertEvent(pEvent); if( theErr == HXR_OUTOFMEMORY ) { return HXR_OUTOFMEMORY; } pRendInfo->m_ulNumberOfPacketsQueued++; } continue; } if (!pPacket->IsLost()) { ulPacketTime = pPacket->GetTime(); llActualPacketTime = pRendInfo->m_pStreamInfo->BufferingState().CreateINT64Timestamp(ulPacketTime); if (m_llLatestPacketTime < llActualPacketTime) { m_llLatestPacketTime = llActualPacketTime; } pRendInfo->m_ulLatestEventTime = pEvent->GetTimeStartPos(); if (pSource->IsLive() && pRendInfo->m_bIsFirstPacket) { pRendInfo->m_bIsFirstPacket = FALSE; /* * -- LIVE SYNC SUPPORT -- * * We used to just set the stream start time to the * timestamp of this first packet. Now we use this * helper function to implement support for sharing * start times for sources off of the same wall clock. * See other LIVE SYNC SUPPORT comments for more * details. */ UINT32 ulLiveStart = CalculateLiveStartTime(pPacket); pRendInfo->m_ulStreamStartTime = ulLiveStart; m_ulStreamStartTime = ulLiveStart; UINT32 ulLowestTime = 0; BOOL bAtLeastOneLowestTime = FALSE; UINT16 uNumLowestKnown = 0; CHXMapLongToObj::Iterator tmpndxRend = m_pRendererMap->Begin(); for (;!theErr && tmpndxRend != m_pRendererMap->End(); ++tmpndxRend) { RendererInfo* pTmpRendInfo = (RendererInfo*)(*tmpndxRend); /* Have we received the lowest packet?*/ if (!pTmpRendInfo->m_bIsFirstPacket) { uNumLowestKnown++; if (!bAtLeastOneLowestTime) { bAtLeastOneLowestTime = TRUE; ulLowestTime = pTmpRendInfo->m_ulStreamStartTime; SetLiveSyncStartTime(pSource, pTmpRendInfo, ulLowestTime); } else { if (ulLowestTime > pTmpRendInfo->m_ulStreamStartTime) { ulLowestTime = pTmpRendInfo->m_ulStreamStartTime; } } } } if (uNumLowestKnown > 1) { tmpndxRend = m_pRendererMap->Begin(); for (;!theErr && tmpndxRend != m_pRendererMap->End(); ++tmpndxRend) { RendererInfo* pTmpRendInfo = (RendererInfo*)(*tmpndxRend); /* Have we received the lowest packet?*/ if (!pTmpRendInfo->m_bIsFirstPacket) { pTmpRendInfo->m_ulStreamStartTime = ulLowestTime; SetLiveSyncStartTime(pSource, pTmpRendInfo, ulLowestTime); } } } } if ((!pSource->IsLive() || pSource->isRestrictedLiveStream()) && llActualPacketTime > llLastExpectedPacketTime) { // XXX HP // work around since the rule flag of all RTSP packets are set to // HX_ASM_SWITCH_ON only and this could cause the stream doesn't end // properly if its endtime was changed after the first resume has been // sent // THIS WILL BE FIXED IN THE NEXT SERVER RELEASE("dial-tone") if (pSource->m_bRTSPRuleFlagWorkAround) { bSentMe = FALSE; bEndMe = TRUE; } else { pRendInfo->m_pStream->PostEndTimePacket(pPacket, bSentMe, bEndMe); } } } if (bSentMe) { // clear up the post events which were not sent if (pStreamInfo->m_pPostEndTimeEventList) { while (pStreamInfo->m_pPostEndTimeEventList->GetNumEvents()) { CHXEvent* pPostEndTimeEvent = pStreamInfo->m_pPostEndTimeEventList->RemoveHead(); // associate the packet with its renderer.. pPostEndTimeEvent->m_pRendererInfo = pRendInfo; // insert event in the common packet/event list... theErr = m_pPlayer->m_EventList.InsertEvent(pPostEndTimeEvent); if( theErr == HXR_OUTOFMEMORY ) { return HXR_OUTOFMEMORY; } pRendInfo->m_ulNumberOfPacketsQueued++; } } // associate the packet with its renderer.. pEvent->m_pRendererInfo = pRendInfo; // insert event in the common packet/event list... theErr = m_pPlayer->m_EventList.InsertEvent(pEvent); if( theErr == HXR_OUTOFMEMORY ) { return HXR_OUTOFMEMORY; } pRendInfo->m_ulNumberOfPacketsQueued++; } else { if (!pStreamInfo->m_pPostEndTimeEventList) { pStreamInfo->m_pPostEndTimeEventList = new CHXEventList(); } if (pStreamInfo->m_pPostEndTimeEventList) {//{FILE* f1 = ::fopen("c:\\temp\\out.txt", "a+"); ::fprintf(f1, "bSentMe is FALSE PacketTime: %lu PacketRule: %u\n", pEvent->GetPacket()->GetTime(), pEvent->GetPacket()->GetASMRuleNumber());::fclose(f1);} theErr = pStreamInfo->m_pPostEndTimeEventList->InsertEvent(pEvent); if( theErr == HXR_OUTOFMEMORY ) { return theErr; } } } } else { bHandled = FALSE; } if (theErr && !bPersistent) { if (!pStreamInfo->m_bSrcInfoStreamFillingDone && ulNumStreamsToBeFilled > 0) { pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE; ulNumStreamsToBeFilled--; } } } else { if (!pStreamInfo->m_bSrcInfoStreamFillingDone && ulNumStreamsToBeFilled > 0) { pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE; ulNumStreamsToBeFilled--; } } if (theErr == HXR_BUFFERING) { if (bPersistent) { bIsBuffering = TRUE; } } else if (theErr == HXR_AT_END) { if (!pStreamInfo->m_bSrcInfoStreamDone) { if (!bAtInterrupt || pRendInfo->m_bInterruptSafe) { pStreamInfo->m_bSrcInfoStreamDone = TRUE; pStreamInfo->ResetPostEndTimeEventList(); if (pRendInfo->m_ulNumberOfPacketsQueued == 0 && pRendInfo->m_pRenderer) { m_pPlayer->SendPostSeekIfNecessary(pRendInfo); pRendInfo->m_pRenderer->OnEndofPackets(); pRendInfo->m_bOnEndOfPacketSent = TRUE; } CheckIfDone(); } else { ScheduleProcessCallback(); continue; } } } else if (theErr == HXR_NO_DATA) { /* mask this error */ theErr = HXR_OK; } if (!llActualPacketTime) { STREAM_INFO* pStrInfo = pRendInfo->m_pStreamInfo; UINT32 ulPktTime = pStrInfo->BufferingState().LastPacketTimestamp(); llActualPacketTime = pStrInfo->BufferingState().CreateINT64Timestamp(ulPktTime); /* if this is a stream where we do not have to wait to receive * a packet >= stream's last expected packet time, * make the highest timestamp to be the HIGHEST timestamp * across ALL streams for this source. * * This is to fix end tag support on sources with sparse streams * e.g. audio/video with an event stream where we may not really * have a packet till way down in the future. */ if (pRendInfo->m_pStreamInfo->m_bCanBeStoppedAnyTime && !pStreamInfo->m_bSrcInfoStreamDone && m_llLatestPacketTime > llLastExpectedPacketTime) { /* check if ALL other streams have ended */ if (AllOtherStreamsHaveEnded(pStreamInfo)) { /* * The logic above was designed to handle endTime's * on a/v streams, so that once we received a/v packets * past the end time (even though more packets are * still coming in), we can go ahead and end the * event stream. However, this was causing a bug * where syncmm event streams were getting terminated * even though there was a packet waiting for it * at the transport. This additional test imposes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -