Source code of Windows XP (NT5)
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.

569 lines
16 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Declaration of CParams.
  4. //
  5. #include "dmerror.h"
  6. #include "param.h"
  7. #include "math.h"
  8. #include "validate.h"
  9. #include "debug.h"
  10. #pragma warning(disable:4296)
  11. CCurveList::~CCurveList()
  12. {
  13. while(this->GetHead())
  14. {
  15. delete this->RemoveHead();
  16. }
  17. }
  18. CParamsManager::CParamsManager()
  19. {
  20. m_fDirty = FALSE;
  21. m_cTimeFormats = 0;
  22. m_pguidTimeFormats = NULL;
  23. m_guidCurrentTimeFormat = GUID_NULL;
  24. m_cParams = 0;
  25. m_pCurveLists = NULL;
  26. m_pParamInfos = NULL;
  27. m_dwActiveBits = 0;
  28. InitializeCriticalSection(&m_ParamsCriticalSection);
  29. }
  30. CParamsManager::~CParamsManager()
  31. {
  32. delete[] m_pguidTimeFormats;
  33. delete[] m_pCurveLists;
  34. delete[] m_pParamInfos;
  35. DeleteCriticalSection(&m_ParamsCriticalSection);
  36. }
  37. HRESULT CParamsManager::InitParams(DWORD cTimeFormats, const GUID *pguidTimeFormats, DWORD dwFormatIndex, MP_TIMEDATA mptdTimeData, DWORD cParams, ParamInfo *pParamInfo)
  38. {
  39. //check that the index is in a valid range
  40. if (0 > dwFormatIndex || dwFormatIndex >= cTimeFormats || cParams > sizeof(DWORD) * 8)
  41. return E_INVALIDARG;
  42. m_pCurveLists = new CCurveList[cParams];
  43. if (!m_pCurveLists)
  44. return E_OUTOFMEMORY;
  45. // save the time formats
  46. m_pguidTimeFormats = new GUID[cTimeFormats];
  47. if (!m_pguidTimeFormats)
  48. return E_OUTOFMEMORY;
  49. for (DWORD dwIndex = 0; dwIndex < cTimeFormats; dwIndex++)
  50. {
  51. memcpy(&m_pguidTimeFormats[dwIndex], &pguidTimeFormats[dwIndex], sizeof(*pguidTimeFormats));
  52. }
  53. // save the count of formats
  54. m_cTimeFormats = cTimeFormats;
  55. // save the current time format
  56. m_guidCurrentTimeFormat = m_pguidTimeFormats[dwFormatIndex];
  57. // save the TimeData
  58. m_mptdCurrentTimeData = mptdTimeData;
  59. // save the parameter info
  60. m_pParamInfos
  61. = new ParamInfo[cParams];
  62. if (!m_pParamInfos)
  63. return E_OUTOFMEMORY;
  64. for (dwIndex = 0; dwIndex < cParams; dwIndex++)
  65. {
  66. if (pParamInfo[dwIndex].dwIndex < cParams)
  67. {
  68. memcpy(&m_pParamInfos[pParamInfo[dwIndex].dwIndex],&pParamInfo[dwIndex],sizeof(ParamInfo));
  69. }
  70. }
  71. m_cParams = cParams;
  72. return S_OK;
  73. }
  74. HRESULT CParamsManager::GetParamCount(DWORD *pdwParams)
  75. {
  76. if (pdwParams == NULL)
  77. return E_POINTER;
  78. *pdwParams = m_cParams;
  79. return S_OK;
  80. }
  81. HRESULT CParamsManager::GetParamInfo(DWORD dwParamIndex,MP_PARAMINFO *pInfo)
  82. {
  83. if (!pInfo)
  84. {
  85. return E_POINTER;
  86. }
  87. if (dwParamIndex < m_cParams)
  88. {
  89. *pInfo = m_pParamInfos[dwParamIndex].MParamInfo;
  90. return S_OK;
  91. }
  92. else
  93. {
  94. return E_INVALIDARG;
  95. }
  96. }
  97. HRESULT CParamsManager::GetParamText(DWORD dwParamIndex,WCHAR **ppwchText)
  98. {
  99. if (!ppwchText)
  100. {
  101. return E_POINTER;
  102. }
  103. if (dwParamIndex < m_cParams)
  104. {
  105. // write string of format: "Label\0Unit\0Enums1\0Enum2\0...EnumN\0\0"
  106. ParamInfo &pinfo = m_pParamInfos[dwParamIndex];
  107. int iUnit = wcslen(pinfo.MParamInfo.szLabel) + 1; // begin writing unit text here
  108. int iEnums = iUnit + wcslen(pinfo.MParamInfo.szUnitText) + 1; // begin writing enum text here
  109. int iEnd = iEnums + wcslen(pinfo.pwchText) + 1; // write the final (second) null terminator here
  110. WCHAR *pwsz = static_cast<WCHAR *>(CoTaskMemAlloc((iEnd + 1) * sizeof(WCHAR)));
  111. if (!pwsz)
  112. return E_OUTOFMEMORY;
  113. // wcscpy will write into various points of the string, neatly terminating each with a null
  114. wcscpy(pwsz, pinfo.MParamInfo.szLabel);
  115. wcscpy(pwsz + iUnit, pinfo.MParamInfo.szUnitText);
  116. wcscpy(pwsz + iEnums, pinfo.pwchText);
  117. // The text field was defined with commas to separate the enum values.
  118. // Replace them with NULL characters now.
  119. for (WCHAR *pwch = pwsz + iEnums; *pwch; ++pwch)
  120. {
  121. if (*pwch == L',')
  122. *pwch = L'\0';
  123. }
  124. pwsz[iEnd] = L'\0';
  125. *ppwchText = pwsz;
  126. return S_OK;
  127. }
  128. else
  129. {
  130. return E_INVALIDARG;
  131. }
  132. }
  133. HRESULT CParamsManager::GetNumTimeFormats(DWORD *pdwNumTimeFormats)
  134. {
  135. if (!pdwNumTimeFormats)
  136. {
  137. return E_POINTER;
  138. }
  139. *pdwNumTimeFormats = m_cTimeFormats;
  140. return S_OK;
  141. }
  142. HRESULT CParamsManager::GetSupportedTimeFormat(DWORD dwFormatIndex,GUID *pguidTimeFormat)
  143. {
  144. if (!pguidTimeFormat)
  145. {
  146. return E_POINTER;
  147. }
  148. if (dwFormatIndex >= m_cTimeFormats)
  149. {
  150. return E_INVALIDARG;
  151. }
  152. *pguidTimeFormat = m_pguidTimeFormats[dwFormatIndex];
  153. return S_OK;
  154. }
  155. HRESULT CParamsManager::GetCurrentTimeFormat( GUID *pguidTimeFormat,MP_TIMEDATA *pTimeData)
  156. {
  157. HRESULT hr=S_OK;
  158. // Parameter Validation
  159. if ((pguidTimeFormat == NULL) || (pTimeData == NULL))
  160. {
  161. hr = E_POINTER;
  162. Trace(1,"ERROR: pGuidTimeFormat or pTimeData is NULL\n");
  163. }
  164. // Return the values
  165. if (SUCCEEDED(hr))
  166. {
  167. *pguidTimeFormat = m_guidCurrentTimeFormat;
  168. *pTimeData = m_mptdCurrentTimeData;
  169. }
  170. return hr;
  171. }
  172. HRESULT CParamsManager::CopyParamsFromSource( CParamsManager * pSource)
  173. {
  174. HRESULT hr = S_OK;
  175. DWORD dwIndex;
  176. for (dwIndex = 0; dwIndex < m_cParams; dwIndex++)
  177. {
  178. if (pSource->m_guidCurrentTimeFormat == m_pguidTimeFormats[dwIndex])
  179. {
  180. break;
  181. }
  182. }
  183. hr = InitParams(pSource->m_cTimeFormats, pSource->m_pguidTimeFormats, dwIndex, pSource->m_mptdCurrentTimeData, pSource->m_cParams,pSource->m_pParamInfos);
  184. if (SUCCEEDED(hr))
  185. {
  186. for (dwIndex = 0; dwIndex < m_cParams; dwIndex++)
  187. {
  188. CCurveItem *pCurve = pSource->m_pCurveLists[dwIndex].GetHead();
  189. for (;pCurve;pCurve = pCurve->GetNext())
  190. {
  191. CCurveItem *pNew = new CCurveItem;
  192. if (!pNew)
  193. {
  194. return E_OUTOFMEMORY;
  195. }
  196. pNew->m_Envelope = pCurve->m_Envelope;
  197. m_pCurveLists[dwIndex].AddTail(pNew);
  198. }
  199. }
  200. }
  201. return hr;
  202. }
  203. void
  204. CParamsManager ::UpdateActiveParams(REFERENCE_TIME rtTime, UpdateCallback &rThis)
  205. {
  206. if (!m_dwActiveBits)
  207. return; // nothing to recalc
  208. DWORD dwBit = 1;
  209. for (DWORD dwIndex = 0; dwIndex < m_cParams; dwIndex++, dwBit = dwBit << 1)
  210. {
  211. if (m_dwActiveBits & dwBit)
  212. {
  213. float fVal = 0;
  214. HRESULT hr = GetParamFloat(dwIndex, rtTime, &fVal);
  215. rThis.SetParamUpdate(dwIndex, fVal);
  216. if (hr == S_FALSE)
  217. m_dwActiveBits &= ~dwBit; // we're beyond the last curve, don't need to recalc next time
  218. TraceI(6, "DMO value: time %I64d, param #%d, current value %hf\n", rtTime, dwIndex, fVal);
  219. }
  220. }
  221. }
  222. inline float ValRange(float valToClip, float valMin, float valMax)
  223. {
  224. return valToClip < valMin
  225. ? valMin
  226. : (valToClip > valMax ? valMax : valToClip);
  227. }
  228. HRESULT CParamsManager::GetParamFloat(DWORD dwParamIndex,REFERENCE_TIME rtTime,float *pval)
  229. {
  230. HRESULT hr = S_OK;
  231. if (dwParamIndex >= m_cParams)
  232. return E_INVALIDARG;
  233. EnterCriticalSection(&m_ParamsCriticalSection);
  234. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  235. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  236. // if no points, then neutral value
  237. CCurveItem *pCurveHead = pList->GetHead();
  238. if (!pCurveHead)
  239. {
  240. *pval = pInfo->MParamInfo.mpdNeutralValue;
  241. LeaveCriticalSection(&m_ParamsCriticalSection);
  242. return S_FALSE;
  243. }
  244. // Find the curve during or before the requested time
  245. // If the time is during a curve, we will use that.
  246. // If not, we need the end value of the previous curve.
  247. // Our list keeps these in backwards order, so we are scanning from the
  248. // highest point in time backwards.
  249. for (CCurveItem *pCurve = pCurveHead; pCurve && pCurve->m_Envelope.rtStart > rtTime;pCurve = pCurve->GetNext());
  250. // If there is no pCurve, there was no curve prior to or during rtTime. Give up.
  251. if (!pCurve)
  252. {
  253. *pval = pInfo->MParamInfo.mpdNeutralValue;
  254. LeaveCriticalSection(&m_ParamsCriticalSection);
  255. return S_OK;
  256. }
  257. // Now, if pCurve ends before the requested time,
  258. // return the final value of pCurve, since that will hold until the start of the next curve.
  259. if (pCurve->m_Envelope.rtEnd < rtTime)
  260. {
  261. *pval = pCurve->m_Envelope.valEnd;
  262. LeaveCriticalSection(&m_ParamsCriticalSection);
  263. if (pCurve == pCurveHead)
  264. return S_FALSE; // past last curve
  265. else
  266. return S_OK; // there are more curves ahead
  267. }
  268. // If we get this far, the curve must bound rtTime.
  269. if (pCurve->m_Envelope.iCurve & MP_CURVE_JUMP)
  270. {
  271. *pval = pCurve->m_Envelope.valEnd;
  272. LeaveCriticalSection(&m_ParamsCriticalSection);
  273. return S_OK;
  274. }
  275. REFERENCE_TIME rtTimeChange = pCurve->m_Envelope.rtEnd - pCurve->m_Envelope.rtStart;
  276. REFERENCE_TIME rtTimeIntermediate = rtTime - pCurve->m_Envelope.rtStart;
  277. float fltScalingX = static_cast<float>(rtTimeIntermediate) / rtTimeChange; // horizontal distance along curve between 0 and 1
  278. float fltScalingY; // height of curve at that point between 0 and 1 based on curve function
  279. switch (pCurve->m_Envelope.iCurve)
  280. {
  281. case MP_CURVE_SQUARE:
  282. fltScalingY = fltScalingX * fltScalingX;
  283. break;
  284. case MP_CURVE_INVSQUARE:
  285. fltScalingY = (float) sqrt(fltScalingX);
  286. break;
  287. case MP_CURVE_SINE:
  288. // �� Maybe we should have a lookup table here?
  289. fltScalingY = (float) (sin(fltScalingX * 3.1415926535 - (3.1415926535/2)) + 1) / 2;
  290. break;
  291. case MP_CURVE_LINEAR:
  292. default:
  293. fltScalingY = fltScalingX;
  294. }
  295. // Find out if we need to pull the start point from the previous curve,
  296. // the default neutral value, or the current curve.
  297. float fStartVal = pCurve->m_Envelope.valStart;
  298. if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_NEUTRALVAL)
  299. {
  300. fStartVal = pInfo->MParamInfo.mpdNeutralValue;
  301. }
  302. // Currentval, if it exists, will override neutralval.
  303. if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_CURRENTVAL)
  304. {
  305. // Take advantage of the fact that these are inserted in backwards order.
  306. // Scan for the previous curve that ends before this time.
  307. CCurveItem *pPrevious = pCurve->GetNext();
  308. for (;pPrevious && pPrevious->m_Envelope.rtEnd > rtTime;pPrevious = pPrevious->GetNext());
  309. if (pPrevious)
  310. {
  311. fStartVal = pPrevious->m_Envelope.valEnd;
  312. }
  313. }
  314. // Apply that scaling to the range of the actual points
  315. *pval = (pCurve->m_Envelope.valEnd - fStartVal) * fltScalingY + fStartVal;
  316. LeaveCriticalSection(&m_ParamsCriticalSection);
  317. return hr;
  318. }
  319. HRESULT CParamsManager::GetParamInt(DWORD dwParamIndex,REFERENCE_TIME rt,long *pval)
  320. {
  321. HRESULT hr = E_POINTER;
  322. if (pval)
  323. {
  324. float fVal;
  325. hr = GetParamFloat(dwParamIndex,rt,&fVal);
  326. if (SUCCEEDED(hr))
  327. {
  328. *pval = (long) (fVal + 1/2); // Round.
  329. }
  330. }
  331. else
  332. {
  333. Trace(1,"ERROR: pval is NULL\n");
  334. }
  335. return hr;
  336. }
  337. //////////////////////////////////////////////////////////////////////
  338. // IMediaParams
  339. HRESULT CParamsManager::GetParam(DWORD dwParamIndex,MP_DATA *pValue)
  340. {
  341. V_INAME(CParams::GetParam);
  342. V_PTR_WRITE(pValue, MP_DATA);
  343. if (dwParamIndex >= m_cParams)
  344. return E_INVALIDARG;
  345. EnterCriticalSection(&m_ParamsCriticalSection);
  346. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  347. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  348. // if no points, then neutral value
  349. CCurveItem *pCurve = pList->GetHead();
  350. if (pCurve)
  351. {
  352. *pValue = pCurve->m_Envelope.valEnd;
  353. }
  354. else
  355. {
  356. *pValue = pInfo->MParamInfo.mpdNeutralValue;
  357. }
  358. LeaveCriticalSection(&m_ParamsCriticalSection);
  359. return S_OK;
  360. }
  361. HRESULT CParamsManager::SetParam(DWORD dwParamIndex,MP_DATA value)
  362. {
  363. V_INAME(CParams::SetParam);
  364. if (dwParamIndex >= m_cParams)
  365. return E_INVALIDARG;
  366. EnterCriticalSection(&m_ParamsCriticalSection);
  367. m_fDirty = TRUE;
  368. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  369. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  370. // If we've already got a list, just force the most recent curve item to this value.
  371. // Otherwise, create a node and add it.
  372. CCurveItem *pCurve = pList->GetHead();
  373. if (!pCurve)
  374. {
  375. pCurve = new CCurveItem;
  376. if (pCurve)
  377. {
  378. pCurve->m_Envelope.rtStart = 0x8000000000000000; // Max negative.
  379. pCurve->m_Envelope.rtEnd = 0x7FFFFFFFFFFFFFFF; // Max positive.
  380. pCurve->m_Envelope.flags = 0;
  381. pList->AddHead(pCurve);
  382. }
  383. else
  384. {
  385. LeaveCriticalSection(&m_ParamsCriticalSection);
  386. return E_OUTOFMEMORY;
  387. }
  388. }
  389. pCurve->m_Envelope.valStart = value;
  390. pCurve->m_Envelope.valEnd = value;
  391. pCurve->m_Envelope.iCurve = MP_CURVE_JUMP;
  392. LeaveCriticalSection(&m_ParamsCriticalSection);
  393. return S_OK;
  394. }
  395. HRESULT CParamsManager::AddEnvelope(
  396. DWORD dwParamIndex,
  397. DWORD cPoints,
  398. MP_ENVELOPE_SEGMENT *ppEnvelope)
  399. {
  400. V_INAME(CParams::AddEnvelope);
  401. V_PTR_READ(ppEnvelope, *ppEnvelope);
  402. if (dwParamIndex >= m_cParams)
  403. return E_INVALIDARG;
  404. if (!m_pParamInfos)
  405. return DMUS_E_NOT_INIT;
  406. HRESULT hr = S_OK;
  407. EnterCriticalSection(&m_ParamsCriticalSection);
  408. m_fDirty = TRUE;
  409. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  410. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  411. DWORD dwCount;
  412. for (dwCount = 0; dwCount < cPoints; dwCount++)
  413. {
  414. CCurveItem *pCurve = new CCurveItem;
  415. if (!pCurve)
  416. {
  417. hr = E_OUTOFMEMORY;
  418. Trace(1,"ERROR: Out of memory\n");
  419. break;
  420. }
  421. pCurve->m_Envelope = ppEnvelope[dwCount];
  422. pCurve->m_Envelope.valEnd = ValRange(pCurve->m_Envelope.valEnd,
  423. pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  424. pCurve->m_Envelope.valStart = ValRange(pCurve->m_Envelope.valStart,
  425. pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  426. pList->AddHead(pCurve);
  427. m_dwActiveBits |= 1 << dwParamIndex; // next call to UpdateActiveParams will ensure the parameter's value is recalculated
  428. TraceI(6, "DMO envelope: time %I64d-%I64d, param #%d, value %hf-%hf\n",
  429. pCurve->m_Envelope.rtStart, pCurve->m_Envelope.rtEnd,
  430. dwParamIndex, pCurve->m_Envelope.valStart, pCurve->m_Envelope.valEnd);
  431. }
  432. LeaveCriticalSection(&m_ParamsCriticalSection);
  433. return hr;
  434. }
  435. HRESULT CParamsManager::FlushEnvelope(
  436. DWORD dwParamIndex,
  437. REFERENCE_TIME refTimeStart,
  438. REFERENCE_TIME refTimeEnd)
  439. {
  440. if (dwParamIndex >= m_cParams)
  441. return E_INVALIDARG;
  442. if (!m_pParamInfos)
  443. return DMUS_E_NOT_INIT;
  444. if (refTimeStart >= refTimeEnd)
  445. return E_INVALIDARG;
  446. EnterCriticalSection(&m_ParamsCriticalSection);
  447. m_fDirty = TRUE;
  448. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  449. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  450. CCurveList TempList;
  451. CCurveItem *pCurve;
  452. while (pCurve = pList->RemoveHead())
  453. {
  454. if ((pCurve->m_Envelope.rtStart >= refTimeStart) &&
  455. (pCurve->m_Envelope.rtEnd <= refTimeEnd))
  456. {
  457. delete pCurve;
  458. }
  459. else
  460. {
  461. TempList.AddHead(pCurve);
  462. }
  463. }
  464. while (pCurve = TempList.RemoveHead())
  465. {
  466. pList->AddHead(pCurve);
  467. }
  468. LeaveCriticalSection(&m_ParamsCriticalSection);
  469. return S_OK;
  470. }
  471. HRESULT CParamsManager::SetTimeFormat(
  472. GUID guidTimeFormat,
  473. MP_TIMEDATA mpTimeData)
  474. {
  475. for (DWORD dwIndex = 0; dwIndex < m_cTimeFormats; dwIndex++)
  476. {
  477. if (guidTimeFormat == m_pguidTimeFormats[dwIndex])
  478. {
  479. m_guidCurrentTimeFormat = m_pguidTimeFormats[dwIndex];
  480. return S_OK;
  481. }
  482. }
  483. return E_INVALIDARG;
  484. }