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

📄 fbbufctl.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:

/************************************************************************
 *      Method:
 *          IHXCallback::Func
 *      Purpose:
 *          This is the function that will be called when a callback is
 *          to be executed.
 */
STDMETHODIMP HXFeedbackBufferControl::Func(THIS)
{
    DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::Func"));

    if (Initialized())
    {
        UINT32 ulNewBandwidth = 0;
        if (csPlaying == m_state)
        {
            UINT32 ulTotalBits = 0;
            UINT32 ulControlBits = 0;
            UINT32 ulNewBandwidth = 0;
            
            GetControlData(ulTotalBits, ulControlBits);
            
            if (HXR_OK == Control(ulControlBits, ulNewBandwidth))
            {
                SetBandwidth(ulNewBandwidth);
            }
        }
        else if (csBuffering == m_state)
        {
            // Bandwidth used during buffering and seeking
            SetBandwidth(m_ulClipBw);
        }

        ScheduleCallback();
    }

    return HXR_OK;
}


void HXFeedbackBufferControl::ChangeState(ControlState newState)
{
    if (csError != m_state)
    {
        DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
                  (s, "FBBC::CS : %lu %d -> %d", 
                   HX_GET_TICKCOUNT(), m_state, newState));
        m_state = newState;
    }
    else
    {
        DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
                  (s, "FBBC::CS : Tried to leave error state"));
        HX_ASSERT(csError == m_state);
    }
}

void HXFeedbackBufferControl::ScheduleCallback()
{
    if (m_pScheduler)
    {
        UINT32 uDelayInMs = (UINT32)(m_control.SamplePeriod() * 1000);
        m_lastTime.tv_sec += uDelayInMs / 1000;
        m_lastTime.tv_usec += (uDelayInMs * 1000) * 1000;
        
        m_callbackHandle = m_pScheduler->AbsoluteEnter(this, m_lastTime);
    }
}

void HXFeedbackBufferControl::StartCallback()
{
    if (m_pScheduler)
    {
        m_lastTime = m_pScheduler->GetCurrentSchedulerTime();
        
        ScheduleCallback();
    }
}

void HXFeedbackBufferControl::StopCallback()
{
    if (m_pScheduler && m_callbackHandle)
    {
        m_pScheduler->Remove(m_callbackHandle);
        m_callbackHandle = 0;
    }
}

HX_RESULT HXFeedbackBufferControl::GetBwInfo(REF(UINT32) ulClipBw,
                                             REF(UINT16) nControlStream, 
                                             REF(UINT32) ulControlBw)
{
    HX_RESULT res = HXR_OK;

    if (!m_pSource)
    {
        res = HXR_FAILED;
    }
    else if (m_pSource->GetStreamCount() == 0)
    {
        res = HXR_NO_DATA;
    }
    else
    {
        ulClipBw = 0;
        nControlStream = 0;
        ulControlBw = 0;
        
        UINT32 ulHighestBw = 0;
        UINT16 nHighestBwStream = 0;

        BOOL bFoundAudio = FALSE;
        UINT32 ulLowAudioBw = 0;
        UINT16 nLowestBwAudioStream = 0;

        for (UINT16 i = 0; (HXR_OK == res) && (i < m_pSource->GetStreamCount()); i++)
        {
            UINT32 ulStreamBw = 0;
            if (HXR_OK == GetStreamBw(i, ulStreamBw))
            {
                if (ulStreamBw > ulHighestBw)
                {
                    ulHighestBw = ulStreamBw;
                    nHighestBwStream = i;
                }

                if (IsAudioStream(i) &&
                    (!bFoundAudio || (ulStreamBw < ulLowAudioBw)))
                {
                    bFoundAudio = TRUE;
                    ulLowAudioBw = ulStreamBw;
                    nLowestBwAudioStream = i;
                }

                ulClipBw += ulStreamBw;
            }
        }

        if (bFoundAudio)
        {
            nControlStream = nLowestBwAudioStream;
            ulControlBw = ulLowAudioBw;
        }
        else
        {
            nControlStream = nHighestBwStream;
            ulControlBw = ulHighestBw;
        }
    }

    return res;
}

HX_RESULT 
HXFeedbackBufferControl::GetStreamBw(UINT16 uStreamNumber, 
                                     REF(UINT32) ulBandwidth)
{
    HX_RESULT res = HXR_FAILED;

    if (m_pSource)
    {
        IUnknown* pUnk = NULL;
        res = m_pSource->GetStream(uStreamNumber, pUnk);
        
        if (HXR_OK == res)
        {
            IHXASMProps* pProps = NULL;
            
            res = pUnk->QueryInterface(IID_IHXASMProps, (void**)&pProps);
            if (HXR_OK == res)
            {
                res = pProps->GetBandwidth(ulBandwidth);
                
                pProps->Release();
            }
            pUnk->Release();
        }
    }

    return res;
}

BOOL HXFeedbackBufferControl::IsAudioStream(UINT16 uStreamNumber)
{
    BOOL bRet = FALSE;

    if (m_pSource)
    {
        IUnknown* pUnk = NULL;
        IHXStream* pStream = NULL;
        IHXValues* pHeader = NULL;
        IHXBuffer* pMimetype = NULL;
        if ((HXR_OK == m_pSource->GetStream(uStreamNumber, pUnk)) &&
            (HXR_OK == pUnk->QueryInterface(IID_IHXStream, (void**)&pStream))&&
            (NULL != (pHeader = pStream->GetHeader())) &&
            (HXR_OK == pHeader->GetPropertyCString("MimeType", pMimetype)) &&
            (!strncasecmp("audio", (char*)pMimetype->GetBuffer(), 5)))
        {
            bRet = TRUE;
        }
        HX_RELEASE(pMimetype);
        HX_RELEASE(pHeader);
        HX_RELEASE(pStream);
        HX_RELEASE(pUnk);
    }

    return bRet;
}

void HXFeedbackBufferControl::GetControlData(REF(UINT32) ulTotalBits,
                                             REF(UINT32) ulControlBits)
{
    ulTotalBits = 0;
    ulControlBits = 0;
    
    for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
    {
        UINT32 ulBytes;
        
        HX_RESULT res = HXR_FAILED;

        INT64 llLowTS;
        INT64 llHighTS;
        BOOL bDone;

        res = m_pBufferStats->GetTotalBuffering(i, 
                                                llLowTS, llHighTS,
                                                ulBytes,
                                                bDone);

        if (HXR_OK == res)
        {
            ulTotalBits += 8 * ulBytes;
            
            if (i == m_nControlStream)
            {
                ulControlBits = 8 * ulBytes;
            }
        }
    }
}


HX_RESULT HXFeedbackBufferControl::Control(UINT32 ulControlBits, 
                                           REF(UINT32) ulNewBandwidth)
{
    UINT32 ulSetPoint = m_control.SetPoint();
    INT32 error = (INT32)ulSetPoint - (INT32)ulControlBits;
    
    double errorFactor = error;

    ulNewBandwidth = m_control.Control(ulControlBits);

    ulNewBandwidth = ControlToTotal(ulNewBandwidth);

    if (ulSetPoint)
    {
        errorFactor = (double)error / (double)ulSetPoint;
    }

    DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, 
              (s, "FBBC::CTL %lu %d %lu %lu %2.4f",
               HX_GET_TICKCOUNT(),
               error, 
               ulNewBandwidth, 
               ulControlBits,
               errorFactor));
    
    return HXR_OK;
}

void HXFeedbackBufferControl::SetBandwidth(UINT32 ulBandwidth)
{
    DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, 
              (s, "FBBC::SB %lu %lu ", 
               HX_GET_TICKCOUNT(), ulBandwidth));

    if (m_pThin)
    {
        m_pThin->SetDeliveryBandwidth(ulBandwidth, 0);
    }
}

HX_RESULT HXFeedbackBufferControl::ReadPrefSettings()
{
    HX_RESULT res = HXR_FAILED;
    
    UINT32 ulMin = 1000;
    UINT32 ulMax = 0;
    ReadPrefINT32(m_pPrefs, "MinDelBandwidth", ulMin);

    /* Get initial bandwidth guess from Prefs */
    if (HXR_OK == ReadPrefINT32(m_pPrefs, "Bandwidth", ulMax))
    {
        UINT32 ulSustainFactor = 0;
        /* See if we have a sustainable bandwidth factor */
        if (HXR_OK == ReadPrefINT32(m_pPrefs, "SustainableBwFactor", 
                                    ulSustainFactor))
        {
            /* clamp value to 0 <= ulTemp <= 100 range */
            if (ulSustainFactor > 100)
            {
                ulSustainFactor = 100;
            }
            
            /* Apply factor */
            ulMax = (((ulMax / 100) * ulSustainFactor) + 
                     (((ulMax % 100) * ulSustainFactor) / 100));
        }

        if (ulMax > 0)
        {
            if (ulMin > ulMax)
            {
                // Make the minimum bandwidh 1% of the max
                // rounded up to the next bit/second
                ulMin = (ulMax + 99) / 100;
            }
            
            m_control.SetLimits(ulMin, ulMax);
            
            res = HXR_OK;
        }
    }

    return res;
}

void HXFeedbackBufferControl::SetTransportByteLimits(UINT32 ulClipBw)
{
    UINT32 ulTotalByteLimit = 0;
    IHXTransportBufferLimit* pBufLimit = NULL;

    ReadPrefINT32(m_pPrefs, "TransportByteLimit", ulTotalByteLimit);

    if (m_pSource && 
        (HXR_OK == m_pSource->QueryInterface(IID_IHXTransportBufferLimit,
                                             (void**)&pBufLimit)))
    {
        // Divide the byte limit amoung the streams

        for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
        {
            UINT32 ulStreamBw = 0;

            if (HXR_OK == GetStreamBw(i, ulStreamBw))
            {
                // Byte limit for this stream is
                // (ulTotalByteLimit * ulStreamBw) / ulClipBw
                UINT32 ulByteLimit = MulDiv(ulTotalByteLimit,
                                            ulStreamBw, ulClipBw);
                
                if ((ulByteLimit == 0) &&
                    (ulTotalByteLimit != 0))
                {
                    // Make sure all streams have a byte limit
                    // if ulTotalByteLimit is non-zero. This is done
                    // because a byte limit of 0 means unlimited
                    // buffering is allowed

                    ulByteLimit = 1;
                }

                pBufLimit->SetByteLimit(i, ulByteLimit);
            }
        }
    }

    HX_RELEASE(pBufLimit);
}

HX_RESULT HXFeedbackBufferControl::InitTesting(IUnknown* pContext)
{
    HX_RESULT res = HXR_OK;

    IHXRequest* pRequest = NULL;
    const char* pURL = 0;
    if (HXR_OK == pContext->QueryInterface(IID_IHXRequest, 
                                           (void**)&pRequest) &&
        HXR_OK == pRequest->GetURL(pURL))
    {
        CHXURL url(pURL, pContext);
        
        DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
                  (s, "FBBC : url %s", pURL));
        
        IHXValues* pOptions = url.GetOptions();
        ULONG32 ulTmp;
        
        if (pOptions)
        {
            if (HXR_OK == pOptions->GetPropertyULONG32("FBBC-total_control",
                                                       ulTmp))
            {
                DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
                          (s, "FBBC : total control %lu", ulTmp));
                m_bControlTotal = (ulTmp > 0) ? TRUE : FALSE;
            }
        }
        
        HX_RELEASE(pOptions);
        HX_RELEASE(pRequest);
    }

    return res;
}

BOOL HXFeedbackBufferControl::IsBuffering()
{
    BOOL bRet = FALSE;

    IHXBuffer* pStatusDesc = NULL;
    UINT16 unStatusCode    = 0;
    UINT16 unPercentDone   = 0;
    if (m_pStatus &&
        (HXR_OK == m_pStatus->GetStatus(unStatusCode, 
                                        pStatusDesc, unPercentDone)) &&
        (unStatusCode == HX_STATUS_BUFFERING))
    {
        bRet = TRUE;
    }
    HX_RELEASE(pStatusDesc);

    return bRet;
}

UINT32 HXFeedbackBufferControl::ClampBandwidth(UINT32 ulBandwidth) const
{
    UINT32 ulRet = ulBandwidth;

    if (ulRet < m_control.Min())
    {
        ulRet = m_control.Min();
    }
    else if (ulRet > m_control.Max())
    {
        ulRet = m_control.Max();
    }

    return ulRet;
}

UINT32 HXFeedbackBufferControl::ControlToTotal(UINT32 ulValue)
{
    return MulDiv(ulValue, m_ulClipBw, m_ulControlBw);
}

UINT32 HXFeedbackBufferControl::TotalToControl(UINT32 ulValue)
{
    return MulDiv(ulValue, m_ulControlBw, m_ulClipBw);
}

UINT32 HXFeedbackBufferControl::MulDiv(UINT32 ulValue, 
                                       UINT32 ulMult, UINT32 ulDiv)
{
    return (((ulValue / ulDiv) * ulMult) +
            ((ulValue % ulDiv) * ulMult) / ulDiv);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -