Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

592 lines
15 KiB

  1. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. //
  3. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  4. //
  5. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  6. // sources).
  7. //
  8. // The one place we use exceptions is around construction of objects that call
  9. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  10. // the restriction given by not using -GX (automatic objects in the call chain between
  11. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  12. // size because of the unwind code.
  13. //
  14. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  15. //
  16. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  17. //
  18. #pragma warning(disable:4530)
  19. // MarkTrk.cpp : Implementation of CMarkerTrack
  20. #include "dmime.h"
  21. #include "..\shared\dmstrm.h"
  22. #include "MarkTrk.h"
  23. #include "dmusici.h"
  24. #include "dmusicf.h"
  25. #include "debug.h"
  26. #include "..\shared\Validate.h"
  27. #include "debug.h"
  28. #define ASSERT assert
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CMarkerTrack
  31. void CMarkerTrack::Construct()
  32. {
  33. InterlockedIncrement(&g_cComponent);
  34. m_cRef = 1;
  35. m_fCSInitialized = FALSE;
  36. InitializeCriticalSection(&m_CrSec);
  37. m_fCSInitialized = TRUE;
  38. m_dwValidate = 0;
  39. }
  40. CMarkerTrack::CMarkerTrack()
  41. {
  42. Construct();
  43. }
  44. CMarkerTrack::CMarkerTrack(
  45. CMarkerTrack *pSourceTrack, MUSIC_TIME mtStart, MUSIC_TIME mtEnd)
  46. {
  47. Construct();
  48. // Clone the valid start point list.
  49. CValidStartItem* pVScan = pSourceTrack->m_ValidStartList.GetHead();
  50. CValidStartItem* pVPrevious = NULL;
  51. for(; pVScan; pVScan = pVScan->GetNext())
  52. {
  53. if (pVScan->m_ValidStart.mtTime < mtStart)
  54. {
  55. pVPrevious = pVScan;
  56. }
  57. else if (pVScan->m_ValidStart.mtTime < mtEnd)
  58. {
  59. if (pVScan->m_ValidStart.mtTime == mtStart)
  60. {
  61. pVPrevious = NULL;
  62. }
  63. CValidStartItem* pNew = new CValidStartItem;
  64. if (pNew)
  65. {
  66. pNew->m_ValidStart.mtTime = pVScan->m_ValidStart.mtTime - mtStart;
  67. m_ValidStartList.AddHead(pNew); // instead of AddTail, which is n^2. We reverse below.
  68. }
  69. }
  70. else break;
  71. }
  72. m_ValidStartList.Reverse(); // Now, put list in order.
  73. // Then, install the time signature that precedes the clone.
  74. if (pVPrevious)
  75. {
  76. CValidStartItem* pNew = new CValidStartItem;
  77. if (pNew)
  78. {
  79. pNew->m_ValidStart.mtTime = 0;
  80. m_ValidStartList.AddHead(pNew);
  81. }
  82. }
  83. // Clone the play marker list. Gee, this is identical code...
  84. CPlayMarkerItem* pPScan = pSourceTrack->m_PlayMarkerList.GetHead();
  85. CPlayMarkerItem* pPPrevious = NULL;
  86. for(; pPScan; pPScan = pPScan->GetNext())
  87. {
  88. if (pPScan->m_PlayMarker.mtTime < mtStart)
  89. {
  90. pPPrevious = pPScan;
  91. }
  92. else if (pPScan->m_PlayMarker.mtTime < mtEnd)
  93. {
  94. if (pPScan->m_PlayMarker.mtTime == mtStart)
  95. {
  96. pPPrevious = NULL;
  97. }
  98. CPlayMarkerItem* pNew = new CPlayMarkerItem;
  99. if (pNew)
  100. {
  101. pNew->m_PlayMarker.mtTime = pPScan->m_PlayMarker.mtTime - mtStart;
  102. m_PlayMarkerList.AddHead(pNew); // instead of AddTail, which is n^2. We reverse below.
  103. }
  104. }
  105. else break;
  106. }
  107. m_PlayMarkerList.Reverse(); // Now, put list in order.
  108. // Then, install the time signature that precedes the clone.
  109. if (pPPrevious)
  110. {
  111. CPlayMarkerItem* pNew = new CPlayMarkerItem;
  112. if (pNew)
  113. {
  114. pNew->m_PlayMarker.mtTime = 0;
  115. m_PlayMarkerList.AddHead(pNew);
  116. }
  117. }
  118. }
  119. void CMarkerTrack::Clear()
  120. {
  121. CValidStartItem* pStart;
  122. while( pStart = m_ValidStartList.RemoveHead() )
  123. {
  124. delete pStart;
  125. }
  126. CPlayMarkerItem* pPlay;
  127. while( pPlay = m_PlayMarkerList.RemoveHead() )
  128. {
  129. delete pPlay;
  130. }
  131. }
  132. CMarkerTrack::~CMarkerTrack()
  133. {
  134. Clear();
  135. if (m_fCSInitialized)
  136. {
  137. DeleteCriticalSection(&m_CrSec);
  138. }
  139. InterlockedDecrement(&g_cComponent);
  140. }
  141. STDMETHODIMP CMarkerTrack::QueryInterface(
  142. const IID &iid, // @parm Interface to query for
  143. void **ppv) // @parm The requested interface will be returned here
  144. {
  145. V_INAME(CMarkerTrack::QueryInterface);
  146. V_PTRPTR_WRITE(ppv);
  147. V_REFGUID(iid);
  148. if (iid == IID_IUnknown || iid == IID_IDirectMusicTrack)
  149. {
  150. *ppv = static_cast<IDirectMusicTrack*>(this);
  151. } else
  152. if (iid == IID_IPersistStream)
  153. {
  154. *ppv = static_cast<IPersistStream*>(this);
  155. } else
  156. {
  157. *ppv = NULL;
  158. Trace(4,"Warning: Request to query unknown interface on Marker Track\n");
  159. return E_NOINTERFACE;
  160. }
  161. reinterpret_cast<IUnknown*>(this)->AddRef();
  162. return S_OK;
  163. }
  164. STDMETHODIMP_(ULONG) CMarkerTrack::AddRef()
  165. {
  166. return InterlockedIncrement(&m_cRef);
  167. }
  168. STDMETHODIMP_(ULONG) CMarkerTrack::Release()
  169. {
  170. if (!InterlockedDecrement(&m_cRef))
  171. {
  172. delete this;
  173. return 0;
  174. }
  175. return m_cRef;
  176. }
  177. /////////////////////////////////////////////////////////////////////////////
  178. // IPersist
  179. HRESULT CMarkerTrack::GetClassID( CLSID* pClassID )
  180. {
  181. V_INAME(CMarkerTrack::GetClassID);
  182. V_PTR_WRITE(pClassID, CLSID);
  183. *pClassID = CLSID_DirectMusicMarkerTrack;
  184. return S_OK;
  185. }
  186. /////////////////////////////////////////////////////////////////////////////
  187. // IPersistStream functions
  188. HRESULT CMarkerTrack::IsDirty()
  189. {
  190. return S_FALSE;
  191. }
  192. HRESULT CMarkerTrack::Load( IStream* pIStream )
  193. {
  194. V_INAME(CMarkerTrack::Load);
  195. V_INTERFACE(pIStream);
  196. CRiffParser Parser(pIStream);
  197. EnterCriticalSection(&m_CrSec);
  198. m_dwValidate++; // used to validate state data that's out there
  199. RIFFIO ckMain;
  200. HRESULT hr = S_OK;
  201. Parser.EnterList(&ckMain);
  202. if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_MARKERTRACK_LIST))
  203. {
  204. Clear();
  205. RIFFIO ckNext; // Descends into the children chunks.
  206. Parser.EnterList(&ckNext);
  207. while (Parser.NextChunk(&hr))
  208. {
  209. switch(ckNext.ckid)
  210. {
  211. case DMUS_FOURCC_VALIDSTART_CHUNK :
  212. hr = LoadValidStartList(&Parser,ckNext.cksize);
  213. break;
  214. case DMUS_FOURCC_PLAYMARKER_CHUNK :
  215. hr = LoadPlayMarkerList(&Parser,ckNext.cksize);
  216. break;
  217. }
  218. }
  219. Parser.LeaveList();
  220. }
  221. else
  222. {
  223. Trace(1,"Error: Invalid Marker Track.\n");
  224. hr = DMUS_E_CHUNKNOTFOUND;
  225. }
  226. Parser.LeaveList();
  227. LeaveCriticalSection(&m_CrSec);
  228. return hr;
  229. }
  230. HRESULT CMarkerTrack::LoadPlayMarkerList( CRiffParser *pParser, long lChunkSize )
  231. {
  232. HRESULT hr;
  233. // copy contents of the stream into the list.
  234. DWORD dwSubSize;
  235. // read in the size of the data structures
  236. hr = pParser->Read( &dwSubSize, sizeof(DWORD));
  237. if (SUCCEEDED(hr))
  238. {
  239. lChunkSize -= sizeof(DWORD);
  240. DWORD dwRead, dwSeek;
  241. if( dwSubSize > sizeof(DMUS_IO_PLAY_MARKER) )
  242. {
  243. dwRead = sizeof(DMUS_IO_PLAY_MARKER);
  244. dwSeek = dwSubSize - dwRead;
  245. }
  246. else
  247. {
  248. dwRead = dwSubSize;
  249. dwSeek = 0;
  250. }
  251. if( 0 == dwRead )
  252. {
  253. Trace(1,"Error: Invalid Marker Track.\n");
  254. hr = DMUS_E_CANNOTREAD;
  255. }
  256. else
  257. {
  258. while( lChunkSize > 0 )
  259. {
  260. CPlayMarkerItem *pNew = new CPlayMarkerItem;
  261. if (pNew)
  262. {
  263. if( FAILED( pParser->Read( &pNew->m_PlayMarker, dwRead)))
  264. {
  265. delete pNew;
  266. hr = DMUS_E_CANNOTREAD;
  267. break;
  268. }
  269. m_PlayMarkerList.AddHead(pNew); // Insert in reverse order for speed.
  270. lChunkSize -= dwRead;
  271. if( dwSeek )
  272. {
  273. if( FAILED( pParser->Skip(dwSeek)))
  274. {
  275. hr = DMUS_E_CANNOTSEEK;
  276. break;
  277. }
  278. lChunkSize -= dwSeek;
  279. }
  280. }
  281. }
  282. m_PlayMarkerList.Reverse(); // Reverse to put in time order.
  283. }
  284. }
  285. return hr;
  286. }
  287. HRESULT CMarkerTrack::LoadValidStartList( CRiffParser *pParser, long lChunkSize )
  288. {
  289. HRESULT hr;
  290. // copy contents of the stream into the list.
  291. DWORD dwSubSize;
  292. // read in the size of the data structures
  293. hr = pParser->Read( &dwSubSize, sizeof(DWORD));
  294. if (SUCCEEDED(hr))
  295. {
  296. lChunkSize -= sizeof(DWORD);
  297. DWORD dwRead, dwSeek;
  298. if( dwSubSize > sizeof(DMUS_IO_VALID_START) )
  299. {
  300. dwRead = sizeof(DMUS_IO_VALID_START);
  301. dwSeek = dwSubSize - dwRead;
  302. }
  303. else
  304. {
  305. dwRead = dwSubSize;
  306. dwSeek = 0;
  307. }
  308. if( 0 == dwRead )
  309. {
  310. hr = DMUS_E_CANNOTREAD;
  311. }
  312. else
  313. {
  314. while( lChunkSize > 0 )
  315. {
  316. CValidStartItem *pNew = new CValidStartItem;
  317. if (pNew)
  318. {
  319. if( FAILED( pParser->Read( &pNew->m_ValidStart, dwRead)))
  320. {
  321. delete pNew;
  322. hr = DMUS_E_CANNOTREAD;
  323. break;
  324. }
  325. m_ValidStartList.AddHead(pNew); // Insert in reverse order for speed.
  326. lChunkSize -= dwRead;
  327. if( dwSeek )
  328. {
  329. if( FAILED( pParser->Skip(dwSeek)))
  330. {
  331. hr = DMUS_E_CANNOTSEEK;
  332. break;
  333. }
  334. lChunkSize -= dwSeek;
  335. }
  336. }
  337. }
  338. m_ValidStartList.Reverse(); // Reverse to put in time order.
  339. }
  340. }
  341. return hr;
  342. }
  343. HRESULT CMarkerTrack::Save( IStream* pIStream, BOOL fClearDirty )
  344. {
  345. return E_NOTIMPL;
  346. }
  347. HRESULT CMarkerTrack::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
  348. {
  349. return E_NOTIMPL;
  350. }
  351. // IDirectMusicTrack
  352. HRESULT STDMETHODCALLTYPE CMarkerTrack::IsParamSupported(
  353. /* [in] */ REFGUID rguid)
  354. {
  355. V_INAME(CMarkerTrack::IsParamSupported);
  356. V_REFGUID(rguid);
  357. if ((rguid == GUID_Valid_Start_Time) ||
  358. (rguid == GUID_Play_Marker))
  359. return S_OK;
  360. return DMUS_E_TYPE_UNSUPPORTED;
  361. }
  362. //////////////////////////////////////////////////////////////////////
  363. // IDirectMusicTrack::Init
  364. HRESULT CMarkerTrack::Init(
  365. /* [in] */ IDirectMusicSegment *pSegment)
  366. {
  367. return S_OK;
  368. }
  369. HRESULT CMarkerTrack::InitPlay(
  370. /* [in] */ IDirectMusicSegmentState *pSegmentState,
  371. /* [in] */ IDirectMusicPerformance *pPerformance,
  372. /* [out] */ void **ppStateData,
  373. /* [in] */ DWORD dwTrackID,
  374. /* [in] */ DWORD dwFlags)
  375. {
  376. return S_OK;
  377. }
  378. HRESULT CMarkerTrack::EndPlay(
  379. /* [in] */ void *pStateData)
  380. {
  381. return S_OK;
  382. }
  383. HRESULT CMarkerTrack::Play(
  384. /* [in] */ void *pStateData,
  385. /* [in] */ MUSIC_TIME mtStart,
  386. /* [in] */ MUSIC_TIME mtEnd,
  387. /* [in] */ MUSIC_TIME mtOffset,
  388. DWORD dwFlags,
  389. IDirectMusicPerformance* pPerf,
  390. IDirectMusicSegmentState* pSegSt,
  391. DWORD dwVirtualID
  392. )
  393. {
  394. return S_OK;
  395. }
  396. HRESULT CMarkerTrack::GetParam(
  397. REFGUID rguid,
  398. MUSIC_TIME mtTime,
  399. MUSIC_TIME* pmtNext,
  400. void *pData)
  401. {
  402. V_INAME(CMarkerTrack::GetParam);
  403. V_PTR_WRITE_OPT(pmtNext,MUSIC_TIME);
  404. V_REFGUID(rguid);
  405. HRESULT hr = DMUS_E_GET_UNSUPPORTED;
  406. EnterCriticalSection(&m_CrSec);
  407. if( NULL == pData )
  408. {
  409. hr = E_POINTER;
  410. }
  411. else if( GUID_Valid_Start_Time == rguid )
  412. {
  413. DMUS_VALID_START_PARAM* pValidStartData = (DMUS_VALID_START_PARAM*)pData;
  414. CValidStartItem* pScan = m_ValidStartList.GetHead();
  415. for (; pScan; pScan = pScan->GetNext())
  416. {
  417. if (pScan->m_ValidStart.mtTime >= mtTime)
  418. {
  419. pValidStartData->mtTime = pScan->m_ValidStart.mtTime - mtTime;
  420. break;
  421. }
  422. }
  423. if (pScan)
  424. {
  425. if (pmtNext)
  426. {
  427. if (pScan && (pScan = pScan->GetNext()))
  428. {
  429. *pmtNext = pScan->m_ValidStart.mtTime - mtTime;
  430. }
  431. else
  432. {
  433. *pmtNext = 0;
  434. }
  435. }
  436. hr = S_OK;
  437. }
  438. else
  439. {
  440. hr = DMUS_E_NOT_FOUND;
  441. }
  442. }
  443. else if( GUID_Play_Marker == rguid )
  444. {
  445. // This is a little different. The marker should be the one in existence
  446. // BEFORE, not after the requested time.
  447. DMUS_PLAY_MARKER_PARAM* pPlayMarkerData = (DMUS_PLAY_MARKER_PARAM*)pData;
  448. CPlayMarkerItem* pScan = m_PlayMarkerList.GetHead();
  449. CPlayMarkerItem* pNext;
  450. // For fallback, treat it as if there were a marker at the start of the segment, but return S_FALSE.
  451. hr = S_FALSE;
  452. pPlayMarkerData->mtTime = -mtTime;
  453. for (; pScan; pScan = pNext)
  454. {
  455. pNext = pScan->GetNext();
  456. if (pScan->m_PlayMarker.mtTime <= mtTime)
  457. {
  458. if (!pNext || (pNext->m_PlayMarker.mtTime > mtTime))
  459. {
  460. pPlayMarkerData->mtTime = pScan->m_PlayMarker.mtTime - mtTime;
  461. if (pmtNext && pNext)
  462. {
  463. *pmtNext = pNext->m_PlayMarker.mtTime - mtTime;
  464. }
  465. hr = S_OK;
  466. break;
  467. }
  468. }
  469. else
  470. {
  471. // Didn't find a marker before the requested time.
  472. if (pmtNext)
  473. {
  474. *pmtNext = pScan->m_PlayMarker.mtTime - mtTime;
  475. }
  476. break;
  477. }
  478. }
  479. }
  480. #ifdef DBG
  481. if (hr == DMUS_E_GET_UNSUPPORTED)
  482. {
  483. Trace(1,"Error: MarkerTrack does not support requested GetParam call.\n");
  484. }
  485. #endif
  486. LeaveCriticalSection(&m_CrSec);
  487. return hr;
  488. }
  489. HRESULT CMarkerTrack::SetParam(
  490. REFGUID rguid,
  491. MUSIC_TIME mtTime,
  492. void *pData)
  493. {
  494. return DMUS_E_SET_UNSUPPORTED;
  495. }
  496. HRESULT STDMETHODCALLTYPE CMarkerTrack::AddNotificationType(
  497. /* [in] */ REFGUID rguidNotification)
  498. {
  499. return S_FALSE;
  500. }
  501. HRESULT STDMETHODCALLTYPE CMarkerTrack::RemoveNotificationType(
  502. /* [in] */ REFGUID rguidNotification)
  503. {
  504. return S_FALSE;
  505. }
  506. HRESULT STDMETHODCALLTYPE CMarkerTrack::Clone(
  507. MUSIC_TIME mtStart,
  508. MUSIC_TIME mtEnd,
  509. IDirectMusicTrack** ppTrack)
  510. {
  511. V_INAME(IDirectMusicTrack::Clone);
  512. V_PTRPTR_WRITE(ppTrack);
  513. HRESULT hr = S_OK;
  514. if(mtStart < 0 )
  515. {
  516. Trace(1,"Error: Unable to clone marker track because the start point is less than 0.\n");
  517. return E_INVALIDARG;
  518. }
  519. if(mtStart > mtEnd)
  520. {
  521. Trace(1,"Error: Unable to clone marker track because the start point is greater than the length.\n");
  522. return E_INVALIDARG;
  523. }
  524. EnterCriticalSection(&m_CrSec);
  525. CMarkerTrack *pDM;
  526. try
  527. {
  528. pDM = new CMarkerTrack(this, mtStart, mtEnd);
  529. }
  530. catch( ... )
  531. {
  532. pDM = NULL;
  533. }
  534. LeaveCriticalSection(&m_CrSec);
  535. if (pDM == NULL) {
  536. return E_OUTOFMEMORY;
  537. }
  538. hr = pDM->QueryInterface(IID_IDirectMusicTrack, (void**)ppTrack);
  539. pDM->Release();
  540. return hr;
  541. }