hxflsrc.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:81k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxflsrc.cpp,v 1.43.2.9 2004/07/09 02:05:57 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49.       
  50. #include "hxcom.h"
  51. #include "hlxclib/stdio.h"
  52. #include "hxassert.h"
  53. #include "hxslist.h"
  54. #include "hxcomm.h"
  55. #include "hxengin.h"
  56. #include "ihxpckts.h"
  57. #include "hxplugn.h"
  58. #include "hxfiles.h"
  59. #include "hxformt.h"
  60. #include "hxmeta.h"
  61. #include "hxcore.h"
  62. #include "hxprefs.h"
  63. #include "hxausvc.h"
  64. #include "hxgroup.h"
  65. #include "hxsmbw.h"
  66. #include "hxstring.h"
  67. #include "chxeven.h"
  68. #include "chxelst.h"
  69. #include "strminfo.h"
  70. #include "hxflsrc.h"
  71. //#include "raevents.h"
  72. #include "hxtick.h"
  73. #include "hxplay.h"
  74. #include "hxtypes.h"
  75. #include "timeval.h"
  76. #include "pq.h"
  77. #include "hxsched.h"
  78. #include "hxstat.h"
  79. #include "dbcs.h"
  80. #include "hxcleng.h"
  81. #include "hxauth.h"
  82. #include "hxrquest.h"
  83. #include "hxstrutl.h"
  84. #include "hxupgrd.h"
  85. #include "srcinfo.h"
  86. #include "plghand2.h"
  87. #include "rmfftype.h"
  88. #include "hxxfile.h"
  89. #include "upgrdcol.h"
  90. #include "uri_schemes.h"
  91. #include "stream_desc_hlpr.h"
  92. #include "findfile.h"
  93. #include "hxheap.h"
  94. #ifdef _DEBUG
  95. #undef HX_THIS_FILE
  96. static const char HX_THIS_FILE[] = __FILE__;
  97. #endif
  98. #define FILEREAD_SIZE   4096
  99. HXFileSource::HXFileSource() 
  100.     : m_lRefCount(0)
  101.     , m_pFSObject(NULL)
  102.     , m_pFFObject(NULL)
  103.     , m_pRAMFFObject(NULL)
  104.     , m_pFileResponse(NULL)
  105.     , m_pFileFormatEnumerator(NULL)
  106.     , m_pCurrentFileFormatUnk(NULL)
  107.     , m_bCurrentFileFormatUnkInUse(FALSE)
  108.     , m_pFileObject(NULL)
  109.     , m_pRequestHandler(NULL)
  110.     , m_pMimeType(NULL)
  111.     , m_pExtension(NULL)
  112.     , m_pMimeFinderResponse(NULL)
  113.     , m_ulLastBufferingReturned(0)
  114.     , m_ulMaxPreRoll(0)
  115.     , m_uNumStreamsToBeFilled(0)
  116.     , m_bInFillMode(FALSE)
  117.     , m_llFillEndTime(0)
  118.     , m_llLastFillEndTime (0)
  119.     , m_bInitialPacket(TRUE)
  120.     , m_bFastStartInProgress(FALSE)
  121.     , m_bAddDefaultUpgrade(FALSE)
  122.     , m_pDefaultUpgradeString(NULL)
  123. #if defined(HELIX_FEATURE_ASM)
  124.     , m_pSimulatedSourceBandwidth(NULL)
  125. #endif /* HELIX_FEATURE_ASM */
  126.     , m_bValidateMetaDone(FALSE)
  127.     , m_pFileRecognizer(NULL)
  128.     , m_pFileReader(NULL)
  129. {
  130.     m_bAltURL = FALSE;
  131.     m_bPerfectPlay = TRUE;
  132. }
  133. HXFileSource::~HXFileSource()
  134. {
  135.     DoCleanup();
  136. }
  137. /////////////////////////////////////////////////////////////////////////
  138. // Method:
  139. // IUnknown::QueryInterface
  140. // Purpose:
  141. // Implement this to export the interfaces supported by your 
  142. // object.
  143. //
  144. STDMETHODIMP 
  145. HXFileSource::QueryInterface(REFIID riid, void** ppvObj)
  146. {
  147.     if (HXSource::QueryInterface(riid, ppvObj) == HXR_OK)
  148.     {
  149. return HXR_OK;
  150.     }
  151.     else if (IsEqualIID(riid, IID_IHXRegistryID))
  152.     {
  153. AddRef();
  154. *ppvObj = (IHXRegistryID*)this;
  155. return HXR_OK;
  156.     }
  157.     else if (IsEqualIID(riid, IID_IHXFormatResponse))
  158.     {
  159. AddRef();
  160. *ppvObj = (IHXFormatResponse*)this;
  161. return HXR_OK;
  162.     }
  163.     // XXX HP
  164.     // we assume the FF object doesn't QI from its m_pContext within
  165.     // its ::QueryInterface(), otherwise we are in trouble!! - indefinite
  166.     // loop
  167.     // This is for IHXBackChannel, IHXASMSource
  168.     else if (m_pFFObject && m_pFFObject->QueryInterface(riid, ppvObj) == HXR_OK)
  169.     {
  170. return HXR_OK;
  171.     }
  172. #if defined(HELIX_FEATURE_ASM)
  173.     else if (m_pSimulatedSourceBandwidth &&
  174.      m_pSimulatedSourceBandwidth->QueryInterface(riid, ppvObj) == HXR_OK)
  175.     {
  176. return HXR_OK;
  177.     }
  178. #endif /* HELIX_FEATURE_ASM */
  179.     else if (m_pPlayer &&
  180.      m_pPlayer->QueryInterface(riid, ppvObj) == HXR_OK)
  181.     {
  182. return HXR_OK;
  183.     }
  184.     // we don't have m_pPlayer during AutoConfig    
  185.     else if (m_pEngine &&
  186.      m_pEngine->QueryInterface(riid, ppvObj) == HXR_OK)
  187.     {
  188. return HXR_OK;
  189.     }
  190.     *ppvObj = NULL;
  191.     return HXR_NOINTERFACE;
  192. }
  193. /////////////////////////////////////////////////////////////////////////
  194. // Method:
  195. // IUnknown::AddRef
  196. // Purpose:
  197. // Everyone usually implements this the same... feel free to use
  198. // this implementation.
  199. //
  200. STDMETHODIMP_(ULONG32) 
  201. HXFileSource::AddRef()
  202. {
  203.     return InterlockedIncrement(&m_lRefCount);
  204. }
  205. /////////////////////////////////////////////////////////////////////////
  206. // Method:
  207. // IUnknown::Release
  208. // Purpose:
  209. // Everyone usually implements this the same... feel free to use
  210. // this implementation.
  211. //
  212. STDMETHODIMP_(ULONG32) 
  213. HXFileSource::Release()
  214. {
  215.     if (InterlockedDecrement(&m_lRefCount) > 0)
  216.     {
  217. return m_lRefCount;
  218.     }
  219.     delete this;
  220.     return 0;
  221. }
  222. void
  223. HXFileSource::ReSetup()
  224. {
  225.     m_ulLastBufferingReturned = 0;;
  226.     m_ulFirstPacketTime = 0;
  227.     m_llFillEndTime = 0;
  228.     m_llLastFillEndTime = 0;
  229.     m_ulMaxPreRoll = 0;
  230.     m_uNumStreamsToBeFilled = 0;    
  231.     m_bInitialized = FALSE;
  232.     m_bInFillMode = FALSE;
  233.     m_bInitialPacket = TRUE;
  234.     m_bFastStartInProgress = FALSE;
  235.     m_ulStreamHeadersExpected = 0;
  236.     if (m_pURL)
  237.     {
  238.         CHXURL* pURL = new CHXURL(*m_pURL);
  239. #if defined(HELIX_FEATURE_SMIL_REPEAT)
  240. if (m_pSourceInfo)
  241. {
  242.     CHXSimpleList* pRepeatList = m_pSourceInfo->m_bLeadingSource?m_pSourceInfo->m_pRepeatList:
  243.  m_pSourceInfo->m_pPeerSourceInfo->m_pRepeatList;
  244.     if (pRepeatList)
  245.     {
  246. RepeatInfo* pRepeatInfo = (RepeatInfo*)pRepeatList->GetAt(m_pSourceInfo->m_curPosition);
  247. m_ulDelay = m_pSourceInfo->m_ulRepeatDelayTimeOffset + pRepeatInfo->ulDelay;
  248. if (m_pSourceInfo->m_bRepeatIndefinite &&
  249.     m_pSourceInfo->m_ulMaxDuration &&
  250.     m_ulDelay + pRepeatInfo->ulDuration > m_ulOriginalDelay + m_pSourceInfo->m_ulMaxDuration)
  251. {
  252.     m_ulRestrictedDuration = m_ulOriginalDelay + m_pSourceInfo->m_ulMaxDuration - m_ulDelay;
  253. }
  254. else
  255. {
  256.     m_ulRestrictedDuration = pRepeatInfo->ulDuration;
  257. }
  258.     }
  259. }
  260. #endif /* HELIX_FEATURE_SMIL_REPEAT */
  261. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  262. m_pStats->Reset();
  263. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  264. m_bReSetup = TRUE;
  265. Setup(pURL, FALSE);
  266.         delete pURL;
  267.     }
  268.     return;
  269. }
  270. // pURL may be in the form of URL
  271. // events will be opened as a separate source by HXPlayer...
  272. HX_RESULT 
  273. HXFileSource::Setup(const CHXURL* pURL, BOOL bAltURL)
  274. {
  275.     HX_RESULT     theErr = HXR_OK;    
  276.     IUnknown*     pUnknown = NULL;
  277.     IUnknown*     pObject = NULL;
  278.     IHXPlugin*     pHXPlugin = NULL;
  279.     mLastError = HXR_OK;
  280.  
  281.     if (!pURL)
  282.     {
  283. return( HXR_INVALID_PATH );
  284.     }                       
  285.     const char* purl = pURL->GetURL();
  286.     if (!purl || !*purl)
  287.     {
  288. return( HXR_INVALID_PATH );
  289.     }                       
  290.     if (!m_bReSetup)
  291.     {
  292. theErr = SetupRegistry();
  293. m_ulOriginalDelay = m_ulDelay;
  294.     }
  295.     ReadPreferences();
  296.     HX_VECTOR_DELETE(m_pszURL);
  297.     HX_DELETE(m_pURL);
  298.     if (!theErr && pURL)
  299.     {
  300. m_pszURL = new char[strlen(purl) + 1];
  301. if (m_pszURL)
  302. {
  303.     strcpy(m_pszURL, purl); /* Flawfinder: ignore */
  304.     m_pURL = new CHXURL(*pURL);
  305.     if( !m_pURL )
  306.     {
  307.         theErr = HXR_OUTOFMEMORY;
  308.     }
  309. }
  310. else
  311. {
  312.     theErr = HXR_OUTOFMEMORY;
  313. }
  314.     }
  315. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  316.     if (!theErr && m_pStats)
  317.     {
  318. // save URL to the registry
  319. if (m_pStats->m_pSourceName && m_pszURL)
  320. {
  321.     m_pStats->m_pSourceName->SetStr((char*)m_pszURL);
  322. }
  323. // update transport mode(local machine)
  324. if (m_pStats->m_pTransportMode && m_pURL)
  325. {
  326.     UINT16 uProtocol = m_pURL->GetProtocol();
  327.     if (uProtocol == httpProtocol)
  328.     {
  329. m_pStats->m_pTransportMode->SetStr("HTTP");
  330.     }
  331.     else
  332.     {
  333. m_pStats->m_pTransportMode->SetStr("Local");
  334.     }
  335. }
  336.     }
  337. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY*/
  338. #if defined(HELIX_FEATURE_ASM) && defined(HELIX_FEATURE_REGISTRY)
  339.     if (!theErr && m_pPlayer && !m_pSimulatedSourceBandwidth && m_pRegistry)
  340.     {
  341. /* Check if the core is used for simulated network playback for
  342.  * local files. This feature is used by the Tools group
  343.  * for Preview mode at different bandwidths.
  344.  */
  345. INT32 lUseNetBandwidth = 0;
  346. if ((m_pRegistry->GetIntByName("UseNetBandwidthForLocalPlayback", 
  347. lUseNetBandwidth) == HXR_OK) && 
  348.     (lUseNetBandwidth == 1))
  349. {
  350.     m_pSimulatedSourceBandwidth = new SourceBandwidthInfo;
  351.     m_pSimulatedSourceBandwidth->AddRef();
  352. }
  353.    }
  354. #endif /* HELIX_FEATURE_ASM && HELIX_FEATURE_REGISTRY*/
  355.     if (!theErr)
  356.     {
  357. const char* pProtocolEnd = HXFindChar(purl,':');
  358. if (!pProtocolEnd)
  359. {
  360.     goto exit;
  361. }
  362. int nLength = pProtocolEnd - purl;
  363. CHXString strProtocol(purl,nLength);
  364. IHXPlugin2Handler* pPlugin2Handler;
  365. if (HXR_OK != m_pEngine->QueryInterface(IID_IHXPlugin2Handler, (void**)&pPlugin2Handler))
  366. {
  367.     theErr = HXR_UNEXPECTED;
  368.     goto exit;
  369. }
  370. if (HXR_OK == pPlugin2Handler->FindPluginUsingStrings(PLUGIN_CLASS, PLUGIN_FILESYSTEM_TYPE, 
  371.     PLUGIN_FILESYSTEMPROTOCOL, (char*)(const char*)strProtocol, NULL, NULL, pUnknown))
  372. {
  373.     pUnknown->QueryInterface(IID_IHXFileSystemObject, (void**) &m_pFSObject);
  374.             HX_RELEASE(pUnknown);
  375. }
  376. else
  377. {
  378.     MergeUpgradeRequest(TRUE, (char*)(const char*) strProtocol);
  379.     theErr = HXR_NO_FILESYSTEM;
  380. }
  381. HX_RELEASE(pPlugin2Handler);
  382. // Initialize the File System plugin...
  383. if (!theErr)
  384. {
  385.     if (HXR_OK != m_pFSObject->QueryInterface(IID_IHXPlugin,(void**)&pHXPlugin))
  386.     {
  387. theErr = HXR_NOT_INITIALIZED;
  388. goto exit;
  389.     }
  390.     if (HXR_OK != pHXPlugin->InitPlugin((IUnknown*) (IHXStreamSource*)this))
  391.     {
  392. theErr = HXR_NOT_INITIALIZED;
  393. goto exit;
  394.     }
  395. }
  396. // Create a FileObject in order to determine the mime-type of the file
  397. if (!theErr)
  398. {
  399.             // Create the file object...
  400.     if (HXR_OK != m_pFSObject->CreateFile(&pObject))
  401.     {
  402. theErr = HXR_NOT_INITIALIZED;
  403. goto exit;
  404.     }
  405.          
  406.     if ((HXR_OK != pObject->QueryInterface(IID_IHXFileObject,
  407. (void**)&m_pFileObject)) ||
  408.         (HXR_OK != pObject->QueryInterface(IID_IHXRequestHandler,
  409. (void**)&m_pRequestHandler)))
  410.     {
  411. theErr = HXR_NOT_INITIALIZED;
  412. goto exit;
  413.     }
  414.     IHXHTTPRedirect* pHttpRedirect = NULL;
  415.             m_pFileObject->QueryInterface(IID_IHXHTTPRedirect, (void**)&pHttpRedirect);
  416.             if (pHttpRedirect)
  417.             {
  418.                 pHttpRedirect->SetResponseObject((IHXHTTPRedirectResponse*) this);
  419.                 pHttpRedirect->Release();
  420.             }
  421.     // set request
  422.     SetRequest(m_pURL, bAltURL);
  423.     
  424.     // we want to protect against the TLC opening another URL
  425.     m_pPlayer->SetModal(TRUE);
  426.     theErr = m_pRequestHandler->SetRequest(m_pRequest);
  427.     m_pPlayer->SetModal(FALSE);
  428.     if (theErr != HXR_OK)
  429.     {
  430. theErr = HXR_NOT_INITIALIZED;
  431. goto exit;
  432.     }
  433.     theErr = ExtendedSetup(purl);
  434. }
  435.     }
  436. exit:
  437.     HX_RELEASE(pHXPlugin);
  438.     HX_RELEASE(pObject);
  439.     if (theErr)
  440.     {
  441. HX_RELEASE(m_pFSObject);
  442.     }
  443.     
  444.     return theErr;
  445. }
  446. HX_RESULT
  447. HXFileSource::ExtendedSetup(const char* pszURL)
  448. {
  449.     HX_RESULT theErr = HXR_OK;
  450.     char* pszTemp = NULL;
  451.     const char* pMimeType = NULL;
  452.     IHXBuffer* pValue = NULL;
  453.     IHXValues* pResponseHeaders = NULL;
  454.     IHXFileMimeMapper* pFileMimeMapper = NULL;
  455.     /* Does the file object support finding of mime types */
  456.     if (HXR_OK == m_pFileObject->QueryInterface(IID_IHXFileMimeMapper,(void**)&pFileMimeMapper))
  457.     {
  458.         if (!m_pMimeFinderResponse)
  459. {
  460.     // Initialize our MimeFinder!
  461.     m_pMimeFinderResponse = new CMimeFinderFileResponse(this);
  462.     if (!m_pMimeFinderResponse)
  463.     {
  464. theErr = HXR_NOT_INITIALIZED;
  465.     }
  466.     else
  467.     {
  468. m_pMimeFinderResponse->AddRef();
  469.     }
  470. }
  471. // Init the file object, and ask for the mime type!
  472. if (!theErr && HXR_OK != pFileMimeMapper->FindMimeType(pszURL, m_pMimeFinderResponse))
  473. {
  474.     theErr = HXR_DOC_MISSING;
  475. }
  476. HX_RELEASE(pFileMimeMapper);
  477.     }
  478.     else
  479.     {
  480. if (HXR_OK == m_pRequest->GetResponseHeaders(pResponseHeaders) &&
  481. pResponseHeaders)
  482. {
  483.     if (HXR_OK == pResponseHeaders->GetPropertyCString("Content-Type", pValue) &&
  484. pValue)
  485.     {
  486. pMimeType = (char*)pValue->GetBuffer();
  487.     }
  488.     HX_RELEASE(pValue);
  489. }
  490. HX_RELEASE(pResponseHeaders);
  491. if (!pMimeType)
  492. {
  493.     if (HXXFile::IsPlusURL(pszURL))
  494.     {
  495. pMimeType = "application/x-pn-plusurl";
  496.     }
  497.     else
  498.     {
  499. // separate options from the URL
  500. pszTemp = (char*) ::HXFindChar(pszURL, '?');
  501. if (pszTemp)
  502. {
  503.     *pszTemp = '';
  504. }
  505.     }
  506. }
  507. FinishSetup(HXR_OK, pMimeType);
  508. theErr = mLastError;
  509.     }
  510.     return theErr;
  511. }
  512. void 
  513. HXFileSource::FinishSetup(HX_RESULT status, const char* pMimeType)
  514. {
  515. #if !defined(HELIX_FEATURE_META)
  516.     m_bValidateMetaDone = TRUE;
  517.     m_bIsMeta = FALSE;
  518. #endif /* HELIX_FEATURE_META */
  519.     if (status == HXR_OK)
  520.     {
  521. if (pMimeType)
  522. {
  523.     HX_VECTOR_DELETE(m_pMimeType);
  524.     m_pMimeType = ::new_string(pMimeType);
  525. }
  526. // detect if this is a valid meta file if we haven't done so
  527. if (!m_bValidateMetaDone)
  528. {
  529.     AttempToLoadFilePlugin(RAM_MIMETYPE);
  530. }
  531. #if defined(HELIX_FEATURE_SDPLITE)
  532.         // retrieve the whole SDP file without SDP fileformat/renderer which
  533.         // requires basic group&track
  534. else if (m_pMimeType && 0 == strcasecmp(m_pMimeType, "application/sdp"))
  535.         {
  536.             if (!m_pFileReader)
  537.             {
  538.                 m_pFileReader = new CFileReader(this);
  539.                 HX_ADDREF(m_pFileReader);
  540.             }
  541.             if (m_pFileReader)
  542.             {
  543.                 m_pFileReader->GetFile(m_pFileObject);
  544.             }
  545.             return;
  546.         }
  547. #endif /* HELIX_FEATURE_SDPLITE */
  548. // we have already validated the file and know whether
  549. // it is a meta or not
  550.         else
  551. {
  552.     if (m_bIsMeta)
  553.     {
  554. AttempToLoadFilePlugin(RAM_MIMETYPE);
  555.     }
  556.     else
  557.     {
  558.                 // Call recognizer here if we do not have a definite
  559.                 // mimetype from the filesytem
  560.                 if ((!m_pMimeType || m_pMimeType == "*") && !m_pFileRecognizer)
  561.                 {
  562.                     m_pFileRecognizer = new CHXFileRecognizer;
  563.                     if (m_pFileRecognizer)
  564.                     {
  565.                         m_pFileRecognizer->AddRef();
  566.                         if (!m_pMimeFinderResponse)
  567.                         {
  568.                             m_pMimeFinderResponse = new CMimeFinderFileResponse(this);                        
  569.                             HX_ADDREF(m_pMimeFinderResponse);
  570.                         }
  571.                         if (m_pMimeFinderResponse)
  572.                         {
  573.                             m_pFileRecognizer->GetMimeType(m_pFileObject, 
  574.                                                            (IHXFileRecognizerResponse*)m_pMimeFinderResponse);
  575.                             return;
  576.                         }
  577.                         else
  578.                         {
  579.                             HX_DELETE(m_pFileRecognizer); 
  580.                         }
  581.                     }
  582.                 }
  583.                 
  584.                 AttempToLoadFilePlugin(m_pMimeType);
  585.     }
  586. }
  587.     }
  588.     else if (!mLastError)
  589.     {
  590. mLastError = status;
  591. ReportError(mLastError);
  592.     }
  593. }
  594. void 
  595. HXFileSource::AttempToLoadFilePlugin(const char* pMimeType)
  596. {
  597.     char*   pExtension = NULL;
  598.     char*   pPos = NULL;
  599.     char*   pszTemp = NULL;
  600.     char*   pszURL = NULL;
  601.     HX_RESULT theErr = HXR_OK;
  602.     IUnknown* pUnknown = NULL;
  603.     
  604.     if (!m_bValidateMetaDone)
  605.     {
  606. pExtension = "ram";
  607.     }
  608.     else
  609.     {
  610. // This will fix up any redirected 
  611. GetURL();
  612.     
  613. // make a copy of the URL
  614. pszURL = new char[strlen(m_pszURL)+1];
  615. memset(pszURL, 0, strlen(m_pszURL)+1);
  616. strcpy(pszURL, m_pszURL); /* Flawfinder: ignore */
  617. // separate fragment from the URL
  618. pszTemp = (char*) ::HXFindChar(pszURL, '#');
  619. if (pszTemp)
  620. {
  621.     *pszTemp = '';
  622. }
  623. // separate options from the URL
  624. pszTemp = (char*) ::HXFindChar(pszURL, '?');
  625. if (pszTemp)
  626. {
  627.     *pszTemp = '';
  628. }
  629. // load plugin
  630.         // find the extension, stopping if we hit any path separators
  631.         pPos = pszURL;
  632.         while (*pPos)
  633.         {
  634.             pPos++;
  635.         }
  636.         while (pPos != pszURL)
  637.         {
  638.             if (*pPos == '.')
  639.             {
  640.                 pExtension = pPos + 1;
  641.                 break;
  642.             }
  643.             if (strncmp(pPos, OS_PATH_DELIMITER, strlen(OS_PATH_DELIMITER)) == 0)
  644.             {
  645.                 // Don't search past a directory separator for an extension
  646.                 break;
  647.             }
  648.                             
  649.             pPos--;
  650.         }
  651.              
  652. if (pExtension)
  653. {
  654.     HX_VECTOR_DELETE(m_pExtension);
  655.     m_pExtension = ::new_string(pExtension);
  656. }
  657.     }
  658.     if (!m_pCurrentFileFormatUnk)
  659.     {
  660. IHXPluginHandler3* pPlugin2Handler3 = NULL;
  661. HX_VERIFY(HXR_OK ==
  662.     m_pPlayer->m_pPlugin2Handler->QueryInterface(IID_IHXPluginHandler3, (void**) &pPlugin2Handler3));
  663. if (pMimeType)
  664. {
  665.     pPlugin2Handler3->FindGroupOfPluginsUsingStrings(PLUGIN_CLASS, PLUGIN_FILEFORMAT_TYPE, 
  666.     PLUGIN_FILEMIMETYPES, (char*)pMimeType, 0, 0, m_pFileFormatEnumerator);
  667. }
  668. if (!m_pFileFormatEnumerator)
  669. {
  670.     pPlugin2Handler3->FindGroupOfPluginsUsingStrings(PLUGIN_CLASS, PLUGIN_FILEFORMAT_TYPE, 
  671. PLUGIN_FILEEXTENSIONS, pExtension, 0 ,0, m_pFileFormatEnumerator);
  672. }
  673. HX_RELEASE(pPlugin2Handler3);
  674. if (m_pFileFormatEnumerator)
  675. {
  676.     m_pFileFormatEnumerator->GetNextPlugin(m_pCurrentFileFormatUnk, NULL);
  677.     HX_ASSERT(m_pCurrentFileFormatUnk != NULL);
  678. }
  679.     }
  680.     if (!m_pCurrentFileFormatUnk)
  681.     {
  682. if (!m_bDefaultAltURL)
  683. {
  684.     theErr = HXR_NO_FILEFORMAT;
  685. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  686.     IHXUpgradeCollection* pUpgradeCollection = NULL;
  687.     if(m_pPlayer)
  688. m_pPlayer->QueryInterface(IID_IHXUpgradeCollection, (void**)&pUpgradeCollection);
  689.     if(pUpgradeCollection)
  690.     {
  691. IHXBuffer* pPluginID = (IHXBuffer*) new CHXBuffer;
  692. pPluginID->AddRef();
  693. if (pMimeType && !(*pMimeType == '*'))
  694. {
  695.     pPluginID->Set((const UINT8*)pMimeType, strlen(pMimeType) + 1);
  696. }
  697. else if (pExtension)
  698. {
  699.     // return file extension if mimeType is unknown
  700.     pPluginID->Set((const UINT8*)pExtension, strlen(pExtension) + 1);
  701. }
  702. else
  703. {
  704.     pPluginID->Set((const UINT8*)"Unknown FileFormat", strlen("Unknown FileFormat") + 1);
  705. }
  706. pUpgradeCollection->Add(eUT_Required, pPluginID, 0, 0);
  707. pPluginID->Release();
  708. pUpgradeCollection->Release();
  709.     }
  710. #endif /* HELIX_FEATURE_AUTOUPGRADE */
  711. }
  712. else
  713. {
  714.     theErr = HXR_INVALID_FILE;
  715. }
  716.     }
  717.     // initialize fileformat plugins...
  718.     if (!theErr)
  719.     {
  720. theErr = InitializeFileFormat();
  721.     }
  722.     HX_VECTOR_DELETE(pszURL);
  723.     // if there is an error, make sure there is no m_pCurrentFileFormatUnk...
  724.     // if m_pCurrentFileFormatUnk is not NULL, it means we need to try 
  725.     // the next plugin that supports this mimetype.
  726.     // ignore error in this case.
  727.     if (theErr && !m_pCurrentFileFormatUnk)
  728.     {
  729. mLastError = theErr;
  730. CheckForDefaultUpgrade(theErr);
  731. // merge any upgrade requests for this source to the player
  732. MergeUpgradeRequest(m_bAddDefaultUpgrade, m_pDefaultUpgradeString);
  733. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  734. if (theErr != HXR_NO_FILEFORMAT)
  735. #endif
  736. {
  737.     ReportError(theErr);
  738.     DoCleanup();
  739. }
  740.     }
  741. }
  742. HX_RESULT
  743. HXFileSource::InitializeFileFormat()
  744. {
  745.     HX_RESULT theErr = HXR_OK;
  746.     HX_RESULT resultInitFF = HXR_OK;
  747.     IHXRequest* pRequest = NULL;
  748.     IHXPlugin* pPlugin = NULL;
  749.     
  750.     HX_ASSERT(m_pCurrentFileFormatUnk != NULL);
  751.     if (m_pCurrentFileFormatUnk)
  752.     {
  753. HX_VERIFY(HXR_OK ==
  754.     m_pCurrentFileFormatUnk->QueryInterface(IID_IHXFileFormatObject, (void**) &m_pFFObject));
  755.     }
  756.     
  757.     HX_RELEASE(m_pCurrentFileFormatUnk);
  758.     m_bCurrentFileFormatUnkInUse = FALSE;
  759.     HX_ASSERT(m_pFFObject != NULL);
  760.     if (!m_pFFObject)
  761.     {
  762. return HXR_INVALID_FILE; //??
  763.     }
  764.     // we keep RAM FF object around by AddRef()
  765.     // to avoid self-destruct in ::InitDone when it's not a RAM
  766.     // It will be released in ::FinishSetup().
  767.     
  768.     if (!m_bValidateMetaDone)
  769.     {
  770. HX_ASSERT(!m_pRAMFFObject);
  771. m_pRAMFFObject = m_pFFObject;
  772. m_pRAMFFObject->AddRef();
  773.     }
  774.     
  775.     if (HXR_OK != m_pFFObject->QueryInterface(IID_IHXPlugin,(void**)&pPlugin))
  776.     {
  777. theErr = HXR_NOT_INITIALIZED;
  778. goto exit;
  779.     }
  780.     if (HXR_OK != pPlugin->InitPlugin((IUnknown*) (IHXStreamSource*)this))
  781.     {
  782. theErr = HXR_NOT_INITIALIZED;
  783. goto exit;
  784.     }
  785.     if (m_pRequestHandler->GetRequest(pRequest) != HXR_OK)
  786.     {
  787. theErr = HXR_NOT_INITIALIZED;
  788. goto exit;
  789.     }
  790.     if (HXR_OK != (resultInitFF=m_pFFObject->InitFileFormat(pRequest,
  791.                                       this,
  792.                                       m_pFileObject)) )
  793.     {
  794. if(HXR_UNSUPPORTED_VIDEO == resultInitFF ||
  795.    HXR_UNSUPPORTED_AUDIO == resultInitFF ||
  796.    HXR_DOC_MISSING == resultInitFF)
  797. {
  798.     theErr = resultInitFF;
  799. }
  800. else
  801. {
  802.     theErr = HXR_INVALID_FILE; //HXR_NOT_INITIALIZED;
  803. }
  804. goto exit;
  805.     }
  806. exit:
  807.     HX_RELEASE(pRequest);
  808.     HX_RELEASE(pPlugin);
  809.     if (theErr)
  810.     {
  811. /* do we need to try the next one! */
  812. if (!m_pCurrentFileFormatUnk && m_pFileFormatEnumerator)
  813. {
  814.     m_pFileFormatEnumerator->GetNextPlugin(m_pCurrentFileFormatUnk, NULL);
  815.     if (m_pCurrentFileFormatUnk && m_pSourceInfo)
  816.     {
  817. m_pSourceInfo->ScheduleProcessCallback();
  818.     }
  819. }
  820.     }
  821.     return theErr;
  822. }
  823. HX_RESULT 
  824. HXFileSource::DoCleanup(EndCode endCode)
  825. {
  826.     /* UnRegister any previously registered source */
  827.     if (m_pSourceInfo)
  828.     {
  829.         m_pSourceInfo->UnRegister();
  830.     }
  831.     CleanupFileObjects();
  832.     HX_RELEASE(m_pCurrentFileFormatUnk);
  833.     m_bCurrentFileFormatUnkInUse = FALSE;
  834.     HX_RELEASE(m_pFileFormatEnumerator);
  835. #if defined(HELIX_FEATURE_ASM)
  836.     HX_RELEASE(m_pSimulatedSourceBandwidth);
  837. #endif /* HELIX_FEATURE_ASM */
  838.     HX_VECTOR_DELETE(m_pMimeType);
  839.     HX_VECTOR_DELETE(m_pExtension);
  840.     HX_VECTOR_DELETE(m_pDefaultUpgradeString);    
  841.     m_bAddDefaultUpgrade = FALSE;
  842.     HX_RELEASE(m_pFileRecognizer);
  843. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  844.     /* Reason to add this code is because in FileSource 
  845.      * we create/delete it while in NetSource
  846.      * case, Protocol creates/deletes it
  847.      */
  848.     for (CHXMapLongToObj::Iterator i = mStreamInfoTable->Begin();
  849.          i != mStreamInfoTable->End(); ++i) 
  850.     {    
  851. STREAM_INFO* sInfo = (STREAM_INFO*) (*i);
  852. if (sInfo)
  853. {
  854.     HX_DELETE (sInfo->m_pStats);
  855. }
  856.     }
  857. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY*/
  858.     HXSource::DoCleanup();
  859.     return HXR_OK;
  860. }
  861. void
  862. HXFileSource::ReportError(HX_RESULT theErr)
  863. {
  864.     CHXString DecodedURL;
  865.     CHXURL::decodeURL(m_pURL->GetURL(), DecodedURL);
  866.     m_pPlayer->ReportError( this, theErr, DecodedURL );
  867. }
  868. void
  869. HXFileSource::CleanupFileObjects()
  870. {
  871.     HX_RELEASE (m_pFSObject);
  872.     if (m_pFFObject)
  873.     {
  874. m_pFFObject->Close();
  875. HX_RELEASE (m_pFFObject);
  876.     }    
  877.     
  878.     HX_RELEASE (m_pFileResponse);
  879.     if (m_pFileObject)
  880.     {
  881. m_pFileObject->Close();
  882. HX_RELEASE (m_pFileObject);
  883.     }
  884.     HX_RELEASE (m_pRequestHandler);
  885.     HX_RELEASE (m_pMimeFinderResponse);
  886. }
  887. HX_RESULT
  888. HXFileSource::DoSeek(ULONG32 seekTime)
  889. {
  890.     /* Add any start time to seek time */
  891.     if (seekTime >= m_ulDelay)
  892.     {
  893. seekTime    -= m_ulDelay;
  894. m_bDelayed   = FALSE;
  895.     }
  896.     else
  897.     {
  898. seekTime = 0;
  899. /* This source has not been even started yet...
  900.  * Do not attempt to seek it if the start time = 0
  901.  */
  902. if (m_bDelayed && m_ulStartTime == 0 && !m_bSourceEnd)
  903. {
  904.     // will start pre-fetch again in TryResume()
  905.     if (!m_bIsPreBufferingDone)
  906.     {
  907. m_bIsPreBufferingStarted = FALSE;
  908. // will be registered again in DoResume() or TryResume()
  909. if (m_pSourceInfo)
  910. {
  911.     m_pSourceInfo->UnRegister();
  912. }
  913.     }
  914.     return HXR_OK;
  915. }
  916. m_bDelayed = TRUE;
  917.     }
  918.     seekTime += m_ulStartTime;
  919.     /* Are we seeking past the last expected packet time?
  920.      * If so, don't bother... and mark this source as done
  921.      */
  922.     HX_ASSERT(m_llLastExpectedPacketTime < MAX_UINT32);
  923.     // XXX HP make sure the source has been initialized otherwise
  924.     // m_llLastExpectedPacketTime could be 0 and we could falsely
  925.     // mark the source ended
  926.     if (m_bInitialized && !mLiveStream && seekTime >= INT64_TO_UINT32(m_llLastExpectedPacketTime))
  927.     {
  928. if (m_pSourceInfo && m_pSourceInfo->m_bSeekToLastFrame)
  929. {
  930.     seekTime = INT64_TO_UINT32(m_llLastExpectedPacketTime);
  931. }
  932. else
  933. {
  934.     m_bSourceEnd = TRUE;
  935.     m_bForcedSourceEnd = TRUE;
  936.     AdjustClipBandwidthStats(FALSE);
  937.     goto cleanup;
  938. }
  939.     }
  940.     m_bInitialBuffering = TRUE;
  941.     m_bForcedSourceEnd = FALSE;
  942.     m_uActiveStreams = m_uNumStreams; 
  943.     m_bIsPreBufferingStarted = FALSE;
  944.     m_bIsPreBufferingDone = FALSE;
  945.     if (m_nSeeking == 0)
  946.     {
  947. m_nSeeking++;
  948.     }
  949. #if defined(HELIX_FEATURE_RECORDCONTROL)
  950.     if (m_pRecordControl && m_pRecordControl->Seek(seekTime) == HXR_OK &&
  951. m_bPlayFromRecordControl)
  952.     {
  953. m_pBufferManager->DoSeek(seekTime, TRUE);
  954. SeekDone(HXR_OK);
  955.     }
  956.     else
  957. #endif /* HELIX_FEATURE_RECORDCONTROL */
  958.     {
  959. m_bSourceEnd = FALSE;
  960. m_pBufferManager->DoSeek(seekTime, FALSE);
  961. if (HXR_OK != m_pFFObject->Seek(seekTime))
  962. {
  963.     if (m_nSeeking)
  964.     {
  965. m_nSeeking--;
  966.     }
  967. }
  968.     }
  969.     m_llLastFillEndTime = 0;   
  970. cleanup:
  971.     return HXR_OK;
  972. }
  973. HX_RESULT
  974. HXFileSource::DoPause(void)
  975. {
  976.     if (m_bPaused)
  977.     {
  978. return HXR_OK;
  979.     }
  980.     /* Only if it is an external pause */
  981.     if (!m_bSourceEnd && !m_bDelayed && m_pBufferManager)
  982.     {
  983. m_pBufferManager->DoPause();
  984.     }
  985.     m_bPaused = TRUE;
  986.     return HXR_OK;
  987. }
  988. HX_RESULT   
  989. HXFileSource::StartInitialization(void)
  990. {
  991.     m_bFastStartInProgress = TRUE;
  992.     m_pBufferManager->DoResume();
  993.     if (m_pSourceInfo)
  994.     {
  995. m_pSourceInfo->Resumed();
  996.     }
  997.     return HXR_OK;
  998. }
  999. HX_RESULT   
  1000. HXFileSource::DoResume(void)
  1001. {
  1002.     HX_RESULT theErr = HXR_OK;
  1003.     m_bFastStartInProgress = FALSE;
  1004.     /* This may happen if a new source is added from SMIL renderer during 
  1005.      * initialization of exisitng sources. We will eventually call Resume 
  1006.      * on this source once it is initialized in SourceInfo::ProcessIdle
  1007.      */
  1008.     if (!m_bInitialized || (m_pSourceInfo && !m_pSourceInfo->IsInitialized()))
  1009.     {
  1010. return HXR_OK;
  1011.     }
  1012.     if (m_bSourceEnd || CanBeResumed())
  1013.     {
  1014. m_bResumePending = FALSE;
  1015. if (!m_bSourceEnd)
  1016. {
  1017.     m_pBufferManager->DoResume();
  1018. }
  1019. // resume the audio streams if the source is added
  1020. // while the player is in play mode
  1021. // CAUTION: this will cause rewind in audio service
  1022. if (m_bFirstResume && m_pPlayer->IsPlaying() &&
  1023.     m_ulDelay <= m_pPlayer->GetInternalCurrentPlayTime())
  1024. {
  1025.     ResumeAudioStreams();
  1026. }
  1027. m_bFirstResume = FALSE;
  1028. m_bPaused = FALSE;
  1029. if (m_pSourceInfo)
  1030. {
  1031.     m_pSourceInfo->Resumed();
  1032. }
  1033. if (!m_bSourceEnd)
  1034. {
  1035.     theErr = FillBuffers();
  1036. }
  1037.     }
  1038.     if (!theErr && !m_bIsActive && !m_bDelayed &&
  1039. m_pPlayer->GetInternalCurrentPlayTime() >= m_ulDelay)
  1040.     {
  1041. AdjustClipBandwidthStats(TRUE);
  1042.     }
  1043.     if (theErr == HXR_AT_END)
  1044.     {
  1045. SetEndOfClip();
  1046. theErr = HXR_OK;
  1047.     }
  1048.     return theErr;
  1049. }
  1050. /************************************************************************
  1051.  * Method:
  1052.  *     IHXPendingStatus::GetStatus
  1053.  * Purpose:
  1054.  *     Called by the user to get the current pending status from an object
  1055.  */
  1056. STDMETHODIMP
  1057. HXFileSource::GetStatus
  1058. (
  1059.     REF(UINT16) uStatusCode, 
  1060.     REF(IHXBuffer*) pStatusDesc, 
  1061.     REF(UINT16) ulPercentDone
  1062. )
  1063. {
  1064.     HX_RESULT hResult = HXR_OK;
  1065.     IHXPendingStatus* pStatus = NULL;
  1066.     UINT16  buffer = 100;
  1067.     UINT16  statusCode = HX_STATUS_READY;
  1068.     UINT16  percentDone = 0;
  1069.     uStatusCode     = HX_STATUS_READY;
  1070.     pStatusDesc     = 0;
  1071.     ulPercentDone   = 0;
  1072.     
  1073.     if (m_bDelayed)
  1074.     {
  1075. return HXR_OK;
  1076.     }
  1077.     if (m_bSourceEnd)
  1078.     {
  1079. if (!IsRebufferDone())
  1080. {
  1081.     uStatusCode = HX_STATUS_BUFFERING;
  1082.     ulPercentDone = 99;
  1083. }
  1084. else
  1085. {
  1086.     if (m_bInitialBuffering)
  1087.     {
  1088. InitialBufferingDone();
  1089.     }
  1090.     m_ulLastBufferingReturned = 100;
  1091.     uStatusCode = HX_STATUS_READY;
  1092. }
  1093. return HXR_OK;
  1094.     }
  1095.     if (m_bInitialized)
  1096.     {
  1097. if (m_bFirstResume)
  1098. {
  1099.     uStatusCode     = HX_STATUS_INITIALIZING;
  1100.     return HXR_OK;
  1101. }
  1102. m_pBufferManager->GetStatus(uStatusCode, 
  1103.     pStatusDesc,
  1104.     ulPercentDone);
  1105. buffer = ulPercentDone;
  1106. /* We only aggregate buffering from a lower level if we are in a buffering mode.
  1107.  * Reason: Once the initial bufering is done, we go in buffering more ONLY IF the
  1108.  * renderer tells us that it is in a panic state and we run out of packets.
  1109.  */
  1110. if (buffer == 100 && !m_bInitialBuffering)
  1111. {     
  1112.     // Rebuffer requested by the Renderer might not be
  1113.     // done yet
  1114.     if (!IsRebufferDone())
  1115.     {
  1116. uStatusCode = HX_STATUS_BUFFERING;
  1117. ulPercentDone = 99;
  1118.     }
  1119.     else
  1120.     {
  1121. uStatusCode = HX_STATUS_READY;
  1122.     }
  1123.     return HXR_OK;
  1124. }
  1125.     }
  1126.     if (m_pFFObject)
  1127.     {
  1128. if (HXR_OK != m_pFFObject->QueryInterface(IID_IHXPendingStatus, (void**)&pStatus))
  1129. {
  1130.     goto exit;
  1131. }
  1132. if (HXR_OK != pStatus->GetStatus(statusCode, pStatusDesc, percentDone))
  1133. {
  1134.     goto exit;
  1135. }
  1136.     }
  1137.     else if (m_pFileObject)
  1138.     {
  1139. if (HXR_OK != m_pFileObject->QueryInterface(IID_IHXPendingStatus, (void**)&pStatus))
  1140. {
  1141.     goto exit;
  1142. }
  1143. if (HXR_OK != pStatus->GetStatus(statusCode, pStatusDesc, percentDone))
  1144. {
  1145.     goto exit;
  1146. }
  1147.     }
  1148. exit:
  1149.     
  1150.     if (HX_STATUS_CONTACTING == statusCode)
  1151.     {
  1152. uStatusCode = HX_STATUS_CONTACTING;
  1153. ulPercentDone = 0;
  1154.     }
  1155.     else if (!m_bInitialized)
  1156.     {
  1157. uStatusCode = HX_STATUS_INITIALIZING;
  1158. ulPercentDone = 0;
  1159.     }
  1160.     else if (HX_STATUS_READY == statusCode && 100 == buffer)
  1161.     {
  1162. uStatusCode = HX_STATUS_READY;
  1163. ulPercentDone = 0;
  1164. m_ulLastBufferingReturned = 100;
  1165.     }
  1166.     else
  1167.     {
  1168. uStatusCode = HX_STATUS_BUFFERING;
  1169. if (HX_STATUS_READY == statusCode)
  1170. {
  1171.     ulPercentDone = (UINT16)buffer;
  1172. }
  1173. else
  1174. {
  1175.     ulPercentDone = (UINT16)((buffer + percentDone) * 0.5);
  1176. }
  1177. // Do not go back
  1178. if (ulPercentDone < m_ulLastBufferingReturned && m_ulLastBufferingReturned != 100)
  1179. {
  1180.     ulPercentDone = (UINT16) m_ulLastBufferingReturned;
  1181. }
  1182. else
  1183. {
  1184.     m_ulLastBufferingReturned = ulPercentDone;
  1185. }
  1186.     }
  1187.     HX_RELEASE(pStatus);
  1188.   
  1189.     ulPercentDone = ulPercentDone <= 100 ? (UINT16)ulPercentDone : 100;
  1190.     if (m_bInitialBuffering && HX_STATUS_READY == uStatusCode)
  1191.     {
  1192. InitialBufferingDone();
  1193.     }
  1194.     /* If we had a delayed start, we do not want to show that we are
  1195.      * in buffering state UNLESS it is really time to give out packets
  1196.      * and we do not have 
  1197.      */
  1198.     if (m_bInitialized && m_ulDelay > 0 && 
  1199. uStatusCode == HX_STATUS_BUFFERING && 
  1200. ulPercentDone < 100)
  1201.     {
  1202. UINT32 ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
  1203. if ((ulCurrentTime + MIN_BUFFERTIME_BEFORE_DELAY) < m_ulDelay)
  1204. {
  1205.     ulPercentDone = 100;
  1206. }
  1207.     }
  1208.     return hResult;
  1209. }
  1210. UINT16
  1211. HXFileSource::GetNumStreams(void)
  1212. {
  1213.     HX_ASSERT(m_bInitialized);
  1214.     
  1215.     return m_uNumStreams;
  1216. }
  1217. HX_RESULT
  1218. HXFileSource::GetStreamInfo(ULONG32     ulStreamNumber,
  1219.      STREAM_INFO*&  theStreamInfo)
  1220. {
  1221.     HX_RESULT theErr = HXR_OK;
  1222.     STREAM_INFO* lpStreamInfo = 0;
  1223.     if (!mStreamInfoTable->Lookup((LONG32)ulStreamNumber, (void *&)lpStreamInfo))
  1224.     {
  1225. theErr = HXR_INVALID_PARAMETER;
  1226.     }
  1227.     theStreamInfo = lpStreamInfo;
  1228.     return theErr;
  1229. }
  1230. HX_RESULT    
  1231. HXFileSource::GetEvent(UINT16 usStreamNumber, CHXEvent*& theEvent)
  1232. {
  1233.     HX_RESULT theErr = HXR_OK;
  1234.     HX_TRACE("HXFileSource::GetEvent");
  1235.     theEvent = 0;
  1236.     
  1237.     if (!m_bInitialized)
  1238.     {
  1239. return HXR_NOT_INITIALIZED;
  1240.     }
  1241.     if (mLastError != HXR_OK)
  1242.     {
  1243. return mLastError;
  1244.     }
  1245.     if (m_bPaused && m_bDelayed)
  1246.     {
  1247. if (TryResume())
  1248. {
  1249.     m_pPlayer->RegisterSourcesDone();
  1250.          DoResume();
  1251. }
  1252. else
  1253. {
  1254.     return HXR_NO_DATA;
  1255. }
  1256.     }
  1257.     STREAM_INFO * lpStreamInfo;
  1258.     if (!mStreamInfoTable->Lookup((LONG32) usStreamNumber, (void *&) lpStreamInfo))
  1259.     {
  1260. theErr = HXR_INVALID_PARAMETER;
  1261. return theErr;
  1262.     }
  1263. #if defined(HELIX_FEATURE_RECORDCONTROL)
  1264.     if (m_bPlayFromRecordControl && m_pRecordControl)
  1265.     {
  1266. IHXPacket* pPacket = NULL;
  1267. HX_ASSERT(m_pRecordControl);
  1268. theErr = m_pRecordControl->GetPacket(usStreamNumber, pPacket);
  1269. if(theErr == HXR_OK)
  1270. {
  1271.             UINT32 streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),1000);
  1272.     INT64 llPacketTime = 
  1273. lpStreamInfo->BufferingState().CreateINT64Timestamp(pPacket->GetTime());
  1274.     theEvent = new CHXEvent(pPacket, 
  1275.     GetEventBeginTime(llPacketTime, 
  1276.       streamPreRoll));
  1277.     if(theEvent) 
  1278. theEvent->SetTimeOffset(m_ulStartTime - m_ulDelay); 
  1279.     else
  1280. theErr = HXR_OUTOFMEMORY;
  1281.     if(m_pBufferManager)
  1282. m_pBufferManager->UpdateCounters(pPacket);
  1283.     HX_RELEASE(pPacket);
  1284. }
  1285. else
  1286. {
  1287.     if(theErr == HXR_NO_DATA && (m_bSourceEnd || lpStreamInfo->m_bSrcStreamDone))
  1288. theErr = HXR_AT_END;
  1289.     if(theErr == HXR_NO_DATA)
  1290.     {
  1291. if (lpStreamInfo->m_unNeeded > 0 &&
  1292.     lpStreamInfo->m_unNeeded != lpStreamInfo->m_unAvailable)
  1293. {
  1294.     // Re-initialize buffering
  1295.     m_pBufferManager->ReBuffer();
  1296.     FillBuffers();
  1297.     theErr = HXR_BUFFERING;
  1298. }
  1299.     }
  1300. }
  1301. return theErr;
  1302.     }
  1303. #endif /* HELIX_FEATURE_RECORDCONTROL */
  1304.     // get the packet list for this stream
  1305.     CHXEventList  * lEventList = &lpStreamInfo->m_EventList;
  1306.     // do we need to fill buffers...
  1307.     if (lEventList->GetNumEvents() == 0)
  1308.     {
  1309. theErr = FillBuffers();
  1310. if (theErr == HXR_AT_END)
  1311. {
  1312.     SetEndOfClip();
  1313.     theErr = HXR_OK;
  1314. }
  1315. // check if we have packets now...
  1316. if (!theErr && lEventList->GetNumEvents() == 0)
  1317. {
  1318.     if (m_bSourceEnd || lpStreamInfo->m_bSrcStreamDone)
  1319.     {
  1320. return HXR_AT_END;     
  1321.     }
  1322.     else
  1323.     {
  1324. if (lpStreamInfo->m_unNeeded > 0 &&
  1325.     lpStreamInfo->m_unNeeded != lpStreamInfo->m_unAvailable)
  1326. {
  1327.     // Re-initialize buffering
  1328.     m_pBufferManager->ReBuffer();
  1329.     FillBuffers();
  1330.     return HXR_BUFFERING;
  1331. }
  1332. return HXR_NO_DATA;
  1333.     }
  1334. }
  1335.     }
  1336.     if (!theErr)
  1337.     {
  1338. // this event will be deleted by the player...
  1339. theEvent = lEventList->RemoveHead();
  1340.     }
  1341. #ifdef LOSS_HACK
  1342.     if (m_ulLossHack > 0 && ((UINT32) (rand() % 100) < m_ulLossHack) &&
  1343. !theErr && theEvent && !(theEvent->GetPacket())->IsLost())
  1344.     {
  1345. GenerateFakeLostPacket(theEvent);
  1346. /* Update the stats */
  1347. if (lpStreamInfo->m_ulReceived > 0)
  1348. {
  1349.     lpStreamInfo->m_ulReceived--;
  1350.     lpStreamInfo->m_ulLost++;
  1351. }
  1352.     }
  1353. #endif /* LOSS_HACK */
  1354.     return theErr;
  1355. }
  1356. void 
  1357. HXFileSource::ReBuffer()
  1358. {
  1359.     UINT32  ulRemainToBufferInMs = 0;
  1360.     UINT32  ulRemainToBuffer = 0;
  1361.     m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
  1362. ulRemainToBuffer);
  1363.     if 
  1364.     (
  1365. ulRemainToBufferInMs == 0 &&
  1366. ulRemainToBuffer == 0
  1367.     )
  1368.     {
  1369. m_pBufferManager->ReBuffer();
  1370. FillBuffers();
  1371.     }
  1372. }
  1373. BOOL
  1374. HXFileSource::IsStatisticsReady(void)
  1375. {
  1376.     return HXR_OK;
  1377. }
  1378. HX_RESULT
  1379. HXFileSource::UpdateRegistry(UINT32 ulRegistryID)
  1380. {
  1381.     HX_RESULT     theErr = HXR_OK;
  1382. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1383.     UINT32     ulRegId = 0;
  1384.     char     szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  1385.     IHXBuffer*     pParentName = NULL;
  1386.     STREAM_INFO*    pStreamInfo = NULL;
  1387.     CHXMapLongToObj::Iterator ndxStream;
  1388.     m_ulRegistryID = ulRegistryID;
  1389.     if (!m_pStats)
  1390.     {
  1391. SetupRegistry();
  1392.     }
  1393.     else
  1394.     {
  1395. if (m_pSourceInfo     &&
  1396.     m_pSourceInfo->m_bLeadingSource &&
  1397.     !m_pSourceInfo->m_pRepeatList)
  1398. {
  1399.             //Copy over the 'next group' stats.
  1400.             SOURCE_STATS* pTmpSourceStats = new SOURCE_STATS(m_pRegistry, m_ulRegistryID);
  1401.             *pTmpSourceStats = *m_pStats;
  1402.             
  1403.     ndxStream = mStreamInfoTable->Begin();
  1404.     for(; ndxStream != mStreamInfoTable->End(); ++ndxStream)
  1405.     {
  1406. pStreamInfo = (STREAM_INFO*) (*ndxStream);
  1407. if (m_pRegistry     && 
  1408.     pTmpSourceStats &&
  1409.     HXR_OK == m_pRegistry->GetPropName(pTmpSourceStats->m_ulRegistryID, pParentName))
  1410. {
  1411.     SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Stream%ld", pParentName->GetBuffer(), 
  1412.     pStreamInfo->m_uStreamNumber);
  1413.     ulRegId = m_pRegistry->GetId(szRegName);
  1414.     if (!ulRegId)
  1415.     {
  1416. ulRegId = m_pRegistry->AddComp(szRegName);
  1417.     }
  1418.     STREAM_STATS* pTmpStreamStats = new STREAM_STATS(m_pRegistry, ulRegId);
  1419.                     //Copy over the "next-group" stats
  1420.                     *pTmpStreamStats = *pStreamInfo->m_pStats;
  1421.                     HX_DELETE(pStreamInfo->m_pStats);
  1422.                     pStreamInfo->m_pStats = pTmpStreamStats;
  1423. }
  1424. HX_RELEASE(pParentName);
  1425.     }
  1426.             HX_DELETE(m_pStats);
  1427.             m_pStats = pTmpSourceStats;
  1428. }
  1429. else if (m_pStatsManager)
  1430. {
  1431.     m_pStatsManager->UpdateRegistry(m_ulRegistryID);
  1432. }
  1433.     }
  1434. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1435.     return theErr;
  1436. }
  1437. HX_RESULT
  1438. HXFileSource::UpdateStatistics(void)
  1439. {
  1440. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1441.     ULONG32 ulSourceLost = 0;    
  1442.     ULONG32 ulSourceTotal = 0;    
  1443.     ULONG32 ulSourceReceived = 0;   
  1444.     ULONG32 ulSourceNormal = 0;       
  1445.     ULONG32 ulSourceBandwidth = 0;   
  1446.   
  1447.     CHXMapLongToObj::Iterator ndxStream = mStreamInfoTable->Begin();
  1448.     for (; ndxStream != mStreamInfoTable->End(); ++ndxStream) 
  1449.     {
  1450.         STREAM_INFO* pStreamInfo   = (STREAM_INFO*) (*ndxStream);
  1451.         ULONG32 ulStreamTotal = 0;
  1452.         ULONG32 ulStreamReceived = 0;
  1453.         ULONG32 ulStreamNormal = 0;
  1454.     
  1455. // update the statistics in the registry
  1456. ulStreamNormal = pStreamInfo->m_ulReceived;
  1457. ulStreamReceived = ulStreamNormal;
  1458. ulStreamTotal = ulStreamNormal + pStreamInfo->m_ulLost;
  1459. pStreamInfo->m_pStats->m_pNormal->SetInt((INT32)ulStreamNormal);
  1460. pStreamInfo->m_pStats->m_pReceived->SetInt((INT32)ulStreamReceived);     
  1461. pStreamInfo->m_pStats->m_pLost->SetInt((INT32)pStreamInfo->m_ulLost);
  1462. pStreamInfo->m_pStats->m_pTotal->SetInt((INT32)ulStreamTotal);
  1463. ulSourceTotal += ulStreamTotal;
  1464. ulSourceReceived += ulStreamReceived;
  1465. ulSourceNormal += ulStreamNormal;
  1466. ulSourceLost += pStreamInfo->m_ulLost;
  1467. ulSourceBandwidth += pStreamInfo->m_pStats->m_pClipBandwidth->GetInt();
  1468.     }
  1469.     if (m_pStats->m_pNormal) m_pStats->m_pNormal->SetInt((INT32)ulSourceNormal);
  1470.     if (m_pStats->m_pReceived) m_pStats->m_pReceived->SetInt((INT32)ulSourceReceived);
  1471.     if (m_pStats->m_pTotal) m_pStats->m_pTotal->SetInt((INT32)ulSourceTotal);
  1472.     if (m_pStats->m_pClipBandwidth) m_pStats->m_pClipBandwidth->SetInt((INT32)ulSourceBandwidth);
  1473.     if (m_pStats->m_pLost) m_pStats->m_pLost->SetInt((INT32)ulSourceLost);    
  1474.     if (m_pStats->m_pCurBandwidth) m_pStats->m_pCurBandwidth->SetInt((INT32)ulSourceBandwidth);
  1475.     if (m_pStats->m_pAvgBandwidth) m_pStats->m_pAvgBandwidth->SetInt((INT32)ulSourceBandwidth);
  1476.     // update buffering mode(local machine)
  1477.     if (m_pStats->m_pBufferingMode)
  1478.     {
  1479. m_pStats->m_pBufferingMode->SetInt(NORMAL_PLAY);
  1480.     }
  1481. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1482.     
  1483.     return HXR_OK;
  1484. }
  1485. HX_RESULT
  1486. HXFileSource::_ProcessIdle(BOOL atInterrupt)
  1487. {
  1488.     HX_RESULT theErr = HXR_OK;
  1489.     if (m_bLocked)
  1490.     {
  1491. return HXR_OK;
  1492.     }
  1493.     theErr = _ProcessIdleExt(atInterrupt);
  1494.     if (HXR_ABORT == theErr)
  1495.     {
  1496. return HXR_OK;
  1497.     }
  1498.     // need to try the next fileformat for same mimetype...
  1499.     // cannot do it at interrupt time!
  1500.     if (m_pCurrentFileFormatUnk && 
  1501. (m_bCurrentFileFormatUnkInUse || atInterrupt))
  1502.     {
  1503. return HXR_OK;
  1504.     }
  1505.     m_bLocked = TRUE;
  1506.     if (m_pCurrentFileFormatUnk)
  1507.     {
  1508. m_bCurrentFileFormatUnkInUse = TRUE;
  1509. CleanupFileObjects();
  1510. ReSetup();
  1511. m_bLocked = FALSE;
  1512. return HXR_OK;
  1513.     }
  1514.     if (!m_bInitialized)
  1515.     {
  1516.         m_bLocked = FALSE;
  1517.         return theErr;
  1518.     }
  1519.     if (m_bRedirectPending && !m_bPartOfNextGroup)
  1520.     {
  1521.         m_bRedirectPending = FALSE;
  1522.         HX_ASSERT(m_pRedirectURL);
  1523. theErr = m_pSourceInfo->HandleRedirectRequest((char*)m_pRedirectURL->GetURL());
  1524.         HX_DELETE(m_pRedirectURL);
  1525.         m_bLocked = FALSE;
  1526.         return theErr;
  1527.     }
  1528.     // we keep RAM FF object around by AddRef() in ::InitFileFormat
  1529.     // to avoid self-destruct in ::InitDone when it's not a RAM 
  1530.     HX_RELEASE(m_pRAMFFObject);
  1531.     if (!m_bSourceEnd && !m_bFirstResume)
  1532.     {
  1533. theErr = FillBuffers();
  1534. if (theErr == HXR_AT_END)
  1535. {
  1536.     SetEndOfClip();
  1537.     theErr = HXR_OK;
  1538. }
  1539.     }
  1540.     if (!theErr)
  1541.     {
  1542. UINT32 ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
  1543. // set m_bDelayed to FALSE as soon as it's due to begin playback
  1544. // even it's still in pre-fetch mode
  1545. if (!m_bPaused && m_bDelayed)
  1546. {
  1547.     UINT32 ulStartTime = 0;
  1548.     if (m_ulDelay > m_ulPreRollInMs + NETWORK_FUDGE_FACTOR)
  1549.     {
  1550. ulStartTime = m_ulDelay - (m_ulPreRollInMs + NETWORK_FUDGE_FACTOR);
  1551.     }
  1552.   
  1553.     if (ulCurrentTime >= ulStartTime)
  1554.          {
  1555. m_bDelayed = FALSE;
  1556.     }
  1557. }
  1558. if  (!m_bSourceEnd && m_bIsPreBufferingStarted && !m_bIsPreBufferingDone)
  1559. {
  1560.     /* Get Current buffering status every 1 sec. */
  1561.     UINT32 ulCurrentSystemTime = HX_GET_TICKCOUNT();
  1562.     if (CALCULATE_ELAPSED_TICKS(m_ulLastBufferingCalcTime, 
  1563. ulCurrentSystemTime) > 1000)
  1564.     {
  1565. m_ulLastBufferingCalcTime = ulCurrentSystemTime;
  1566. CalculateCurrentBuffering();
  1567.     }
  1568. }
  1569. // XXX HP TBD HTTP prefetch
  1570. // no prefetch support for now
  1571. if (m_bPrefetch)
  1572. {
  1573.     LeavePrefetch();
  1574. }
  1575. // rebuffer if the source hasn't satisfy its initial preroll when it's 
  1576. // time to start
  1577. // resume in InitialBufferingDone()
  1578. if (m_pPlayer->IsPlaying()  &&
  1579.     !m_bPartOfPrefetchGroup &&
  1580.     m_bInitialBuffering     && 
  1581.     !m_bRebufferingRequired &&
  1582.     (ulCurrentTime + MIN_BUFFERTIME_BEFORE_DELAY) >= m_ulDelay)
  1583. {
  1584.          DoRebuffer();
  1585. }
  1586.     }
  1587.     m_bLocked = FALSE;
  1588.     if (!theErr && !m_bIsActive && !m_bDelayed &&
  1589. m_pPlayer->GetInternalCurrentPlayTime() >= m_ulDelay)
  1590.     {
  1591. AdjustClipBandwidthStats(TRUE);
  1592.     }
  1593.     /* tell the player about the error...
  1594.      * This is crucial...
  1595.      */
  1596.     if (theErr)
  1597.     {
  1598. ReportError(theErr);
  1599.     }
  1600.     return theErr;
  1601. }
  1602. HX_RESULT
  1603. HXFileSource::_ProcessIdleExt(BOOL atInterrupt)
  1604. {
  1605.     return HXR_OK;
  1606. }
  1607. STDMETHODIMP
  1608. HXFileSource::InitDone
  1609. (
  1610.     HX_RESULT status
  1611. )
  1612. {
  1613.     if (!m_bValidateMetaDone)
  1614.     {
  1615. m_bValidateMetaDone = TRUE;
  1616. if (HXR_OK == status)
  1617. {
  1618.     m_bIsMeta = TRUE;
  1619.     // reset all the timing attributes since meta file(RAM)
  1620.     // doesn't support any
  1621.     SetPlayTimes(0, 0, 0, 0);
  1622. }
  1623. else
  1624. {
  1625.     m_bIsMeta = FALSE;
  1626.     HX_RELEASE(m_pFFObject);
  1627.     HX_RELEASE(m_pCurrentFileFormatUnk);
  1628.     HX_RELEASE(m_pFileFormatEnumerator);
  1629.     
  1630.     // not a meta file, since the file object has been initialized,
  1631.     // calling ExtendedSetup() again to find the actual mimetype if
  1632.     // the file object supports findings of mimetypes.
  1633.     return ExtendedSetup(m_pszURL);
  1634. }
  1635.     }
  1636.     if (!mLastError && status != HXR_OK)
  1637.     {
  1638. CheckForDefaultUpgrade(status);
  1639. /* do we need to try the next one! */
  1640. if (!m_pCurrentFileFormatUnk && m_pFileFormatEnumerator)
  1641. {
  1642.     m_pFileFormatEnumerator->GetNextPlugin(m_pCurrentFileFormatUnk, NULL);
  1643.     if (m_pCurrentFileFormatUnk && m_pSourceInfo)
  1644.     {
  1645. m_pSourceInfo->ScheduleProcessCallback();
  1646.     }
  1647. }
  1648. // early exit to try next fileformat for the same mimetype!
  1649. if (m_pCurrentFileFormatUnk)
  1650. {
  1651.     return HXR_OK;
  1652. }
  1653. mLastError = status;
  1654. // merge any upgrade requests for this source to the player
  1655. MergeUpgradeRequest(m_bAddDefaultUpgrade, m_pDefaultUpgradeString);
  1656.     }
  1657.     if (HXR_OK == status && m_ulStreamHeadersExpected == 0)
  1658.     {
  1659. HX_RELEASE(m_pBackChannel);
  1660. HX_RELEASE(m_pASMSource);
  1661. m_pFFObject->QueryInterface(IID_IHXBackChannel, (void**) &m_pBackChannel);
  1662. m_pFFObject->QueryInterface(IID_IHXASMSource, (void**) &m_pASMSource);
  1663. HX_RESULT result = m_pFFObject->GetFileHeader();
  1664.      return result;
  1665.     }
  1666.     else 
  1667.     {
  1668. ReportError(status);
  1669.     }
  1670.     return HXR_OK;
  1671. }
  1672. STDMETHODIMP
  1673. HXFileSource::FileHeaderReady
  1674. (
  1675.     HX_RESULT     status,
  1676.     IHXValues*     pHeader
  1677. )
  1678. {
  1679.     HX_RELEASE(m_pFileHeader);
  1680.     if (HXR_OK == status)
  1681.     {
  1682. status = HandleSDPData(pHeader);
  1683.     }
  1684. #if defined(HELIX_FEATURE_RECORDCONTROL)
  1685.     SendHeaderToRecordControl(TRUE, pHeader);
  1686. #endif /* HELIX_FEATURE_RECORDCONTROL */
  1687.     return ContinueWithFileHeader(status, pHeader);
  1688. }
  1689. HX_RESULT
  1690. HXFileSource::ContinueWithFileHeader(HX_RESULT status, IHXValues* pHeader)
  1691. {
  1692.     HX_RESULT      result = HXR_OK;
  1693.     HX_ASSERT(!m_pFileHeader);
  1694.     if( pHeader )
  1695.     {
  1696. m_pFileHeader = pHeader;
  1697. m_pFileHeader->AddRef();
  1698.     }
  1699.     result = ContinueWithFileHeaderExt(status, m_pFileHeader);
  1700.     if (result == HXR_REQUEST_UPGRADE)
  1701.     {
  1702. mLastError = result;
  1703. return HXR_OK;
  1704.     }
  1705.     else if (result == HXR_WOULD_BLOCK)
  1706.     {
  1707. return HXR_OK;
  1708.     }
  1709.     m_bContinueWithHeaders = FALSE;
  1710.     if (status != HXR_OK)
  1711.     {
  1712. CheckForDefaultUpgrade(status);
  1713. /* do we need to try the next one! */
  1714. if (!m_pCurrentFileFormatUnk && m_pFileFormatEnumerator)
  1715. {
  1716.     m_pFileFormatEnumerator->GetNextPlugin(m_pCurrentFileFormatUnk, NULL);
  1717.     // only proceed source info(renderer) initialization in the 
  1718.     // CURRENT group so that sources in the NEXT group won't have
  1719.     // effect(i.e. layout) in the current playback
  1720.     if (m_pCurrentFileFormatUnk && 
  1721. m_pPlayer &&
  1722. m_pSourceInfo &&
  1723. m_pPlayer->GetCurrentGroupID() == m_pSourceInfo->m_uGroupID)
  1724.     {
  1725. m_pSourceInfo->ScheduleProcessCallback();
  1726.     }
  1727. }
  1728. // early exit to try next fileformat for the same mimetype!
  1729. if (m_pCurrentFileFormatUnk)
  1730. {
  1731.     return HXR_OK;
  1732. }
  1733.      mLastError = status;
  1734. // merge any upgrade requests for this source to the player
  1735. MergeUpgradeRequest(m_bAddDefaultUpgrade, m_pDefaultUpgradeString);
  1736. ReportError(mLastError);
  1737. return HXR_FAILED;
  1738.     }
  1739.     ProcessFileHeader();
  1740.     if( m_pFileHeader )
  1741.     {
  1742. UINT32 ulLiveStream = 0;
  1743. m_pFileHeader->GetPropertyULONG32("LiveStream", ulLiveStream);
  1744. mLiveStream = ulLiveStream ? TRUE : FALSE;
  1745. ULONG32 ulFlags = 0;
  1746. m_pFileHeader->GetPropertyULONG32("Flags", ulFlags);
  1747. mSaveAsAllowed = ulFlags & HX_SAVE_ENABLED ? TRUE : FALSE;
  1748. for (UINT16 i=0; (result == HXR_OK) && i < m_ulStreamHeadersExpected; i++)
  1749. {
  1750.     result = m_pFFObject->GetStreamHeader(i);
  1751. }
  1752.     }
  1753.     return result;
  1754. }
  1755. HX_RESULT
  1756. HXFileSource::ContinueWithFileHeaderExt(HX_RESULT status, IHXValues* pHeader)
  1757. {
  1758.     return HXR_OK;
  1759. }
  1760. STDMETHODIMP
  1761. HXFileSource::StreamHeaderReady(HX_RESULT status, IHXValues* pHeader)
  1762. {
  1763.     HX_RESULT     theErr = HXR_OK;
  1764.     char     szRegKeyName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  1765.     IHXBuffer*     pszParentName = NULL;
  1766.     STREAM_INFO*    pStreamInfo = NULL;
  1767.     // we do not support receiving headers once we have started getting data...
  1768.     if (m_bReceivedData)
  1769. return HXR_FAILED; // define some more appropriate error code..
  1770.     if (HXR_OK == status)
  1771.     {
  1772. status = HandleSDPData(pHeader);
  1773.     }
  1774.     if (HXR_OK != status)
  1775.     {
  1776. mLastError = status;
  1777.      ReportError(mLastError);
  1778. return HXR_OK;
  1779.     }
  1780. #if defined(HELIX_FEATURE_RECORDCONTROL)
  1781.     SendHeaderToRecordControl(FALSE, pHeader);
  1782. #endif /* HELIX_FEATURE_RECORDCONTROL */
  1783.     StreamHeaderReadyExt(pHeader);
  1784.     // fileformat initialized...clear any pending upgrade requests for this source!
  1785.     ClearUpgradeRequest();
  1786.     // we have already received enough headers...
  1787.     if (m_uNumStreams >= m_ulStreamHeadersExpected)
  1788. return HXR_FAILED;
  1789.     theErr = ProcessStreamHeaders(pHeader, pStreamInfo);
  1790.     if (!theErr)
  1791.     {
  1792. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1793.         HX_ASSERT(pStreamInfo);
  1794. // create all the statistic registry keys
  1795. if (m_pRegistry && m_pStats &&
  1796.     HXR_OK == m_pRegistry->GetPropName(m_pStats->m_ulRegistryID, pszParentName))
  1797. {
  1798.     SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.Stream%ld", pszParentName->GetBuffer(), 
  1799. m_ulStreamIndex);
  1800.     /* does this ID already exists ? */
  1801.     UINT32 ulRegistryID = m_pRegistry->GetId(szRegKeyName);
  1802.     if (!ulRegistryID)
  1803.     {
  1804. ulRegistryID = m_pRegistry->AddComp(szRegKeyName);
  1805.     }
  1806.     pStreamInfo->m_pStats = new STREAM_STATS(m_pRegistry, ulRegistryID);
  1807.             if(pStreamInfo->m_pStats)
  1808.             {
  1809.         // set stream bandwidth
  1810.         pStreamInfo->m_pStats->m_pClipBandwidth->SetInt((INT32)pStreamInfo->BufferingState().AvgBandwidth());
  1811.             }
  1812.             else
  1813.             {
  1814.                 // NOTE: It may be that we can still function without the 
  1815.                 // m_pStats object, but can we still function if we are 
  1816.                 // running out of memory at this point? Assuming no.
  1817.                 theErr = HXR_OUTOFMEMORY;
  1818.             }
  1819. }
  1820. HX_RELEASE(pszParentName);
  1821. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1822.         m_ulStreamIndex++;
  1823.         m_uNumStreams++;
  1824.     }
  1825.     if (!theErr && m_uNumStreams == m_ulStreamHeadersExpected)
  1826.     {
  1827. m_uActiveStreams = m_uNumStreams;
  1828. m_ulOriginalDuration = m_ulDuration;
  1829. m_bInitialized     = TRUE;
  1830. theErr = AdjustClipTime();
  1831. m_pBufferManager->Init();
  1832.     }
  1833.     return theErr;
  1834. }
  1835. HX_RESULT
  1836. HXFileSource::StreamHeaderReadyExt(IHXValues* pHeader)
  1837. {
  1838.     return HXR_OK;
  1839. }
  1840. STDMETHODIMP
  1841. HXFileSource::PacketReady(HX_RESULT status, IHXPacket* pPacket)
  1842. {
  1843.     HX_RESULT theErr = HXR_OK;
  1844.     // We should have been initialized by now
  1845.     HX_ASSERT(m_bInitialized);
  1846.     if (!m_bInitialized)
  1847.     {
  1848. return HXR_NOT_INITIALIZED;
  1849.     }
  1850.     
  1851.     // Report a non-HXR_OK error code only if no packet. If a packet
  1852.     // accompanies the error code we assume end of stream and handle
  1853.     // later on (see below).
  1854.     if (!pPacket)
  1855.     {
  1856.         if (HXR_OK != status)
  1857.         {
  1858.     mLastError = status;
  1859.     ReportError(mLastError);
  1860.             return HXR_OK;
  1861.         }
  1862.         else
  1863.         {
  1864.     // HXR_OK with a NULL packet makes no sense
  1865.     return HXR_INVALID_PARAMETER;
  1866.         }
  1867.     }
  1868.     
  1869.     IHXBuffer*     pBuffer     = 0;
  1870.     UINT32     ulPacketTime    = 0;     // packet time encoded
  1871.     UINT32     ulPacketFilledDuration = 0;     // packets' time have been filled 
  1872.     UINT32      ulEventBeginTime = 0;     // start pos of the packet(event) 
  1873.     INT64     llActualPacketTime = 0;     // packet time with timestamp rollover
  1874.     INT64     llActualEventBeginTime = 0;     // start pos of the packet(event) with timestamp rollover
  1875.     ULONG32     ulFlags     = 0;
  1876.     UINT16     uStreamNumber   = 0;
  1877.     UINT8     unASMFlags     = 0;
  1878.     UINT16     unASMRuleNumber = 0;
  1879.     UINT32     streamPreRoll   = 0;
  1880.     UINT32     ulMinimumTotalPreroll = 0;
  1881.     if (HXR_OK != pPacket->Get(pBuffer, ulPacketTime, uStreamNumber, unASMFlags, unASMRuleNumber))
  1882.     {
  1883. theErr = HXR_FAILED;
  1884. return theErr;
  1885.     }
  1886. #if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
  1887.     HXStaticStatLog::StatPrintf("Packet: StreamNumber: %u TimeStamp: %lun", uStreamNumber, ulPacketTime);
  1888. #endif
  1889.     HX_RELEASE(pBuffer);
  1890.     CHXEvent*     theEvent     = NULL;
  1891.     STREAM_INFO*    lpStreamInfo    = NULL;
  1892.     CHXEventList*  lEventList     = NULL;
  1893.     if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo))
  1894.     {
  1895. return HXR_INVALID_PARAMETER;
  1896.     }
  1897.     if (status != HXR_OK)
  1898.     {
  1899. if (!lpStreamInfo->m_bSrcStreamDone)
  1900. {
  1901.     // if the status is not OK, it is probably the end of the stream..
  1902.     // we should mark this stream as DONE...
  1903.     lpStreamInfo->m_bPacketRequested     = FALSE;
  1904.     lpStreamInfo->m_bSrcStreamFillingDone   = TRUE;
  1905.     lpStreamInfo->m_bSrcStreamDone     = TRUE;
  1906.     if (m_uNumStreamsToBeFilled > 0)
  1907.     {
  1908. m_uNumStreamsToBeFilled--;
  1909.     }
  1910.     
  1911.     if (m_uActiveStreams > 0)
  1912.     {
  1913. m_uActiveStreams--;
  1914.     }
  1915.     
  1916.     if (m_uActiveStreams == 0)
  1917.     {
  1918. SetEndOfClip();
  1919.     }
  1920. }
  1921. return HXR_OK;
  1922.     }
  1923.     lpStreamInfo->m_ulReceived++;
  1924.     if (!theErr)
  1925.     {
  1926. // reset
  1927. lpStreamInfo->m_bPacketRequested    = FALSE;
  1928. lEventList = &lpStreamInfo->m_EventList;
  1929.     }
  1930.     /*
  1931.      * Save off the initial timestamp for live streams so we can buffer
  1932.      * relative to the first timstamp
  1933.      */
  1934.     if (m_bInitialPacket)
  1935.     {
  1936. m_bInitialPacket = FALSE;
  1937. m_ulFirstPacketTime = ulPacketTime;
  1938.     }
  1939.     // This is the time according to the stream...
  1940.     llActualPacketTime = 
  1941. lpStreamInfo->BufferingState().CreateINT64Timestamp(ulPacketTime);
  1942.     llActualEventBeginTime = llActualPacketTime + m_ulDelay;
  1943.     /* subtract start time from player time */
  1944.     if (m_ulStartTime > 0)
  1945.     {
  1946. if (m_ulStartTime < llActualPacketTime) 
  1947. {
  1948.     llActualPacketTime -= m_ulStartTime; 
  1949. }
  1950. else
  1951. {
  1952.     llActualPacketTime = 0;
  1953. }
  1954. if (m_ulStartTime < llActualEventBeginTime) 
  1955. {
  1956.     llActualEventBeginTime -= m_ulStartTime; 
  1957. }
  1958. else
  1959. {
  1960.     llActualEventBeginTime = 0;
  1961. }
  1962.     }
  1963.     
  1964.     HX_ASSERT(llActualEventBeginTime < MAX_UINT32);
  1965.     HX_ASSERT(llActualPacketTime < MAX_UINT32);
  1966.     ulEventBeginTime = INT64_TO_UINT32(llActualEventBeginTime);
  1967.     ulPacketFilledDuration = INT64_TO_UINT32(llActualPacketTime);
  1968. #if defined(HELIX_FEATURE_RECORDCONTROL)
  1969.     if (m_pRecordControl)
  1970.     {
  1971. m_pRecordControl->OnPacket(pPacket, m_ulStartTime - m_ulDelay);
  1972.     }
  1973. #endif /* HELIX_FEATURE_RECORDCONTROL */
  1974.     if (!m_bPlayFromRecordControl)
  1975.     {
  1976. /* 
  1977.  * force a minimum preroll of 1 second to ensure that we deliver
  1978.  * packet in time to the renderers. e.g. with delayed RealText
  1979.  * with a preroll of 0 and delay of 10 seconds, it is 
  1980.  * possible to send packets at time 0 AFTER 10 seconds if we 
  1981.  * do not ensure this minimum preroll
  1982.  * helps in fixing random "realtext not displaying" bug
  1983.  */
  1984. #ifdef HELIX_FEATURE_MIN_PREROLL
  1985.         streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),150);
  1986. #else  //HELIX_FEATURE_MIN_PREROLL
  1987.         streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),1000);
  1988. #endif //HELIX_FEATURE_MIN_PREROLL
  1989. ulEventBeginTime = (ulEventBeginTime > streamPreRoll) ? (ulEventBeginTime - streamPreRoll) : 0;
  1990. theEvent = new CHXEvent(pPacket, ulEventBeginTime);
  1991. if(!theEvent) 
  1992. {
  1993.     theErr = HXR_OUTOFMEMORY;
  1994. }
  1995. // enqueue the event into event queue
  1996. if(!theErr) 
  1997. {
  1998.          /* offset used by Player::ProcessCurrentEvents to send to renderer::OnPacket */
  1999.          theEvent->SetTimeOffset(m_ulStartTime - m_ulDelay); 
  2000.     theErr = lEventList->InsertEvent(theEvent);
  2001. }
  2002. if (!theErr)
  2003. {
  2004.     m_pBufferManager->UpdateCounters(pPacket);
  2005. }
  2006.     }
  2007.     m_llLastFillEndTime = llActualPacketTime;
  2008.     if (m_bInFillMode)
  2009.     {
  2010. UINT32 ulDuration = 0;
  2011. UINT32 ulRemainToBufferInMs = 0;
  2012. UINT32 ulRemainToBuffer = 0;
  2013. m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
  2014.     ulRemainToBuffer);
  2015. /* Logic:
  2016.     In FillBuffers(), we ask for a packet for a particular stream. If
  2017.     the fileformat does not return the packet immediately (i.e. we 
  2018.     go again to ask for the packet from the same stream but find out that
  2019.     we had already asked for it earlier and have not yet received it,
  2020.     the streamFilling is marked as done for that fillbuffer() iteration.
  2021.     In the meantime, we keep on asking for the packets from other streams
  2022.     In meanwhile, if the fileformat returns a packet for the stream marked 
  2023.     as done earlier, we re-activate that stream if the time of the packet
  2024.     is less than the time we fill all streams up to.
  2025.  */
  2026. if (lpStreamInfo->m_bSrcStreamFillingDone &&
  2027.     (ulRemainToBufferInMs > 0 || ulRemainToBuffer > 0) &&
  2028.     ulPacketFilledDuration <= lpStreamInfo->m_ulDuration &&
  2029.     !lpStreamInfo->m_bSrcStreamDone)
  2030. {
  2031.     lpStreamInfo->m_bSrcStreamFillingDone = FALSE;
  2032.          m_uNumStreamsToBeFilled++;
  2033. }
  2034. if (!lpStreamInfo->m_bSrcStreamDone && 
  2035.     !lpStreamInfo->m_bSrcStreamFillingDone &&
  2036.     m_uNumStreamsToBeFilled > 0)
  2037. {
  2038.             /* When playing from Record Control buffering can happen after seek to 
  2039.                a cached position. In this case we dont need to accelerate packet 
  2040.                retriaval and can stop filling the stream.
  2041.              */
  2042.     if (ulPacketFilledDuration > lpStreamInfo->m_ulDuration ||
  2043. (ulRemainToBufferInMs == 0 && ulRemainToBuffer == 0) ||
  2044.                 (m_bPlayFromRecordControl && ulPacketFilledDuration >= m_pPlayer->GetInternalCurrentPlayTime() + ulRemainToBufferInMs))
  2045.     {
  2046. // this value also updated in PacketReady()
  2047. lpStreamInfo->m_bSrcStreamFillingDone  = TRUE;
  2048. if (m_uNumStreamsToBeFilled > 0)
  2049. {
  2050.     m_uNumStreamsToBeFilled--;
  2051. }
  2052.     }
  2053. }
  2054.     }
  2055.     if (!theErr)
  2056.     {
  2057. m_bReceivedData     = TRUE;
  2058.     }
  2059.     else if (theEvent)
  2060.     {
  2061.         HX_DELETE(theEvent);
  2062.     }
  2063.     return theErr;
  2064. }
  2065. STDMETHODIMP
  2066. HXFileSource::StreamDone(UINT16   uStreamNumber)
  2067. {
  2068.     STREAM_INFO    *lpStreamInfo    = NULL;
  2069.     if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo))
  2070.     {
  2071. return HXR_INVALID_PARAMETER;
  2072.     }
  2073.     if (!lpStreamInfo->m_bSrcStreamDone)
  2074.     {
  2075. lpStreamInfo->m_bSrcStreamDone = TRUE;
  2076. lpStreamInfo->m_bSrcStreamFillingDone = TRUE;
  2077. lpStreamInfo->m_bPacketRequested = FALSE;
  2078. if (m_uNumStreamsToBeFilled > 0)
  2079. {
  2080.     m_uNumStreamsToBeFilled--;
  2081. }
  2082. if (m_uActiveStreams > 0)
  2083. {
  2084.     m_uActiveStreams--;
  2085. }
  2086.     
  2087. if (m_uActiveStreams == 0)
  2088. {
  2089.     SetEndOfClip();
  2090. }
  2091.     }
  2092.     return HXR_OK;
  2093. }
  2094. STDMETHODIMP
  2095. HXFileSource::SeekDone(HX_RESULT status)
  2096. {
  2097.     HX_RESULT lResult = HXR_OK;
  2098.     
  2099.     if (m_nSeeking > 0)
  2100.     {
  2101. m_nSeeking--;
  2102.     }
  2103.     _ProcessIdle(FALSE);
  2104.     return lResult;
  2105. }
  2106. STDMETHODIMP HXFileSource::RedirectDone(IHXBuffer* pURL)
  2107. {
  2108.     HX_RESULT hr = HXR_NOTIMPL;
  2109.     // handle redirect to diff. protocol from HTTP file system
  2110.     if (m_pszURL && pURL)
  2111.     {
  2112. if (strncasecmp(m_pszURL, "http://", 7) == 0 &&
  2113.     strncasecmp((const char*)pURL->GetBuffer(), "http://", 7) != 0)
  2114. {
  2115.             if (m_bPartOfNextGroup)
  2116.             {
  2117.                 m_bRedirectPending = TRUE;
  2118.                 HX_DELETE(m_pRedirectURL);
  2119.                 m_pRedirectURL = new CHXURL((const char*)pURL->GetBuffer());
  2120.             }
  2121.             else
  2122.             {
  2123.           hr = m_pSourceInfo->HandleRedirectRequest((char*)pURL->GetBuffer());
  2124.             }
  2125. }
  2126.     }
  2127.     
  2128.     return hr;
  2129. }
  2130. // routine to read from the file to keep all streams filled to their preroll value
  2131. HX_RESULT    
  2132. HXFileSource::FillBuffers(void)
  2133. {
  2134.     /* 
  2135.      * Do not call GetPacket if we have not yet received SeekDone from
  2136.      * the file format plugin.
  2137.      *     || 
  2138.      * We are in a paused state and no rebuffering and no fast start 
  2139.      * is required.
  2140.      *     ||
  2141.      * We are in force end mode such as seeking to the end of the source duration
  2142.      */
  2143.     if (m_nSeeking > 0 ||
  2144. (m_bPaused && !m_bFastStartInProgress && !m_bRebufferingRequired && !m_pRecordControl) ||
  2145. m_bForcedSourceEnd)
  2146.     {
  2147. return HXR_OK;
  2148.     }
  2149.     HX_RESULT theErr = HXR_OK;
  2150.     UINT32 ulRemainToBufferInMs = 0; 
  2151.     UINT32 ulRemainToBuffer = 0;
  2152.     UINT32 lPlayPos = m_pPlayer->GetInternalCurrentPlayTime();
  2153.     UINT32 ulCurrentTime = HX_GET_TICKCOUNT();
  2154.     m_uNumStreamsToBeFilled = 0;
  2155.     m_ulMaxPreRoll = 0;
  2156.   
  2157.     CHXMapLongToObj::Iterator ndxStream = mStreamInfoTable->Begin();
  2158.     STREAM_INFO* lpStreamInfo    = NULL;
  2159.     m_pBufferManager->GetMaximumPreroll(m_ulMaxPreRoll);
  2160.     m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
  2161. ulRemainToBuffer);
  2162.     for(; ndxStream != mStreamInfoTable->End(); ++ndxStream)
  2163.     {
  2164. lpStreamInfo = (STREAM_INFO*) (*ndxStream);
  2165. if(!lpStreamInfo->m_bSrcStreamDone)
  2166. {
  2167.     m_uNumStreamsToBeFilled++;
  2168.     lpStreamInfo->m_bSrcStreamFillingDone = FALSE;
  2169. }
  2170.     }
  2171.     /*
  2172.      * The fill end time must be offset by the intial timestamp if this
  2173.      * is a live stream which is saved in the initial PacketReady
  2174.      */
  2175.     // we will always attempt to have m_MaxPreRoll time of data in the audio and video event queues
  2176.     m_llFillEndTime = CAST_TO_INT64 (lPlayPos + 
  2177.       m_ulMaxPreRoll + m_pPlayer->m_ulMinimumAudioPreroll + 
  2178.       m_pPlayer->GetGranularity());
  2179.     if (!m_pRecordControl &&
  2180. !m_bRebufferingRequired &&
  2181. ulRemainToBufferInMs == 0 &&
  2182. ulRemainToBuffer == 0 && 
  2183. m_llFillEndTime <= m_llLastFillEndTime)
  2184.     {
  2185. return HXR_OK;
  2186.     }
  2187. #if defined(HELIX_FEATURE_RECORDCONTROL)
  2188.     if (m_pRecordControl && !m_pRecordControl->CanAcceptPackets())
  2189.     {
  2190. return HXR_OK;
  2191.     }
  2192. #endif /* HELIX_FEATURE_RECORDCONTROL */
  2193.     m_bInFillMode   = TRUE;
  2194.     while(!theErr && m_uNumStreamsToBeFilled > 0)
  2195.     {
  2196. ndxStream = mStreamInfoTable->Begin();
  2197. for (; !theErr && ndxStream != mStreamInfoTable->End(); ++ndxStream)
  2198. {
  2199.     lpStreamInfo    = (STREAM_INFO*) (*ndxStream);
  2200.     if (!lpStreamInfo->m_bSrcStreamDone && 
  2201. !lpStreamInfo->m_bSrcStreamFillingDone && 
  2202. !lpStreamInfo->m_bPacketRequested)
  2203.     {
  2204. // this will be reset in PacketReady()
  2205. lpStreamInfo->m_bPacketRequested    = TRUE;
  2206.                 HX_RESULT retVal = m_pFFObject->GetPacket((UINT16) lpStreamInfo->m_uStreamNumber);
  2207. if (HXR_OK != retVal )
  2208. {
  2209.                     StreamDone(lpStreamInfo->m_uStreamNumber);
  2210.                     // Don't lose OOM errors.
  2211.                     if( retVal == HXR_OUTOFMEMORY )
  2212.                     {
  2213.                         theErr = retVal;
  2214.                     }
  2215. #ifdef HELIX_FEATURE_STOP_STREAM_BY_TEMP_FILE_ERROR
  2216.                     if( retVal == HXR_TEMP_FILE )
  2217.                     {
  2218. theErr = retVal;
  2219. m_pBufferManager->Stop();
  2220. SetEndOfClip();
  2221. mLastError = retVal;
  2222. ReportError(mLastError);
  2223.                     }
  2224. #endif //HELIX_FEATURE_STOP_STREAM_BY_TEMP_FILE_ERROR
  2225. }
  2226.     } 
  2227.     else if (lpStreamInfo->m_bPacketRequested)
  2228.     {
  2229. /* This logic applies to only single threaded application
  2230.  * where if we request a packet, we are either gonna get it 
  2231.  * immediately or not get it at all till a later time--
  2232.  * GetPacket() to ff->read to fs->readdone to ff->
  2233.  * packetready to fileresponse(this) 
  2234.  * In this case, m_uNumStreamsToBeFilled
  2235.  * will be adjusted in packetready depending on timestamp of stream
  2236.  * and where we wanna fill that stream upto
  2237.  * If packet requested is TRUE, it means fileformat did not response
  2238.  * immediately and thus one less stream is to be filled.
  2239.  * This however may not work in multi-threaded case where
  2240.  * fileplugin can send a response at any time.
  2241.  */
  2242. if (!lpStreamInfo->m_bSrcStreamFillingDone)
  2243. {
  2244.     lpStreamInfo->m_bSrcStreamFillingDone = TRUE;
  2245.     if (m_uNumStreamsToBeFilled > 0)
  2246.       {
  2247.      m_uNumStreamsToBeFilled--;
  2248.     }
  2249. }
  2250.     }
  2251. }
  2252.     }
  2253.     m_bInFillMode   = FALSE;
  2254.     return theErr;
  2255. }
  2256. void
  2257. HXFileSource::SetEndOfClip(BOOL bForcedEndofClip) 
  2258. {
  2259.     m_bForcedSourceEnd = bForcedEndofClip;
  2260.     if (!m_bSourceEnd)
  2261.     {
  2262. m_bSourceEnd = TRUE;   
  2263. m_pBufferManager->Stop();
  2264. m_pPlayer->EndOfSource(this);
  2265. #if defined(HELIX_FEATURE_RECORDCONTROL)
  2266. if (m_pRecordControl)
  2267. {
  2268.     m_pRecordControl->OnEndOfPackets();
  2269. }
  2270. #endif /* HELIX_FEATURE_RECORDCONTROL*/
  2271.     }
  2272. }
  2273. // IUnknown methods
  2274. /////////////////////////////////////////////////////////////////////////
  2275. // Method:
  2276. // IUnknown::QueryInterface
  2277. // Purpose:
  2278. // Implement this to export the interfaces supported by your 
  2279. // object.
  2280. //
  2281. STDMETHODIMP 
  2282. HXFileSource::CMimeFinderFileResponse::QueryInterface(REFIID riid, void** ppvObj)
  2283. {
  2284.     QInterfaceList qiList[] =
  2285.         {
  2286.             { GET_IIDHANDLE(IID_IHXFileMimeMapperResponse), (IHXFileMimeMapperResponse*)this },
  2287.             { GET_IIDHANDLE(IID_IHXFileRecognizerResponse), (IHXFileRecognizerResponse*)this },
  2288.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXFileMimeMapperResponse*)this },
  2289.         };
  2290.     
  2291.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  2292. }
  2293. /////////////////////////////////////////////////////////////////////////
  2294. // Method:
  2295. // IUnknown::AddRef
  2296. // Purpose:
  2297. // Everyone usually implements this the same... feel free to use
  2298. // this implementation.
  2299. //
  2300. STDMETHODIMP_(ULONG32) 
  2301. HXFileSource::CMimeFinderFileResponse::AddRef()
  2302. {
  2303.     return InterlockedIncrement(&m_lRefCount);
  2304. }
  2305. /////////////////////////////////////////////////////////////////////////
  2306. // Method:
  2307. // IUnknown::Release
  2308. // Purpose:
  2309. // Everyone usually implements this the same... feel free to use
  2310. // this implementation.
  2311. //
  2312. STDMETHODIMP_(ULONG32) 
  2313. HXFileSource::CMimeFinderFileResponse::Release()
  2314. {
  2315.     if (InterlockedDecrement(&m_lRefCount) > 0)
  2316.     {
  2317. return m_lRefCount;
  2318.     }
  2319.     delete this;
  2320.     return 0;
  2321. }
  2322. // IHXFileMimeMapperResponse methods
  2323. STDMETHODIMP 
  2324. HXFileSource::CMimeFinderFileResponse::MimeTypeFound(HX_RESULT status,
  2325.                                      const char* pMimeType)
  2326. {
  2327.     m_pSource->FinishSetup(status,pMimeType); 
  2328.     return HXR_OK; 
  2329. }
  2330. STDMETHODIMP 
  2331. HXFileSource::CMimeFinderFileResponse::GetMimeTypeDone(HX_RESULT status,
  2332.                                                        IHXBuffer* pMimeType)
  2333. {
  2334.     char* szMimeType = NULL;
  2335.     if (SUCCEEDED(status) && pMimeType)
  2336.     {
  2337.         pMimeType->AddRef();
  2338.         szMimeType = (char*)pMimeType->GetBuffer();
  2339.     }
  2340. #if !defined(_SYMBIAN)
  2341.     //XXXLCM temporary fix until recognizer return codes are better defined and handled; this
  2342.     //       forces fallback to load-by-file-extension logic in FinishSetup()
  2343.     if (status == HXR_FAIL)
  2344.     {
  2345.         status = HXR_OK;
  2346.     }
  2347. #endif
  2348.     m_pSource->FinishSetup(status, szMimeType);
  2349.     HX_RELEASE(pMimeType);
  2350.     
  2351.     return status;
  2352. }
  2353. /*
  2354.  * IHXRegistryID methods
  2355.  */
  2356. /************************************************************************
  2357.  * Method:
  2358.  *     IHXRegistryID::GetID
  2359.  * Purpose:
  2360.  *     Get registry ID(hash_key) of the objects(player, source and stream)
  2361.  *
  2362.  */
  2363. STDMETHODIMP 
  2364. HXFileSource::GetID(REF(UINT32) /*OUT*/ ulRegistryID)
  2365. {
  2366. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2367.     (m_pStats)?(ulRegistryID = m_pStats->m_ulRegistryID):(ulRegistryID = 0);
  2368.    
  2369.     return HXR_OK;
  2370. #else
  2371.     return HXR_NOTIMPL;
  2372. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2373. }
  2374. /************************************************************************
  2375.  * Method:
  2376.  *     IHXInfoLogger::LogInformation
  2377.  * Purpose:
  2378.  *     Logs any user defined information in form of action and 
  2379.  *     associated data.
  2380.  */
  2381. STDMETHODIMP
  2382. HXFileSource::LogInformation(const char* /*IN*/ pAction,
  2383.       const char* /*IN*/ pData)
  2384. {
  2385.     return HXR_OK;
  2386. }
  2387. BOOL
  2388. HXFileSource::IsSourceDone(void)
  2389. {
  2390.     return m_bSourceEnd;
  2391. }
  2392. STDMETHODIMP 
  2393. HXFileSource::GetCurrentBuffering (UINT16  uStreamNumber,
  2394.    REF(INT64)  llLowestTimestamp, 
  2395.    REF(INT64)  llHighestTimestamp,
  2396.    REF(UINT32) ulNumBytes,
  2397.    REF(BOOL)   bDone)
  2398. {
  2399.     llLowestTimestamp = 0; 
  2400.     llHighestTimestamp = 0;
  2401.     ulNumBytes = 0;
  2402.     bDone = FALSE;
  2403.     return HXR_OK;
  2404. }
  2405. void
  2406. HXFileSource::AdjustClipBandwidthStats(BOOL bActivate /* = FALSE */)
  2407. {
  2408.     m_bIsActive = bActivate;
  2409.     for (CHXMapLongToObj::Iterator i = mStreamInfoTable->Begin();
  2410.          i != mStreamInfoTable->End(); ++i) 
  2411.     {    
  2412. STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*i);
  2413. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2414. HX_ASSERT(pStreamInfo->m_pStats);
  2415. if (!pStreamInfo->m_pStats)
  2416. {
  2417.     continue;
  2418. }
  2419. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2420. if (bActivate)
  2421. {
  2422.     pStreamInfo->BufferingState().SetAvgBWToASMBw();
  2423. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2424.     pStreamInfo->m_pStats->m_pClipBandwidth->SetInt((INT32)pStreamInfo->BufferingState().AvgBandwidth());
  2425. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2426. }
  2427. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2428. else
  2429. {
  2430.     pStreamInfo->m_pStats->m_pClipBandwidth->SetInt(0);
  2431. }
  2432. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2433.     }
  2434. }
  2435. BOOL
  2436. HXFileSource::CanBeResumed()
  2437. {
  2438.     BOOL    bResult = TRUE;
  2439.     UINT32  ulCurrentTime = 0;
  2440.     if (!m_bInitialized     ||
  2441. !m_pPlayer->IsInitialized() ||
  2442. m_bSourceEnd     ||
  2443. (m_pSourceInfo && !m_pSourceInfo->AreStreamsSetup()))
  2444.     {
  2445. bResult = FALSE;
  2446.     }
  2447.     else if (m_bPrefetch)
  2448.     {
  2449. HX_ASSERT(m_pSourceInfo?(m_pPlayer->GetCurrentGroupID() == m_pSourceInfo->m_uGroupID):TRUE);
  2450. ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
  2451. if (ulCurrentTime < m_ulPrefetchDelay)
  2452. {
  2453.     bResult = FALSE;
  2454. }
  2455.     }
  2456.     else if ((!m_bIsPreBufferingStarted && m_bDelayed) ||
  2457.      (m_bIsPreBufferingDone && ((!m_bPaused && !m_bFirstResume) || m_bDelayed)))
  2458.     {
  2459. bResult = FALSE;
  2460.     }
  2461.     return bResult;
  2462. }
  2463. #if defined(HELIX_FEATURE_ASM)
  2464. // SourceBandwidthInfo
  2465. STDMETHODIMP 
  2466. HXFileSource::SourceBandwidthInfo::QueryInterface(REFIID riid, void** ppvObj)
  2467. {
  2468.     QInterfaceList qiList[] =
  2469.         {
  2470.             { GET_IIDHANDLE(IID_IHXSourceBandwidthInfo), (IHXSourceBandwidthInfo*)this },
  2471.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXSourceBandwidthInfo*)this },
  2472.         };
  2473.     
  2474.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  2475. }
  2476. STDMETHODIMP_(ULONG32) 
  2477. HXFileSource::SourceBandwidthInfo::AddRef()
  2478. {
  2479.     return InterlockedIncrement(&m_lRefCount);
  2480. }
  2481. STDMETHODIMP_(ULONG32) 
  2482. HXFileSource::SourceBandwidthInfo::Release()
  2483. {
  2484.     if (InterlockedDecrement(&m_lRefCount) > 0)
  2485.     {
  2486. return m_lRefCount;
  2487.     }
  2488.     delete this;
  2489.     return 0;
  2490. }
  2491. STDMETHODIMP
  2492. HXFileSource::SourceBandwidthInfo::InitBw(IHXBandwidthManagerInput* pBwMgr)
  2493. {
  2494.     return HXR_OK;
  2495. }
  2496. STDMETHODIMP
  2497. HXFileSource::SourceBandwidthInfo::SetTransmitRate(UINT32 ulBitRate)
  2498. {
  2499.     return HXR_OK;
  2500. }
  2501. #endif /* HELIX_FEATURE_ASM */
  2502. void 
  2503. HXFileSource::CalculateCurrentBuffering(void)
  2504. {
  2505.     UINT32 ulRemainToBufferInMs = 0;
  2506.     UINT32 ulRemainToBuffer = 0;
  2507.     UINT32 ulExcessBufferInMs = 0;
  2508.     UINT32 ulExcessBuffer = 0;
  2509.     BOOL bValidInfo = FALSE;
  2510.     UINT32 ulActualExcessBufferInMs= 0;
  2511.     UINT32 ulActualExcessBuffer = 0;
  2512.     m_pBufferManager->GetExcessBufferInfo(ulRemainToBufferInMs,
  2513.   ulRemainToBuffer,
  2514.   ulExcessBufferInMs,
  2515.   ulExcessBuffer,
  2516.   bValidInfo,
  2517.      ulActualExcessBufferInMs,
  2518.      ulActualExcessBuffer);
  2519.     /* Be conservative in marking pre-buffering done */
  2520.     if (bValidInfo     &&
  2521. !m_bIsPreBufferingDone     &&
  2522. ulRemainToBufferInMs == 0   && 
  2523. ulRemainToBuffer == 0     && 
  2524. (ulExcessBuffer > m_ulAvgBandwidth/8 || 
  2525.  ulExcessBufferInMs > m_ulPreRollInMs))
  2526.     {
  2527. if (m_bDelayed && m_pPlayer)
  2528. {
  2529.     // pause the src if it's not time to play but it's done
  2530.     // with the pre-fetch
  2531.     if (m_pSourceInfo)
  2532.     {
  2533. m_pSourceInfo->UnRegister();
  2534.     }
  2535.     DoPause();
  2536. }
  2537. m_bIsPreBufferingDone = TRUE;
  2538.     }
  2539. }
  2540. void
  2541. HXFileSource::GetFileDone(HX_RESULT rc, IHXBuffer* pFile)
  2542. {
  2543.     HX_RESULT   ret = rc;
  2544.     UINT32      ulSDPBufferSize = 0;
  2545.     char*       pszSDPBuffer = NULL;
  2546.     CHXString   escapedSDP;
  2547.     CHXString   url;
  2548.     CHXBuffer*  pBuffer = NULL;
  2549.     if (HXR_OK != ret || !pFile)
  2550.     {
  2551.         goto cleanup;
  2552.     }
  2553.     ulSDPBufferSize = pFile->GetSize() + 1;
  2554.     pszSDPBuffer = new char[ulSDPBufferSize];
  2555.     if (NULL == pszSDPBuffer)
  2556.     {
  2557.         ret = HXR_OUTOFMEMORY;
  2558.         goto cleanup;
  2559.     }
  2560.     memset(pszSDPBuffer, 0, ulSDPBufferSize);
  2561.     strncpy(pszSDPBuffer, (const char*)pFile->GetBuffer(), pFile->GetSize());
  2562.     CHXURL::encodeURL(pszSDPBuffer, escapedSDP);
  2563.     url = HELIX_SDP_SCHEME;
  2564.     url += ":";
  2565.     url += escapedSDP;
  2566.     pBuffer = new CHXBuffer();
  2567.     if (NULL == pBuffer)
  2568.     {
  2569.         ret = HXR_OUTOFMEMORY;
  2570.         goto cleanup;
  2571.     }
  2572.     pBuffer->AddRef();
  2573.     pBuffer->Set((UCHAR*)(const char*)url, url.GetLength() + 1);
  2574.     ret = m_pSourceInfo->HandleRedirectRequest((char*)pBuffer->GetBuffer());
  2575. cleanup:
  2576.     HX_VECTOR_DELETE(pszSDPBuffer);
  2577.     HX_RELEASE(pBuffer);
  2578.     if (HXR_OK != ret)
  2579.     {
  2580. mLastError = ret;
  2581. ReportError(mLastError);
  2582.     }
  2583.     return;
  2584. }
  2585. void
  2586. HXFileSource::CheckForDefaultUpgrade(HX_RESULT status)
  2587. {
  2588. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  2589.     if (status == HXR_REQUEST_UPGRADE && !m_bAddDefaultUpgrade)
  2590.     {
  2591. m_bAddDefaultUpgrade = TRUE;
  2592. if (m_pMimeType && !(*m_pMimeType == '*'))
  2593. {
  2594.     m_pDefaultUpgradeString = ::new_string(m_pMimeType);
  2595. }
  2596. else if (m_pExtension)
  2597. {
  2598.     m_pDefaultUpgradeString = ::new_string(m_pExtension);
  2599. }
  2600.     }
  2601. #endif /* HELIX_FEATURE_AUTOUPGRADE */ 
  2602. }
  2603. UINT32 
  2604. HXFileSource::GetEventBeginTime(INT64 llPacketTime, UINT32 streamPreRoll)
  2605. {
  2606.     UINT32      ulEventBeginTime = 0;     // start pos of the packet(event) 
  2607.     INT64     llActualEventBeginTime = 0;     // start pos of the packet(event) with timestamp rollover
  2608.     UINT32     ulMinimumTotalPreroll = 0;
  2609.     // This is the time according to the stream...
  2610.     llActualEventBeginTime = llPacketTime + m_ulDelay;
  2611.     /* subtract start time from player time */
  2612.     if (m_ulStartTime > 0)
  2613.     {
  2614. if (m_ulStartTime < llActualEventBeginTime) 
  2615. {
  2616.     llActualEventBeginTime -= m_ulStartTime; 
  2617. }
  2618. else
  2619. {
  2620.     llActualEventBeginTime = 0;
  2621. }
  2622.     }
  2623.     
  2624.     HX_ASSERT(llActualEventBeginTime < MAX_UINT32);
  2625.     ulEventBeginTime = INT64_TO_UINT32(llActualEventBeginTime);
  2626.     ulEventBeginTime = (ulEventBeginTime > streamPreRoll) ? (ulEventBeginTime - streamPreRoll) : 0;
  2627.     return ulEventBeginTime;
  2628. }
  2629. HX_RESULT
  2630. HXFileSource::FillRecordControl()
  2631. {
  2632. #if defined(HELIX_FEATURE_RECORDCONTROL)
  2633.     if(!m_pRecordControl)
  2634. return HXR_FAILED; 
  2635.     FillBuffers();
  2636.     return HXR_OK;
  2637. #else
  2638.     return HXR_NOTIMPL;
  2639. #endif /* HELIX_FEATURE_RECORDCONTROL */
  2640. }
  2641. HX_RESULT HXFileSource::HandleSDPData(IHXValues* pHeader)
  2642. {
  2643.     HX_RESULT res = HXR_OK;
  2644.     IHXBuffer* pSDPDataBuf = NULL;
  2645.     if (!pHeader)
  2646.     {
  2647. HX_ASSERT(FALSE);
  2648. res = HX_INVALID_HEADER;
  2649.     }
  2650.     else if (HXR_OK == pHeader->GetPropertyCString("SDPData", pSDPDataBuf))
  2651.     {
  2652. IHXStreamDescription* pSD = 
  2653.     HXStreamDescriptionHelper::GetInstance((IHXClientEngine*)m_pEngine, 
  2654.    "application/sdp");
  2655. if (pSD)
  2656. {
  2657.     UINT16 nValues = 0;
  2658.     IHXValues** ppValues = NULL;
  2659.     res = pSD->GetValues(pSDPDataBuf, nValues, ppValues);
  2660.     if (HXR_OK == res)
  2661.     {
  2662. if (nValues >= 1)
  2663. {
  2664.     /* Merge headers from only the first header
  2665.      * since we aren't expecting 'm=' lines in the
  2666.      * SDP
  2667.      */
  2668.     CHXHeader::mergeHeaders(pHeader, ppValues[0]);
  2669. }
  2670. // Clean up the headers returned
  2671. for (UINT16 i = 0; i < nValues; i++)
  2672. {
  2673.     HX_RELEASE(ppValues[i]);
  2674. }
  2675. HX_VECTOR_DELETE(ppValues);
  2676.     }
  2677.     else if (HXR_OUTOFMEMORY != res)
  2678.     {
  2679. /* Mask any errors other than OUTOFMEMORY
  2680.  * because conversion of the SDPData field
  2681.  * is not critical
  2682.  */
  2683. res = HXR_OK;
  2684.     }
  2685.     HX_RELEASE(pSD);
  2686. }
  2687.     }
  2688.     HX_RELEASE(pSDPDataBuf);
  2689.     return res;
  2690. }
  2691. HXFileSource::CFileReader::CFileReader(HXFileSource* pOwner)
  2692.     : m_lRefCount(0),
  2693.       m_bGetFilePending(FALSE),
  2694.       m_pBuffer(NULL),
  2695.       m_pFile(NULL),
  2696.       m_pOwner(pOwner)
  2697. {
  2698. }
  2699. HXFileSource::CFileReader::~CFileReader()
  2700. {
  2701.     Close();
  2702. }
  2703. STDMETHODIMP HXFileSource::CFileReader::QueryInterface(REFIID riid, void** ppvObj)
  2704. {
  2705.     QInterfaceList qiList[] =
  2706.         {
  2707.             { GET_IIDHANDLE(IID_IHXFileResponse), (IHXFileResponse*)this },
  2708.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXFileResponse*)this },
  2709.         };
  2710.     
  2711.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  2712. }
  2713. STDMETHODIMP_(ULONG32) HXFileSource::CFileReader::AddRef()
  2714. {
  2715.     return InterlockedIncrement(&m_lRefCount);
  2716. }
  2717. STDMETHODIMP_(ULONG32) HXFileSource::CFileReader::Release()
  2718. {
  2719.     if (InterlockedDecrement(&m_lRefCount) > 0)
  2720.     {
  2721.         return m_lRefCount;
  2722.     }
  2723.     delete this;
  2724.     return 0;
  2725. }
  2726. STDMETHODIMP HXFileSource::CFileReader::InitDone(HX_RESULT status)
  2727. {
  2728.     HX_RESULT ret = HXR_FAIL;
  2729.     if (FAILED(status))
  2730.     {
  2731.         m_bGetFilePending = FALSE;
  2732.         m_pOwner->GetFileDone(HXR_FAILED, NULL);
  2733.     }
  2734.     else
  2735.     {
  2736. ret = m_pFile->Read(FILEREAD_SIZE);
  2737.     }
  2738.     return ret;
  2739. }
  2740. STDMETHODIMP HXFileSource::CFileReader::SeekDone(HX_RESULT /* status */)
  2741. {
  2742.     return HXR_OK;
  2743. }
  2744. STDMETHODIMP HXFileSource::CFileReader::ReadDone(HX_RESULT status,
  2745.          IHXBuffer* pBuffer)
  2746. {
  2747.     HX_RESULT   ret = status;
  2748.     IHXBuffer*  pMergedBuffer = NULL;
  2749.     if (SUCCEEDED(ret))
  2750.     {
  2751.         pMergedBuffer = new CHXBuffer();
  2752.         if (!pMergedBuffer)
  2753.         {
  2754.             ret = HXR_OUTOFMEMORY;
  2755.             goto cleanup;
  2756.         }
  2757.         pMergedBuffer->AddRef();
  2758.         if (!m_pBuffer)
  2759.         {
  2760.             pMergedBuffer->SetSize(pBuffer->GetSize());
  2761.             pMergedBuffer->Set(pBuffer->GetBuffer(), pBuffer->GetSize());
  2762.         }
  2763.         else
  2764.         {
  2765.             pMergedBuffer->SetSize(m_pBuffer->GetSize() + pBuffer->GetSize());
  2766.     memcpy(pMergedBuffer->GetBuffer(), m_pBuffer->GetBuffer(), m_pBuffer->GetSize()); /* Flawfinder: ignore */
  2767.     memcpy(pMergedBuffer->GetBuffer()+m_pBuffer->GetSize(), pBuffer->GetBuffer(), pBuffer->GetSize()); /* Flawfinder: ignore */
  2768. }
  2769. HX_RELEASE(m_pBuffer);
  2770. m_pBuffer = pMergedBuffer;
  2771. m_pFile->Read(FILEREAD_SIZE);
  2772.     }
  2773.     else
  2774.     {
  2775.         m_bGetFilePending = FALSE;
  2776. if (m_pBuffer && m_pBuffer->GetSize())
  2777. {     
  2778.             m_pOwner->GetFileDone(HXR_OK, m_pBuffer);
  2779. }
  2780. else
  2781. {     
  2782.     m_pFile->Seek(0, FALSE);
  2783.             m_pOwner->GetFileDone(HXR_FAILED, NULL);
  2784. }
  2785.     }
  2786. cleanup:
  2787.     return ret;
  2788. }
  2789. STDMETHODIMP HXFileSource::CFileReader::WriteDone(HX_RESULT /* status */)
  2790. {
  2791.     return HXR_OK;
  2792. }
  2793. STDMETHODIMP HXFileSource::CFileReader::CloseDone(HX_RESULT /* status */)
  2794. {
  2795.     return HXR_OK;
  2796. }
  2797. HX_RESULT
  2798. HXFileSource::CFileReader::GetFile(IHXFileObject* /*IN*/ pFile)
  2799. {
  2800.     HX_RESULT   ret = HXR_OK;
  2801.     if (m_bGetFilePending || !m_pOwner)
  2802.     {
  2803.         return HXR_FAILED;
  2804.     }
  2805.     Close();
  2806.     // get our own IHXFileResponse interface
  2807.     IHXFileResponse* pFileResponse = NULL;
  2808.     ret = QueryInterface(IID_IHXFileResponse, (void**) &pFileResponse);
  2809.     if (pFile != NULL)
  2810.     {
  2811. m_pFile = pFile;
  2812. m_pFile->AddRef();
  2813.     
  2814. if (pFileResponse)
  2815. {
  2816.     ret = m_pFile->Init(HX_FILE_READ | HX_FILE_BINARY,
  2817. pFileResponse);
  2818. }
  2819.     }
  2820.     if (FAILED(ret))
  2821.     {
  2822.         m_pOwner->GetFileDone(HXR_FAIL, NULL);
  2823.     }
  2824.     else
  2825.     {
  2826.         m_bGetFilePending = TRUE;
  2827.     }
  2828.     
  2829.     HX_RELEASE(pFileResponse);
  2830.     return ret;
  2831. }
  2832. void
  2833. HXFileSource::CFileReader::Close(void)
  2834. {
  2835.     m_bGetFilePending = FALSE;
  2836.     HX_RELEASE(m_pBuffer);
  2837.     HX_RELEASE(m_pFile);
  2838. }