📄 hxbufstate.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2003 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 "hxbufstate.h"
#include "hxassert.h"
class HXBufferedPktInfo
{
public:
HXBufferedPktInfo(INT64 llTimestamp, UINT32 ulSize);
INT64 Timestamp() const { return m_llTimestamp;}
UINT32 Size() const { return m_ulSize;}
private:
INT64 m_llTimestamp;
UINT32 m_ulSize;
};
inline
HXBufferedPktInfo::HXBufferedPktInfo(INT64 llTimestamp,
UINT32 ulSize) :
m_llTimestamp(llTimestamp),
m_ulSize(ulSize)
{}
HXBufferingState::HXBufferingState() :
m_ulPreroll(0)
, m_ulPredata(0)
, m_ulMinimumPrerollInMs(0)
, m_ulMinimumPreroll(0)
, m_ulMinimumBufferingInMs(0)
, m_ulMinimumBuffering(0)
, m_ulRemainingToBufferInMs(0)
, m_ulRemainingToBuffer(0)
, m_ulCurrentBufferingInMs(0)
, m_ulCurrentBuffering(0)
, m_bIsFirstPacket(TRUE)
, m_preDataAtStart(FALSE)
, m_prerollAtStart(FALSE)
, m_preDataAfterSeek(FALSE)
, m_prerollAfterSeek(FALSE)
, m_llLowestTimeStamp(0)
, m_llHighestTimeStamp(0)
, m_llLowestTimestampAtTransport(0)
, m_llHighestTimestampAtTransport(0)
, m_ulNumBytesAtTransport(0)
, m_bDoneAtTransport(FALSE)
, m_ulTSRollOver(0)
, m_ulLastPacketTimeStamp(0)
, m_ulAvgBandwidth(0)
, m_pASMProps(NULL)
, m_llCurrentPlaybackTime(0)
, m_ulBufferedData(0)
, m_ulLastTimeSync(0)
, m_llFirstLivePacketTimestamp(0)
, m_ulTimeSyncRollOver(0)
{}
HXBufferingState::~HXBufferingState()
{
HX_RELEASE(m_pASMProps);
ClearPktInfo();
}
void HXBufferingState::OnStreamHeader(UINT32 ulPreroll,
UINT32 ulPredata,
BOOL preDataAtStart,
BOOL preDataAfterSeek,
BOOL prerollAtStart,
BOOL prerollAfterSeek,
ULONG32 ulAvgBitRate)
{
m_ulPreroll = ulPreroll;
m_ulPredata = ulPredata;
m_preDataAtStart = preDataAtStart;
m_preDataAfterSeek = preDataAfterSeek;
m_prerollAtStart = prerollAtStart;
m_prerollAfterSeek = prerollAfterSeek;
m_ulAvgBandwidth = ulAvgBitRate;
}
void HXBufferingState::OnStream(IUnknown* pStream)
{
HX_RELEASE(m_pASMProps);
if (pStream)
{
pStream->QueryInterface(IID_IHXASMProps, (void**) &m_pASMProps);
}
}
void HXBufferingState::Init(ULONG32 ulPerfectPlayTime)
{
SetMinPrerollInMs(m_ulPreroll, m_ulPreroll + ulPerfectPlayTime);
SetMinPreroll();
}
void HXBufferingState::SetMinimumPreroll(UINT32 ulSourcePreroll,
UINT32 ulInitialAudioPreroll,
UINT32 ulPerfectPlayTime,
BOOL bIsRebuffering)
{
UINT32 ulMinimumPreroll = m_ulPreroll;
ulMinimumPreroll += ulInitialAudioPreroll;
if (ulMinimumPreroll < ulSourcePreroll)
{
ulMinimumPreroll = ulSourcePreroll;
}
SetMinPrerollInMs(ulMinimumPreroll,
ulMinimumPreroll + ulPerfectPlayTime);
m_ulCurrentBufferingInMs = 0;
/* If we have received at lest one packet for this stream,
* mark the lowest timestamp to be the
* last packet timstamp to reset buffering calculations
*/
if (bIsRebuffering && !m_bIsFirstPacket)
{
m_bIsFirstPacket = TRUE;
m_llLowestTimeStamp =
CAST_TO_INT64 (m_ulTSRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 (m_ulLastPacketTimeStamp);
}
UpdateMinPredata();
}
void HXBufferingState::Stop()
{
m_ulRemainingToBufferInMs = 0;
m_ulRemainingToBuffer = 0;
}
void HXBufferingState::Reset(BOOL bIsSeeking, UINT32 ulSeekTime)
{
m_ulRemainingToBufferInMs = m_ulMinimumBufferingInMs;
m_ulRemainingToBuffer = m_ulMinimumBuffering;
m_ulCurrentBufferingInMs = 0;
m_ulCurrentBuffering = 0;
m_ulTSRollOver = 0;
m_ulLastPacketTimeStamp = 0;
m_bIsFirstPacket = TRUE;
ClearPktInfo();
if (bIsSeeking)
{
m_llLowestTimeStamp = CAST_TO_INT64 ulSeekTime;
m_llHighestTimeStamp = CAST_TO_INT64 ulSeekTime;
}
}
void HXBufferingState::GetRemainToBuffer(REF(UINT32) ulRemainToBufferInMs,
REF(UINT32) ulRemainToBuffer)
{
ulRemainToBufferInMs = m_ulRemainingToBufferInMs;
ulRemainToBuffer = m_ulRemainingToBuffer;
}
UINT16 HXBufferingState::GetPercentDone(BOOL bIsSeekPerformed)
{
UINT16 uTotalPercentDone = 100;
UINT16 uPreDataPercentDone = 100;
UINT16 uPrerollPercentDone = 100;
BOOL bHasPreroll;
BOOL bHasPredata;
BOOL bNeedsData = FALSE;
if (!bIsSeekPerformed)
{
// start/rebuffer mode
bHasPreroll = m_prerollAtStart;
bHasPredata = m_preDataAtStart;
}
else
{
// seek mode
bHasPreroll = m_prerollAfterSeek;
bHasPredata = m_preDataAfterSeek;
}
// satisfy the preroll (by default + pre-set)
if (!bHasPredata || bHasPreroll)
{
// percent done on preroll
if (m_ulMinimumBufferingInMs)
{
uPrerollPercentDone =
((m_ulMinimumBufferingInMs-m_ulRemainingToBufferInMs ) * 100) /
m_ulMinimumBufferingInMs;
}
uTotalPercentDone = uPrerollPercentDone;
bNeedsData = (m_ulRemainingToBufferInMs > 0);
}
// satisfy the predata
if (bHasPredata)
{
// percent done on predata
if (m_ulMinimumBuffering)
{
uPreDataPercentDone =
((m_ulMinimumBuffering - m_ulRemainingToBuffer ) * 100) /
m_ulMinimumBuffering;
}
uTotalPercentDone = uPreDataPercentDone;
bNeedsData = (m_ulRemainingToBuffer > 0);
}
if (bHasPredata && bHasPreroll)
{
uTotalPercentDone = (uPrerollPercentDone + uPreDataPercentDone) / 2;
}
else if ((bIsSeekPerformed) &&
(uTotalPercentDone == 100) &&
(bNeedsData))
{
uTotalPercentDone = 99;
}
return uTotalPercentDone;
}
void HXBufferingState::UpdatePreroll(ULONG32 ulPreroll)
{
UINT32 ulExtraPrerollInMs = m_ulMinimumPrerollInMs - m_ulPreroll;
UINT32 ulExtraBufferingInMs = m_ulMinimumBufferingInMs - m_ulPreroll;
SetPreroll(ulPreroll);
SetMinPrerollInMs(ulPreroll + ulExtraPrerollInMs,
ulPreroll + ulExtraBufferingInMs);
SetMinPreroll();
// Notice that we don't call ClearCurrentBufferingInMs()
// or ClearCurrentBuffering(). This allows us to count
// any data we have already received as part of the
// new preroll
CalcRemainingToBufferInMs();
CalcRemainingToBuffer();
}
INT64 HXBufferingState::CreateINT64Timestamp(UINT32 ulTime)
{
return CAST_TO_INT64 (m_ulTSRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 ulTime;
}
INT64 HXBufferingState::CreateINT64Timesync(UINT32 ulTime)
{
return CAST_TO_INT64 (m_ulTimeSyncRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 ulTime;
}
void HXBufferingState::OnPacket(UINT32 ulTimestamp, UINT32 ulPacketSize,
UINT32 ulElapsedTime,
BOOL bIsLive, BOOL bIsBufferedPlayMode)
{
// 0xFA .. 0xFF [roll over] (0x01)
if (m_ulLastPacketTimeStamp > ulTimestamp &&
((m_ulLastPacketTimeStamp - ulTimestamp) > MAX_TIMESTAMP_GAP))
{
m_ulTSRollOver++;
}
INT64 llActualTimeStamp = CreateINT64Timestamp(ulTimestamp);
m_ulLastPacketTimeStamp = ulTimestamp;
if (m_bIsFirstPacket)
{
/* Only if we are live, store the first packet timestemp
* as the lowest timestamp. In any other case, we consider
* the lowest ts to be 0 OR the Seek time.
* This is to fix the post-seek buffering where we should not
* account any packets < seek ts towards buffering completion.
*/
if (bIsLive)
{
m_llLowestTimeStamp = CAST_TO_INT64 ulTimestamp;
m_llFirstLivePacketTimestamp = m_llLowestTimeStamp;
}
m_llHighestTimeStamp = CAST_TO_INT64 ulTimestamp;
m_bIsFirstPacket = FALSE;
}
// Add this packet to our packet info statistics
AddPktInfo(llActualTimeStamp, ulPacketSize);
// data based preroll
if (DataBasedPreroll())
{
m_ulCurrentBuffering += ulPacketSize;
if (bIsBufferedPlayMode)
{
/*
* We wait to have at least 1 second worth of data
* before doing any calculations. This may need some
* tweaking.
*/
if ((m_ulRemainingToBuffer != 0) &&
(m_ulCurrentBuffering >= m_ulAvgBandwidth / 8))
{
/*
* Highly unlikely, but may happen from a server on the
* local machine.
*/
if (ulElapsedTime == 0)
{
if (m_ulCurrentBuffering >= m_ulMinimumPreroll)
{
m_ulRemainingToBuffer = 0;
}
}
else
{
UINT32 ulDenom = ulElapsedTime * m_ulAvgBandwidth / 8000;
/* Sanity check - may be 0 only when bandwidth
* is really low
*/
ulDenom = ulDenom > 0 ? ulDenom : 1;
CalcRemainingToBuffer(ulDenom);
}
}
}
else
{
/* bIsBufferedPlayMode == FALSE */
if (m_ulRemainingToBuffer)
{
CalcRemainingToBuffer();
}
}
}
if (llActualTimeStamp >= m_llHighestTimeStamp)
{
m_llHighestTimeStamp = llActualTimeStamp;
}
}
void HXBufferingState::UpdateBufferingInMs(INT64 llRefLowTimestamp,
INT64 llHighTimestamp,
BOOL bIsBufferedPlayMode,
BOOL bIsTimestampDelivery,
UINT32 ulElapsedTime)
{
UpdateCurrentBufferingInMs(llRefLowTimestamp, llHighTimestamp);
if (bIsBufferedPlayMode)
{
/* We handle time stamp delivered streams differently
* in case of BUffered/PerfectPlay. This is because
* server sends timestamp delivered stream based
* on the timestamps on the packet and pretty
* much streams in realtime.
* So even if we are on LAN and streaming a RealText
* file, we will get packets in realtime even though
* we have enough bandwidth available
*
* For timestamp delivered streams, we just fulfill
* preroll.
*/
if (bIsTimestampDelivery &&
m_ulCurrentBufferingInMs > m_ulMinimumPrerollInMs)
{
m_ulRemainingToBufferInMs = 0;
}
else if ((m_ulRemainingToBufferInMs != 0) &&
(m_ulCurrentBufferingInMs >= 1000))
{
/*
* Highly unlikely, but may happen from a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -