📄 mp3rend.cpp
字号:
/* ***** 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
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -