mp3ff.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:83k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // Defines
  37. #define   INITGUID     // Interface ID's
  38. ///////////////////////////////////////////////////////////////////////////////
  39. // Includes
  40. #include "hlxclib/string.h"     // strrchr
  41. #include "hlxclib/stdlib.h"     // atol
  42. #include "hlxclib/stdio.h"      // sprintf
  43. #include "hxtypes.h"    // Standard Real types
  44. #include "hxcom.h"      // IUnknown
  45. #include "hxcomm.h"     // IHXCommonClassFactory
  46. #include "ihxpckts.h"   // IHXBuffer, IHXPacket, IHXValues
  47. #include "hxplugn.h"    // IHXPlugin
  48. #include "hxfiles.h"    // IHXFileResponse
  49. #include "hxformt.h"    // IHXFileFormatObject
  50. #include "hxcore.h"     // IHXPlayer
  51. #include "hxerror.h"    // IHXErrorMessages
  52. #include "hxmon.h"      // IHXRegistry
  53. #include "defslice.h"   // Registry types
  54. #include "dbcsutil.h"   // Double byte char set functions
  55. #include "hxver.h"
  56. #include "hxupgrd.h"    // IHXUpgradeCollection
  57. #include "hxbuffer.h"
  58. #include "ringbuf.h"
  59. #include "mp3format.h"  // CMp3Format
  60. #include "mp3ff.h"      // CRnMp3Fmt
  61. #include "mhead.h"      // MP3 header info
  62. #include "dxhead.h"     // Xing MP3 header info
  63. #include "pckunpck.h"
  64. #include "metautil.h"
  65. #include "hxstrutl.h"
  66. #define MP3FF_4BYTE_SYSTEM 0x000001ba
  67. #define MP3FF_4BYTE_VIDEO  0x000001b3
  68. #define MP3FF_4BYTE_RIFF   0x52494646
  69. #define MP3FF_4BYTE_CDXA   0x43445841
  70. #define MP3FF_4BYTE_free   0x66726565
  71. #define MP3FF_4BYTE_skip   0x736B6970
  72. #define MP3FF_4BYTE_pnot   0x706e6f74
  73. #define MP3FF_4BYTE_mdat   0x6d646174
  74. #define MP3FF_4BYTE_moov   0x6d6f6f76
  75. //#include "rmfftype.h" // for the HX_SAVE_ENABLED flag
  76. #ifdef _AIX
  77. #include "dllpath.h"
  78. ENABLE_MULTILOAD_DLLACCESS_PATHS(Rnmp3fmt);
  79. #endif
  80. IHXBuffer* NewPacketBufferGetter(
  81.    IHXCommonClassFactory * pClassFactory, // not used for new version
  82.    IHXBuffer * pExistingBuffer,
  83.    UCHAR * pModFrameStart,
  84.    int nModFrameSize
  85. )
  86. {
  87.    IHXBuffer * pPacketBuffer = new CHXBufferFragment(
  88.       pExistingBuffer,
  89.       pModFrameStart,
  90.       nModFrameSize);
  91.    pPacketBuffer->AddRef();
  92.    return pPacketBuffer;
  93. }
  94. IHXBuffer* OldPacketBufferGetter(
  95.    IHXCommonClassFactory * pClassFactory,
  96.    IHXBuffer * pExistingBuffer, // not used for old version
  97.    UCHAR * pModFrameStart, // not used for old version
  98.    int nModFrameSize // not used for old version
  99. )
  100. {
  101.    IHXBuffer * pPacketBuffer = NULL;
  102.    pClassFactory->CreateInstance(CLSID_IHXBuffer,
  103.       (void**)&pPacketBuffer);
  104.    return pPacketBuffer;
  105. }
  106. ///////////////////////////////////////////////////////////////////////////////
  107. //  HXCreateInstance                                        ref:  hxplugn.h
  108. //
  109. //  This routine creates a new instance of the CRnMp3Fmt class.
  110. //  It is called when the RMA core application is launched, and whenever
  111. //  an URL associated with this plug-in is opened.
  112. STDAPI ENTRYPOINT
  113. (HXCREATEINSTANCE)(IUnknown** ppExFileFormatObj)
  114. {
  115.     *ppExFileFormatObj = (IUnknown*)(IHXPlugin*)new CRnMp3Fmt();
  116.     if (*ppExFileFormatObj != NULL)
  117.     {
  118.         (*ppExFileFormatObj)->AddRef();
  119.         return HXR_OK;
  120.     }
  121.     return HXR_OUTOFMEMORY;
  122. }
  123. /****************************************************************************
  124.  * 
  125.  *  Function:
  126.  * 
  127.  *  CanUnload2()
  128.  * 
  129.  *  Purpose:
  130.  * 
  131.  *  Function implemented by all plugin DLL's if it returns HXR_OK 
  132.  *  then the pluginhandler can unload the DLL
  133.  *
  134.  */
  135. STDAPI ENTRYPOINT(CanUnload2)(void)
  136. {
  137.     return (CHXBaseCountingObject::ObjectsActive() > 0 ? HXR_FAIL : HXR_OK );
  138. }
  139. ///////////////////////////////////////////////////////////////////////////////
  140. //  CRnMp3Fmt static variables                    ref:  filefmt1.h
  141. //
  142. //  These variables are passed to the RMA core to provide information about
  143. //  this plug-in. They are required to be static in order to remain valid
  144. //  for the lifetime of the plug-in.
  145. const char* const CRnMp3Fmt::zm_pDescription = MY_DESCRIPTION;
  146. const char* const CRnMp3Fmt::zm_pCopyright   = HXVER_COPYRIGHT;
  147. const char* const CRnMp3Fmt::zm_pMoreInfoURL = HXVER_MOREINFO;
  148. const char* const CRnMp3Fmt::zm_pFileMimeTypes[]  = MY_FILE_MIME_TYPES;
  149. const char* const CRnMp3Fmt::zm_pFileExtensions[] = MY_FILE_EXTENSIONS;
  150. const char* const CRnMp3Fmt::zm_pFileOpenNames[]  = MY_FILE_OPEN_NAMES;
  151. // Leave rtp out until the bug is fixed that makes it always get used.
  152. //const char* CRnMp3Fmt::zm_pPacketFormats[]  = {"rdt", "rtp", NULL};
  153. const char* const CRnMp3Fmt::zm_pPacketFormats[]  = {"rdt", NULL};
  154. ///////////////////////////////////////////////////////////////////////////////
  155. //  CRnMp3Fmt::CRnMp3Fmt               ref:  filefmt1.h
  156. //
  157. //  Constructor
  158. //
  159. CRnMp3Fmt::CRnMp3Fmt(void)
  160.     : m_RefCount      (0),
  161.       m_pClassFactory (NULL),
  162.       m_pFileObj      (NULL),
  163.       m_pStatus       (NULL),
  164.       m_pError        (NULL),
  165.       m_pRegistry     (NULL),
  166.       m_szPlayerReg   (NULL),
  167.       m_State         (Ready),
  168.       m_ulNextPacketDeliveryTime(0),
  169.       m_ulFileSize(0),
  170.       m_ulMetaReadSize(0),
  171.       m_ulNextMetaPos((UINT32)-1),
  172.       m_ulMetaLength(0),
  173.       m_ulMaxSampRate(0),
  174.       m_ulBytesRead(0),
  175.       m_ulFileOffset(0),
  176.       m_nChannels(0),
  177.       m_dNextPts(0.0),
  178.       m_bEOF(0),
  179.       m_bRtp(0),
  180.       m_bHasVbrHdr(0),
  181.       m_bSkipVbrHdr(0),
  182.       m_bStreaming(0),
  183.       m_bMetaPacket(0),
  184.       m_bNeedPacket(0),
  185.       m_bCheckBadData(0),
  186.       m_bLive(0),
  187.       m_bLicensed(0),
  188.       m_pFmtBuf(NULL),
  189.       m_pMp3Fmt(NULL),
  190.       m_ulGarbageBytesRead(0),
  191.       m_bAcceptMetaInfo(FALSE),
  192.       m_bAllMetaInfo(FALSE),
  193.       m_pMetaProps(NULL),
  194.       m_pContext(NULL),
  195.       m_bIsVBR(FALSE),
  196.       m_bFirstMeta(FALSE),
  197.       m_bClosed(TRUE),
  198.       m_pCreatePacketFunction(NULL)
  199. {
  200.     memset(&m_ReadBuf, 0, sizeof(m_ReadBuf));
  201.     memset(&m_Info, 0, sizeof(m_Info));
  202.     memset(&m_RtpPackets, 0, sizeof(m_RtpPackets));
  203.     m_pMp3Fmt = new CMp3Format;
  204. }
  205. #if defined(MPA_FMT_DRAFT00)
  206. ///////////////////////////////////////////////////////////////////////////
  207. // IHXPacketFormat Interface Methods                   ref:  rmaformat.h
  208. ///////////////////////////////////////////////////////////////////////////
  209. STDMETHODIMP CRnMp3Fmt::GetSupportedPacketFormats(REF(const char**) pFormats)
  210. {
  211.     pFormats = (const char**) zm_pPacketFormats;
  212.     return HXR_OK;
  213. }
  214. STDMETHODIMP CRnMp3Fmt::SetPacketFormat(const char* pFormat)
  215. {
  216.     if (!strcmp(pFormat, "rtp"))
  217.         m_bRtp = 1;
  218.     else
  219.         m_bRtp = 0;
  220.     return HXR_OK;
  221. }
  222. #endif /* #if defined(MPA_FMT_DRAFT00) */
  223. ///////////////////////////////////////////////////////////////////////////////
  224. //  IHXPlugin::GetPluginInfo                                ref:  hxplugn.h
  225. //
  226. //  This routine returns descriptive information about the plug-in, most
  227. //  of which is used in the About box of the user interface. It is called
  228. //  when the RMA core application is launched.
  229. //
  230. STDMETHODIMP 
  231. CRnMp3Fmt::GetPluginInfo(REF(int)         bLoadMultiple,
  232.                          REF(const char*) pDescription,
  233.                          REF(const char*) pCopyright,
  234.                          REF(const char*) pMoreInfoURL,
  235.                          REF(UINT32)      versionNumber)
  236. {
  237.     // File Format plug-ins MUST be able to be multiply instantiated
  238.     bLoadMultiple = TRUE;
  239.     pDescription  = (const char*) zm_pDescription;
  240.     pCopyright    = (const char*) zm_pCopyright;
  241.     pMoreInfoURL  = (const char*) zm_pMoreInfoURL;
  242.     versionNumber = MY_PLUGIN_VERSION;
  243.     return HXR_OK;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. //  IHXThreadSafeMethods::IsThreadsafe                        ref:  hxengin.h
  247. //
  248. //  This routine returns threadsafeness informaiton about the plugin
  249. //  which is used by the server for improved performance.
  250. //
  251. STDMETHODIMP_(UINT32)
  252. CRnMp3Fmt::IsThreadSafe()
  253. {
  254.     return HX_THREADSAFE_METHOD_FF_GETPACKET | HX_THREADSAFE_METHOD_FSR_READDONE;
  255. }
  256. ///////////////////////////////////////////////////////////////////////////////
  257. //  IHXFileFormatObject::GetFileFormatInfo                  ref:  hxformt.h
  258. //
  259. //  This routine returns crucial information required to associate this
  260. //  plug-in with a given MIME type. This information tells the core which
  261. //  File Format plug-in to use for a particular URL. The routine is called
  262. //  when the RMA core application is launched.
  263. //
  264. STDMETHODIMP
  265. CRnMp3Fmt::GetFileFormatInfo(REF(const char**) pFileMimeTypes,
  266.                              REF(const char**) pFileExtensions,
  267.                              REF(const char**) pFileOpenNames)
  268. {
  269.     pFileMimeTypes  = (const char**) zm_pFileMimeTypes;
  270.     pFileExtensions = (const char**) zm_pFileExtensions;
  271.     pFileOpenNames  = (const char**) zm_pFileOpenNames;
  272.     return HXR_OK;
  273. }
  274. ///////////////////////////////////////////////////////////////////////////////
  275. //  IHXPlugin::InitPlugin                                   ref:  hxplugn.h
  276. //
  277. //  This routine performs initialization steps such as determining whether
  278. //  required interfaces are available. It is called when the RMA core 
  279. //  application is launched, and whenever an URL associated with this
  280. //  plug-in is opened.
  281. //
  282. STDMETHODIMP
  283. CRnMp3Fmt::InitPlugin(IUnknown* pHXCore)
  284. {
  285.     HX_RELEASE(m_pContext);
  286.     m_pContext = pHXCore;
  287.     m_pContext->AddRef();
  288.     pHXCore->QueryInterface(IID_IHXCommonClassFactory, 
  289.                               (void**)&m_pClassFactory);
  290.     if (m_pClassFactory == NULL)
  291.         return HXR_NOTIMPL;
  292.     m_bStreaming = 1;
  293.     // Check if we are being loaded by the player or ther server.  If
  294.     // the context contains IHXPlayer, we are in the player, else, we
  295.     // are in the server.  This determines whether packet loss is possilbe
  296.     // or not (only possible in the server).  So, if m_bStreaming is
  297.     // set to 1, we must do data reformatting to handle packet loss in the
  298.     // render plugin.
  299.     //
  300.     // Also, check the server license for streaming mpa
  301.     IHXPlayer  *pPlayer = NULL;
  302.     pHXCore->QueryInterface(IID_IHXPlayer, (void**)&pPlayer);
  303.     if (pPlayer)
  304.     {
  305. #if defined(HELIX_FEATURE_REGISTRY)
  306.         // Get the player's registry
  307.         IHXRegistryID *pRegistryId = NULL;
  308.         pPlayer->QueryInterface(IID_IHXRegistryID, (void**)&pRegistryId);
  309.         UINT32 ulPlayerRegistryID = 0;
  310.         if (pRegistryId)
  311.         {
  312.             // Get the player's base registry name
  313.             pRegistryId->GetID(ulPlayerRegistryID);
  314.             HX_RELEASE(pRegistryId);
  315.         }
  316.         
  317.         // Get the core's registry
  318.         pHXCore->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
  319.         if (m_pRegistry)
  320.         {
  321.             if (ulPlayerRegistryID)
  322.             {
  323.                 m_pRegistry->GetPropName(ulPlayerRegistryID, m_szPlayerReg);
  324.                 m_szPlayerReg->SetSize(m_szPlayerReg->GetSize() + 25);
  325.                 strcat((char*)m_szPlayerReg->GetBuffer(), ".Author"); /* Flawfinder: ignore */
  326.             }
  327.         }
  328. #endif /* #if defined(HELIX_FEATURE_REGISTRY) */
  329.         pPlayer->Release();
  330.         m_bStreaming = 0;
  331.         m_bLicensed = 1;
  332.     }
  333. #if defined (MPA_FMT_DRAFT00) && defined(HELIX_FEATURE_REGISTRY)
  334.     else
  335.     {
  336.         // Query registry interface    
  337.         INT32  nLicensed = 0;
  338.         IHXRegistry *pRegistry = NULL;
  339.         pHXCore->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
  340.     
  341.         if (!pRegistry)
  342.             return HXR_UNEXPECTED;
  343.         
  344.         // On the Server, check the license section of the registry
  345.         if (HXR_OK != pRegistry->GetIntByName(REGISTRY_REALMPA_ENABLED, nLicensed))
  346.             nLicensed = LICENSE_REALMPA_ENABLED;
  347.         m_bLicensed = (nLicensed) ? (TRUE) : (FALSE);
  348.         HX_RELEASE(pRegistry);
  349.     }
  350. #endif //MPA_FMT_DRAFT00
  351.     pHXCore->QueryInterface(IID_IHXErrorMessages, (void**)&m_pError);
  352.     
  353.     return HXR_OK;
  354. }
  355. ///////////////////////////////////////////////////////////////////////////////
  356. //  IHXFileFormatObject::InitFileFormat                     ref:  hxformt.h
  357. //
  358. //  This routine initializes the file, and stores references to objects used
  359. //  throughout the example. It is called whenever an URL associated with this
  360. //  plug-in is opened.
  361. //
  362. STDMETHODIMP
  363. CRnMp3Fmt::InitFileFormat(IHXRequest*        pRequest,
  364.                           IHXFormatResponse* pFormatResponse,
  365.                           IHXFileObject*     pFileObject)
  366. {
  367.     // The format response object is used to notify RMA core of our status
  368.     m_pStatus = pFormatResponse;
  369.     if (m_pStatus != NULL)
  370.         m_pStatus->AddRef();
  371. #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO)
  372.     // See if meta info has been requested
  373.     BOOL bAcceptMetaInfo = m_bAcceptMetaInfo;
  374.     BOOL bAllMetaInfo    = m_bAllMetaInfo;
  375.     CheckMetaInfoRequest(pRequest,
  376.                          m_pClassFactory,
  377.                          bAcceptMetaInfo,
  378.                          bAllMetaInfo,
  379.                          m_pMetaProps);
  380.     m_bAcceptMetaInfo = bAcceptMetaInfo;
  381.     m_bAllMetaInfo    = bAllMetaInfo;
  382. #endif /* #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO) */
  383.     // The file object is used to handle file I/O
  384.     m_pFileObj = pFileObject;
  385.     if (m_pFileObj != NULL)
  386.     {
  387.         m_pFileObj->AddRef();
  388.         
  389.         // Initialize and check validity of file. Also, associate the file
  390.         // with a response object which is notified when the file operation is
  391.         // complete.
  392.         m_bClosed = FALSE;
  393.         m_State = InitPending;
  394.         m_pFileObj->Init(HX_FILE_READ | HX_FILE_BINARY, this);  // asynchronous
  395.         // Since this class was designated at the response object, this
  396.         // class's IHXFileResponse::InitDone method will be called when
  397.         // the initialization of the file is complete. (See InitDone).
  398.     } 
  399.     return HXR_OK;
  400. }
  401. ///////////////////////////////////////////////////////////////////////////////
  402. //  IHXFileResponse::InitDone                               ref:  hxfiles.h
  403. //
  404. //  This routine notifies the RMA core that the initialization of the file is
  405. //  done. It is called automatically when the initialization of the file
  406. //  has completed.
  407. //
  408. STDMETHODIMP
  409. CRnMp3Fmt::InitDone(HX_RESULT status)
  410. {
  411.     if (m_State != InitPending)
  412.         return HXR_UNEXPECTED;
  413.     IHXFileStat *pStat = NULL;
  414.     m_pFileObj->QueryInterface(IID_IHXFileStat, (void**)&pStat);
  415.     if (pStat)
  416.     {
  417.         pStat->Stat((IHXFileStatResponse*)this);
  418.         pStat->Release();
  419.     }
  420.     // Notify RMA core that intialization started in InitFileFormat is done
  421.     m_State = Ready;
  422.     AddRef();
  423.     m_pStatus->InitDone(status);
  424. #if defined (MPA_FMT_DRAFT00)    
  425.     if (!m_bClosed && m_bStreaming && !m_bRtp)
  426.         m_pFmtBuf = new CIHXRingBuffer(m_pClassFactory, 8192, (1024<<1)+512);
  427. #endif //MPA_FMT_DRAFT00
  428.     Release();
  429.     // There are 2 ways to get a packet buffer: a heap optimal way 
  430.     // (the 'new' way), or the 'old' way, which involves making a 
  431.     // whole new buffer. We can't optimize heap usage (by re-using 
  432.     // the read buffer) if m_bRtp is true, because that requires 
  433.     // increasing the buffer size: see code under comment 'Copy the 
  434.     // rtp payload header'. We do this here because m_bRtp is set in
  435.     // SetPacketFormat, which will have been called at this point.
  436.     // We also use the 'old' packet buffer getter if we are running
  437.     // as part of the server (m_bStreaming -- bad name), or if we are
  438.     // playing a metadata file.
  439.     if( m_bStreaming || m_bRtp || m_pMp3Fmt->GetMetaRepeat() )
  440.     {
  441.        m_pCreatePacketFunction = &OldPacketBufferGetter;
  442.     }
  443.     else
  444.     {
  445.        m_pCreatePacketFunction = &NewPacketBufferGetter;
  446.     }
  447.     return HXR_OK;
  448. }
  449. ///////////////////////////////////////////////////////////////////////////////
  450. //  IHXFileFormatObject::GetFileHeader                      ref:  hxformt.h
  451. //
  452. //  This routine returns to the RMA core an object containing the file
  453. //  header information. Several routines are actually required to complete
  454. //  the process due to the asynchronous nature of the RMA file system. This
  455. //  method is called by the RMA core after the file has been initialized.
  456. //
  457. STDMETHODIMP
  458. CRnMp3Fmt::GetFileHeader(void)
  459. {
  460.     if (m_State != Ready)
  461.         return HXR_UNEXPECTED;
  462.     // For local files, look for ID3 v1 tags
  463.     if (m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESS) != HXR_ADVISE_PREFER_LINEAR &&
  464.         m_ulFileSize > ID3HeaderLen)
  465.     {
  466.         m_State = GetId3HeaderSeekPending;
  467.         
  468.         // Inform the file system that we need an actual seek.  An http seek
  469.         // may download all the data to the seek point which is bad especially
  470.         // on a huge seek.
  471.         m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESSONLY);
  472.         
  473.         // For some reason, http 1.1 servers on mp3.com do not give us data if
  474.         // we seek to the last 128 bytes. So, fudge this to seek to 129 
  475.         // bytes from the end (ID3HeaderLen-1) and adjust the read pointer
  476.         // in ReadDone.
  477.         m_pFileObj->Seek(m_ulFileSize-ID3HeaderLen-BytesBeforeID3Header, FALSE);
  478.     
  479.         return HXR_OK;
  480.     }
  481.     // Since Seek() is asynchronous we need to note our state in order to
  482.     // correctly respond in SeekDone() when finished.
  483.     m_State = GetFileHeaderSeekPending;
  484.     // Move to the beginning of the header data in the file
  485.     m_pFileObj->Seek(MY_FILE_HEADER_START+m_ulFileOffset, FALSE);
  486.     return HXR_OK;
  487. }
  488. ///////////////////////////////////////////////////////////////////////////////
  489. //  CRnMp3Fmt::MyCreateFileHeaderObj_hr             ref:  filefmt1.h
  490. //
  491. //  This routine creates a "file header" object and passes it off to the
  492. //  RMA core, which in turn transports it to the renderer. This object must
  493. //  contain a property stating the number of streams contained in this file
  494. //  format. Any additional header information read from the file can also be
  495. //  placed in this object. This method is called after the header data from
  496. //  the file has been completely read.
  497. //
  498. HX_RESULT
  499. CRnMp3Fmt::MyCreateFileHeaderObj_hr(HX_RESULT   status,
  500.                                     IHXBuffer* pHeader)
  501. {
  502.     // We are in the process of handling the GetFileHeader() request...
  503.     // See GetFileHeader(), SeekDone(), and ReadDone() for previous steps.
  504.     m_State = Ready;
  505.     // Create new object containing the header data
  506.     IHXValues* pHeaderObj = NULL;
  507.     m_pClassFactory->CreateInstance(CLSID_IHXValues, (void**)&pHeaderObj);
  508.     if (pHeaderObj != NULL)
  509.     {
  510.         char pUpgrade[16] = "";
  511.         HRESULT hr = HXR_OK;
  512.         INT16 wStreams = InitStream_n(pHeader, &m_Info, hr, pUpgrade, sizeof(pUpgrade));
  513.         // The header proceeding the data is too large for
  514.         // our buffer.  So seek past header and try again.
  515.         if (!wStreams)
  516.         {
  517.             pHeaderObj->Release();
  518.             if (m_ulFileOffset)
  519.             {
  520.                 m_State = GetFileHeaderSeekPending;
  521.                 m_pFileObj->Seek(MY_FILE_HEADER_START+m_ulFileOffset, FALSE);
  522.                 return hr;
  523.             }
  524.             // Server is full
  525.             else
  526.             {
  527.                 m_pError->Report(HXLOG_ERR, HXR_NOT_AUTHORIZED, 0,
  528.                                  "The requested server is full.",
  529.                                  MY_MORE_INFO_URL);
  530.                 return HXR_NOT_AUTHORIZED;
  531.             }
  532.         }
  533.         
  534.         // Invalid stream
  535.         else if (wStreams < 0)
  536.         {
  537.             pHeaderObj->Release();
  538. #if defined (MPA_FMT_DRAFT00)
  539.             // Print to common display if we are running on a server
  540.             if (m_bStreaming)
  541.                 printf("Unsupported File Type.  The selected file is not a valid MPEG audio file.n");
  542. #endif //MPA_FMT_DRAFT00
  543.             
  544.             // Send a player AU request if necessary
  545.             IHXPlayer  *pPlayer = NULL;
  546.             m_pContext->QueryInterface(IID_IHXPlayer, (void**)&pPlayer);
  547.             if (pPlayer && strlen(pUpgrade))
  548.             {
  549.                 IHXUpgradeCollection* pUpgradeCol = NULL;
  550.                 pPlayer->QueryInterface(IID_IHXUpgradeCollection, (void**)&pUpgradeCol);
  551.                 if (pUpgradeCol)
  552.                 {
  553.                     IHXBuffer *pText = NULL;
  554.                     m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pText);
  555.                     if (!pText)
  556.                         return HXR_FAIL;
  557.                     pText->Set((const unsigned char*)pUpgrade, strlen(pUpgrade)+1);
  558.                     pUpgradeCol->Add(eUT_FileTypeNotSupported, pText, 0,0);
  559.                     pText->Release();
  560.                 }
  561.                 HX_RELEASE(pUpgradeCol);
  562.             }
  563.             HX_RELEASE(pPlayer);
  564.             
  565.             m_pStatus->FileHeaderReady(hr, NULL);
  566.             return hr;
  567.         }
  568.         pHeaderObj->SetPropertyULONG32("StreamCount",  1);
  569.         
  570.         // Disable slider for "live" streams (http streaming)
  571.         if (m_bLive)
  572.             pHeaderObj->SetPropertyULONG32("LiveStream", 1);
  573.         // Set title
  574.         int   nLen = 0;
  575.         char* pszTmp = (char*) m_pMp3Fmt->GetId3Title(nLen);
  576.         if (nLen)
  577.         {
  578.             SetCStringProperty(pHeaderObj,
  579.                                "Title",
  580.                                (const char*) pszTmp,
  581.                                m_pContext,
  582.                                TRUE); // Forces a SetPropertyBuffer()
  583.         }
  584.         // Set artist
  585.         nLen   = 0;
  586.         pszTmp = (char*) m_pMp3Fmt->GetId3Artist(nLen);
  587.         if (nLen)
  588.         {
  589.             SetCStringProperty(pHeaderObj,
  590.                                "Author",
  591.                                (const char*) pszTmp,
  592.                                m_pContext,
  593.                                TRUE); // Forces a SetPropertyBuffer()
  594.         }
  595.         // Set album
  596.         nLen   = 0;
  597.         pszTmp = (char*) m_pMp3Fmt->GetId3Album(nLen);
  598.         if (nLen)
  599.         {
  600.             SetCStringProperty(pHeaderObj,
  601.                                "Abstract",
  602.                                (const char*) pszTmp,
  603.                                m_pContext,
  604.                                TRUE); // Forces a SetPropertyBuffer()
  605.         }
  606. // Set genre
  607.         nLen   = 0;
  608.         pszTmp = (char*) m_pMp3Fmt->GetId3Genre(nLen);
  609.         if (nLen)
  610.         {
  611.             SetCStringProperty(pHeaderObj,
  612.                                "Genre",
  613.                                (const char*) pszTmp,
  614.                                m_pContext,
  615.                                TRUE); // Forces a SetPropertyBuffer()
  616.         }
  617.         
  618.         // Optional Property: "OpaqueData"
  619.         // Any other user defined data 
  620.         //pHeaderObj->SetPropertyBuffer("OpaqueData", pHeader);
  621.         // Move back to the beginning of the file
  622.         m_pFileObj->Seek(MY_FILE_HEADER_START+m_ulFileOffset, FALSE);
  623.         // do not allow recording of MP3 audio at this time
  624.         //pHeaderObj->SetPropertyULONG32("Flags",HX_SAVE_ENABLED);
  625. #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO)
  626.         // If additional meta info has been requested, then
  627.         // provide it here.
  628.         if (m_bAcceptMetaInfo)
  629.         {
  630.             if (m_bAllMetaInfo)
  631.             {
  632.                 SetMetaInfo(pHeaderObj, "SrcCodec");
  633.                 SetMetaInfo(pHeaderObj, "SrcBitRate");
  634.                 SetMetaInfo(pHeaderObj, "SrcVBREnabled");
  635.                 SetMetaInfo(pHeaderObj, "SrcInterleaved");
  636.                 SetMetaInfo(pHeaderObj, "SrcSamplesPerSecond");
  637.                 SetMetaInfo(pHeaderObj, "SrcBitsPerSample");
  638.                 SetMetaInfo(pHeaderObj, "SrcNumChannels");
  639.             }
  640.             else
  641.             {
  642.                 if (m_pMetaProps)
  643.                 {
  644.                     const char* pszProp = NULL;
  645.                     UINT32      ulTmp   = 0;
  646.                     HX_RESULT rv = m_pMetaProps->GetFirstPropertyULONG32(pszProp, ulTmp);
  647.                     while (SUCCEEDED(rv))
  648.                     {
  649.                         SetMetaInfo(pHeaderObj, pszProp);
  650.                         rv = m_pMetaProps->GetNextPropertyULONG32(pszProp, ulTmp);
  651.                     }
  652.                 }
  653.             }
  654.         }
  655. #endif /* #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO) */
  656.         // Notify the RMA core that header object is ready
  657.         m_pStatus->FileHeaderReady(status, pHeaderObj);
  658.         // Release the object since we are done with it
  659.         pHeaderObj->Release();
  660.     }
  661.     return HXR_OK;
  662. }
  663. ///////////////////////////////////////////////////////////////////////////////
  664. //  IHXFileFormatObject::GetStreamHeader                    ref:  hxformt.h
  665. //
  666. //  This routine returns to the RMA core an object containing the stream
  667. //  header information for a particular stream. Several routines are actually
  668. //  required to complete the process due to the asynchronous nature of the
  669. //  RMA file system. This method is called (after the file header has been
  670. //  read) by the RMA core for each stream in the file format.
  671. //
  672. STDMETHODIMP CRnMp3Fmt::GetStreamHeader(UINT16 streamNo)
  673. {
  674.     if ((m_State != Ready) || (streamNo != MY_STREAM_NO))
  675.         return HXR_UNEXPECTED;
  676.     if (eHXUnknown == m_Info.eType)
  677.         return HXR_INVALID_FILE;
  678.                 
  679.     m_State = GetStreamHeaderSeekPending;
  680.     MyCreateStreamHeaderObj_v(HX_STATUS_OK, NULL);
  681.     return HXR_OK;
  682. }
  683. ///////////////////////////////////////////////////////////////////////////////
  684. //  CRnMp3Fmt::MyCreateStreamHeaderObj_v            ref:  filefmt1.h
  685. //
  686. //  This routine creates a "stream header" object and passes it off to the
  687. //  RMA core, which in turn transports it to the renderer. This object must
  688. //  contain certain properties required to characterize the stream. Any
  689. //  additional stream information read from the file can also be placed in
  690. //  this object. This method is called after the stream header data from the
  691. //  file has been completely read.
  692. void
  693. CRnMp3Fmt::MyCreateStreamHeaderObj_v(HX_RESULT   status,
  694.                                      IHXBuffer* pStreamHeader)
  695. {
  696.     m_State = Ready;
  697.     // Create new object containing the stream header data
  698.     IHXValues* pStreamHeaderObj = NULL;
  699.     m_pClassFactory->CreateInstance(CLSID_IHXValues,
  700.                                      (void**)&pStreamHeaderObj);
  701.     if (pStreamHeaderObj != NULL)
  702.     {
  703.         // REQUIRED Properties:
  704.         pStreamHeaderObj->SetPropertyULONG32("StreamNumber", MY_STREAM_NO);
  705.         pStreamHeaderObj->SetPropertyULONG32("AvgBitRate", m_Info.ulBitRate);
  706.         pStreamHeaderObj->SetPropertyULONG32("SampleRate", m_ulMaxSampRate);
  707.         pStreamHeaderObj->SetPropertyULONG32("NumChannels", m_nChannels);
  708.         UINT32 ulPreRoll = 1000;
  709.         if (m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESS) == HXR_ADVISE_PREFER_LINEAR)
  710.             ulPreRoll += 2000;
  711.         pStreamHeaderObj->SetPropertyULONG32("Preroll", ulPreRoll);
  712.         m_Info.nPacketSize = min(m_Info.nPacketSize, kReadSize);
  713.         double dDur;
  714.         dDur = m_ulFileSize / (double)(m_Info.ulBitRate>>3) * 1000.0;
  715.         
  716.         pStreamHeaderObj->SetPropertyULONG32("Duration", (UINT32)dDur);
  717.         pStreamHeaderObj->SetPropertyULONG32("MaxPacketSize", 1024);
  718.         pStreamHeaderObj->SetPropertyULONG32("AvgPacketSize", m_Info.nPacketSize);
  719.         pStreamHeaderObj->SetPropertyULONG32("StartTime", 0);
  720. #if defined (MPA_FMT_DRAFT00)
  721.         // MPA is 14 Dynamic is > 96
  722.         if (m_bRtp)
  723.         {
  724.             pStreamHeaderObj->SetPropertyULONG32("RTPPayloadType", 14);
  725.             pStreamHeaderObj->SetPropertyULONG32("RTPTimestampConversionFactor", 90);
  726.             pStreamHeaderObj->SetPropertyULONG32("HXTimestampConversionFactor", 1);
  727.         }
  728. #endif //MPA_FMT_DRAFT00
  729.         
  730.         // "MimeType": this stream's MIME type. This associates this
  731.         // stream type with a particular renderer.
  732.         const char* pszTmp = MY_LOCAL_MIME_TYPE;
  733. #if defined (MPA_FMT_DRAFT00)
  734.         if (m_bStreaming)
  735.         {
  736.             if(m_bRtp)
  737.                 pszTmp = MY_RTP_MIME_TYPE;
  738.             else
  739.                 pszTmp = MY_STREAM_MIME_TYPE;
  740.         }
  741. #endif //MPA_FMT_DRAFT00
  742.         SetCStringProperty(pStreamHeaderObj, "MimeType", pszTmp, m_pContext);
  743.         // Set the ASM rule book
  744.         char* pRuleBook = new char[sizeof(char) * 100];
  745.         if (pRuleBook)
  746.         {
  747.             // Create the string
  748.             if (m_bRtp)
  749.             {
  750.                 SafeSprintf(pRuleBook, 100,
  751.                             "marker=0, AverageBandwidth=%ld, Priority=9, "
  752.                             "timestampdelivery=true;",
  753.                             m_Info.ulBitRate); 
  754.             }
  755.             else
  756.             {
  757.                 SafeSprintf(pRuleBook, 100,
  758.                             "AverageBandwidth=%ld, AverageBandwidthStd=0, "
  759.                             "Priority=9;",
  760.                             m_Info.ulBitRate);
  761.             }
  762.             // Set it into the stream header
  763.             SetCStringProperty(pStreamHeaderObj, "ASMRuleBook",
  764.                                (const char*) pRuleBook, m_pContext);
  765.         }
  766.         HX_VECTOR_DELETE(pRuleBook);
  767. #if defined(HELIX_FEATURE_SERVER)
  768.         if (!m_bLicensed)
  769.         {
  770.             if (m_pError)
  771.             {
  772.                 m_pError->Report(HXLOG_ALERT, HXR_NOT_LICENSED, 
  773.                         0, "This server is NOT licensed to deliver MPEG Audio "
  774.                         "streams. A Player attempting to access MPEG Audio content "
  775.                         "has been disconnected. Please contact RealNetworks to "
  776.                         "obtain a license for this feature.n", NULL);
  777.             }
  778.             status = HXR_NOT_LICENSED;
  779.         }
  780. #endif /* #if defined(HELIX_FEATURE_SERVER) */
  781.         
  782.         // Notify the RMA core that stream header object is ready
  783.         m_pStatus->StreamHeaderReady(status, pStreamHeaderObj);
  784.         // Release the object since we are done with it
  785.         pStreamHeaderObj->Release();
  786.     }
  787. }
  788. ///////////////////////////////////////////////////////////////////////////////
  789. //  IHXFileFormatObject::GetPacket                          ref:  hxformt.h
  790. //
  791. //  This routine returns to the RMA core an object containing the packet
  792. //  data for a particular stream. Several routines are actually required to
  793. //  complete the process due to the asynchronous nature of the RMA file
  794. //  system. This method is called by the RMA core each time it needs another
  795. //  packet.
  796. //
  797. STDMETHODIMP
  798. CRnMp3Fmt::GetPacket(UINT16 streamNo)
  799. {
  800.     // with asyncfsys it is possible that a GetPacket() call is outstanding
  801.     // even after Close() has been called. so check for m_bClosed for that
  802.     // case (b'cuz m_pFileObj is released inside Close())
  803.     if (m_bClosed || (m_State != Ready) || (streamNo != MY_STREAM_NO))
  804.         return HXR_UNEXPECTED;
  805.     // Read our first buffer
  806.     if (!m_ReadBuf.pReadBuffer)
  807.     {
  808.         m_bNeedPacket = 1;
  809.         m_State = GetPacketReadPending;
  810.         m_pFileObj->Read(kReadSize);
  811.         return HXR_OK;
  812.     }
  813.     return MyCreatePacketObj_hr(m_ReadBuf.status, &m_ReadBuf);
  814. }
  815. ///////////////////////////////////////////////////////////////////////////////
  816. //  CRnMp3Fmt::MyCreatePacketObj_hr                 ref:  filefmt1.h
  817. //
  818. //  This routine creates a packet object and passes it off to the RMA core,
  819. //  which in turn transports it to the renderer. The object contains the
  820. //  packet data read from the file along with the time when it should be
  821. //  delivered to the renderer. If there are no more packets available for
  822. //  this stream, the RMA core is notified. This method is called after the
  823. //  packet data from the file has been read.
  824. //
  825. HX_RESULT
  826. CRnMp3Fmt::MyCreatePacketObj_hr(HX_RESULT   status,
  827.                                 tReadBuffer* pPacketData)
  828. {
  829.     m_State = Ready;
  830.     if (status == HX_STATUS_OK)
  831.     {
  832.         // Create new object containing the packet data
  833.         IHXPacket* pPacketObj = NULL;
  834.         m_pClassFactory->CreateInstance(CLSID_IHXPacket,
  835.                                          (void**)&pPacketObj);
  836.         if (pPacketObj != NULL)
  837.         {
  838.             // Fill in the packet
  839.             UINT32 deliveryTime = m_ulNextPacketDeliveryTime;
  840.             UINT16 streamNo     = MY_STREAM_NO;
  841.             UINT8  ASMFlags     = HX_ASM_SWITCH_ON | HX_ASM_SWITCH_OFF;
  842.             UINT16 ASMRuleNo    = 0;
  843.     
  844.             IHXBuffer* pPacketBuffer = NULL;
  845. TOP:
  846.             int     nSyncSize = 0;
  847.             UCHAR   *pModFrameStart = NULL;
  848.             // Extract an audio frame from the read buffer
  849.             pModFrameStart = GetMP3Frame_p(pPacketData, nSyncSize);
  850.             // Handle read buffer wraps
  851.             if (!pModFrameStart)
  852.             {
  853.                 UCHAR   bNoData = m_bEOF;
  854.                 
  855.                 // Check for mp3 streams w/ garbage on the end (non-SureStream)
  856.                 // If the next 2 bytes are not a sync word, stop playback
  857.                 if (pPacketData->dwBytesRemaining >= 2)
  858.                 {
  859.                     if (pPacketData->pBuffer[0] != 0xFF ||
  860.                         !m_pMp3Fmt->IsValidSyncWord(pPacketData->pBuffer[1]))
  861.                     {
  862.                         // The rest of this buffer does not contain
  863.                         // a syncword, so skip the buffer
  864.                         m_bCheckBadData = 1;
  865.                     }
  866.                     else
  867.                     {
  868.                         // We have a syncword, but just not
  869.                         // enough data in the buffer to complete the
  870.                         // frame. So this is NOT bad data, just another
  871.                         // read is necessary
  872.                         m_bCheckBadData = 0;
  873.                     }
  874.                 }
  875.                 
  876.                 if (bNoData)
  877.                 {
  878. #if defined (MPA_FMT_DRAFT00)
  879.                      // Check for last frame when streaming - we buffer one frame   
  880.                      if (m_bStreaming && !m_bRtp)   
  881.                      {   
  882.                          UINT32 ulTemp = 0;   
  883.                          pModFrameStart = m_pFmtBuf->GetReadPointer(ulTemp);   
  884.                             
  885.                          bNoData = (ulTemp == 0);   
  886.                      }
  887. #endif //MPA_FMT_DRAFT00
  888.     
  889.                      if (bNoData)   
  890.                      { 
  891.                     
  892.                         HX_RELEASE(pPacketData->pReadBuffer);
  893.                         pPacketData->dwBytesRemaining = 0;
  894.                         m_bEOF = TRUE;
  895.                         m_pStatus->StreamDone(0);
  896.                         pPacketObj->Release();
  897.                         if (pPacketBuffer)
  898.                             pPacketBuffer->Release();
  899.                         return HXR_OK;
  900.                     }
  901.                 }
  902.                 
  903.                 // If we need more data, seek back the number of bytes
  904.                 // we have left and read more.
  905.                 if (!pModFrameStart)
  906.                 {
  907.                     m_bNeedPacket = 1;
  908.                     m_State = GetPacketSeekPending;
  909.                     // XXXMEH - if m_bCheckBadData == 0, then we
  910.                     // found a frame, but it is just incomplete.
  911.                     // Therefore, we need to read some more to
  912.                     // complete the frame. This is a normal occurrence.
  913.                     // We will seek to the end of the last frame we 
  914.                     // found and do a read. This should allow us to
  915.                     // get the entire frame in the read buffer.
  916.                     // However, if m_bCheckBadData == 1, then we
  917.                     // didn't find a frame in the rest of the buffer
  918.                     // we currently have. Therefore, don't want to 
  919.                     // seek to the end of the last frame, we want to
  920.                     // seek to the end of where we just read, thus
  921.                     // skipping this data in which we know no frames
  922.                     // are present.
  923.                     if (!m_bCheckBadData)
  924.                     {
  925.                         m_ulBytesRead -= pPacketData->dwBytesRemaining;
  926.                     }
  927.                     else
  928.                     {
  929.                         // Add to the amount of bad data we're skipping
  930.                         m_ulGarbageBytesRead += pPacketData->dwBytesRemaining;
  931.                     }
  932.                     pPacketData->dwBytesRemaining = 0;
  933.                     HX_RELEASE(pPacketData->pReadBuffer);
  934.                     if (m_ulGarbageBytesRead < MAX_GARBAGE_BYTES)
  935.                     {
  936.                         m_pFileObj->Seek(m_ulBytesRead, FALSE);
  937.                     }
  938.                     else
  939.                     {
  940.                         m_State = Ready;
  941.                         m_pStatus->StreamDone(0);
  942.                     }
  943.         
  944.                     pPacketObj->Release();
  945.                     if (pPacketBuffer)
  946.                         pPacketBuffer->Release();
  947.                     return HXR_OK;
  948.                 }
  949.             }
  950.             else
  951.             {
  952.                 UINT32 ulOffset = m_ulBytesRead - pPacketData->dwBytesRemaining;
  953. //                char szDbgStr[256];
  954. //                sprintf(szDbgStr, "Frame of size %d found at offset %lu (%02x %02x %02x %02x) next offset = %lun",
  955. //                        nSyncSize, ulOffset, pPacketData->pBuffer[0], pPacketData->pBuffer[1],
  956. //                        pPacketData->pBuffer[2], pPacketData->pBuffer[3], ulOffset + nSyncSize);
  957. //                OutputDebugString(szDbgStr);
  958.             }
  959.             // Reformat the current MP3 frame if we are streaming
  960.             int nModFrameSize = nSyncSize;
  961.             
  962. #if defined (MPA_FMT_DRAFT00)
  963.             if (m_bStreaming && !m_bRtp)
  964.             {
  965.                 // We need 1+ audio frames
  966.                 UINT32  ulReadSize = 0;
  967.                 pModFrameStart = m_pFmtBuf->GetReadPointer(ulReadSize);
  968.                 UINT32 nSync = m_pMp3Fmt->CheckValidFrame(pModFrameStart, ulReadSize);
  969.                 if (ulReadSize >= nSync + 6 ||
  970.                     m_bEOF)
  971.                 {
  972.                     nModFrameSize = m_pMp3Fmt->ReformatMP3Frame(&pModFrameStart,
  973.                                                                ulReadSize,
  974.                                                                m_pFmtBuf->GetPrevBytes());
  975.                     // If we did not have enough back data to reformat, skip this frame
  976.                     // in the format buffer
  977.                     if (!nModFrameSize)                        
  978.                         m_pFmtBuf->AdvanceRead(nSync);
  979.                 }
  980.                 else
  981.                     nModFrameSize = 0;
  982.                 
  983.                 if (nModFrameSize)
  984.                     m_pFmtBuf->AdvanceRead(nSync);
  985.                 else
  986.                 {
  987.                     // Are we advancing the buffer by some
  988.                     // positive amount?
  989.                     if (nSyncSize > 0)
  990.                     {
  991.                         // Move to next sync word
  992.                         pPacketData->pBuffer += nSyncSize;
  993.                         pPacketData->dwBytesRemaining -= nSyncSize;
  994.                 
  995.                         goto TOP;
  996.                     }
  997.                     else
  998.                     {
  999.                         // If we get here, then we have gotten
  1000.                         // lost on parsing this file, and likely
  1001.                         // the file is corrupt or unsupported.
  1002.                         // If we had tried to advance the buffer
  1003.                         // by zero, we would have entered an infinite
  1004.                         // loop. Therefore, we bail out.
  1005.                         HX_RELEASE(pPacketData->pReadBuffer);
  1006.                         m_pStatus->StreamDone(0);
  1007.                         return HXR_OK;
  1008.                     }
  1009.                 }
  1010.             }
  1011. #endif //MPA_FMT_DRAFT00
  1012.     // We need the pPacketBuffer here, but not before.
  1013.     pPacketBuffer = (*m_pCreatePacketFunction)( m_pClassFactory, 
  1014. pPacketData->pReadBuffer,
  1015. pModFrameStart,
  1016. nModFrameSize );
  1017.             // Set packet data
  1018.             if (nModFrameSize)
  1019.             {
  1020. #if defined (MPA_FMT_DRAFT00)
  1021.                 // Copy the rtp payload header
  1022.                 if (m_bRtp)
  1023.                 {
  1024.                     pPacketBuffer->SetSize(nModFrameSize+m_RtpPackets.ulHeaderSize);
  1025.                     if (pPacketBuffer->GetSize() != (UINT32)nModFrameSize+m_RtpPackets.ulHeaderSize)
  1026.                     {
  1027.                         HX_RELEASE(pPacketBuffer);
  1028.                         HX_RELEASE(pPacketObj);
  1029.                         return HXR_OUTOFMEMORY;
  1030.                     }
  1031.                     memcpy(pPacketBuffer->GetBuffer(), /* Flawfinder: ignore */
  1032.                            m_RtpPackets.aHeader,
  1033.                            m_RtpPackets.ulHeaderSize);
  1034.                     memcpy(pPacketBuffer->GetBuffer()+m_RtpPackets.ulHeaderSize, /* Flawfinder: ignore */
  1035.                            pModFrameStart,
  1036.                            nModFrameSize);
  1037.                 
  1038.                     // Reset rtp packet values
  1039.                     memset(&m_RtpPackets.aHeader, 0, sizeof(m_RtpPackets.aHeader));
  1040.                     m_RtpPackets.bPacketReady = 0;
  1041.                     m_RtpPackets.ulHeaders = 0;
  1042.                     m_RtpPackets.ulDataChunks = 0;
  1043.                     m_RtpPackets.ulBytesFree = RTP_PACKET_SIZE;
  1044.                 }
  1045. #endif //MPA_FMT_DRAFT00
  1046.                 if( m_bStreaming || m_bRtp || m_pMp3Fmt->GetMetaRepeat() )
  1047.                 {
  1048.                    pPacketBuffer->Set(pModFrameStart,nModFrameSize);
  1049.                 }
  1050.                 
  1051. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)
  1052.                 // If this packet has meta data, left shift the mp3
  1053.                 // data over the meta data.
  1054.                 if (m_bMetaPacket)
  1055.                 {
  1056.                     UCHAR *pTemp = pPacketBuffer->GetBuffer();
  1057.                     
  1058.                     if (m_bRtp)
  1059.                         pTemp += 4;
  1060.                     UINT32 ulBytesToTitle = m_ulNextMetaPos - 
  1061.                         (m_ulBytesRead - pPacketData->dwBytesRemaining);
  1062.                     for (UINT32 i=ulBytesToTitle; 
  1063.                          i<(UINT32)nModFrameSize - m_ulMetaLength; i++)
  1064.                         pTemp[i] = pTemp[i+m_ulMetaLength];
  1065.                     pPacketBuffer->SetSize(pPacketBuffer->GetSize()-m_ulMetaLength);
  1066.                     // Set next meta data offset
  1067.                     m_ulNextMetaPos += m_pMp3Fmt->GetMetaRepeat() + m_ulMetaLength;
  1068.                     m_ulMetaLength = 0;
  1069.                     m_bMetaPacket = 0;
  1070.                 }
  1071. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1072.                 pPacketObj->Set(pPacketBuffer, deliveryTime, streamNo,
  1073.                                 ASMFlags, ASMRuleNo);
  1074.             }
  1075.             // We know we've read good data now, so clear the
  1076.             // amount of consecutive garbage bytes we've read.
  1077.             m_ulGarbageBytesRead = 0;
  1078.             // Set the delivery time for the next packet. Note that each
  1079.             // packet is stamped with a delivery time which is used to pace
  1080.             // the delivery of packets to the rendering plug-ins.
  1081.             m_dNextPts += m_Info.dTimePerFrame;
  1082.             m_ulNextPacketDeliveryTime = (UINT32)m_dNextPts;
  1083.             // Move to next sync word
  1084.             pPacketData->pBuffer += nSyncSize;
  1085.             pPacketData->dwBytesRemaining -= nSyncSize;
  1086.             // Notify the RMA core that the packet object is ready
  1087.             if (nModFrameSize)
  1088.                 m_pStatus->PacketReady(status, pPacketObj);
  1089.             // Release the object since we are done with it
  1090.             pPacketObj->Release();
  1091.             if (pPacketBuffer)
  1092.                 pPacketBuffer->Release();
  1093.         }
  1094.         else
  1095.             return HXR_OUTOFMEMORY;
  1096.     }
  1097.     
  1098.     // No more packets are available for this stream
  1099.     else
  1100.     {
  1101.         // Notify the RMA core that the stream is done
  1102.         m_pStatus->StreamDone(0);
  1103.     }
  1104.     return HXR_OK;
  1105. }
  1106. ///////////////////////////////////////////////////////////////////////////////
  1107. //  IHXFileResponse::SeekDone                               ref:  hxfiles.h
  1108. //
  1109. //  This routine is automatically called when the Seek() operation in the
  1110. //  file is complete. Other actions are then taken dependent on the current
  1111. //  processing state.
  1112. //
  1113. STDMETHODIMP
  1114. CRnMp3Fmt::SeekDone(HX_RESULT status)
  1115. {
  1116.     switch (m_State)
  1117.     {
  1118.         case SeekSeekPending:
  1119.             // We are in the process of handling a Seek() request...
  1120.             m_State = Ready;
  1121.             // Notify the RMA core that the Seek() has completed
  1122.             m_pStatus->SeekDone(status);
  1123.             break;
  1124.         case GetId3HeaderSeekPending:
  1125.             // Return to default access
  1126.             m_pFileObj->Advise(HX_FILEADVISE_ANYACCESS);
  1127.             // If we failed,then we need to try again with
  1128.             // this new HX_FILEADVISE_ANYACCESS mode. If we
  1129.             // succeeded, then we can go ahead and read.
  1130.             if (SUCCEEDED(status))
  1131.             {
  1132.                 // We successfully seeked, so now read the ID3 tags, if any
  1133.                 m_State = GetId3HeaderReadPending;
  1134.                 m_pFileObj->Read(ID3HeaderLen+BytesBeforeID3Header);
  1135.             }
  1136.             else
  1137.             {
  1138.                 // We tried to seek to the end of the file
  1139.                 // in order to get the ID3 tags, but the seek
  1140.                 // failed (that can sometimes happen if we're 
  1141.                 // playing via http and we have a HTTP 1.0 server)
  1142.                 // If this happens, then we won't worry about getting
  1143.                 // the ID3 tags - we'll simply go ahead and seek
  1144.                 // back to the beginning of the file like we do
  1145.                 // after we read the ID3 tags.
  1146.                 m_State = GetFileHeaderSeekPending;
  1147.                 m_pFileObj->Seek(MY_FILE_HEADER_START, FALSE);
  1148.             }
  1149.             break;
  1150.         case GetFileHeaderSeekPending:
  1151.             {
  1152.                 m_State = GetFileHeaderReadPending;
  1153.                 // Read the file header data from the file.
  1154.                 // Read more when we are streaming - we need more   
  1155.                 // accurate avg bitrate for vbrs when streaming.   
  1156.                 UINT32 ulReadSize = MY_FILE_HEADER_LENGTH << 3;
  1157.                 if (m_bLive ||
  1158.                     m_pFileObj->Advise(HX_FILEADVISE_RANDOMACCESS) == HXR_ADVISE_PREFER_LINEAR)
  1159.                 {
  1160.                     ulReadSize = MY_FILE_HEADER_LENGTH;
  1161.                 }
  1162.                 m_pFileObj->Read(ulReadSize);
  1163.             }
  1164.             break;
  1165.         case GetStreamHeaderSeekPending:
  1166.             MyCreateStreamHeaderObj_v(HX_STATUS_OK, NULL);
  1167.             break;
  1168.         case GetPacketSeekPending:
  1169.         {
  1170.             m_State = GetPacketReadPending;
  1171.             UINT32  ulReadSize = kReadSize;
  1172.             
  1173. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)
  1174.             if (m_ulMetaReadSize)
  1175.             {
  1176.                 ulReadSize += m_ulMetaReadSize;
  1177.                 m_ulMetaReadSize = 0;
  1178.             }
  1179. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1180.             m_pFileObj->Read(ulReadSize);
  1181.             break;
  1182.         }
  1183.         case SeekToOffsetNoRead:
  1184.             m_State = Ready;
  1185.             break;
  1186.         default:
  1187.             return HXR_UNEXPECTED;
  1188.     }
  1189.     return HXR_OK;
  1190. }
  1191. ///////////////////////////////////////////////////////////////////////////////
  1192. //  IHXFileResponse::ReadDone                               ref:  hxfiles.h
  1193. //
  1194. //  This routine is automatically called when the Read() from the file is
  1195. //  done. Other actions are then taken dependent on the current processing
  1196. //  state.
  1197. //
  1198. STDMETHODIMP
  1199. CRnMp3Fmt::ReadDone(HX_RESULT   status,
  1200.                     IHXBuffer* pBufferRead)
  1201. {
  1202.     /* This may happen in HTTP streaming when the file system
  1203.      * is in still a seeking mode when the next seek is issued.
  1204.      * The file system will then call SeekDone with a status of 
  1205.      * HXR_CANCELLED for the pending seek.
  1206.      */
  1207.     if (status == HXR_CANCELLED)
  1208.     {
  1209.     return HXR_OK;
  1210.     }
  1211.     switch (m_State)
  1212.     {
  1213.         case GetId3HeaderReadPending:
  1214.         {
  1215.             if (pBufferRead)
  1216.             {
  1217.                 // Try to extract ID3v1 header data
  1218.                 INT32 lTemp;   
  1219.                 m_pMp3Fmt->CheckForHeaders(pBufferRead->GetBuffer()+BytesBeforeID3Header,
  1220.                                            pBufferRead->GetSize()-BytesBeforeID3Header,
  1221.                                            lTemp);
  1222.             }
  1223.             
  1224.             // Go back to the beginning and init the stream
  1225.             m_State = GetFileHeaderSeekPending;
  1226.             m_pFileObj->Seek(MY_FILE_HEADER_START, FALSE);
  1227.             break;
  1228.         }
  1229.         case GetFileHeaderReadPending:
  1230.             if (!pBufferRead)
  1231.                 return HXR_UNEXPECTED;
  1232.             return MyCreateFileHeaderObj_hr(status, pBufferRead);
  1233.             break;
  1234.         case GetStreamHeaderReadPending:
  1235.             if (!pBufferRead)
  1236.                 return HXR_UNEXPECTED;
  1237.             MyCreateStreamHeaderObj_v(status, pBufferRead);
  1238.             break;
  1239.         case GetPacketReadPending:
  1240.         {
  1241.             // Buffer the read packet
  1242.             if (HXR_OK == status && pBufferRead && pBufferRead->GetSize())
  1243.             {
  1244.                 m_ulBytesRead += pBufferRead->GetSize();
  1245.                 m_ReadBuf.pReadBuffer = pBufferRead;
  1246.                 m_ReadBuf.pReadBuffer->AddRef();
  1247.                 m_ReadBuf.pBuffer = pBufferRead->GetBuffer();
  1248.                 m_ReadBuf.dwBytesRemaining = pBufferRead->GetSize();
  1249.                 m_ReadBuf.dwBufferSize = pBufferRead->GetSize();
  1250.                 if (m_ReadBuf.dwBufferSize < kReadSize)
  1251.                     m_bEOF = TRUE;
  1252.                 else
  1253.                     m_bEOF = FALSE;
  1254. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)
  1255.                
  1256.                 // Check for the first shoutcast song title meta data.
  1257.                 // Some servers do not send the data when we expect them
  1258.                 // to so sync the first location.
  1259.                 if (m_bFirstMeta)
  1260.                 {
  1261.                     int nBytes = m_ReadBuf.dwBufferSize;
  1262.                     char *pScan = (char*)m_ReadBuf.pBuffer;
  1263.                     char *p = NULL;
  1264.                     // Look for "StreamTitle" in the binary buffer.  Since meta
  1265.                     // data is text inside of a binary stream, we can not use
  1266.                     // string functions.
  1267.                     while (nBytes>0)
  1268.                     {
  1269.                         p = (char*)memchr((const char *)pScan, 'S', nBytes);
  1270.                         if (p)
  1271.                         {
  1272.                             nBytes -= p - pScan;
  1273.                             if (nBytes > 10 && 
  1274.                                 !strncmp((const char *)p, "StreamTitle", 11))
  1275.                             {
  1276.                                 // Meta data starts one byte before "StreamTitle"
  1277.                                 int offset = (PTR_INT)p - (PTR_INT)m_ReadBuf.pBuffer - 1;
  1278.                                 HX_ASSERT(m_ulNextMetaPos == m_ulBytesRead - m_ReadBuf.dwBytesRemaining + offset);
  1279.                                 
  1280.                                 m_ulNextMetaPos = m_ulBytesRead - m_ReadBuf.dwBytesRemaining + offset;
  1281.                                 m_bFirstMeta = FALSE;
  1282.                                 break;
  1283.                             }
  1284.                             
  1285.                             pScan = p+1;
  1286.                             --nBytes;
  1287.                         }
  1288.                         else
  1289.                         {
  1290.                             break;
  1291.                         }
  1292.                     }
  1293.                 }
  1294.                
  1295.                 // Find the length of the next ShoutCast meta packet
  1296.                 if (m_ulNextMetaPos < m_ulBytesRead && !m_ulMetaLength)
  1297.                 {
  1298.                     UINT32 ulBytesToMeta = m_ulNextMetaPos - (m_ulBytesRead - 
  1299.                         m_ReadBuf.dwBytesRemaining);
  1300.                     m_ulMetaLength = m_ReadBuf.pBuffer[ulBytesToMeta] * 16 + 1;
  1301.                     // The meta data spans this buffer.  So, move the file pointer
  1302.                     // to the start of the meta data and change the properties of
  1303.                     // m_ReadBuf to exclude the partial meta data.  This way, we
  1304.                     // will get the meta data on our next read.
  1305.                     if (m_ulMetaLength + ulBytesToMeta > m_ReadBuf.dwBufferSize)
  1306.                     {
  1307.                         if(m_ulMetaLength < MAX_METADATA)
  1308.                         {
  1309.                             m_ulBytesRead -= m_ReadBuf.dwBufferSize - 
  1310.                                 ulBytesToMeta;
  1311.                             m_ReadBuf.dwBufferSize -= m_ReadBuf.dwBufferSize -
  1312.                                 ulBytesToMeta;
  1313.                             m_ReadBuf.dwBytesRemaining = 
  1314.                                 m_ReadBuf.dwBufferSize;
  1315.                             m_ulMetaReadSize = m_ulMetaLength;
  1316.                             m_ulMetaLength = 0;
  1317.                         
  1318.                             m_State = SeekToOffsetNoRead;
  1319.                             m_pFileObj->Seek(m_ulBytesRead, FALSE);
  1320.                         }
  1321.                         // this is not good meta data
  1322.                         else
  1323.                         {
  1324.                             m_ulNextMetaPos += m_pMp3Fmt->GetMetaRepeat();
  1325.                             m_ulMetaLength = 0;
  1326.                         }
  1327.                     }
  1328.                     unsigned char *pTemp = &m_ReadBuf.pBuffer[ulBytesToMeta+1];
  1329.                     // Update player's gui with the new song title
  1330.                     if (m_ulMetaLength > 1 && 
  1331.                         !strncmp((const char *)pTemp, "StreamTitle", 11))
  1332.                     {
  1333.                         IHXBuffer  *pTitle = NULL;
  1334.                         m_pClassFactory->CreateInstance(CLSID_IHXBuffer, 
  1335.                             (void**)&pTitle);
  1336.                         if (pTitle)
  1337.                         {
  1338.                             pTemp = m_ReadBuf.pBuffer+ulBytesToMeta+14;
  1339.                             size_t nLen;
  1340.                             // Get the length of just the song title
  1341.                             pTemp = (unsigned char*)dbcsFindChar(
  1342.                                     (const char*)pTemp, ';', m_ulMetaLength);
  1343.                             
  1344.                             if(pTemp)
  1345.                             {
  1346.                                 nLen = pTemp - 1 -
  1347.                                     (m_ReadBuf.pBuffer+ulBytesToMeta+14);
  1348.                             }
  1349.                             else
  1350.                             {
  1351.                                 nLen = dbcsStrSize((const char*)
  1352.                                     (m_ReadBuf.pBuffer+ulBytesToMeta+14), 
  1353.                                     m_ulMetaLength);
  1354.                                 if(nLen == m_ulMetaLength)
  1355.                                 {
  1356.                                     // Not good metadata
  1357.                                     m_ulNextMetaPos += 
  1358.                                         m_pMp3Fmt->GetMetaRepeat();
  1359.                                     m_ulMetaLength = 0;
  1360.                                 }
  1361.                             }
  1362. #if defined(HELIX_FEATURE_REGISTRY)
  1363.                             if(m_ulMetaLength)
  1364.                             {
  1365.                                 // Put the song title in an IHXBuffer
  1366.                                 pTitle->Set(m_ReadBuf.pBuffer+ulBytesToMeta+14,
  1367.                                     nLen+1);
  1368.                                 pTitle->GetBuffer()[nLen] = '';
  1369.                                 m_pRegistry->SetStrByName(
  1370.                                     (char*)m_szPlayerReg->GetBuffer(), pTitle);
  1371.                                 HX_RELEASE(pTitle);
  1372.                                 m_pClassFactory->CreateInstance(
  1373.                                     CLSID_IHXBuffer, (void**)&pTitle);
  1374.                                 // Set station as title
  1375.                                 int nTitle = 0;
  1376.                                 m_pMp3Fmt->GetId3Title(nTitle);
  1377.                                 if (nTitle && pTitle)
  1378.                                 {
  1379.                                     pTitle->Set(m_pMp3Fmt->GetId3Title(nTitle),
  1380.                                         nTitle+1);
  1381.                                     // Put the song title in the registry
  1382.                                     char szTitle[128]; /* Flawfinder: ignore */
  1383.                                     
  1384.                                     SafeStrCpy(szTitle, 
  1385.                                          (char*)m_szPlayerReg->GetBuffer(), 128); 
  1386.                                     strcpy(&szTitle[strlen(szTitle)-6], /* Flawfinder: ignore */
  1387.                                         "Title");
  1388.                                     m_pRegistry->SetStrByName(szTitle, pTitle);
  1389.                                 }
  1390.                             }
  1391. #endif /* #if defined(HELIX_FEATURE_REGISTRY) */
  1392.                             HX_RELEASE(pTitle);
  1393.                         }
  1394.                     }
  1395.                 }
  1396. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1397.             }
  1398.             
  1399.             // If there was an error, set EOF
  1400.             else
  1401.             {
  1402.                 m_bEOF = TRUE;
  1403.                 
  1404.                 HX_RELEASE(m_ReadBuf.pReadBuffer);
  1405.                 m_pStatus->StreamDone(0);
  1406.                 return HXR_OK;
  1407.             }
  1408.             m_ReadBuf.status = status;
  1409.             // If the read call did not finish inside of GetPacket
  1410.             // (http streaming), then create a packet when the read finished.
  1411.             if (m_bNeedPacket && m_ReadBuf.dwBytesRemaining)
  1412.             {
  1413.                 m_bNeedPacket = 0;
  1414.                 return MyCreatePacketObj_hr(m_ReadBuf.status, &m_ReadBuf);
  1415.             }
  1416.         }
  1417.         break;
  1418.         default:
  1419.             return HXR_UNEXPECTED;
  1420.     }
  1421.     return HXR_OK;
  1422. }
  1423. ///////////////////////////////////////////////////////////////////////////////
  1424. //  Method:
  1425. //      IHXFileStatResponse::StatDone
  1426. //  Purpose:
  1427. //      Called in response to a Stat call on a IHXFileStat object
  1428. //      
  1429. //
  1430. STDMETHODIMP
  1431. CRnMp3Fmt::StatDone(HX_RESULT status,
  1432.                     UINT32 ulSize,
  1433.                     UINT32 ulCreationTime,
  1434.                     UINT32 ulAccessTime,
  1435.                     UINT32 ulModificationTime,
  1436.                     UINT32 ulMode)
  1437. {
  1438.     // If we do not know the file length, assume it is a live file
  1439.     if (HXR_OK == status && !ulSize)
  1440.         ulSize = 54000000;
  1441.     
  1442.     m_ulFileSize = ulSize;
  1443.     if (m_ulFileSize == 54000000 ||
  1444.         m_ulFileSize == 34000000 ||
  1445.         m_ulFileSize == 99999999)
  1446.         m_bLive = 1;
  1447.     return HXR_OK;
  1448. }
  1449. ///////////////////////////////////////////////////////////////////////////////
  1450. //  IHXFileFormatObject::Seek                               ref:  hxformt.h
  1451. //
  1452. //  This routine moves to the packet nearest to the requested time in the
  1453. //  file. It is called, for example, in response to the user moving the
  1454. //  slider to a different location in the playback timeline.
  1455. //
  1456. STDMETHODIMP
  1457. CRnMp3Fmt::Seek(UINT32 requestedTime)
  1458. {
  1459.     // Find nearest packet to the requested time
  1460.     UINT32 ulPacketNo = (UINT32)(requestedTime / m_Info.dTimePerFrame);
  1461.     UINT32 ulPacketStart = ulPacketNo * m_Info.nPacketSize + m_ulFileOffset;
  1462.     m_dNextPts = ulPacketNo * m_Info.dTimePerFrame;
  1463.     m_ulNextPacketDeliveryTime = (UINT32)(m_dNextPts);
  1464.     // Note state, since Seek() is asynchronous
  1465.     m_State = SeekSeekPending;
  1466.     // Release our buffered reads
  1467.     DiscardReadBuffers_v();
  1468.     m_bEOF = FALSE;
  1469. #if defined (MPA_FMT_DRAFT00)
  1470.     // If we are reformatting mp3 frames, make sure we
  1471.     // skip the vbr header at the start of the file.
  1472.     if (!ulPacketStart && m_bStreaming && !m_bRtp)
  1473.         m_bSkipVbrHdr = m_bHasVbrHdr;
  1474.     memset(&m_RtpPackets, 0, sizeof(m_RtpPackets));
  1475.     m_RtpPackets.ulBytesFree = RTP_PACKET_SIZE;
  1476.     m_RtpPackets.dScr = m_dNextPts;
  1477.     m_RtpPackets.dPts = m_dNextPts;
  1478. #endif //MPA_FMT_DRAFT00
  1479.     
  1480.     // Move to the requested location in the file
  1481.     m_ulBytesRead = ulPacketStart;
  1482.     m_pFileObj->Seek(ulPacketStart, FALSE);
  1483.     return HXR_OK;
  1484. }
  1485. ///////////////////////////////////////////////////////////////////////////////
  1486. //  IHXFileFormatObject::Close                              ref:  hxformt.h
  1487. //
  1488. //  This routine handles any cleanup required before closing the plug-in. All
  1489. //  references to objects should be released and memory deallocated. This is
  1490. //  called by the RMA core when the playback is finished or stopped.
  1491. //
  1492. STDMETHODIMP
  1493. CRnMp3Fmt::Close(void)
  1494. {
  1495.     m_bClosed = TRUE;
  1496.     
  1497.     if (m_pFileObj != NULL)
  1498.     {
  1499.         m_pFileObj->Close();
  1500.         m_pFileObj->Release();
  1501.         m_pFileObj = NULL;
  1502.     }
  1503. #if defined(HELIX_FEATURE_REGISTRY)
  1504.     if (m_pRegistry && m_szPlayerReg)
  1505.     {   
  1506.         m_pRegistry->SetStrByName((char*)m_szPlayerReg->GetBuffer(), NULL);
  1507.     }
  1508.     HX_RELEASE(m_pRegistry);
  1509. #endif /* #if defined(HELIX_FEATURE_REGISTRY) */
  1510.     HX_RELEASE(m_pStatus);
  1511.     HX_RELEASE(m_pError);
  1512.     HX_RELEASE(m_szPlayerReg);
  1513.     HX_RELEASE(m_pClassFactory);
  1514.     HX_RELEASE(m_pContext);
  1515.     HX_RELEASE(m_pMetaProps);
  1516.     
  1517. #if defined(MPA_FMT_DRAFT00)
  1518.     HX_DELETE(m_pFmtBuf);
  1519. #endif /* #if defined(MPA_FMT_DRAFT00) */
  1520.     return HXR_OK;
  1521. }
  1522. ///////////////////////////////////////////////////////////////////////////////
  1523. //  IHXFileResponse::CloseDone, WriteDone                   ref:  hxfiles.h
  1524. //
  1525. //  This routines are not used in this example, but are required to complete
  1526. //  the IHXFileResponse interface.
  1527. //
  1528. STDMETHODIMP CRnMp3Fmt::CloseDone(HX_RESULT /* result */)
  1529. {
  1530.     return HXR_OK;
  1531. }
  1532. STDMETHODIMP CRnMp3Fmt::WriteDone(HX_RESULT /* result */)
  1533. {
  1534.     return HXR_OK;
  1535. }
  1536. ///////////////////////////////////////////////////////////////////////////////
  1537. //  CRnMp3Fmt::~CRnMp3Fmt              ref:  filefmt1.h
  1538. //
  1539. //  Destructor
  1540. //
  1541. CRnMp3Fmt::~CRnMp3Fmt(void)
  1542. {
  1543.     Close();
  1544.     DiscardReadBuffers_v();
  1545.     HX_DELETE(m_pMp3Fmt);
  1546. }
  1547. // IUnknown COM Interface Methods
  1548. ///////////////////////////////////////////////////////////////////////////////
  1549. //  IUnknown::AddRef                                            ref:  hxcom.h
  1550. //
  1551. //  This routine increases the object reference count in a thread safe
  1552. //  manner. The reference count is used to manage the lifetime of an object.
  1553. //  This method must be explicitly called by the user whenever a new
  1554. //  reference to an object is used.
  1555. //
  1556. STDMETHODIMP_(UINT32)
  1557. CRnMp3Fmt::AddRef(void)
  1558. {
  1559.     return InterlockedIncrement(&m_RefCount);
  1560. }
  1561.                        
  1562. ///////////////////////////////////////////////////////////////////////////////
  1563. //  IUnknown::Release                                           ref:  hxcom.h
  1564. //
  1565. //  This routine decreases the object reference count in a thread safe
  1566. //  manner, and deletes the object if no more references to it exist. It must
  1567. //  be called explicitly by the user whenever an object is no longer needed.
  1568. //
  1569. STDMETHODIMP_(UINT32)
  1570. CRnMp3Fmt::Release(void)
  1571. {
  1572.     if (InterlockedDecrement(&m_RefCount) > 0)
  1573.         return m_RefCount;
  1574.     delete this;
  1575.     return 0;
  1576. }
  1577. ///////////////////////////////////////////////////////////////////////////////
  1578. //  IUnknown::QueryInterface                                    ref:  hxcom.h
  1579. //
  1580. //  This routine indicates which interfaces this object supports. If a given
  1581. //  interface is supported, the object's reference count is incremented, and
  1582. //  a reference to that interface is returned. Otherwise a NULL object and
  1583. //  error code are returned. This method is called by other objects to
  1584. //  discover the functionality of this object.
  1585. //
  1586. STDMETHODIMP
  1587. CRnMp3Fmt::QueryInterface(REFIID interfaceID,
  1588.                           void** ppInterfaceObj)
  1589. {
  1590.     // By definition all COM objects support the IUnknown interface
  1591.     if (IsEqualIID(interfaceID, IID_IUnknown))
  1592.     {
  1593.         AddRef();
  1594.         *ppInterfaceObj = (IUnknown*)(IHXPlugin*)this;
  1595.         return HXR_OK;
  1596.     }
  1597.     // IHXPlugin interface is supported
  1598.     else if (IsEqualIID(interfaceID, IID_IHXPlugin))
  1599.     {
  1600.         AddRef();
  1601.         *ppInterfaceObj = (IHXPlugin*)this;
  1602.         return HXR_OK;
  1603.     }
  1604.     // IHXFileResponse interface is supported
  1605.     else if (IsEqualIID(interfaceID, IID_IHXFileResponse))
  1606.     {
  1607.         AddRef();
  1608.         *ppInterfaceObj = (IHXFileResponse*)this;
  1609.         return HXR_OK;
  1610.     }
  1611.     // IHXFileFormatObject interface is supported
  1612.     else if (IsEqualIID(interfaceID, IID_IHXFileFormatObject))
  1613.     {
  1614.         AddRef();
  1615.         *ppInterfaceObj = (IHXFileFormatObject*)this;
  1616.         return HXR_OK;
  1617.     }
  1618. #if defined(MPA_FMT_DRAFT00)
  1619.     // IHXPacketFormat interface is supported
  1620.     else if (IsEqualIID(interfaceID, IID_IHXPacketFormat))
  1621.     {
  1622.         AddRef();
  1623.         *ppInterfaceObj = (IHXPacketFormat*)this;
  1624.         return HXR_OK;
  1625.     }
  1626. #endif /* #if defined(MPA_FMT_DRAFT00) */
  1627.     // IHXThreadSafeMethods interface is supported
  1628.     else if (IsEqualIID(interfaceID, IID_IHXThreadSafeMethods))
  1629.     {
  1630.         AddRef();
  1631.         *ppInterfaceObj = (IHXThreadSafeMethods*)this;
  1632.         return HXR_OK;
  1633.     }
  1634.     
  1635.     // No other interfaces are supported
  1636.     *ppInterfaceObj = NULL;
  1637.     return HXR_NOINTERFACE;
  1638. }
  1639. void CRnMp3Fmt::DiscardReadBuffers_v()
  1640. {
  1641.     HX_RELEASE(m_ReadBuf.pReadBuffer);
  1642. #if defined(MPA_FMT_DRAFT00)
  1643.     if (m_pFmtBuf)
  1644.         m_pFmtBuf->Reset();
  1645. #endif /* #if defined(MPA_FMT_DRAFT00) */
  1646. }
  1647. UCHAR* CRnMp3Fmt::GetMP3Frame_p(tReadBuffer* pPacketData, int &nSyncSize)
  1648. {
  1649.     INT32   lScan = 0;
  1650.     UCHAR   *pFrame = NULL;
  1651. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)    
  1652.     // Sync word is split by meta data
  1653.     if (m_ulMetaLength && 
  1654.         (m_ulNextMetaPos - (m_ulBytesRead - pPacketData->dwBytesRemaining) 
  1655.         <= 3))
  1656.     {
  1657.         IHXBuffer* pBuf;
  1658.         if(SUCCEEDED(m_pClassFactory->CreateInstance(CLSID_IHXBuffer, 
  1659.             (void**)&pBuf)) && pBuf)
  1660.         {
  1661.             //pBuf->Set(pPacketData->pBuffer, pPacketData->dwBytesRemaining);            
  1662.             UINT32 ulBytesToTitle = m_ulNextMetaPos - (m_ulBytesRead - 
  1663.                 pPacketData->dwBytesRemaining);
  1664.             if(SUCCEEDED(pBuf->SetSize(
  1665.                 pPacketData->dwBytesRemaining - m_ulMetaLength)))
  1666.             {
  1667.                 UCHAR* pNewBuf = pBuf->GetBuffer();
  1668.                 UCHAR* pOldBuf = pPacketData->pBuffer;
  1669.                 memcpy(pNewBuf, pOldBuf, ulBytesToTitle); /* Flawfinder: ignore */
  1670.                 memcpy(pNewBuf + ulBytesToTitle, /* Flawfinder: ignore */
  1671.                         pOldBuf + ulBytesToTitle + m_ulMetaLength,
  1672.                         pPacketData->dwBytesRemaining - m_ulMetaLength - 
  1673.                         ulBytesToTitle);
  1674.                 HX_RELEASE(pPacketData->pReadBuffer);
  1675.                 pPacketData->pReadBuffer = pBuf;
  1676.                 pPacketData->pBuffer = pNewBuf;
  1677.                 pPacketData->dwBufferSize = pBuf->GetSize();
  1678.                 pPacketData->dwBytesRemaining = pPacketData->dwBufferSize;
  1679.             }
  1680.         }
  1681.         // Set next meta data offset
  1682.         m_ulNextMetaPos += m_pMp3Fmt->GetMetaRepeat() + m_ulMetaLength;
  1683.         m_ulMetaLength = 0;
  1684.     }
  1685. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1686.     
  1687.     // We should be at an mp3 frame, make sure we are
  1688.     nSyncSize = m_pMp3Fmt->CheckValidFrame(pPacketData->pBuffer,
  1689.                                           pPacketData->dwBytesRemaining);
  1690.     
  1691.     // If we were not at a frame, scan for the next one
  1692.     if (!nSyncSize)
  1693.         lScan = m_pMp3Fmt->ScanForSyncWord(pPacketData->pBuffer,
  1694.                                           pPacketData->dwBytesRemaining,
  1695.                                           nSyncSize);
  1696.     
  1697. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)
  1698.     // Check this frame for meta data
  1699.     if (m_ulNextMetaPos <= m_ulBytesRead - pPacketData->dwBytesRemaining + nSyncSize)
  1700.     {
  1701.         if (nSyncSize + m_ulMetaLength > pPacketData->dwBytesRemaining)
  1702.             return NULL;
  1703.         m_bMetaPacket = 1;
  1704.         nSyncSize += m_ulMetaLength;
  1705.         lScan = 0;
  1706.     }
  1707. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1708.     
  1709.     // Move to current frame
  1710.     if (lScan > 0)
  1711.     {
  1712.         pPacketData->pBuffer += lScan;
  1713.         pPacketData->dwBytesRemaining -= lScan;
  1714.     }
  1715.     
  1716.     if (lScan >= 0)
  1717.         pFrame = pPacketData->pBuffer;
  1718.     
  1719. #if defined(MPA_FMT_DRAFT00)
  1720.     // Copy into format buffer if streaming    
  1721.     if (m_bStreaming && !m_bRtp)
  1722.     {
  1723.         if (m_bSkipVbrHdr)
  1724.             m_bSkipVbrHdr = 0;
  1725.         else
  1726.         {
  1727.             UINT32 ulBytes = 0;
  1728.             
  1729.             if (pFrame)
  1730.                 ulBytes = m_pFmtBuf->CopyData(pFrame, nSyncSize);
  1731.             UCHAR  *pTemp = NULL;
  1732.             pTemp = m_pFmtBuf->GetReadPointer(ulBytes);
  1733.             UINT32  nSync = m_pMp3Fmt->CheckValidFrame(pTemp, ulBytes);
  1734.             // Make sure we have 1+ frame in the buffer
  1735.             if (!nSync ||
  1736.                 (m_pFmtBuf->GetBytesInBuffer() > (UINT32)nSync+6 &&
  1737.                  ulBytes < (UINT32)nSync + 6))
  1738.             {
  1739.                 // Preserve enough data for main_data_begin
  1740.                 m_pFmtBuf->Wrap(512);
  1741.             }
  1742.         }
  1743.     }
  1744. #endif //MPA_FMT_DRAFT00
  1745.     
  1746.     return pFrame;
  1747. }
  1748. INT32 CRnMp3Fmt::GetStartCode(UINT8 **ppBuffer,
  1749.                               UINT32 &ulBytes)
  1750. {
  1751.     if ((INT32)ulBytes < 4)
  1752.         return -1;
  1753.     UINT8 *pStart = *ppBuffer + 2,
  1754.                     *pEnd = *ppBuffer + ulBytes - 4;
  1755.     INT32 ulCode = -1;
  1756.     
  1757.     while (pStart < pEnd)
  1758.     {
  1759.         // Look for a 1
  1760.         pStart = (UINT8*)memchr(pStart, 1, pEnd-pStart);
  1761.         if (!pStart)
  1762.             return -1;
  1763.         // If the previous 2 bytes are 0's assume it is a start code
  1764.         if (pStart[-1] || pStart[-2])
  1765.             ++pStart;
  1766.         else
  1767.         {
  1768.             ulCode = 0x00000100 + pStart[1];
  1769.             pStart -= 2;
  1770.             break;
  1771.             
  1772.         }
  1773.     }
  1774.     ulBytes -= pStart - *ppBuffer;
  1775.     *ppBuffer = pStart;
  1776.     return ulCode;
  1777. }
  1778. ///////////////////////////////////////////////////////////////////////////////
  1779. // Function:    InitStream_n
  1780. // Purpose:     Determine the stream type, prepare our pluigin to handle it.
  1781. // Params:      pDataRead is a buffer read from disk size MY_FILE_HEADER_LENGTH
  1782. //              pInfo is a stream info struct to describe this file
  1783. // Returns:     The number of audio streams in this file
  1784. //              or 0 meaning the header info is greater than MY_FILE_HEADER_LENGTH
  1785. //              or -1 for an unsupported file.
  1786. // Author:      cts
  1787. ///////////////////////////////////////////////////////////////////////////////
  1788. UINT16 CRnMp3Fmt::InitStream_n(IHXBuffer* pDataRead,
  1789.                                tStreamInfo *pInfo,
  1790.                                HX_RESULT &hr,
  1791.                                char* pUpgrade,
  1792.                                int nBufLen)
  1793. {
  1794.     UCHAR   *pBuffer = pDataRead->GetBuffer();
  1795.     UINT32  dwSize = pDataRead->GetSize();
  1796.     INT32   lHeaderSize = 0;
  1797.     hr = HXR_OK;
  1798.     UINT32 ulTag0 = Get4Byte(&pBuffer[0], dwSize);
  1799.     UINT32 ulTag4 = Get4Byte(&pBuffer[4], dwSize - 4);
  1800.     UINT32 ulTag8 = Get4Byte(&pBuffer[8], dwSize - 8);
  1801. #if defined(HELIX_FEATURE_MP3FF_LENIENT)
  1802.     // Since we are saying we support .mpg and .dat streams (in the
  1803.     // MPEG world, system streams and VideoCDs), check for these streams
  1804.     // and notify the core and upgrade is required.  This code allows us
  1805.     // to play mislabled mp3 (ie mp3 stream with an .mpg extension).
  1806.     if(ulTag0 == MP3FF_4BYTE_SYSTEM || // Check for MPEG system streams
  1807.        ulTag0 == MP3FF_4BYTE_VIDEO  || // Check for MPEG video streams
  1808.        (pBuffer[0] == 0x47 &&          // Check for MPEG2 transport streams
  1809.         dwSize > 188 &&
  1810.         pBuffer[188] == 0x47)       ||
  1811.        (ulTag0 == MP3FF_4BYTE_RIFF &&  // Check for VideoCD
  1812.         ulTag8 == MP3FF_4BYTE_CDXA) ||
  1813.        (ulTag0 == MP3FF_4BYTE_RIFF &&  // Check for AVI files
  1814.         pBuffer[8]  == 'A'         &&
  1815.         pBuffer[9]  == 'V'         &&
  1816.         pBuffer[10] == 'I'))
  1817.     {
  1818.         hr = HXR_REQUEST_UPGRADE;
  1819.         return (UINT16)-1;
  1820.     }
  1821.     // Check for QuickTime Atoms (found some labled mpg which
  1822.     // unfortunately contianed bytes that looked like mp3 frames).
  1823.     // There are five atom types (free, skip, pnot, mdat, moov)
  1824.     else if (ulTag4 == MP3FF_4BYTE_free ||
  1825.              ulTag4 == MP3FF_4BYTE_skip ||
  1826.              ulTag4 == MP3FF_4BYTE_pnot ||
  1827.              ulTag4 == MP3FF_4BYTE_mdat ||
  1828.              ulTag4 == MP3FF_4BYTE_moov)
  1829.     {
  1830.         if (pUpgrade)
  1831.         {
  1832.             SafeStrCpy(pUpgrade, "video/quicktime", nBufLen);
  1833.             hr = HXR_REQUEST_UPGRADE;
  1834.         }
  1835.         else
  1836.             hr = HXR_INVALID_FILE;
  1837.         return (UINT16)-1;
  1838.     }
  1839. #endif /* #if defined(HELIX_FEATURE_MP3FF_LENIENT) */
  1840.     
  1841.     // Check for audio only streams
  1842.     if(0xFF == *pBuffer &&
  1843.        (0xF0 == (pBuffer[1] & 0xF0) ||
  1844.         0xE0 == (pBuffer[1] & 0xF0)))   // MPEG2.5
  1845.     {
  1846.         pInfo->eType = eHXAudio;
  1847.         pInfo->eAudio = eHXMPEG;
  1848.         // Packet length is one audio frame
  1849.         int     nFrame;
  1850.         INT32   lScan = 0;
  1851.         lScan = m_pMp3Fmt->ScanForSyncWord(pBuffer, dwSize, nFrame);
  1852.         if (lScan == -1)
  1853.         { 
  1854.             hr = HXR_INVALID_FILE;
  1855.             return (UINT16)-1;
  1856.         }
  1857.         else if (lScan)
  1858.             goto SCAN_JUMP;
  1859.         
  1860.         // Init our reformatter
  1861.         if (!m_pMp3Fmt->Init(pBuffer, dwSize))
  1862.         { 
  1863.             goto SCAN_JUMP;
  1864.         }
  1865.         pInfo->nPacketSize = nFrame;
  1866.         pInfo->cHeader = *(pBuffer+1);
  1867.         
  1868.         int             nLayer = 0,
  1869.                         nSamplesPerFrame = 0;
  1870.         m_nChannels = 0;
  1871.         m_pMp3Fmt->GetEncodeInfo(pBuffer, dwSize,
  1872.                                 pInfo->ulBitRate, m_ulMaxSampRate,
  1873.                                 m_nChannels, nLayer, nSamplesPerFrame);
  1874.                                   
  1875.         // Convert to ms
  1876.         pInfo->dTimePerFrame = nSamplesPerFrame * 1000.0 / m_ulMaxSampRate; 
  1877.         // Do not include the header info in file duration
  1878.         m_ulFileSize -= m_ulFileOffset;
  1879.         // Look for Xing Specific mp3 header
  1880.         if (3 == nLayer)
  1881.         {
  1882.             XHEADDATA   xHead;
  1883.             memset(&xHead, 0, sizeof(xHead));
  1884.             if (GetXingHeader(&xHead, pBuffer) && xHead.flags & FRAMES_FLAG && xHead.frames > 0)
  1885.             {
  1886.                 m_bHasVbrHdr =
  1887.                 m_bSkipVbrHdr = 1;
  1888.                 m_bIsVBR = TRUE;
  1889.                 pInfo->ulBitRate = (UINT32)((m_ulFileSize<<3) / (xHead.frames * pInfo->dTimePerFrame / 1000.0));
  1890.                 pInfo->nPacketSize = m_ulFileSize / xHead.frames; 
  1891.             }
  1892.             // Handle vbr strems w/o a header.  Look at a few frames and calculate
  1893.             // an average bitrate from these.
  1894.             else
  1895.             {
  1896.                 int     nChannels = 0;
  1897.                 UINT32  ulBitRate = pInfo->ulBitRate,
  1898.                         ulFrameSize = nFrame,
  1899.                         ulFrames = 1;
  1900.                 while (nFrame && dwSize > (UINT32)nFrame)
  1901.                 {
  1902.                     pBuffer += nFrame;
  1903.                     dwSize -= nFrame;
  1904.                     UINT32 ulSampleRate = 0;
  1905.                     m_pMp3Fmt->GetEncodeInfo(pBuffer, dwSize,
  1906.                                               pInfo->ulBitRate, ulSampleRate,
  1907.                                               nChannels, nLayer, nSamplesPerFrame);
  1908.                     nFrame = m_pMp3Fmt->CheckValidFrame(pBuffer, dwSize);   
  1909.                     // Oh joy!! meta data!!   
  1910.                     if (!nFrame)   
  1911.                     {   
  1912.                         INT32 lScan = m_pMp3Fmt->ScanForSyncWord(pBuffer, dwSize, nFrame);   
  1913.                         if (lScan > 0)   
  1914.                         {   
  1915.                             pBuffer += lScan - 1;   
  1916.                             dwSize -= lScan -1 ;   
  1917.                             nFrame = 1;   
  1918.                         }   
  1919.                         continue;   
  1920.                     }   
  1921.                     if (ulSampleRate > m_ulMaxSampRate)
  1922.                     {
  1923.                         m_ulMaxSampRate = ulSampleRate;
  1924.                     }
  1925.     
  1926.                     ulFrameSize += nFrame;   
  1927.                 
  1928.                     ulBitRate += pInfo->ulBitRate;
  1929.                     ++ulFrames;
  1930.                 }
  1931.                 // Check for vbr   
  1932.                 if (ulBitRate / ulFrames != pInfo->ulBitRate)   
  1933.                 {   
  1934.                     m_bIsVBR = TRUE;
  1935.                     pInfo->ulBitRate = ulBitRate / ulFrames;
  1936.                     pInfo->ulBitRate += pInfo->ulBitRate / 10; 
  1937.                 }
  1938.                 pInfo->nPacketSize = ulFrameSize / ulFrames;
  1939.             }
  1940.         }
  1941.         return 1;
  1942.     }
  1943.     
  1944.     // Check for mp3 streams with headers
  1945.     else if (m_pMp3Fmt->CheckForHeaders(pBuffer, dwSize, lHeaderSize))
  1946.     {
  1947.         // Handle multiple Id3v2 tags
  1948.         m_ulFileOffset += lHeaderSize;
  1949.         m_ulBytesRead = m_ulFileOffset;
  1950. #if defined(HELIX_FEATURE_MP3FF_SHOUTCAST)
  1951.         if (m_pMp3Fmt->GetHeaderType() == eShoutCast ||
  1952.             m_pMp3Fmt->GetHeaderType() == eIceCast)
  1953.         {
  1954.             m_bLive = 1;
  1955.             // Set first offset to meta data
  1956.             if (m_pMp3Fmt->GetMetaRepeat())
  1957.             {
  1958.                 m_ulNextMetaPos = m_pMp3Fmt->GetMetaOffset() + m_pMp3Fmt->GetMetaRepeat();
  1959.                 m_bFirstMeta = TRUE;
  1960.             }
  1961.         }
  1962. #endif //HELIX_FEATURE_MP3FF_SHOUTCAST
  1963.         return 0;
  1964.     }
  1965.     
  1966.     // Scan the data looking for video/audio packets
  1967.     else
  1968.     {
  1969.         UCHAR *pBitStream;
  1970.         UINT32 nBytesInStream;
  1971.         // If we are beyond some known header, check for a sync word
  1972.         // after all 0 padding bits.
  1973.         if (m_ulFileOffset && !*pBuffer)
  1974.         {
  1975.             pBitStream = pBuffer;
  1976.             nBytesInStream = dwSize;
  1977.             for (; nBytesInStream && !*pBitStream; nBytesInStream--)
  1978.                 ++pBitStream;
  1979.             if(0xFF == *pBitStream &&
  1980.                nBytesInStream > 1 &&
  1981.                (0xF0 == (pBitStream[1] & 0xF0) ||
  1982.                 0xE0 == (pBitStream[1] & 0xF0)))   // MPEG2.5
  1983.             {
  1984.                 m_ulFileOffset += pBitStream-pBuffer;
  1985.                 m_ulBytesRead = m_ulFileOffset;
  1986.                 return 0;
  1987.             }
  1988.         }
  1989.         pBitStream = pBuffer;
  1990.         nBytesInStream = dwSize;
  1991.         {
  1992.             // Is this actually an mpeg video or system stream?
  1993.             INT32 nStartCode = GetStartCode(&pBitStream, nBytesInStream);
  1994.         
  1995.             switch (nStartCode)
  1996.             {
  1997.                 case PACK_HEADER:
  1998.                 case SEQ_START_CODE:
  1999.                 case SYSTEM_HEADER:
  2000.                 case GROUP_START_CODE:
  2001.                 case VIDEO_PACKET:
  2002.                 case AUDIO_PACKET:
  2003.                 hr = HXR_REQUEST_UPGRADE;
  2004.                 return (UINT16)-1;
  2005.             }
  2006.         }
  2007. SCAN_JUMP:        
  2008.         // Scan bitstream for an mpeg audio frame
  2009.         int nFrame;
  2010.         INT32 lScan = m_pMp3Fmt->ScanForSyncWord(pBuffer, dwSize, nFrame);
  2011.         if (lScan > -1)
  2012.         {
  2013.             m_ulFileOffset += lScan;
  2014.             m_ulBytesRead += m_ulFileOffset;
  2015.             return 0;
  2016.         }
  2017.         else
  2018.         {
  2019.             hr = HXR_INVALID_FILE;
  2020.             return (UINT16)-1;
  2021.         }
  2022.     }
  2023. }
  2024. UINT32 CRnMp3Fmt::Get4Byte(UINT8* pBuf, UINT32 ulSize)
  2025. {
  2026.     UINT32 ulRet = 0;
  2027.     if (pBuf && ulSize >= 4)
  2028.     {
  2029.         ulRet = (pBuf[0] << 24) |
  2030.                 (pBuf[1] << 16) |
  2031.                 (pBuf[2] <<  8) |
  2032.                  pBuf[3];
  2033.     }
  2034.     return ulRet;
  2035. }
  2036. #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO)
  2037. void CRnMp3Fmt::SetMetaInfo(IHXValues* pFileHeader, const char* pszProp)
  2038. {
  2039.     if (pFileHeader && pszProp)
  2040.     {
  2041.         if (!strcmp(pszProp, "SrcCodec"))
  2042.         {
  2043.             SetCStringProperty(pFileHeader, "SrcCodec", "mp3", m_pContext);
  2044.         }
  2045.         else if (!strcmp(pszProp, "SrcBitRate"))
  2046.         {
  2047.             pFileHeader->SetPropertyULONG32("SrcBitRate", m_Info.ulBitRate);
  2048.         }
  2049.         else if (!strcmp(pszProp, "SrcVBREnabled"))
  2050.         {
  2051.             pFileHeader->SetPropertyULONG32("SrcVBREnabled", m_bIsVBR);
  2052.         }
  2053.         else if (!strcmp(pszProp, "SrcInterleaved"))
  2054.         {
  2055.             pFileHeader->SetPropertyULONG32("SrcInterleaved", 0);
  2056.         }
  2057.         else if (!strcmp(pszProp, "SrcSamplesPerSecond"))
  2058.         {
  2059.             pFileHeader->SetPropertyULONG32("SrcSamplesPerSecond", m_ulMaxSampRate);
  2060.         }
  2061.         else if (!strcmp(pszProp, "SrcBitsPerSample"))
  2062.         {
  2063.             pFileHeader->SetPropertyULONG32("SrcBitsPerSample", 16);
  2064.         }
  2065.         else if (!strcmp(pszProp, "SrcNumChannels"))
  2066.         {
  2067.             pFileHeader->SetPropertyULONG32("SrcNumChannels", (UINT32) m_nChannels);
  2068.         }
  2069.     }
  2070. }
  2071. #endif /* #if defined(HELIX_FEATURE_MP3FF_ONDEMANDMETAINFO) */