📄 fbbufctl.cpp
字号:
/************************************************************************
* 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 + -