📄 buffmgr.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
#include "hlxclib/stdio.h"
#include "hxcom.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxslist.h"
#include "hxtick.h"
#include "hxcore.h"
#include "chxeven.h"
#include "hxbsrc.h"
#include "hxsrc.h"
#include "hxntsrc.h"
#include "hxstrm.h"
#include "strminfo.h"
#include "buffmgr.h"
#include "hxsmbw.h"
#include "hxgroup.h"
#include "hxplay.h"
#include "errdbg.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
#if defined(__TCS__)
#define MAX_ADDITIONAL_BUFFERING 3000
#else
#define MAX_ADDITIONAL_BUFFERING 10000
#endif /* __TCS__ */
CBufferManager::CBufferManager(HXSource* pParent)
{
m_ulMaxAdditionalBufferingInMs = MAX_ADDITIONAL_BUFFERING;
m_llHighestTimeStamp = 0;
m_ulTotalPauseTime = 0;
m_ulLastPauseTime = 0;
m_ulAdditionalBufferingInMs = 0;
m_bBufferStartTimeToBeSet = TRUE;
m_ulMinimumInitialAudioPreroll = 0;
m_ulMinimumSourcePreroll = 0;
m_bPerfectPlay = FALSE;
m_bPaused = FALSE;
m_state = BUFFMGR_READY;
m_pParent = pParent;
m_pParent->AddRef();
m_bLocalPlayback = pParent->IsLocalSource();
m_pStreamInfoTable = pParent->GetStreamInfoTable();
m_bFirstResumeDone = FALSE;
m_bIsSeekPerformed = FALSE;
m_bBufferedPlay = FALSE;
m_bBufferCalcToBeChanged = FALSE;
m_bIsInitialized = FALSE;
m_ulSeekTime = 0;
}
CBufferManager::~CBufferManager()
{
HX_RELEASE(m_pParent);
}
HX_RESULT
CBufferManager::Init()
{
UINT32 ulPerfectPlayTime = 0;
UINT32 ulMinimumPreroll = 0;
STREAM_INFO* pStreamInfo = NULL;
CHXMapLongToObj::Iterator i;
// There is no buffered or perfect play with MIN_HEAP on.
#if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
SetPerfectPlay(m_pParent->IsPerfectPlay());
if (m_bPerfectPlay || m_bBufferedPlay)
{
// caculate how much extra preroll for the perfect play
ulPerfectPlayTime = m_pParent->GetPerfectPlayTime();
}
#endif
// ajust buffering information of each stream
for (i = m_pStreamInfoTable->Begin(); i != m_pStreamInfoTable->End(); ++i)
{
pStreamInfo = (STREAM_INFO*) (*i);
pStreamInfo->BufferingState().Init(ulPerfectPlayTime);
HX_ASSERT(pStreamInfo->m_EventList.GetHeadPosition() == NULL);
}
m_bIsInitialized = TRUE;
/* Was there a Seek called before Initialization... may happen for a clip
* with Start time
*/
if (m_bIsSeekPerformed)
{
DoSeek(m_ulSeekTime);
}
return HXR_OK;
}
HX_RESULT
CBufferManager::SetMinimumPreroll(BOOL bPerfectPlay, UINT32 ulSourcePreroll,
UINT32 ulInitialAudioPreroll,
BOOL bModifyStartTime /* = TRUE */)
{
m_ulMinimumInitialAudioPreroll = ulInitialAudioPreroll;
m_ulMinimumSourcePreroll = ulSourcePreroll;
SetPerfectPlay(bPerfectPlay);
UpdateMinimumPreroll(bModifyStartTime);
return HXR_OK;
}
void
CBufferManager::UpdateMinimumPreroll(BOOL bModifyStartTime)
{
UINT32 ulMinimumPreroll = 0;
UINT32 ulPerfectPlayTime = 0;
UINT32 ulStartTime = 0;
UINT32 ulEventStartTime = 0;
UINT32 ulPacketTime = 0;
STREAM_INFO* pStreamInfo = NULL;
BOOL bPreDataToBeCalculated = FALSE;
CHXMapLongToObj::Iterator i;
// There is no buffered or perfect play with MIN_HEAP on.
#if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
if (m_bPerfectPlay || m_bBufferedPlay)
{
m_ulMaxAdditionalBufferingInMs = 0;
// caculate how much extra preroll for the perfect play
ulPerfectPlayTime = m_pParent->GetPerfectPlayTime();
}
else
{
m_ulMaxAdditionalBufferingInMs = MAX_ADDITIONAL_BUFFERING;
if (m_ulAdditionalBufferingInMs > m_ulMaxAdditionalBufferingInMs)
{
m_ulAdditionalBufferingInMs = m_ulMaxAdditionalBufferingInMs;
}
ulPerfectPlayTime = m_ulAdditionalBufferingInMs;
}
#endif
ulStartTime = m_pParent->GetStartTime();
// adjust buffering information of each stream
for (i = m_pStreamInfoTable->Begin(); i != m_pStreamInfoTable->End(); ++i)
{
pStreamInfo = (STREAM_INFO*) (*i);
pStreamInfo->BufferingState().SetMinimumPreroll(
m_ulMinimumSourcePreroll,
m_ulMinimumInitialAudioPreroll,
ulPerfectPlayTime,
(m_state == BUFFMGR_REBUFFER));
if (bModifyStartTime)
{
pStreamInfo->UpdateStartTimes(ulStartTime);
}
}
m_bBufferCalcToBeChanged = FALSE;
}
HX_RESULT
CBufferManager::Stop(void)
{
STREAM_INFO* pStreamInfo = NULL;
CHXMapLongToObj::Iterator i;
// stop buffering of each stream
for (i = m_pStreamInfoTable->Begin(); i != m_pStreamInfoTable->End(); ++i)
{
pStreamInfo = (STREAM_INFO*) (*i);
pStreamInfo->BufferingState().Stop();
// DEBUG_OUT(m_pParent->m_pPlayer, (s,
// "BufferManager::Stop %p", pStreamInfo));
}
return HXR_OK;
}
HX_RESULT
CBufferManager::DoSeek(UINT32 ulSeekTime, BOOL bSeekInsideRecordBuffer)
{
m_state = BUFFMGR_SEEK;
m_bIsSeekPerformed = TRUE;
m_ulSeekTime = ulSeekTime;
/* We will call Reset during Init() call */
if (!m_bIsInitialized)
{
return HXR_OK;
}
// reset all the preroll attributes
Reset(ulSeekTime, bSeekInsideRecordBuffer);
return HXR_OK;
}
HX_RESULT
CBufferManager::DoPause(void)
{
m_bPaused = TRUE;
m_ulLastPauseTime = HX_GET_TICKCOUNT();
return HXR_OK;
}
HX_RESULT
CBufferManager::DoResume(void)
{
if (m_bPaused && m_state != BUFFMGR_SEEK && !m_bBufferStartTimeToBeSet)
{
m_ulTotalPauseTime += CALCULATE_ELAPSED_TICKS(m_ulLastPauseTime, HX_GET_TICKCOUNT());
}
m_bPaused = FALSE;
if (!m_bFirstResumeDone)
{
m_bFirstResumeDone = TRUE;
UpdateMinimumPreroll(FALSE);
}
return HXR_OK;
}
HX_RESULT
CBufferManager::ReBuffer(void)
{
// recaculate only if it is out of the buffering stage
// and not in perfect play mode
m_state = BUFFMGR_REBUFFER;
/* go back in buffering mode...
* each time we come in buffering state, increase the
* number of packets we buffer by 1 second worth
* to a max of m_ulMaxAdditionalBuffering secs.
*/
#ifndef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
// increase by 1 sec
m_ulAdditionalBufferingInMs += 1000;
if (m_pParent->IsLive())
{
m_bPerfectPlay = FALSE;
m_bBufferedPlay = FALSE;
}
#endif // HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
UpdateMinimumPreroll(FALSE);
return HXR_OK;
}
HX_RESULT
CBufferManager::Reset(UINT32 ulSeekTime, BOOL bSeekInsideRecordBuffer)
{
STREAM_INFO* pStreamInfo = NULL;
CHXEventList* pEventList = NULL;
CHXEvent* pEvent = NULL;
CHXMapLongToObj::Iterator i;
if (m_bBufferCalcToBeChanged)
{
UpdateMinimumPreroll(FALSE);
}
m_ulBufferingStartTime = 0;
// reset each stream
for (i = m_pStreamInfoTable->Begin(); i != m_pStreamInfoTable->End(); ++i)
{
pStreamInfo = (STREAM_INFO*) (*i);
// reset
if (!bSeekInsideRecordBuffer)
{
pStreamInfo->m_bSrcStreamDone = FALSE;
pStreamInfo->m_bPacketRequested = FALSE;
}
pStreamInfo->m_bSrcStreamFillingDone = FALSE;
// Reset buffering state
pStreamInfo->BufferingState().Reset((m_state == BUFFMGR_SEEK),
ulSeekTime);
HX_ASSERT(m_state == BUFFMGR_SEEK);
if (m_state == BUFFMGR_SEEK)
{
// remove all pending packets
pEventList = &pStreamInfo->m_EventList;
while (pEventList->GetNumEvents() > 0)
{
pEvent = pEventList->RemoveHead();
// Mark it as a pre-seek event and send it to the player
pEvent->SetPreSeekEvent();
m_pParent->EventReady(pEvent);
}
}
}
m_llHighestTimeStamp = 0;
m_ulTotalPauseTime = 0;
m_bBufferStartTimeToBeSet = TRUE;
return HXR_OK;
}
HX_RESULT
CBufferManager::UpdateCounters(IHXPacket* pPacket)
{
HX_RESULT hr = HXR_OK;
UINT32 ulStreamNum = 0;
UINT32 ulBufferSize = 0;
UINT32 ulBufferTime = 0;
UINT32 ulElapsedTime = 0;
INT64 llActualTimeStamp = 0;
IHXBuffer* pBuffer = NULL;
STREAM_INFO* pStreamInfo = NULL;
STREAM_INFO* pThisStreamInfo = NULL;
UINT32 ulCurrentTime = HX_GET_TICKCOUNT();
CHXMapLongToObj::Iterator i;
if (!pPacket)
{
return HXR_INVALID_PARAMETER;
}
if (pPacket->IsLost() &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -