📄 vidrend.cpp
字号:
if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
ulStreamVersion))
{
UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
ULONG32 ulThisMajorVersion = 0;
ULONG32 ulThisMinorVersion = 0;
GetStreamVersion(ulThisMajorVersion, ulThisMinorVersion);
if((ulMajorVersion > ulThisMajorVersion) ||
((ulMinorVersion > ulThisMinorVersion) &&
(ulMajorVersion == ulThisMajorVersion)))
{
bVersionOK = FALSE;
}
}
if(bVersionOK &&
(HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
ulContentVersion)))
{
UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
ULONG32 ulThisMajorVersion = 0;
ULONG32 ulThisMinorVersion = 0;
GetContentVersion(ulThisMajorVersion, ulThisMinorVersion);
if((ulMajorVersion > ulThisMajorVersion) ||
((ulMinorVersion > ulThisMinorVersion) &&
(ulMajorVersion == ulMajorVersion)))
{
bVersionOK = FALSE;
}
}
if(!bVersionOK)
{
AddToAutoUpgradeCollection(GetUpgradeMimeType(), m_pContext);
pnr = HXR_FAIL;
}
return pnr;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IHXRenderer::OnPacket
// Purpose:
// Called by client engine when a packet for this renderer is
// due.
//
STDMETHODIMP CVideoRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
{
m_lTimeLineOffset = lTimeOffset;
#ifdef ENABLE_INPUT_TRACE
if (ulInputTraceIdx < MAX_INPUT_TRACE_ENTRIES)
{
inputTraceArray[ulInputTraceIdx++] =
ComputeTimeAhead(pPacket->GetTime(), 0);
}
#endif // ENABLE_INPUT_TRACE
if (m_bSchedulerStartRequested)
{
StartSchedulers();
}
BOOL bQueueRet = m_pVideoFormat->Enqueue(pPacket);
if(bQueueRet == FALSE && m_pVideoFormat->GetLastError() == HXR_OUTOFMEMORY)
{
return HXR_OUTOFMEMORY;
}
// try to decode a frame
if (m_PlayState == Playing)
{
if (!IsDecoderRunning() || NULL == m_pDecoderPump)
{
BOOL bDecRet = m_pVideoFormat->DecodeFrame();
if( bDecRet == FALSE && m_pVideoFormat->GetLastError() == HXR_OUTOFMEMORY )
{
return HXR_OUTOFMEMORY;
}
}
else
{
m_pDecoderPump->Signal();
}
}
else
{
if (!m_bBaseTimeSet)
{
m_pMutex->Lock();
if (m_PlayState != Playing)
{
m_ulBaseTime = pPacket->GetTime();
}
m_pMutex->Unlock();
m_bBaseTimeSet = TRUE;
}
// If we are seeking, this is a pre-seek packet and there is
// no need to decode it
if (m_PlayState != Seeking)
{
if (!IsDecoderRunning() || NULL == m_pDecoderPump)
{
m_pVideoFormat->DecodeFrame();
}
else
{
m_pDecoderPump->Signal();
}
if (m_PlayState == Buffering)
{
if (IsBufferingComplete(pPacket))
{
RequestBufferingEnd();
}
}
}
}
return HXR_OK;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IHXRenderer::OnTimeSync
// Purpose:
// Called by client engine to inform the renderer of the current
// time relative to the streams synchronized time-line. The
// renderer should use this time value to update its display or
// render it's stream data accordingly.
//
STDMETHODIMP CVideoRenderer::OnTimeSync(ULONG32 ulTime)
{
ULONG32 ulStreamBaseTime = HX_GET_BETTERTICKCOUNT();
ULONG32 ulBaseTime = ulTime;
BOOL bGoodSample = TRUE;
if (m_bSchedulerStartRequested)
{
StartSchedulers();
}
#ifdef HELIX_FEATURE_STATS
if (((ULONG32) (ulStreamBaseTime - m_pVideoStats->GetLastSyncTime())) >=
VIDEO_STAT_INTERVAL)
{
m_pVideoStats->SyncStats(ulStreamBaseTime);
}
#endif /* HELIX_FEATURE_STATS */
#ifdef ENABLE_SYNC_TRACE
ULONG32 ulOrigStreamBaseTime = ulStreamBaseTime;
#endif // ENABLE_SYNC_TRACE
#ifdef SYNC_SMOOTHING_OLD_SCHEME
LONG32 lNewSyncDelta = (LONG32) (ulStreamBaseTime - m_lTrendSyncDelta - ulTime);
m_lTrendSyncDelta += lNewSyncDelta / ((LONG32) (m_ulSyncSmoothingDepth + 1));
ulStreamBaseTime = ulTime + m_lTrendSyncDelta;
if (m_ulSyncSmoothingDepth < m_ulSyncGoalSmoothingDepth)
{
m_ulSyncSmoothingDepth++;
}
#endif // SYNC_SMOOTHING_OLD_SCHEME
#ifdef SYNC_PRE_SMOOTHING
if (m_ulSyncSmoothingDepth > 0)
{
LONG32 lStreamBaseDelta = ((LONG32) (ulStreamBaseTime - m_ulStreamBaseTime));
ULONG32 ulBaseDelta = ulBaseTime - m_ulBaseTime;
BOOL bSkipSmoothing = FALSE;
bGoodSample = ((lStreamBaseDelta <= 0) ||
(((ULONG32) lStreamBaseDelta) <=
(ulBaseDelta + (ulBaseDelta >> AUDIO_SKEW_POWER))) ||
(bSkipSmoothing = ((m_ulBadSeqSampleCount++) > m_ulMaxBadSeqSamples)));
if (bSkipSmoothing)
{
m_ulSyncSmoothingDepth = 0;
m_fTrendSyncDelta = 0.0;
}
}
#endif // SYNC_PRE_SMOOTHING
if (bGoodSample)
{
#ifdef SYNC_SMOOTHING
double fNewSyncDelta = (((double) ((ULONG32) (ulStreamBaseTime - ulTime))) -
m_fTrendSyncDelta);
// If we have a m_fTrendSyncDelta, make sure we consider
// m_fTrendSyncDelta wrap-around in relation to fNewSyncDelta
if (m_ulSyncSmoothingDepth > 0)
{
if (fNewSyncDelta > MAX_LONG32_AS_DOUBLE)
{
fNewSyncDelta = MAX_ULONG32_AS_DOUBLE - fNewSyncDelta;
}
else if (fNewSyncDelta < MIN_LONG32_AS_DOUBLE)
{
fNewSyncDelta += MAX_ULONG32_AS_DOUBLE;
}
}
if (fNewSyncDelta < 0.0)
{
// We are trying to speed up: use speed up smoothing criteria
m_fTrendSyncDelta += (fNewSyncDelta /
((m_ulSyncSmoothingDepth >= m_ulSpeedupGoalSmoothingDepth) ?
m_ulSpeedupGoalSmoothingDepth + 1 : m_ulSyncSmoothingDepth + 1));
}
else
{
m_fTrendSyncDelta += fNewSyncDelta / (m_ulSyncSmoothingDepth + 1);
}
if (m_fTrendSyncDelta > MAX_ULONG32_AS_DOUBLE)
{
m_fTrendSyncDelta -= MAX_ULONG32_AS_DOUBLE;
}
else if (m_fTrendSyncDelta < 0)
{
m_fTrendSyncDelta += MAX_ULONG32_AS_DOUBLE;
}
ulStreamBaseTime = ulTime + ((ULONG32) (m_fTrendSyncDelta));
if (m_ulSyncSmoothingDepth < m_ulSyncGoalSmoothingDepth)
{
m_ulSyncSmoothingDepth++;
}
#endif // SYNC_SMOOTHING
m_ulGoodSeqSampleCount++;
m_ulStreamBaseTime = ulStreamBaseTime;
m_ulBaseTime = ulBaseTime;
m_ulTimeNormalizationOffset = m_ulStreamBaseTime -
m_ulBaseTime -
m_lTimeLineOffset;
if (m_ulGoodSeqSampleCount >= MIN_GOOD_PERSISTENCE_COUNT)
{
m_ulBadSeqSampleCount = 0;
}
}
else
{
// This is a bad sample
if (m_ulBadSeqSampleCount >= MIN_BAD_PERSISTENCE_COUNT)
{
m_ulGoodSeqSampleCount = 0;
}
}
#ifdef ENABLE_SYNC_TRACE
if (ulSyncTraceIdx < MAX_SYNC_TRACE_ENTRIES)
{
syncTraceArray[ulSyncTraceIdx][0] = m_ulBaseTime;
syncTraceArray[ulSyncTraceIdx][1] = m_ulStreamBaseTime;
syncTraceArray[ulSyncTraceIdx++][2] = ulOrigStreamBaseTime;
}
#endif // ENABLE_SYNC_TRACE
if (m_PlayState == Playing)
{
if (!IsDecoderRunning())
{
m_pVideoFormat->DecodeFrame();
}
if (m_bBufferingNeeded)
{
m_pMutex->Lock();
if (m_PlayState == Playing)
{
BeginBuffering();
}
m_pMutex->Unlock();
}
}
else if ((m_PlayState == PlayStarting) ||
(m_PlayState == Buffering))
{
m_pMutex->Lock();
m_bBaseTimeSet = TRUE;
// Reset the offset to avoid race condition
// with m_ulTimeNormalizationOffset setting in OnPacket()
if (bGoodSample)
{
m_ulTimeNormalizationOffset = m_ulStreamBaseTime -
m_ulBaseTime -
m_lTimeLineOffset;
}
if (m_PlayState == Buffering)
{
EndBuffering();
m_PlayState = PlayStarting;
}
if (m_PlayState == PlayStarting)
{
m_PlayState = Playing;
BltIfNeeded();
StartSchedulers();
if (m_pBltrPump)
{
m_pBltrPump->Signal();
}
}
m_pMutex->Unlock();
}
return HXR_OK;
}
HX_RESULT CVideoRenderer::StartSchedulers(void)
{
HX_RESULT retVal = HXR_OK;
#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
// When running the decoder as fast as possible, we dont want to start the scheduler, so short
// circuit this code. Additionally, calls such as BltIfNeeded() and ScheduleCallback() (which
// may still be called) make assumptions based on the state of our interactions with the
// scheduler, so we satisfy them by setting a pending handle representing a nonexistant callback.
if( m_bUntimedRendering )
{
m_hPendingHandle = 1;
return HXR_OK;
}
#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */
m_bSchedulerStartRequested = FALSE;
DisplayMutex_Lock();
if (ShouldKickStartScheduler())
{
m_bBufferingNeeded = FALSE;
ScheduleCallback(0);
}
if (SUCCEEDED(retVal) && (m_pDecoderPump == NULL))
{
CVideoPaceMaker* pVideoPaceMaker;
retVal = HXR_OUTOFMEMORY;
pVideoPaceMaker = new CVideoPaceMaker;
if (pVideoPaceMaker)
{
retVal = pVideoPaceMaker->QueryInterface(
IID_IHXPaceMaker,
(void**) &m_pDecoderPump);
if (SUCCEEDED(retVal))
{
pVideoPaceMaker = NULL;
m_pDecoderPump->Start(this,
GetDecodePriority(),
DECODER_INTERVAL,
m_ulDecoderPacemakerId);
}
}
HX_DELETE(pVideoPaceMaker);
}
if (SUCCEEDED(retVal) && (m_pBltrPump == NULL) && m_bTryVideoSurface2)
{
CVideoPaceMaker* pVideoPaceMaker;
retVal = HXR_OUTOFMEMORY;
pVideoPaceMaker = new CVideoPaceMaker;
if (pVideoPaceMaker)
{
retVal = pVideoPaceMaker->QueryInterface(
IID_IHXPaceMaker,
(void**) &m_pBltrPump);
if (SUCCEEDED(retVal))
{
pVideoPaceMaker = NULL;
m_pBltrPump->Start(this,
DFLT_PRESENT_PRIORITY,
BLTR_INTERVAL,
m_ulBltrPacemakerId);
}
}
HX_DELETE(pVideoPaceMaker);
}
DisplayMutex_Unlock();
return retVal;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IHXRenderer::OnPreSeek
// Purpose:
// Called by client engine to inform the renderer that a seek is
// about to occur. The render is informed the last time for the
// stream's time line before the seek, as well as the first new
// time for the stream's time line after the seek will be completed.
//
STDMETHODIMP CVideoRenderer::OnPreSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
{
// Change state to stop Blts
m_pMutex->Lock();
m_PlayState = Seeking;
m_pMutex->Unlock();
// Suspend the Decoder pump
if (m_pDecoderPump)
{
m_pDecoderPump->Suspend(TRUE);
m_pDecoderPump->Signal();
m_pDecoderPump->WaitForSuspend();
}
// Wait for Blt in progress to complete and reset
// packet queues
DisplayMutex_Lock();
m_pVideoFormat->SetStartTime(ulNewTime);
m_pVideoFormat->Reset();
#if defined(HELIX_FEATURE_STATS)
m_pVideoStats->ResetSequence();
#endif /* HELIX_FEATURE_STATS */
m_bFirstSurfaceUpdate = TRUE;
m_bFirstFrame = TRUE;
m_bBaseTimeSet = FALSE;
DisplayMutex_Unlock();
return HXR_OK;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IHXRenderer::OnPostSeek
// Purpose:
// Called by client engine to inform the renderer that a seek has
// just occured. The render is informed the last time for the
// stream's time line before the seek, as well as the first new
// time for the stream's time line after the seek.
//
STDMETHODIMP CVideoRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
{
DisplayMutex_Lock();
// clean up the packet lists
m_pVideoFormat->SetStartTime(ulNewTime);
m_pVideoFormat->Reset();
#if defined(HELIX_FEATURE_STATS)
m_pVideoStats->ResetSequence();
#endif /* HELIX_FEATURE_STATS */
m_bFirstSurfaceUpdate = TRUE;
m_bFirstFrame = TRUE;
m_ulBaseTime = ulNewTime;
m_bBaseTimeSet = TRUE;
m_bVS2BufferUnavailableOnLastBlt = FALSE;
if (m_pDecoderPump)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -