mp3ff.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:83k
- /* ***** 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 ***** */
- ///////////////////////////////////////////////////////////////////////////////
- // Defines
- #define INITGUID // Interface ID's
- ///////////////////////////////////////////////////////////////////////////////
- // Includes
- #include "hlxclib/string.h" // strrchr
- #include "hlxclib/stdlib.h" // atol
- #include "hlxclib/stdio.h" // sprintf
- #include "hxtypes.h" // Standard Real types
- #include "hxcom.h" // IUnknown
- #include "hxcomm.h" // IHXCommonClassFactory
- #include "ihxpckts.h" // IHXBuffer, IHXPacket, IHXValues
- #include "hxplugn.h" // IHXPlugin
- #include "hxfiles.h" // IHXFileResponse
- #include "hxformt.h" // IHXFileFormatObject
- #include "hxcore.h" // IHXPlayer
- #include "hxerror.h" // IHXErrorMessages
- #include "hxmon.h" // IHXRegistry
- #include "defslice.h" // Registry types
- #include "dbcsutil.h" // Double byte char set functions
- #include "hxver.h"
- #include "hxupgrd.h" // IHXUpgradeCollection
- #include "hxbuffer.h"
- #include "ringbuf.h"
- #include "mp3format.h" // CMp3Format
- #include "mp3ff.h" // CRnMp3Fmt
- #include "mhead.h" // MP3 header info
- #include "dxhead.h" // Xing MP3 header info
- #include "pckunpck.h"
- #include "metautil.h"
- #include "hxstrutl.h"
- #define MP3FF_4BYTE_SYSTEM 0x000001ba
- #define MP3FF_4BYTE_VIDEO 0x000001b3
- #define MP3FF_4BYTE_RIFF 0x52494646
- #define MP3FF_4BYTE_CDXA 0x43445841
- #define MP3FF_4BYTE_free 0x66726565
- #define MP3FF_4BYTE_skip 0x736B6970
- #define MP3FF_4BYTE_pnot 0x706e6f74
- #define MP3FF_4BYTE_mdat 0x6d646174
- #define MP3FF_4BYTE_moov 0x6d6f6f76
- //#include "rmfftype.h" // for the HX_SAVE_ENABLED flag
- #ifdef _AIX
- #include "dllpath.h"
- ENABLE_MULTILOAD_DLLACCESS_PATHS(Rnmp3fmt);
- #endif
- IHXBuffer* NewPacketBufferGetter(
- IHXCommonClassFactory * pClassFactory, // not used for new version
- IHXBuffer * pExistingBuffer,
- UCHAR * pModFrameStart,
- int nModFrameSize
- )
- {
- IHXBuffer * pPacketBuffer = new CHXBufferFragment(
- pExistingBuffer,
- pModFrameStart,
- nModFrameSize);
- pPacketBuffer->AddRef();
- return pPacketBuffer;
- }
- IHXBuffer* OldPacketBufferGetter(
- IHXCommonClassFactory * pClassFactory,
- IHXBuffer * pExistingBuffer, // not used for old version
- UCHAR * pModFrameStart, // not used for old version
- int nModFrameSize // not used for old version
- )
- {
- IHXBuffer * pPacketBuffer = NULL;
- pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&pPacketBuffer);
- return pPacketBuffer;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // HXCreateInstance ref: hxplugn.h
- //
- // This routine creates a new instance of the CRnMp3Fmt class.
- // It is called when the RMA core application is launched, and whenever
- // an URL associated with this plug-in is opened.
- STDAPI ENTRYPOINT
- (HXCREATEINSTANCE)(IUnknown** ppExFileFormatObj)
- {
- *ppExFileFormatObj = (IUnknown*)(IHXPlugin*)new CRnMp3Fmt();
- if (*ppExFileFormatObj != NULL)
- {
- (*ppExFileFormatObj)->AddRef();
- return HXR_OK;
- }
- return HXR_OUTOFMEMORY;
- }
- /****************************************************************************
- *
- * Function:
- *
- * CanUnload2()
- *
- * Purpose:
- *
- * Function implemented by all plugin DLL's if it returns HXR_OK
- * then the pluginhandler can unload the DLL
- *
- */
- STDAPI ENTRYPOINT(CanUnload2)(void)
- {
- return (CHXBaseCountingObject::ObjectsActive() > 0 ? HXR_FAIL : HXR_OK );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Fmt static variables ref: filefmt1.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 CRnMp3Fmt::zm_pDescription = MY_DESCRIPTION;
- const char* const CRnMp3Fmt::zm_pCopyright = HXVER_COPYRIGHT;
- const char* const CRnMp3Fmt::zm_pMoreInfoURL = HXVER_MOREINFO;
- const char* const CRnMp3Fmt::zm_pFileMimeTypes[] = MY_FILE_MIME_TYPES;
- const char* const CRnMp3Fmt::zm_pFileExtensions[] = MY_FILE_EXTENSIONS;
- const char* const CRnMp3Fmt::zm_pFileOpenNames[] = MY_FILE_OPEN_NAMES;
- // Leave rtp out until the bug is fixed that makes it always get used.
- //const char* CRnMp3Fmt::zm_pPacketFormats[] = {"rdt", "rtp", NULL};
- const char* const CRnMp3Fmt::zm_pPacketFormats[] = {"rdt", NULL};
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Fmt::CRnMp3Fmt ref: filefmt1.h
- //
- // Constructor
- //
- CRnMp3Fmt::CRnMp3Fmt(void)
- : m_RefCount (0),
- m_pClassFactory (NULL),
- m_pFileObj (NULL),
- m_pStatus (NULL),
- m_pError (NULL),
- m_pRegistry (NULL),
- m_szPlayerReg (NULL),
- m_State (Ready),
- m_ulNextPacketDeliveryTime(0),
- m_ulFileSize(0),
- m_ulMetaReadSize(0),
- m_ulNextMetaPos((UINT32)-1),
- m_ulMetaLength(0),
- m_ulMaxSampRate(0),
- m_ulBytesRead(0),
- m_ulFileOffset(0),
- m_nChannels(0),
- m_dNextPts(0.0),
- m_bEOF(0),
- m_bRtp(0),
- m_bHasVbrHdr(0),
- m_bSkipVbrHdr(0),
- m_bStreaming(0),
- m_bMetaPacket(0),
- m_bNeedPacket(0),
- m_bCheckBadData(0),
- m_bLive(0),
- m_bLicensed(0),
- m_pFmtBuf(NULL),
- m_pMp3Fmt(NULL),
- m_ulGarbageBytesRead(0),
- m_bAcceptMetaInfo(FALSE),
- m_bAllMetaInfo(FALSE),
- m_pMetaProps(NULL),
- m_pContext(NULL),
- m_bIsVBR(FALSE),
- m_bFirstMeta(FALSE),
- m_bClosed(TRUE),
- m_pCreatePacketFunction(NULL)
- {
- memset(&m_ReadBuf, 0, sizeof(m_ReadBuf));
- memset(&m_Info, 0, sizeof(m_Info));
- memset(&m_RtpPackets, 0, sizeof(m_RtpPackets));
- m_pMp3Fmt = new CMp3Format;
- }
- #if defined(MPA_FMT_DRAFT00)
- ///////////////////////////////////////////////////////////////////////////
- // IHXPacketFormat Interface Methods ref: rmaformat.h
- ///////////////////////////////////////////////////////////////////////////
- STDMETHODIMP CRnMp3Fmt::GetSupportedPacketFormats(REF(const char**) pFormats)
- {
- pFormats = (const char**) zm_pPacketFormats;
- return HXR_OK;
- }
- STDMETHODIMP CRnMp3Fmt::SetPacketFormat(const char* pFormat)
- {
- if (!strcmp(pFormat, "rtp"))
- m_bRtp = 1;
- else
- m_bRtp = 0;
- return HXR_OK;
- }
- #endif /* #if defined(MPA_FMT_DRAFT00) */
- ///////////////////////////////////////////////////////////////////////////////
- // 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
- CRnMp3Fmt::GetPluginInfo(REF(int) bLoadMultiple,
- REF(const char*) pDescription,
- REF(const char*) pCopyright,
- REF(const char*) pMoreInfoURL,
- REF(UINT32) versionNumber)
- {
- // File Format plug-ins MUST be able to be multiply instantiated
- bLoadMultiple = TRUE;
- pDescription = (const char*) zm_pDescription;
- pCopyright = (const char*) zm_pCopyright;
- pMoreInfoURL = (const char*) zm_pMoreInfoURL;
- versionNumber = MY_PLUGIN_VERSION;
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXThreadSafeMethods::IsThreadsafe ref: hxengin.h
- //
- // This routine returns threadsafeness informaiton about the plugin
- // which is used by the server for improved performance.
- //
- STDMETHODIMP_(UINT32)
- CRnMp3Fmt::IsThreadSafe()
- {
- return HX_THREADSAFE_METHOD_FF_GETPACKET | HX_THREADSAFE_METHOD_FSR_READDONE;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXFileFormatObject::GetFileFormatInfo ref: hxformt.h
- //
- // This routine returns crucial information required to associate this
- // plug-in with a given MIME type. This information tells the core which
- // File Format plug-in to use for a particular URL. The routine is called
- // when the RMA core application is launched.
- //
- STDMETHODIMP
- CRnMp3Fmt::GetFileFormatInfo(REF(const char**) pFileMimeTypes,
- REF(const char**) pFileExtensions,
- REF(const char**) pFileOpenNames)
- {
- pFileMimeTypes = (const char**) zm_pFileMimeTypes;
- pFileExtensions = (const char**) zm_pFileExtensions;
- pFileOpenNames = (const char**) zm_pFileOpenNames;
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXPlugin::InitPlugin ref: hxplugn.h
- //
- // This routine performs initialization steps such as determining whether
- // required interfaces are available. It is called when the RMA core
- // application is launched, and whenever an URL associated with this
- // plug-in is opened.
- //
- STDMETHODIMP
- CRnMp3Fmt::InitPlugin(IUnknown* pHXCore)
- {
- HX_RELEASE(m_pContext);
- m_pContext = pHXCore;
- m_pContext->AddRef();
- pHXCore->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pClassFactory);
- if (m_pClassFactory == NULL)
- return HXR_NOTIMPL;
- m_bStreaming = 1;
- // Check if we are being loaded by the player or ther server. If
- // the context contains IHXPlayer, we are in the player, else, we
- // are in the server. This determines whether packet loss is possilbe
- // or not (only possible in the server). So, if m_bStreaming is
- // set to 1, we must do data reformatting to handle packet loss in the
- // render plugin.
- //
- // Also, check the server license for streaming mpa
- IHXPlayer *pPlayer = NULL;
- pHXCore->QueryInterface(IID_IHXPlayer, (void**)&pPlayer);
- if (pPlayer)
- {
- #if defined(HELIX_FEATURE_REGISTRY)
- // Get the player's registry
- IHXRegistryID *pRegistryId = NULL;
- pPlayer->QueryInterface(IID_IHXRegistryID, (void**)&pRegistryId);
- UINT32 ulPlayerRegistryID = 0;
- if (pRegistryId)
- {
- // Get the player's base registry name
- pRegistryId->GetID(ulPlayerRegistryID);
- HX_RELEASE(pRegistryId);
- }
-
- // Get the core's registry
- pHXCore->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
- if (m_pRegistry)
- {
- if (ulPlayerRegistryID)
- {
- m_pRegistry->GetPropName(ulPlayerRegistryID, m_szPlayerReg);
- m_szPlayerReg->SetSize(m_szPlayerReg->GetSize() + 25);
- strcat((char*)m_szPlayerReg->GetBuffer(), ".Author"); /* Flawfinder: ignore */
- }
- }
- #endif /* #if defined(HELIX_FEATURE_REGISTRY) */
- pPlayer->Release();
- m_bStreaming = 0;
- m_bLicensed = 1;
- }
- #if defined (MPA_FMT_DRAFT00) && defined(HELIX_FEATURE_REGISTRY)
- else
- {
- // Query registry interface
- INT32 nLicensed = 0;
- IHXRegistry *pRegistry = NULL;
- pHXCore->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
-
- if (!pRegistry)
- return HXR_UNEXPECTED;
-
- // On the Server, check the license section of the registry
- if (HXR_OK != pRegistry->GetIntByName(REGISTRY_REALMPA_ENABLED, nLicensed))
- nLicensed = LICENSE_REALMPA_ENABLED;
- m_bLicensed = (nLicensed) ? (TRUE) : (FALSE);
- HX_RELEASE(pRegistry);
- }
- #endif //MPA_FMT_DRAFT00
- pHXCore->QueryInterface(IID_IHXErrorMessages, (void**)&m_pError);
-
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXFileFormatObject::InitFileFormat ref: hxformt.h
- //
- // This routine initializes the file, and stores references to objects used
- // throughout the example. It is called whenever an URL associated with this
- // plug-in is opened.
- //
- STDMETHODIMP
- CRnMp3Fmt::InitFileFormat(IHXRequest* pRequest,
- IHXFormatResponse* pFormatResponse,
- IHXFileObject* pFileObject)
- {
- // The format response object is used to notify RMA core of our status
- m_pStatus = pFormatResponse;
- if (m_pStatus != NULL)
- m_pStatus->AddRef();
- #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO)
- // See if meta info has been requested
- BOOL bAcceptMetaInfo = m_bAcceptMetaInfo;
- BOOL bAllMetaInfo = m_bAllMetaInfo;
- CheckMetaInfoRequest(pRequest,
- m_pClassFactory,
- bAcceptMetaInfo,
- bAllMetaInfo,
- m_pMetaProps);
- m_bAcceptMetaInfo = bAcceptMetaInfo;
- m_bAllMetaInfo = bAllMetaInfo;
- #endif /* #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO) */
- // The file object is used to handle file I/O
- m_pFileObj = pFileObject;
- if (m_pFileObj != NULL)
- {
- m_pFileObj->AddRef();
-
- // Initialize and check validity of file. Also, associate the file
- // with a response object which is notified when the file operation is
- // complete.
- m_bClosed = FALSE;
- m_State = InitPending;
- m_pFileObj->Init(HX_FILE_READ | HX_FILE_BINARY, this); // asynchronous
- // Since this class was designated at the response object, this
- // class's IHXFileResponse::InitDone method will be called when
- // the initialization of the file is complete. (See InitDone).
- }
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXFileResponse::InitDone ref: hxfiles.h
- //
- // This routine notifies the RMA core that the initialization of the file is
- // done. It is called automatically when the initialization of the file
- // has completed.
- //
- STDMETHODIMP
- CRnMp3Fmt::InitDone(HX_RESULT status)
- {
- if (m_State != InitPending)
- return HXR_UNEXPECTED;
- IHXFileStat *pStat = NULL;
- m_pFileObj->QueryInterface(IID_IHXFileStat, (void**)&pStat);
- if (pStat)
- {
- pStat->Stat((IHXFileStatResponse*)this);
- pStat->Release();
- }
- // Notify RMA core that intialization started in InitFileFormat is done
- m_State = Ready;
- AddRef();
- m_pStatus->InitDone(status);
- #if defined (MPA_FMT_DRAFT00)
- if (!m_bClosed && m_bStreaming && !m_bRtp)
- m_pFmtBuf = new CIHXRingBuffer(m_pClassFactory, 8192, (1024<<1)+512);
- #endif //MPA_FMT_DRAFT00
- Release();
- // There are 2 ways to get a packet buffer: a heap optimal way
- // (the 'new' way), or the 'old' way, which involves making a
- // whole new buffer. We can't optimize heap usage (by re-using
- // the read buffer) if m_bRtp is true, because that requires
- // increasing the buffer size: see code under comment 'Copy the
- // rtp payload header'. We do this here because m_bRtp is set in
- // SetPacketFormat, which will have been called at this point.
- // We also use the 'old' packet buffer getter if we are running
- // as part of the server (m_bStreaming -- bad name), or if we are
- // playing a metadata file.
- if( m_bStreaming || m_bRtp || m_pMp3Fmt->GetMetaRepeat() )
- {
- m_pCreatePacketFunction = &OldPacketBufferGetter;
- }
- else
- {
- m_pCreatePacketFunction = &NewPacketBufferGetter;
- }
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // IHXFileFormatObject::GetFileHeader ref: hxformt.h
- //
- // This routine returns to the RMA core an object containing the file
- // header information. Several routines are actually required to complete
- // the process due to the asynchronous nature of the RMA file system. This
- // method is called by the RMA core after the file has been initialized.
- //
- STDMETHODIMP
- CRnMp3Fmt::GetFileHeader(void)
- {
- if (m_State != Ready)
- return HXR_UNEXPECTED;
- // For local files, look for ID3 v1 tags
- if (m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESS) != HXR_ADVISE_PREFER_LINEAR &&
- m_ulFileSize > ID3HeaderLen)
- {
- m_State = GetId3HeaderSeekPending;
-
- // Inform the file system that we need an actual seek. An http seek
- // may download all the data to the seek point which is bad especially
- // on a huge seek.
- m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESSONLY);
-
- // For some reason, http 1.1 servers on mp3.com do not give us data if
- // we seek to the last 128 bytes. So, fudge this to seek to 129
- // bytes from the end (ID3HeaderLen-1) and adjust the read pointer
- // in ReadDone.
- m_pFileObj->Seek(m_ulFileSize-ID3HeaderLen-BytesBeforeID3Header, FALSE);
-
- return HXR_OK;
- }
- // Since Seek() is asynchronous we need to note our state in order to
- // correctly respond in SeekDone() when finished.
- m_State = GetFileHeaderSeekPending;
- // Move to the beginning of the header data in the file
- m_pFileObj->Seek(MY_FILE_HEADER_START+m_ulFileOffset, FALSE);
- return HXR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // CRnMp3Fmt::MyCreateFileHeaderObj_hr ref: filefmt1.h
- //
- // This routine creates a "file header" object and passes it off to the
- // RMA core, which in turn transports it to the renderer. This object must
- // contain a property stating the number of streams contained in this file
- // format. Any additional header information read from the file can also be
- // placed in this object. This method is called after the header data from
- // the file has been completely read.
- //
- HX_RESULT
- CRnMp3Fmt::MyCreateFileHeaderObj_hr(HX_RESULT status,
- IHXBuffer* pHeader)
- {
- // We are in the process of handling the GetFileHeader() request...
- // See GetFileHeader(), SeekDone(), and ReadDone() for previous steps.
- m_State = Ready;
- // Create new object containing the header data
- IHXValues* pHeaderObj = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXValues, (void**)&pHeaderObj);
- if (pHeaderObj != NULL)
- {
- char pUpgrade[16] = "