📄 hxflsrc.cpp
字号:
#if defined(HELIX_FEATURE_RECORDCONTROL)
SendHeaderToRecordControl(FALSE, pHeader);
#endif /* HELIX_FEATURE_RECORDCONTROL */
StreamHeaderReadyExt(pHeader);
// fileformat initialized...clear any pending upgrade requests for this source!
ClearUpgradeRequest();
// we have already received enough headers...
if (m_uNumStreams >= m_ulStreamHeadersExpected)
return HXR_FAILED;
theErr = ProcessStreamHeaders(pHeader, pStreamInfo);
if (!theErr)
{
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
HX_ASSERT(pStreamInfo);
// create all the statistic registry keys
if (m_pRegistry && m_pStats &&
HXR_OK == m_pRegistry->GetPropName(m_pStats->m_ulRegistryID, pszParentName))
{
SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.Stream%ld", pszParentName->GetBuffer(),
m_ulStreamIndex);
/* does this ID already exists ? */
UINT32 ulRegistryID = m_pRegistry->GetId(szRegKeyName);
if (!ulRegistryID)
{
ulRegistryID = m_pRegistry->AddComp(szRegKeyName);
}
pStreamInfo->m_pStats = new STREAM_STATS(m_pRegistry, ulRegistryID);
if(pStreamInfo->m_pStats)
{
// set stream bandwidth
pStreamInfo->m_pStats->m_pClipBandwidth->SetInt((INT32)pStreamInfo->BufferingState().AvgBandwidth());
}
else
{
// NOTE: It may be that we can still function without the
// m_pStats object, but can we still function if we are
// running out of memory at this point? Assuming no.
theErr = HXR_OUTOFMEMORY;
}
}
HX_RELEASE(pszParentName);
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
m_ulStreamIndex++;
m_uNumStreams++;
}
if (!theErr && m_uNumStreams == m_ulStreamHeadersExpected)
{
m_uActiveStreams = m_uNumStreams;
m_ulOriginalDuration = m_ulDuration;
m_bInitialized = TRUE;
theErr = AdjustClipTime();
m_pBufferManager->Init();
}
return theErr;
}
HX_RESULT
HXFileSource::StreamHeaderReadyExt(IHXValues* pHeader)
{
return HXR_OK;
}
STDMETHODIMP
HXFileSource::PacketReady(HX_RESULT status, IHXPacket* pPacket)
{
HX_RESULT theErr = HXR_OK;
// We should have been initialized by now
HX_ASSERT(m_bInitialized);
if (!m_bInitialized)
{
return HXR_NOT_INITIALIZED;
}
// Report a non-HXR_OK error code only if no packet. If a packet
// accompanies the error code we assume end of stream and handle
// later on (see below).
if (!pPacket)
{
if (HXR_OK != status)
{
mLastError = status;
ReportError(mLastError);
return HXR_OK;
}
else
{
// HXR_OK with a NULL packet makes no sense
return HXR_INVALID_PARAMETER;
}
}
IHXBuffer* pBuffer = 0;
UINT32 ulPacketTime = 0; // packet time encoded
UINT32 ulPacketFilledDuration = 0; // packets' time have been filled
UINT32 ulEventBeginTime = 0; // start pos of the packet(event)
INT64 llActualPacketTime = 0; // packet time with timestamp rollover
INT64 llActualEventBeginTime = 0; // start pos of the packet(event) with timestamp rollover
ULONG32 ulFlags = 0;
UINT16 uStreamNumber = 0;
UINT8 unASMFlags = 0;
UINT16 unASMRuleNumber = 0;
UINT32 streamPreRoll = 0;
UINT32 ulMinimumTotalPreroll = 0;
if (HXR_OK != pPacket->Get(pBuffer, ulPacketTime, uStreamNumber, unASMFlags, unASMRuleNumber))
{
theErr = HXR_FAILED;
return theErr;
}
#if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
HXStaticStatLog::StatPrintf("Packet: StreamNumber: %u TimeStamp: %lu\n", uStreamNumber, ulPacketTime);
#endif
HX_RELEASE(pBuffer);
CHXEvent* theEvent = NULL;
STREAM_INFO* lpStreamInfo = NULL;
CHXEventList* lEventList = NULL;
if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo))
{
return HXR_INVALID_PARAMETER;
}
if (status != HXR_OK)
{
if (!lpStreamInfo->m_bSrcStreamDone)
{
// if the status is not OK, it is probably the end of the stream..
// we should mark this stream as DONE...
lpStreamInfo->m_bPacketRequested = FALSE;
lpStreamInfo->m_bSrcStreamFillingDone = TRUE;
lpStreamInfo->m_bSrcStreamDone = TRUE;
if (m_uNumStreamsToBeFilled > 0)
{
m_uNumStreamsToBeFilled--;
}
if (m_uActiveStreams > 0)
{
m_uActiveStreams--;
}
if (m_uActiveStreams == 0)
{
SetEndOfClip();
}
}
return HXR_OK;
}
lpStreamInfo->m_ulReceived++;
if (!theErr)
{
// reset
lpStreamInfo->m_bPacketRequested = FALSE;
lEventList = &lpStreamInfo->m_EventList;
}
/*
* Save off the initial timestamp for live streams so we can buffer
* relative to the first timstamp
*/
if (m_bInitialPacket)
{
m_bInitialPacket = FALSE;
m_ulFirstPacketTime = ulPacketTime;
}
// This is the time according to the stream...
llActualPacketTime =
lpStreamInfo->BufferingState().CreateINT64Timestamp(ulPacketTime);
llActualEventBeginTime = llActualPacketTime + m_ulDelay;
/* subtract start time from player time */
if (m_ulStartTime > 0)
{
if (m_ulStartTime < llActualPacketTime)
{
llActualPacketTime -= m_ulStartTime;
}
else
{
llActualPacketTime = 0;
}
if (m_ulStartTime < llActualEventBeginTime)
{
llActualEventBeginTime -= m_ulStartTime;
}
else
{
llActualEventBeginTime = 0;
}
}
HX_ASSERT(llActualEventBeginTime < MAX_UINT32);
HX_ASSERT(llActualPacketTime < MAX_UINT32);
ulEventBeginTime = INT64_TO_UINT32(llActualEventBeginTime);
ulPacketFilledDuration = INT64_TO_UINT32(llActualPacketTime);
#if defined(HELIX_FEATURE_RECORDCONTROL)
if (m_pRecordControl)
{
m_pRecordControl->OnPacket(pPacket, m_ulStartTime - m_ulDelay);
}
#endif /* HELIX_FEATURE_RECORDCONTROL */
if (!m_bPlayFromRecordControl)
{
/*
* force a minimum preroll of 1 second to ensure that we deliver
* packet in time to the renderers. e.g. with delayed RealText
* with a preroll of 0 and delay of 10 seconds, it is
* possible to send packets at time 0 AFTER 10 seconds if we
* do not ensure this minimum preroll
* helps in fixing random "realtext not displaying" bug
*/
#ifdef HELIX_FEATURE_MIN_PREROLL
streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),150);
#else //HELIX_FEATURE_MIN_PREROLL
streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),1000);
#endif //HELIX_FEATURE_MIN_PREROLL
ulEventBeginTime = (ulEventBeginTime > streamPreRoll) ? (ulEventBeginTime - streamPreRoll) : 0;
theEvent = new CHXEvent(pPacket, ulEventBeginTime);
if(!theEvent)
{
theErr = HXR_OUTOFMEMORY;
}
// enqueue the event into event queue
if(!theErr)
{
/* offset used by Player::ProcessCurrentEvents to send to renderer::OnPacket */
theEvent->SetTimeOffset(m_ulStartTime - m_ulDelay);
theErr = lEventList->InsertEvent(theEvent);
}
if (!theErr)
{
m_pBufferManager->UpdateCounters(pPacket);
}
}
m_llLastFillEndTime = llActualPacketTime;
if (m_bInFillMode)
{
UINT32 ulDuration = 0;
UINT32 ulRemainToBufferInMs = 0;
UINT32 ulRemainToBuffer = 0;
m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
ulRemainToBuffer);
/* Logic:
In FillBuffers(), we ask for a packet for a particular stream. If
the fileformat does not return the packet immediately (i.e. we
go again to ask for the packet from the same stream but find out that
we had already asked for it earlier and have not yet received it,
the streamFilling is marked as done for that fillbuffer() iteration.
In the meantime, we keep on asking for the packets from other streams
In meanwhile, if the fileformat returns a packet for the stream marked
as done earlier, we re-activate that stream if the time of the packet
is less than the time we fill all streams up to.
*/
if (lpStreamInfo->m_bSrcStreamFillingDone &&
(ulRemainToBufferInMs > 0 || ulRemainToBuffer > 0) &&
ulPacketFilledDuration <= lpStreamInfo->m_ulDuration &&
!lpStreamInfo->m_bSrcStreamDone)
{
lpStreamInfo->m_bSrcStreamFillingDone = FALSE;
m_uNumStreamsToBeFilled++;
}
if (!lpStreamInfo->m_bSrcStreamDone &&
!lpStreamInfo->m_bSrcStreamFillingDone &&
m_uNumStreamsToBeFilled > 0)
{
/* When playing from Record Control buffering can happen after seek to
a cached position. In this case we dont need to accelerate packet
retriaval and can stop filling the stream.
*/
if (ulPacketFilledDuration > lpStreamInfo->m_ulDuration ||
(ulRemainToBufferInMs == 0 && ulRemainToBuffer == 0) ||
(m_bPlayFromRecordControl && ulPacketFilledDuration >= m_pPlayer->GetInternalCurrentPlayTime() + ulRemainToBufferInMs))
{
// this value also updated in PacketReady()
lpStreamInfo->m_bSrcStreamFillingDone = TRUE;
if (m_uNumStreamsToBeFilled > 0)
{
m_uNumStreamsToBeFilled--;
}
}
}
}
if (!theErr)
{
m_bReceivedData = TRUE;
}
else if (theEvent)
{
HX_DELETE(theEvent);
}
return theErr;
}
STDMETHODIMP
HXFileSource::StreamDone(UINT16 uStreamNumber)
{
STREAM_INFO *lpStreamInfo = NULL;
if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo))
{
return HXR_INVALID_PARAMETER;
}
if (!lpStreamInfo->m_bSrcStreamDone)
{
lpStreamInfo->m_bSrcStreamDone = TRUE;
lpStreamInfo->m_bSrcStreamFillingDone = TRUE;
lpStreamInfo->m_bPacketRequested = FALSE;
if (m_uNumStreamsToBeFilled > 0)
{
m_uNumStreamsToBeFilled--;
}
if (m_uActiveStreams > 0)
{
m_uActiveStreams--;
}
if (m_uActiveStreams == 0)
{
SetEndOfClip();
}
}
return HXR_OK;
}
STDMETHODIMP
HXFileSource::SeekDone(HX_RESULT status)
{
HX_RESULT lResult = HXR_OK;
if (m_nSeeking > 0)
{
m_nSeeking--;
}
_ProcessIdle(FALSE);
return lResult;
}
STDMETHODIMP HXFileSource::RedirectDone(IHXBuffer* pURL)
{
HX_RESULT hr = HXR_NOTIMPL;
// handle redirect to diff. protocol from HTTP file system
if (m_pszURL && pURL)
{
if (strncasecmp(m_pszURL, "http://", 7) == 0 &&
strncasecmp((const char*)pURL->GetBuffer(), "http://", 7) != 0)
{
if (m_bPartOfNextGroup)
{
m_bRedirectPending = TRUE;
HX_DELETE(m_pRedirectURL);
m_pRedirectURL = new CHXURL((const char*)pURL->GetBuffer());
}
else
{
hr = m_pSourceInfo->HandleRedirectRequest((char*)pURL->GetBuffer());
}
}
}
return hr;
}
// routine to read from the file to keep all streams filled to their preroll value
HX_RESULT
HXFileSource::FillBuffers(void)
{
/*
* Do not call GetPacket if we have not yet received SeekDone from
* the file format plugin.
* ||
* We are in a paused state and no rebuffering and no fast start
* is required.
* ||
* We are in force end mode such as seeking to the end of the source duration
*/
if (m_nSeeking > 0 ||
(m_bPaused && !m_bFastStartInProgress && !m_bRebufferingRequired && !m_pRecordControl) ||
m_bForcedSourceEnd)
{
return HXR_OK;
}
HX_RESULT theErr = HXR_OK;
UINT32 ulRemainToBufferInMs = 0;
UINT32 ulRemainToBuffer = 0;
UINT32 lPlayPos = m_pPlayer->GetInternalCurrentPlayTime();
UINT32 ulCurrentTime = HX_GET_TICKCOUNT();
m_uNumStreamsToBeFilled = 0;
m_ulMaxPreRoll = 0;
CHXMapLongToObj::Iterator ndxStream = mStreamInfoTable->Begin();
STREAM_INFO* lpStreamInfo = NULL;
m_pBufferManager->GetMaximumPreroll(m_ulMaxPreRoll);
m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
ulRemainToBuffer);
for(; ndxStream != mStreamInfoTable->End(); ++ndxStream)
{
lpStreamInfo = (STREAM_INFO*) (*ndxStream);
if(!lpStreamInfo->m_bSrcStreamDone)
{
m_uNumStreamsToBeFilled++;
lpStreamInfo->m_bSrcStreamFillingDone = FALSE;
}
}
/*
* The fill end time must be offset by the intial timestamp if this
* is a live stream which is saved in the initial PacketReady
*/
// we will always attempt to have m_MaxPreRoll time of data in the audio and video event queues
m_llFillEndTime = CAST_TO_INT64 (lPlayPos +
m_ulMaxPreRoll + m_pPlayer->m_ulMinimumAudioPreroll +
m_pPlayer->GetGranularity());
if (!m_pRecordControl &&
!m_bRebufferingRequired &&
ulRemainToBufferInMs == 0 &&
ulRemainToBuffer == 0 &&
m_llFillEndTime <= m_llLastFillEndTime)
{
return HXR_OK;
}
#if defined(HELIX_FEATURE_RECORDCONTROL)
if (m_pRecordControl && !m_pRecordControl->CanAcceptPackets())
{
return HXR_OK;
}
#endif /* HELIX_FEATURE_RECORDCONTROL */
m_bInFillMode = TRUE;
while(!theErr && m_uNumStreamsToBeFilled > 0)
{
ndxStream = mStreamInfoTable->Begin();
for (; !theErr && ndxStream != mStreamInfoTable->End(); ++ndxStream)
{
lpStreamInfo = (STREAM_INFO*) (*ndxStream);
if (!lpStreamInfo->m_bSrcStreamDone &&
!lpStreamInfo->m_bSrcStreamFillingDone &&
!lpStreamInfo->m_bPacketRequested)
{
// this will be reset in PacketReady()
lpStreamInfo->m_bPacketRequested = TRUE;
HX_RESULT retVal = m_pFFObject->GetPacket((UINT16) lpStreamInfo->m_uStreamNumber);
if (HXR_OK != retVal )
{
StreamDone(lpStreamInfo->m_uStreamNumber);
// Don't lose OOM errors.
if( retVal == HXR_OUTOFMEMORY )
{
theErr = retVal;
}
#ifdef HELIX_FEATURE_STOP_STREAM_BY_TEMP_FILE_ERROR
if( retVal == HXR_TEMP_FILE )
{
theErr = retVal;
m_pBufferManager->Stop();
SetE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -