📄 mp3rend.cpp
字号:
// This routine is called by the RMA core to inform the Renderer that
// playback has just begun or has been resumed. The stream's time value just
// after resuming the playback is provided.
//
STDMETHODIMP
CRnMp3Ren::OnBegin(UINT32 timeAfterBegin)
{
#ifdef _WIN32
#ifdef _DEBUG
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnBegin timeAfter %ld\n"),timeAfterBegin);
OutputDebugString(szTmp);
#endif
#endif
if(m_pPacketParser)
{
m_pPacketParser->Begin(timeAfterBegin);
}
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::GetDisplayType ref: hxrendr.h
//
// This routine returns the preferred display type of the Renderer. Any
// other additional information necessary for the display can also be
// provided. This method is called by the RMA core when the plug-in is being
// initialized.
//
STDMETHODIMP
CRnMp3Ren::GetDisplayType(REF(HX_DISPLAY_TYPE) displayType,
REF(IHXBuffer*) pDisplayInfo)
{
displayType = HX_DISPLAY_NONE;
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnPacket ref: hxrendr.h
//
// This routine is passed the packet object streamed by the associated
// file format plug-in. It is called by the RMA core when a packet is due
// to be delivered. In most cases, the actual rendering of the packet is
// done in this method. The stream's time offset with respect to the master
// timeline is provided.
//
STDMETHODIMP
CRnMp3Ren::OnPacket(IHXPacket* pPacketObj,
INT32 streamOffsetTime)
{
if (m_bInSeekMode)
return HXR_OK;
if(!m_pPacketParser)
return HXR_NOT_INITIALIZED;
if (!pPacketObj)
return HXR_INVALID_PARAMETER;
#ifdef _DEBUG
++m_ulPacketsDecoded;
#endif
m_lTimeLineOffset = streamOffsetTime;
HX_RESULT res = m_pPacketParser->AddPacket(pPacketObj, 0);
if(FAILED(res))
{
return HXR_OK;
}
if(m_pDefaultPacketHookHelper)
m_pDefaultPacketHookHelper->OnPacket(pPacketObj);
#if 0
#ifdef HELIX_CONFIG_ONLY_DECODE_IF_DRY
// Only decode audio if audio device is low
// IMPORTANT NOTE: since the implementation of AddPacket in the parser
// does not have a queue, in general if we return here and we do NOT get
// an OnDryNotification, the next time OnPacket is called, it will clobber
// an undecoded packet. As it turns out, this doesn't seem to happen in
// testing to date, but this is a TBD.
// Testing without this code seems to show that we can get the same results
// without it. Nevertheless, we are going to leave this code here until an
// absolute final decision can be made on the best solution.
UINT32 ulBytesInAudioDevice = 0;
m_pAudioPushdown2->GetCurrentAudioDevicePushdown( ulBytesInAudioDevice );
if( ulBytesInAudioDevice >= OPTIMAL_AUDIO_PUSHDOWN )
{
return HXR_OK;
}
#endif // HELIX_CONFIG_ONLY_DECODE_IF_DRY
#endif // 0
// Decode and render all frames available
HX_RESULT theErr = m_pPacketParser->RenderAll();
if( theErr == HXR_OUTOFMEMORY )
{
return theErr;
}
// Handle rebuffering
if (m_bStarving)
{
// Waiting for more packets
if (++m_ulNumPackets < m_nPacketsNeeded)
{
m_pStream->ReportRebufferStatus(m_nPacketsNeeded, (UINT8)m_ulNumPackets);
return HXR_OK;
}
#ifdef _WIN32
#ifdef _DEBUG
OutputDebugString(TEXT("Rebuffer Complete\n"));
#endif
#endif
m_pStream->ReportRebufferStatus(m_nPacketsNeeded, m_nPacketsNeeded);
m_bStarving = FALSE;
}
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnTimeSync ref: hxrendr.h
//
// This routine is called by the RMA core periodically passing the current
// playback time. The Renderer should use this time value to synchronize the
// playback of various streams.
//
STDMETHODIMP
CRnMp3Ren::OnTimeSync(UINT32 currentPlayBackTime)
{
#if 0
#ifdef _DEBUG
#ifdef _WIN32
if (!m_bStarted)
{
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnTimeSync %ld Preroll %ld\n"),
currentPlayBackTime, m_ulPacketsDecoded*m_dFrameTime);
OutputDebugString(szTmp);
m_bStarted = 1;
}
#endif
#endif
#endif
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnPreSeek ref: hxrendr.h
//
// This routine is called by the RMA core before a seek is about to occur.
// The stream's time value just before the seek, and the time value just
// after the seek are provided.
//
STDMETHODIMP
CRnMp3Ren::OnPreSeek(UINT32 timeBeforeSeek,
UINT32 timeAfterSeek)
{
#ifdef _WIN32
#ifdef _DEBUG
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnPreSeek timeb4 %ld timeAfter %ld\n"), timeBeforeSeek, timeAfterSeek);
OutputDebugString(szTmp);
m_ulPacketsDecoded = 0;
m_ulFramesDecoded = 0;
m_bStarted = 0;
#endif
#endif
// Wait for decode thread to become idle and
// release all buffered packets
m_bInSeekMode = TRUE;
m_bDiscontinuity = TRUE;
if(m_pPacketParser)
{
m_pPacketParser->PreSeek();
}
#ifdef DEMUXER
if (m_pRegistry) m_pRegistry->SetIntByName("FirstPts", -1);
#endif
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnPostSeek ref: hxrendr.h
//
// This routine is called by the RMA core just after a seek has occured.
// The stream's time value just before the seek, and the time value just
// after the seek are provided.
//
STDMETHODIMP
CRnMp3Ren::OnPostSeek(UINT32 timeBeforeSeek,
UINT32 timeAfterSeek)
{
#ifdef _WIN32
#ifdef _DEBUG
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnPostSeek timeb4 %ld timeAfter %ld\n"), timeBeforeSeek, timeAfterSeek);
OutputDebugString(szTmp);
#endif
#endif
m_bInSeekMode = FALSE;
if(m_pPacketParser)
{
m_pPacketParser->PostSeek(timeAfterSeek);
}
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnPause ref: hxrendr.h
//
// This routine is called by the RMA core just after a pause has occured.
// The stream's time value just before pausing is provided.
//
STDMETHODIMP
CRnMp3Ren::OnPause(UINT32 timeBeforePause)
{
#ifdef _WIN32
#ifdef _DEBUG
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnPause timeb4 %ld\n"), timeBeforePause);
OutputDebugString(szTmp);
#endif
#endif
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnBuffering ref: hxrendr.h
//
// This routine is called by the RMA core to inform the Renderer that
// buffering of data is occuring. The reason for buffering (e.g. start-up
// of stream, seek has occured, network congestion, etc.), as well as the
// percentage of the buffering process complete are provided.
//
STDMETHODIMP
CRnMp3Ren::OnBuffering(UINT32 reason,
UINT16 percentComplete)
{
#ifdef _WIN32
#ifdef _DEBUG
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("OnBuffer percent %d\n"), percentComplete);
OutputDebugString(szTmp);
#endif
#endif
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::OnEndofPackets ref: hxrendr.h
//
// Called by client engine to inform the renderer that all the
// packets have been delivered. However, if the user seeks before
// EndStream() is called, renderer may start getting packets again
// and the client engine will eventually call this function again.
//
STDMETHODIMP
CRnMp3Ren::OnEndofPackets(void)
{
m_bEndOfPackets = TRUE;
if (m_bStarving)
{
m_bStarving = FALSE;
m_pStream->ReportRebufferStatus(m_nPacketsNeeded, m_nPacketsNeeded);
}
if(m_pPacketParser)
{
m_pPacketParser->EndOfPackets();
}
if(m_pDefaultPacketHookHelper)
m_pDefaultPacketHookHelper->OnEndOfPackets();
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXRenderer::EndStream ref: hxrendr.h
//
// This routine is called by the RMA core when the rendering of the stream
// has completed. Deallocation of any resources should be done here.
//
STDMETHODIMP
CRnMp3Ren::EndStream(void)
{
HX_RELEASE(m_pContext);
HX_RELEASE(m_pClassFactory);
HX_DELETE(m_pPacketParser);
if(m_pDefaultPacketHookHelper)
{
m_pDefaultPacketHookHelper->Terminate();
HX_RELEASE(m_pDefaultPacketHookHelper);
}
#ifdef DEMUXER
if (m_pRegistry)
m_pRegistry->DeleteByName("FirstPts");
#endif
for (int i=0; i<=m_wAudStream; i++)
HX_RELEASE(m_aAudStreamList[i]);
HX_RELEASE(m_pDefAudStream);
HX_RELEASE(m_pStream);
HX_RELEASE(m_pHeader);
HX_RELEASE(m_pAudioPlayer);
HX_RELEASE(m_pAudioPushdown2);
HX_RELEASE(m_pRegistry);
#ifdef PCM_CAPTURE
if (fpOut)
{
write_pcm_tailer_wave(fpOut, g_dwTotalPcmBytes);
fclose(fpOut);
fpOut = NULL;
}
#endif //PCM_CAPTURE
return HXR_OK;
}
///////////////////////////////////////////////////////////////////////////////
// IHXDryNotification::OnDryNotification ref: hxausvc.h
//
// This function is called when it is time to write to audio device
// and there is not enough data in the audio stream. The renderer can
// then decide to add more data to the audio stream. This should be
// done synchronously within the call to this function.
// It is OK to not write any data. Silence will be played instead.
//
STDMETHODIMP
CRnMp3Ren::OnDryNotification(UINT32 /*IN*/ ulCurrentStreamTime,
UINT32 /*IN*/ ulMinimumDurationRequired)
{
// We do not set our rebuffer flag at the end of a stream
if (m_bEndOfPackets || !m_pStream)
return HXR_OK;
#ifdef _DEBUG
#ifdef _WIN32
TCHAR szTmp[128];
wsprintf(szTmp, TEXT("DryNot: dur %ld\n"), ulMinimumDurationRequired);
OutputDebugString(szTmp);
#endif
#endif
// NOTE: We still need to scrutinize this low-heap solution because it
// skips the rebuffering call. XXXJHHB
#if defined(HELIX_CONFIG_ONLY_DECODE_IF_DRY)
HX_RESULT theErr = m_pPacketParser->RenderAll();
if( theErr == HXR_OUTOFMEMORY )
{
return theErr;
}
#else
// Rebuffer if we are late
if (ulCurrentStreamTime+m_ulPreroll > m_ulDelay)
{
m_ulNumPackets = 0;
m_bStarving = TRUE;
if(m_pPacketParser)
{
m_nPacketsNeeded = (UINT8)(ulMinimumDurationRequired /
m_pPacketParser->GetTimePerPkt() + 1);
}
m_pStream->ReportRebufferStatus(m_nPacketsNeeded, 0);
}
#endif
return HXR_OK;
}
STDMETHODIMP
CRnMp3Ren::InitializeStatistics(UINT32 ulRegistryID)
{
#if defined(HELIX_FEATURE_STATS)
m_ulRegistryID = ulRegistryID;
m_ulChannelsRegID = 0;
m_ulCodecRegID = 0;
return HXR_OK;
#else
return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_STATS */
}
STDMETHODIMP
CRnMp3Ren::UpdateStatistics()
{
#if defined(HELIX_FEATURE_STATS)
if (m_pRegistry)
{
char szRegistryEntry[MAX_DISPLAY_NAME] = "0"; /* Flawfinder: ignore */
// Get the registry name for the specified id
IHXBuffer* pszRegistryName = NULL;
UINT32 ulChannels = m_pPacketParser ? m_pPacketParser->GetChannels() : 0;
if (!m_ulChannelsRegID && HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName))
{
// Get the channel registry and set the value
SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.Channels", pszRegistryName->GetBuffer());
m_ulChannelsRegID = m_pRegistry->AddInt (szRegistryEntry, ulChannels);
HX_RELEASE(pszRegistryName);
}
// Set the channels value based on id
else
m_pRegistry->SetIntById(m_ulChannelsRegID, ulChannels);
// Set the codec name in registry
if (!m_ulCodecRegID)
{
// Get the current registry key name
if (!m_ulCodecRegID && (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName)))
{
SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.Codec", pszRegistryName->GetBuffer());
IHXBuffer *pValue = NULL;
m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**) &pValue);
if (pValue)
{
UCHAR pCodecName[] = "MPEG Audio";
pValue->Set((const UCHAR*)pCodecName, strlen((const char*)pCodecName)+1);
m_ulCodecRegID = m_pRegistry->AddStr(szRegistryEntry, pValue);
pValue->Release();
}
pszRegistryName->Release();
pszRegistryName = NULL;
}
}
else
{
IHXBuffer *pValue = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -