mp3rend.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:42k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 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 ***** */
- // system
- #include "hlxclib/stdio.h"
- // include
- #include "hxcom.h" // IUnknown
- #include "hxcomm.h" // IHXCommonClassFactory
- #include "ihxpckts.h" // IHXBuffer, IHXPacket, IHXValues
- #include "hxplugn.h" // IHXPlugin
- #include "hxrendr.h" // IHXRenderer
- #include "hxengin.h" // IHXInterruptSafe
- #include "hxcore.h" // IHXStream
- #include "hxausvc.h" // Audio Services
- #include "hxmon.h" // IHXStatistics
- #include "hxupgrd.h" // IHXUpgradeCollection
- #include "rmfftype.h" // AudioTypeSpecificData
- #include "hxprefs.h"
- #include "hxcore.h" // IHXUpdateProperties
- #include "hxver.h"
- // pnmisc
- #include "hxstrutl.h" // strcasecmp()
- // rmpadec
- #include "mpadecobj.h" // MPEG Audio Decoder (selects fixed-pt or floating-pt based on HELIX_CONFIG_FIXEDPOINT)
- // rmp3lib
- #include "mp3format.h" // MP3 formatter
- // mpgcommon
- #ifdef DEMUXER
- #include "xmddemuxer.h" // Demuxer
- #include "xmdtypes.h"
- #endif
- #include "addupcol.h"
- // mp3rend
- #include "mp3rend.h" // CRnMp3Ren
- #include "pktparse.h" // CPacketParser
- #if defined (MPA_FMT_RAW)
- #include "mpapktparse.h" // CMpaPacketParser, C2250PacketParser
- #endif /* #if defined (MPA_FMT_RAW) */
- #if defined(MPA_FMT_DRAFT00)
- #include "fmtpktparse.h" // CFmtPacketParser
- #endif /* #if defined(MPA_FMT_DRAFT00) */
- #if defined(MPA_FMT_RFC3119)
- #include "robpktparse.h" // CRobustPacketParser
- #endif /* #if defined(MPA_FMT_RFC3119) */
- #include "hxdefpackethookhlp.h"
- #include "adjtime.h"
- // The value below is derived from trial and error as the lowest we can
- // get away with on the platforms tested. Feel free to experiment with
- // different values on your platform.
- #define OPTIMAL_AUDIO_PUSHDOWN 160
- #ifdef PCM_CAPTURE
- #include <stdio.h>
- #include "wavep.h"
- static UINT32 g_dwTotalPcmBytes = 0;
- static FILE *fpOut = NULL;
- #endif // PCM_CAPTURE
- #if defined(HELIX_FEATURE_MIN_HEAP)
- #define MAXIMUM_MP3_PREROLL 3000
- #else
- #define MAXIMUM_MP3_PREROLL 15000
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Ren static variables ref: ff1rendr.h
- //
- // These variables are passed to the RMA core to provide information about
- // this plug-in. They are required to be static in order to remain valid
- // for the lifetime of the plug-in.
- //
- const char* const CRnMp3Ren::zm_pDescription = MY_DESCRIPTION;
- const char* const CRnMp3Ren::zm_pCopyright = HXVER_COPYRIGHT;
- const char* const CRnMp3Ren::zm_pMoreInfoURL = HXVER_MOREINFO;
- const char* const CRnMp3Ren::zm_pStreamMimeTypes[] = MY_STREAM_MIME_TYPES;
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Ren::CRnMp3Ren ref: ff1rendr.h
- //
- // Constructor
- //
- CRnMp3Ren::CRnMp3Ren(void)
- : m_RefCount (0),
- m_pContext (NULL),
- m_pClassFactory (NULL),
- m_pStream (NULL),
- m_pAudioPlayer (NULL),
- m_pAudioStream (NULL),
- m_pAudioPushdown2 (NULL),
- m_pDefAudStream (NULL),
- m_pHeader (NULL),
- m_pPacketParser (NULL),
- m_bInSeekMode (FALSE),
- m_bDiscontinuity (TRUE),
- m_wAudStream (0),
- m_nPacketsNeeded (0),
- m_bStarving (0),
- m_bEndOfPackets (0),
- m_ulNumPackets (0),
- m_pRegistry (NULL),
- m_ulPreroll (0),
- m_ulRegistryID (0),
- m_ulDelay (0),
- m_lTimeLineOffset (0),
- m_ulChannelsRegID (0),
- m_ulCodecRegID (0),
- m_ulPacketsDecoded(0),
- m_ulFramesDecoded (0),
- m_ulBadPackets (0),
- m_bStarted (0),
- m_bTrustPackets(FALSE),
- m_pDefaultPacketHookHelper(NULL)
- {
- memset(m_aAudStreamList, 0, sizeof(m_aAudStreamList));
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXPlugin::GetPluginInfo ref: hxplugn.h
- //
- // This routine returns descriptive information about the plug-in, most
- // of which is used in the About box of the user interface. It is called
- // when the RMA core application is launched.
- //
- STDMETHODIMP
- CRnMp3Ren::GetPluginInfo(REF(int) bLoadMultiple,
- REF(const char*) pDescription,
- REF(const char*) pCopyright,
- REF(const char*) pMoreInfoURL,
- REF(UINT32) versionNumber)
- {
- bLoadMultiple = TRUE;
- pDescription = zm_pDescription;
- pCopyright = zm_pCopyright;
- pMoreInfoURL = zm_pMoreInfoURL;
- versionNumber = MY_PLUGIN_VERSION;
-
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXRenderer::GetRendererInfo ref: hxrendr.h
- //
- // This routine returns crucial information required to associate this
- // plug-in with a given stream MIME type. This information tells the HX
- // core which Renderer to use to display a particular type of stream. This
- // method is called when the RMA core application is launched.
- //
- STDMETHODIMP
- CRnMp3Ren::GetRendererInfo(REF(const char**) pStreamMimeTypes,
- REF(UINT32) initialGranularity)
- {
- // Associate this Renderer with a given stream MIME type
- pStreamMimeTypes = (const char**) zm_pStreamMimeTypes;
- // Set frequency of OnTimeSync() updates
- initialGranularity = 50;
-
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXPlugin::InitPlugin ref: hxplugn.h
- //
- // This routine performs initialization steps such as determining if
- // required interfaces are available. It is called when the RMA core
- // application is launched, and whenever a stream associated with this
- // plug-in needs to be rendered.
- //
- STDMETHODIMP
- CRnMp3Ren::InitPlugin(IUnknown* pHXCore)
- {
- m_pContext = pHXCore;
- m_pContext->AddRef();
-
- // Store a reference to the IHXCommonClassFactory interface which is
- // used to create commonly used HX objects such as IHXPacket,
- // IHXValues, and IHXBuffers.
- pHXCore->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pClassFactory);
- if (!m_pClassFactory)
- return HXR_NOTIMPL;
-
- pHXCore->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
- #ifdef DEMUXER
- if (m_pRegistry) m_pRegistry->AddInt("FirstPts", -1);
- #endif
-
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXRenderer::StartStream ref: hxrendr.h
- //
- // The RMA core calls this routine to provide access to the stream and
- // player. It is called when the plug-in is being initialized.
- //
- STDMETHODIMP
- CRnMp3Ren::StartStream(IHXStream *pStream,
- IHXPlayer *pPlayer)
- {
- m_bEndOfPackets = FALSE;
- m_pStream = pStream;
- m_pStream->AddRef();
- // Get interface to audio player
- if (HXR_OK != pPlayer->QueryInterface(IID_IHXAudioPlayer, (void**) &m_pAudioPlayer))
- return !HXR_OK;
- pPlayer->QueryInterface(IID_IHXAudioPushdown2, (void**) &m_pAudioPushdown2);
- #ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
- m_pAudioPushdown2->SetAudioPushdown( OPTIMAL_AUDIO_PUSHDOWN );
- #endif // HELIX_CONFIG_MIN_PUSHDOWN_BYTES
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXRenderer::OnHeader ref: hxrendr.h
- //
- // This routine is passed the stream header object created by the associated
- // file format plug-in. Use the methods defined in the IHXValues interface
- // to access the stream header data. This method is called from the HX
- // core when the plug-in is being initialized.
- //
- STDMETHODIMP
- CRnMp3Ren::OnHeader(IHXValues* pStreamHeaderObj)
- {
- UINT32 ulAvgBitRate = 0,
- ulAvgPacketSize = 0,
- ulStreaming = 0,
- ulSampRate = 0,
- ulChannels = 0;
- HX_RESULT pr;
- pr = CheckStreamVersions(pStreamHeaderObj);
-
- if (HXR_OK != pr)
- return pr;
-
- m_pHeader = pStreamHeaderObj;
- m_pHeader->AddRef();
- pStreamHeaderObj->GetPropertyULONG32("AvgBitRate", ulAvgBitRate);
- pStreamHeaderObj->GetPropertyULONG32("AvgPacketSize", ulAvgPacketSize);
- pStreamHeaderObj->GetPropertyULONG32("SampleRate", ulSampRate);
- pStreamHeaderObj->GetPropertyULONG32("NumChannels", ulChannels);
- pStreamHeaderObj->GetPropertyULONG32("Delay", m_ulDelay);
- pStreamHeaderObj->SetPropertyULONG32("IsAudioStream", 1);
- // Setup preroll
- // Set to default value if not set in stream header.
- m_ulPreroll = 0;
- pStreamHeaderObj->GetPropertyULONG32("Preroll", m_ulPreroll);
- if (m_ulPreroll == 0)
- {
- // Preroll is not set for this stream - assume default
- m_ulPreroll = MY_DFLT_PREROLL;
- pStreamHeaderObj->SetPropertyULONG32("Preroll", m_ulPreroll);
- }
- // Check that stream header value is not over our max.
- else if( m_ulPreroll > MAXIMUM_MP3_PREROLL )
- {
- m_ulPreroll = MAXIMUM_MP3_PREROLL;
- pStreamHeaderObj->SetPropertyULONG32("Preroll", m_ulPreroll);
- }
-
- // Check standard stream properties if custom properties fail
- if (!ulSampRate)
- pStreamHeaderObj->GetPropertyULONG32("SamplesPerSecond", ulSampRate);
- if (!ulChannels)
- pStreamHeaderObj->GetPropertyULONG32("Channels", ulChannels);
- // Try Opaque Data for SampleRate and/or channels
- if (!ulSampRate || !ulChannels)
- {
- IHXBuffer* pOpaqueData = NULL;
- if (SUCCEEDED(pStreamHeaderObj->GetPropertyBuffer("OpaqueData",
- pOpaqueData)) &&
- pOpaqueData)
- {
- AudioTypeSpecificData audioData;
- memset(&audioData, 0, sizeof(audioData));
-
- audioData.unpack(pOpaqueData->GetBuffer(),
- pOpaqueData->GetSize());
-
- if (audioData.numChannels)
- {
- ulChannels = audioData.numChannels;
- }
- if (audioData.sampleRate)
- {
- ulSampRate = audioData.sampleRate;
- }
- }
- HX_RELEASE(pOpaqueData);
- }
-
- // Check MIME type
- IHXBuffer* pStringObj = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&pStringObj);
- if (pStringObj)
- {
- pStreamHeaderObj->GetPropertyCString("MimeType", pStringObj);
- SetPacketFormat((const char*)(pStringObj->GetBuffer()));
- // Check if we know these packets can be trusted. These
- // are the mime types that we *know* came from our file format
- const char* pszMimeType = (const char*) pStringObj->GetBuffer();
- if (!strcmp(pszMimeType, "audio/MPEG-ELEMENTARY") ||
- !strcmp(pszMimeType, "audio/MPEG-ELEMENTARY-RN") ||
- !strcmp(pszMimeType, "audio/X-MP3-draft-00") ||
- !strcmp(pszMimeType, "audio/X-MP3-draft-00-RN"))
- {
- m_bTrustPackets = TRUE;
- }
- // Set this in the packet parser
- m_pPacketParser->SetTrustPackets(m_bTrustPackets);
-
- HX_RELEASE(pStringObj);
- }
-
- if(m_pPacketParser)
- {
- m_pPacketParser->Init(this, m_pClassFactory);
- }
- if (!ulAvgPacketSize)
- ulAvgPacketSize = 1200;
- UINT32 dwAudBytes = m_ulPreroll * ulAvgBitRate / 8000;
- m_nPacketsNeeded = (UINT8)(dwAudBytes / ulAvgPacketSize);
-
- if (!m_pAudioStream && ulChannels && ulSampRate)
- {
- // Create our audio stream
- m_pAudioPlayer->CreateAudioStream(&m_aAudStreamList[m_wAudStream]);
- m_pAudioStream = m_aAudStreamList[m_wAudStream];
- if (!m_pAudioStream)
- return HXR_OK;
- // Let's override the default class factory and use the one in
- // client/audiosvc that caches our pcm buffers and avoids
- // unnecessary heap fragmentation.
- IHXCommonClassFactory* pCommonClassFactory;
- if (HXR_OK == m_pAudioStream->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&pCommonClassFactory))
- {
- if( m_pPacketParser )
- m_pPacketParser->OverrideFactory(pCommonClassFactory);
- pCommonClassFactory->Release();
- }
- // Init PCM device
- HXAudioFormat audioFmt;
- audioFmt.uChannels = (unsigned short)ulChannels;
- audioFmt.uBitsPerSample = 16;
- audioFmt.ulSamplesPerSec = ulSampRate;
- audioFmt.uMaxBlockSize = (unsigned short)(1152 *
- (audioFmt.uBitsPerSample>>3) *
- audioFmt.uChannels);
- m_pAudioStream->Init(&audioFmt, m_pHeader);
- m_pAudioStream->AddDryNotification(this);
- m_bDiscontinuity = TRUE;
- }
-
- #if 0
- // Create a default stream to prevent rebuffering
- else
- {
- // If the server does not send these properties
- if (!ulSampRate)
- ulSampRate = 44100;
- if (!ulChannels)
- ulChannels = 2;
- ulSampRate = min(ulSampRate, 44100);
- ulChannels = min(ulChannels, 2);
- // Create our audio stream
- m_pAudioPlayer->CreateAudioStream(&m_pDefAudStream);
- if (!m_pDefAudStream)
- return HXR_OK;
- // Init PCM device
- HXAudioFormat audioFmt;
- audioFmt.uChannels = (unsigned short)ulChannels;
- audioFmt.uBitsPerSample = 16;
- audioFmt.ulSamplesPerSec = ulSampRate;
- audioFmt.uMaxBlockSize = (unsigned short)(1152 *
- (audioFmt.uBitsPerSample>>3) *
- audioFmt.uChannels);
- m_pDefAudStream->Init(&audioFmt, m_pHeader);
- }
- #endif
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXRenderer::OnBegin ref: hxrendr.h
- //
- // 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 %ldn"),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 Completen"));
- #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 %ldn"),
- 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 %ldn"), 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 %ldn"), 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 %ldn"), 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 %dn"), 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 %ldn"), 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;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**) &pValue);
-
- if (pValue)
- {
- UCHAR pCodecName[] = "MPEG Audio";
- pValue->Set((const UCHAR*)pCodecName, strlen((const char*)pCodecName)+1);
- m_pRegistry->SetStrById(m_ulCodecRegID, pValue);
- pValue->Release();
- }
- }
- }
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS */
- }
- /************************************************************************
- * IHXUpdateProperties Methods
- */
- /************************************************************************
- * UpdatePacketTimeOffset
- * Call this method to update the timestamp offset of cached packets
- */
- STDMETHODIMP CRnMp3Ren::UpdatePacketTimeOffset(INT32 lTimeOffset)
- {
- m_lTimeLineOffset -= lTimeOffset;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXUpdateProperties::UpdatePlayTimes
- * Purpose:
- * Call this method to update the playtime attributes
- */
- STDMETHODIMP CRnMp3Ren::UpdatePlayTimes(IHXValues* pProps)
- {
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Ren::~CRnMp3Ren ref: ff1rendr.h
- //
- // Destructor
- //
- CRnMp3Ren::~CRnMp3Ren(void)
- {
- //--_gbInit;
- EndStream();
- }
- // IUnknown COM Interface Methods
- ///////////////////////////////////////////////////////////////////////////////
- // IUnknown::AddRef ref: hxcom.h
- //
- // This routine increases the object reference count in a thread safe
- // manner. The reference count is used to manage the lifetime of an object.
- // This method must be explicitly called by the user whenever a new
- // reference to an object is used.
- //
- STDMETHODIMP_(UINT32)
- CRnMp3Ren::AddRef(void)
- {
- return InterlockedIncrement(&m_RefCount);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IUnknown::Release ref: hxcom.h
- //
- // This routine decreases the object reference count in a thread safe
- // manner, and deletes the object if no more references to it exist. It must
- // be called explicitly by the user whenever an object is no longer needed.
- //
- STDMETHODIMP_(UINT32)
- CRnMp3Ren::Release(void)
- {
- if (InterlockedDecrement(&m_RefCount) > 0)
- return m_RefCount;
- delete this;
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IUnknown:]Interface ref: hxcom.h
- //
- // This routine indicates which interfaces this object supports. If a given
- // interface is supported, the object's reference count is incremented, and
- // a reference to that interface is returned. Otherwise a NULL object and
- // error code are returned. This method is called by other objects to
- // discover the functionality of this object.
- //
- STDMETHODIMP
- CRnMp3Ren::QueryInterface(REFIID interfaceID,
- void** ppInterfaceObj)
- {
- // By definition all COM objects support the IUnknown interface
- if (IsEqualIID(interfaceID, IID_IUnknown))
- {
- AddRef();
- *ppInterfaceObj = (IUnknown*)(IHXPlugin*)this;
- return HXR_OK;
- }
- // IHXPlugin interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXPlugin))
- {
- AddRef();
- *ppInterfaceObj = (IHXPlugin*)this;
- return HXR_OK;
- }
- // IHXInterruptSafe interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXInterruptSafe))
- {
- AddRef();
- *ppInterfaceObj = (IHXInterruptSafe*)this;
- return HXR_OK;
- }
- // IHXRenderer interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXRenderer))
- {
- AddRef();
- *ppInterfaceObj = (IHXRenderer*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(interfaceID, IID_IHXDryNotification))
- {
- AddRef();
- *ppInterfaceObj = (IHXDryNotification*)this;
- return HXR_OK;
- }
- #if defined(HELIX_FEATURE_STATS)
- else if (IsEqualIID(interfaceID, IID_IHXStatistics))
- {
- AddRef();
- *ppInterfaceObj = (IHXStatistics*)this;
- return HXR_OK;
- }
- #endif /* #if defined(HELIX_FEATURE_STATS) */
- else if (IsEqualIID(interfaceID, IID_IHXUpdateProperties))
- {
- AddRef();
- *ppInterfaceObj = (IHXUpdateProperties*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(interfaceID, IID_IHXPacketHookHelper))
- {
- if(!m_pDefaultPacketHookHelper)
- {
- m_pDefaultPacketHookHelper = new CHXDefaultPacketHookHelper;
- if(m_pDefaultPacketHookHelper)
- {
- m_pDefaultPacketHookHelper->AddRef();
- m_pDefaultPacketHookHelper->Initialize(m_pContext);
- }
- }
- if(m_pDefaultPacketHookHelper)
- return m_pDefaultPacketHookHelper->QueryInterface(interfaceID, ppInterfaceObj);
- }
- // No other interfaces are supported
- *ppInterfaceObj = NULL;
- return HXR_NOINTERFACE;
- }
- STDMETHODIMP
- CRnMp3Ren::CheckStreamVersions(IHXValues* pHeader)
- {
- // check stream and content versions so an upgrade can
- // be called if necessary...
- HX_RESULT pnr = HXR_OK;
- BOOL bVersionOK = TRUE;
- UINT32 ulStreamVersion = 0;
- UINT32 ulContentVersion = 0;
- if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
- ulStreamVersion))
- {
- UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
- UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
- if((ulMajorVersion > STREAM_MAJOR_VERSION) ||
- (ulMinorVersion > STREAM_MINOR_VERSION &&
- ulMajorVersion == STREAM_MAJOR_VERSION))
- {
- bVersionOK = FALSE;
- }
- }
- if(bVersionOK &&
- HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
- ulContentVersion))
- {
- UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
- UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
- if((ulMajorVersion > CONTENT_MAJOR_VERSION) ||
- (ulMinorVersion > CONTENT_MINOR_VERSION &&
- ulMajorVersion == CONTENT_MAJOR_VERSION))
- {
- bVersionOK = FALSE;
- }
- }
- if(!bVersionOK)
- {
- AddToAutoUpgradeCollection(zm_pStreamMimeTypes[0], m_pContext);
- pnr = HXR_FAIL;
- }
- return pnr;
- }
- BOOL
- CRnMp3Ren::InitAudioStream(HXAudioFormat audioFmt)
- {
- if(m_pAudioStream)
- {
- // if already inited, don't do anything
- return TRUE;
- }
- // If we could not create the stream in OnHeader
- // Create our audio stream
- m_pAudioPlayer->CreateAudioStream(&m_pAudioStream);
- if (!m_pAudioStream)
- return FALSE;
- m_pAudioStream->Init(&audioFmt, m_pHeader);
- #ifdef PCM_CAPTURE
- #ifdef _WIN32
- char szFile[64] = "c:\temp.wav"; /* Flawfinder: ignore */
- #elif _MACINTOSH
- char szFile[64] = "temp.wav"; /* Flawfinder: ignore */
- #endif
- fpOut = fopen(szFile, "wb");
- write_pcm_header_wave(fpOut,
- lPCMSampRate,
- nPCMChannels,
- nBitsPerSample,
- 0);
- g_dwTotalPcmBytes = 0;
-
- #endif // PCM_CAPTURE
-
- m_pAudioStream->AddDryNotification(this);
- m_bDiscontinuity = TRUE;
- return TRUE;
- }
- BOOL
- CRnMp3Ren::ReInitAudioStream(HXAudioFormat audioFmt)
- {
- #if defined _DEBUG && defined _WIN32
- OutputDebugString(TEXT("Dynamic audio src changen"));
- #endif
- IHXAudioStream2 *pStream = NULL;
- m_pAudioStream->QueryInterface(IID_IHXAudioStream2, (void**)&pStream);
- if (pStream)
- {
- pStream->RemoveDryNotification((IHXDryNotification*)this);
- pStream->Release();
- }
-
- m_pAudioStream = m_aAudStreamList[++m_wAudStream];
- return InitAudioStream(audioFmt);
- }
- void CRnMp3Ren::Render(IHXBuffer* pPCMBuffer, double dTime)
- {
- #ifdef PCM_CAPTURE
- if (fpOut)
- {
- fwrite(pPCMBuffer->GetBuffer(), dwPCM, 1, fpOut);
- g_dwTotalPcmBytes += dwPCM;
- }
- #endif //PCM_CAPTURE
- // Write to Audio Services
- HXAudioData audioData;
- audioData.pData = pPCMBuffer;
- audioData.ulAudioTime = (UINT32)dTime;
- #ifdef _DEBUG
- ++m_ulFramesDecoded;
- #endif
-
- #if defined _DEBUG && defined _WIN32
- //wsprintf(szTmp, "Audio Pts %ldn", audioData.ulAudioTime);
- //OutputDebugString(szTmp);
- #endif
- if (m_bDiscontinuity)
- {
- audioData.uAudioStreamType = TIMED_AUDIO;
- m_bDiscontinuity = FALSE;
- }
- else
- audioData.uAudioStreamType = STREAMING_AUDIO;
- audioData.ulAudioTime = AdjustTimestamp( (ULONG32) dTime, m_lTimeLineOffset );
- m_pAudioStream->Write(&audioData);
- }
- void
- CRnMp3Ren::SetPacketFormat(const char* szMimeType)
- {
- if(!szMimeType)
- {
- return;
- }
- int i, j;
- for (i=0; zm_pStreamMimeTypes[i] != NULL; i++)
- if (!strcasecmp(szMimeType, zm_pStreamMimeTypes[i]))
- break;
- if(zm_pStreamMimeTypes[i] == NULL)
- {
- return;
- }
- for (j=0; MIME_FMT_BASIC[j] != -1; j++)
- {
- if(MIME_FMT_BASIC[j] == i)
- {
- #if defined (MPA_FMT_DRAFT00)
- m_pPacketParser = new CFmtPacketParser();
- #if defined(HELIX_FEATURE_MIN_HEAP)
- m_ulPreroll = 0;
- m_pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
- #endif
- #endif //MPA_FMT_DRAFT00
- return;
- }
- }
- for (j=0; MIME_MPA_BASIC[j] != -1; j++)
- {
- if(MIME_MPA_BASIC[j] == i)
- {
- #if defined (MPA_FMT_RAW)
- m_pPacketParser = new CMpaPacketParser();
- #if defined(HELIX_FEATURE_MIN_HEAP)
- m_ulPreroll = 0;
- m_pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
- #endif
- #endif //MPA_FMT_RAW
- return;
- }
- }
- for (j=0; MIME_FMT_3119[j] != -1; j++)
- {
- if(MIME_FMT_3119[j] == i)
- {
- #if defined (MPA_FMT_RFC3119)
- m_pPacketParser = new CRobustPacketParser();
- #endif //MPA_FMT_RFC3119
- return;
- }
- }
- for (j=0; MIME_MPA_2250[j] != -1; j++)
- {
- if(MIME_MPA_2250[j] == i)
- {
- #if defined (MPA_FMT_RFC2250)
- m_pPacketParser = new C2250PacketParser();
- #if defined(HELIX_FEATURE_MIN_HEAP)
- m_ulPreroll = 0;
- m_pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
- #endif
- #endif //MPA_FMT_RFC2250
- return;
- }
- }
- #ifdef DEMUXER
- for (j=0; MIME_MPG1_2250[j] != -1; j++)
- {
- if(MIME_MPG1_2250[j] == i)
- {
- #if defined (MPA_FMT_RFC2250_SYSTEM)
- m_pPacketParser = (CPacketParser*)(CSysPacketParser*)
- (new C2250SysPacketParser(FALSE, m_pRegistry));
- #if defined(HELIX_FEATURE_MIN_HEAP)
- m_ulPreroll = 0;
- m_pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
- #endif
- #endif //MPA_FMT_RFC2250_SYSTEM
- return;
- }
- }
- for (j=0; MIME_MPG2_2250[j] != -1; j++)
- {
- if(MIME_MPG2_2250[j] == i)
- {
- #if defined (MPA_FMT_RFC2250_SYSTEM)
- m_pPacketParser = (CPacketParser*)(CSysPacketParser*)
- (new C2250SysPacketParser(TRUE, m_pRegistry));
- #if defined(HELIX_FEATURE_MIN_HEAP)
- m_ulPreroll = 0;
- m_pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
- #endif
- #endif //MPA_FMT_RFC2250_SYSTEM
- return;
- }
- }
- for (j=0; MIME_MPG1_SYS[j] != -1; j++)
- {
- if(MIME_MPG1_SYS[j] == i)
- {
- #if defined (MPA_FMT_SYSTEM)
- m_pPacketParser = new CSysPacketParser(FALSE, m_pRegistry);
- #endif //MPA_FMT_SYSTEM
- return;
- }
- }
- for (j=0; MIME_MPG2_SYS[j] != -1; j++)
- {
- if(MIME_MPG2_SYS[j] == i)
- {
- #if defined (MPA_FMT_SYSTEM)
- m_pPacketParser = new CSysPacketParser(TRUE, m_pRegistry);
- #endif //MPA_FMT_SYSTEM
- return;
- }
- }
- #endif // DEMUXER
- }