📄 vidrend.cpp
字号:
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) { m_pDecoderPump->Suspend(FALSE); m_pDecoderPump->Signal(); } if (m_bUseVideoSurface2 && m_pMISUSSite) { FlushVideoSurface2(m_pMISUSSite); } DisplayMutex_Unlock(); // PostSeek signals the proper packets are to start arriving m_pMutex->Lock(); m_PlayState = PlayStarting; m_pMutex->Unlock(); return HXR_OK;}/////////////////////////////////////////////////////////////////////////// Method:// IHXRenderer::OnPause// Purpose:// Called by client engine to inform the renderer that a pause has// just occured. The render is informed the last time for the// stream's time line before the pause.//STDMETHODIMP CVideoRenderer::OnPause(ULONG32 ulTime){ m_pMutex->Lock(); m_PlayState = Paused; m_pMutex->Unlock(); return HXR_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -