⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hxbufstate.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** 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 + -