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.

628 lines
17 KiB

  1. // Copyright (c) 1998 - 1999 Microsoft Corporation. All Rights Reserved.
  2. #include <streams.h>
  3. #include <ddraw.h>
  4. #include <VPManager.h>
  5. #include <VPMPin.h>
  6. #include <VPMUtil.h>
  7. #include <ddkernel.h>
  8. //
  9. // Flipping surface implementation
  10. //
  11. // To allow decoders to hold on to surfaces for out of order decode
  12. // we flip directly to the surface pass on Receive rather than
  13. // use the default NULL target surface for Flip().
  14. //
  15. // This works in the following way
  16. //
  17. // The COMPinputPin::m_pDirectDrawSurface points to the FRONT buffer
  18. //
  19. // When Receive is called we Flip() the front buffer and because we
  20. // do an explicit Flip() DirectDraw swaps the memory pointers for the
  21. // current Front buffer and the surface passed in which is then attached
  22. // to the front buffer.
  23. //
  24. // The received buffer is then put at the back of the queue so (correctly)
  25. // the previous front buffer is now at the back of the queue to be handed
  26. // to the application
  27. //
  28. // The allocator actually has one more buffer than was actually requested
  29. // so the previous front buffer won't actually be requested until the next
  30. // Receive and hence the previous Flip() has time to complete.
  31. //
  32. // Video accelerator disable interface
  33. ///////////////////////////////////////////
  34. // CLASS CDDrawMediaSample implemented here
  35. ///////////////////////////////////////////
  36. // constructor
  37. CDDrawMediaSample::CDDrawMediaSample(TCHAR *pName, CBaseAllocator *pAllocator, HRESULT *phr, LPBYTE pBuffer, LONG length,
  38. bool bKernelFlip)
  39. : CMediaSample(pName, pAllocator, phr, pBuffer, length)
  40. {
  41. AMTRACE((TEXT("CDDrawMediaSample::Constructor")));
  42. m_pDirectDrawSurface = NULL;
  43. m_dwDDrawSampleSize = 0;
  44. m_bSurfaceLocked = FALSE;
  45. m_bKernelLock = bKernelFlip;
  46. SetRect(&m_SurfaceRect, 0, 0, 0, 0);
  47. memset(&m_DibData, 0, sizeof(DIBDATA));
  48. m_bInit = FALSE;
  49. return;
  50. }
  51. // destructor
  52. CDDrawMediaSample::~CDDrawMediaSample(void)
  53. {
  54. AMTRACE((TEXT("CDDrawMediaSample::Destructor")));
  55. if (m_pDirectDrawSurface)
  56. {
  57. __try {
  58. m_pDirectDrawSurface->Release() ; // release surface now
  59. }
  60. __except(EXCEPTION_EXECUTE_HANDLER) {
  61. ;
  62. }
  63. m_pDirectDrawSurface = NULL;
  64. }
  65. if (m_bInit)
  66. {
  67. if (m_DibData.hBitmap)
  68. {
  69. EXECUTE_ASSERT(DeleteObject(m_DibData.hBitmap));
  70. }
  71. if (m_DibData.hMapping)
  72. {
  73. EXECUTE_ASSERT(CloseHandle(m_DibData.hMapping));
  74. }
  75. }
  76. return;
  77. }
  78. HRESULT CDDrawMediaSample::SetDDrawSampleSize(DWORD dwDDrawSampleSize)
  79. {
  80. HRESULT hr = NOERROR;
  81. AMTRACE((TEXT("CVPMInputAllocator::SetDDrawSampleSize")));
  82. m_dwDDrawSampleSize = dwDDrawSampleSize;
  83. return hr;
  84. }
  85. HRESULT CDDrawMediaSample::GetDDrawSampleSize(DWORD *pdwDDrawSampleSize)
  86. {
  87. HRESULT hr = NOERROR;
  88. AMTRACE((TEXT("CVPMInputAllocator::SetDDrawSampleSize")));
  89. if (!pdwDDrawSampleSize)
  90. {
  91. DbgLog((LOG_ERROR, 1, TEXT("Bad Arguments, pdwDDrawSampleSize = NULL")));
  92. hr = E_POINTER;
  93. goto CleanUp;
  94. }
  95. *pdwDDrawSampleSize = m_dwDDrawSampleSize;
  96. CleanUp:
  97. return hr;
  98. }
  99. HRESULT CDDrawMediaSample::SetDDrawSurface(LPDIRECTDRAWSURFACE7 pDirectDrawSurface)
  100. {
  101. HRESULT hr = NOERROR;
  102. AMTRACE((TEXT("CVPMInputAllocator::SetDDrawSampleSize")));
  103. if (pDirectDrawSurface) // only if new surface is not NULL...
  104. pDirectDrawSurface->AddRef() ; // ...add a ref count on it
  105. if (m_pDirectDrawSurface) // if there was a surface already...
  106. m_pDirectDrawSurface->Release() ; // ... then release it now
  107. m_pDirectDrawSurface = pDirectDrawSurface;
  108. return hr;
  109. }
  110. HRESULT CDDrawMediaSample::GetDDrawSurface(LPDIRECTDRAWSURFACE7 *ppDirectDrawSurface)
  111. {
  112. HRESULT hr = NOERROR;
  113. AMTRACE((TEXT("CVPMInputAllocator::SetDDrawSampleSize")));
  114. if (!ppDirectDrawSurface)
  115. {
  116. DbgLog((LOG_ERROR, 1, TEXT("Bad Arguments, ppDirectDrawSurface = NULL")));
  117. hr = E_INVALIDARG;
  118. goto CleanUp;
  119. }
  120. *ppDirectDrawSurface = m_pDirectDrawSurface;
  121. CleanUp:
  122. return hr;
  123. }
  124. // overridden to expose IDirectDrawMediaSample
  125. STDMETHODIMP CDDrawMediaSample::QueryInterface(REFIID riid, void **ppv)
  126. {
  127. HRESULT hr = NOERROR;
  128. AMTRACE((TEXT("CDDrawMediaSample::QueryInterface")));
  129. if (riid == IID_IDirectDrawMediaSample && m_pDirectDrawSurface)
  130. {
  131. hr = GetInterface(static_cast<IDirectDrawMediaSample*>(this), ppv);
  132. #ifdef DEBUG
  133. if (FAILED(hr))
  134. {
  135. DbgLog((LOG_ERROR, 2, TEXT("GetInterface(IDirectDrawMediaSample*) failed, hr = 0x%x"), hr));
  136. }
  137. #endif
  138. }
  139. else
  140. {
  141. hr = CMediaSample::QueryInterface(riid, ppv);
  142. #ifdef DEBUG
  143. if (FAILED(hr))
  144. {
  145. DbgLog((LOG_ERROR, 2, TEXT("CUnknown::NonDelegatingQueryInterface failed, hr = 0x%x"), hr));
  146. }
  147. #endif
  148. }
  149. return hr;
  150. }
  151. // Implement IDirectDrawMediaSample
  152. STDMETHODIMP CDDrawMediaSample::GetSurfaceAndReleaseLock(IDirectDrawSurface **ppDirectDrawSurface,
  153. RECT* pRect)
  154. {
  155. HRESULT hr = NOERROR;
  156. BYTE *pBufferPtr;
  157. AMTRACE((TEXT("CDDrawMediaSample::GetSurfaceAndReleaseLock")));
  158. // make sure the surface is locked
  159. if (!m_bSurfaceLocked)
  160. {
  161. DbgLog((LOG_ERROR, 4, TEXT("m_bSurfaceLocked is FALSE, can't unlock surface twice, returning E_UNEXPECTED")));
  162. goto CleanUp;
  163. }
  164. // make sure you have a direct draw surface pointer
  165. if (!m_pDirectDrawSurface)
  166. {
  167. DbgLog((LOG_ERROR, 1, TEXT("m_pDirectDrawSurface is NULL, returning E_FAIL")));
  168. hr = E_FAIL;
  169. goto CleanUp;
  170. }
  171. hr = GetPointer(&pBufferPtr);
  172. if (FAILED(hr))
  173. {
  174. DbgLog((LOG_ERROR, 1, TEXT("GetPointer() failed, hr = 0x%x"), hr));
  175. goto CleanUp;
  176. }
  177. ASSERT(m_pDirectDrawSurface);
  178. hr = m_pDirectDrawSurface->Unlock(NULL); // TBD: was (LPVOID)pBufferPtr);
  179. if (FAILED(hr))
  180. {
  181. DbgLog((LOG_ERROR, 1, TEXT("m_pDirectDrawSurface->Unlock failed, hr = 0x%x"), hr));
  182. goto CleanUp;
  183. }
  184. // Can't do this to make the 829/848 work with the ovmixer. The reason is that those
  185. // drivers unlock the surface just after GetBuffer (to avoid the win16 lock), however
  186. // there is a bunch of code in the proxy which ASSERTS for a valid pointer value
  187. /*
  188. // update the pointer value, however keep the SampleSize around
  189. hr = SetPointer(NULL, 0);
  190. if (FAILED(hr))
  191. {
  192. DbgLog((LOG_ERROR, 1, TEXT("SetPointer() failed, hr = 0x%x"), hr));
  193. goto CleanUp;
  194. }
  195. */
  196. if (ppDirectDrawSurface) {
  197. hr = m_pDirectDrawSurface->QueryInterface( IID_IDirectDrawSurface7, (VOID**)ppDirectDrawSurface );
  198. if( FAILED( hr )) {
  199. ASSERT( FALSE );
  200. *ppDirectDrawSurface = NULL;
  201. }
  202. } else if (pRect) {
  203. *pRect = m_SurfaceRect;
  204. }
  205. m_bSurfaceLocked = FALSE;
  206. CleanUp:
  207. return hr;
  208. }
  209. STDMETHODIMP CDDrawMediaSample::LockMediaSamplePointer(void)
  210. {
  211. HRESULT hr = NOERROR;
  212. DWORD dwDDrawSampleSize = 0;
  213. DDSURFACEDESC2 ddSurfaceDesc;
  214. DWORD dwLockFlags = DDLOCK_WAIT;
  215. AMTRACE((TEXT("CDDrawMediaSample::LockMediaSamplePointer")));
  216. // make sure the surface is locked
  217. if (m_bSurfaceLocked)
  218. {
  219. DbgLog((LOG_ERROR, 1, TEXT("m_bSurfaceLocked is TRUE, can't lock surface twice, returning E_UNEXPECTED")));
  220. hr = E_UNEXPECTED;
  221. goto CleanUp;
  222. }
  223. // make sure you have a direct draw surface pointer
  224. if (!m_pDirectDrawSurface)
  225. {
  226. DbgLog((LOG_ERROR, 1, TEXT("m_pDirectDrawSurface is NULL, returning E_FAIL")));
  227. hr = E_FAIL;
  228. goto CleanUp;
  229. }
  230. // set the dwSize of ddSurfaceDesc
  231. INITDDSTRUCT(ddSurfaceDesc);
  232. // lock the surface - no need to grab the win16 lock
  233. ASSERT(m_pDirectDrawSurface);
  234. // Using DDLOCK_NOSYSLOCK caused us to get DDERR_SURFACEBUSY on some of
  235. // our blts to the primary for painting the color key so we've
  236. // stopped using it for now.
  237. IDirectDrawSurface7 *pSurface7;
  238. if (m_bKernelLock && SUCCEEDED(m_pDirectDrawSurface->QueryInterface(
  239. IID_IDirectDrawSurface7,
  240. (void **)&pSurface7))) {
  241. pSurface7->Release();
  242. dwLockFlags |= DDLOCK_NOSYSLOCK;
  243. }
  244. hr = m_pDirectDrawSurface->Lock(
  245. NULL,
  246. &ddSurfaceDesc,
  247. dwLockFlags,
  248. (HANDLE)NULL);
  249. if (FAILED(hr))
  250. {
  251. DbgLog((LOG_ERROR, 1, TEXT("m_pDirectDrawSurface->Lock() failed, hr = 0x%x"), hr));
  252. goto CleanUp;
  253. }
  254. hr = GetDDrawSampleSize(&dwDDrawSampleSize);
  255. if (FAILED(hr))
  256. {
  257. DbgLog((LOG_ERROR, 1, TEXT("GetDDrawSampleSize() failed, hr = 0x%x"), hr));
  258. goto CleanUp;
  259. }
  260. ASSERT(dwDDrawSampleSize);
  261. // update the pointer value
  262. hr = SetPointer((BYTE*)ddSurfaceDesc.lpSurface, dwDDrawSampleSize);
  263. if (FAILED(hr))
  264. {
  265. DbgLog((LOG_ERROR, 1, TEXT("SetPointer() failed, hr = 0x%x"), hr));
  266. goto CleanUp;
  267. }
  268. m_bSurfaceLocked = TRUE;
  269. CleanUp:
  270. return hr;
  271. }
  272. // Set the shared memory DIB information
  273. void CDDrawMediaSample::SetDIBData(DIBDATA *pDibData)
  274. {
  275. ASSERT(pDibData);
  276. m_DibData = *pDibData;
  277. m_pBuffer = m_DibData.pBase;
  278. m_cbBuffer = m_dwDDrawSampleSize;
  279. m_bInit = TRUE;
  280. }
  281. // Retrieve the shared memory DIB data
  282. DIBDATA *CDDrawMediaSample::GetDIBData()
  283. {
  284. ASSERT(m_bInit == TRUE);
  285. return &m_DibData;
  286. }
  287. ///////////////////////////////////////////
  288. // CLASS CVPMInputAllocator implemented here
  289. ///////////////////////////////////////////
  290. // constructor
  291. CVPMInputAllocator::CVPMInputAllocator(CVPMInputPin& pPin, HRESULT *phr)
  292. : CBaseAllocator(NAME("Video Allocator"), NULL, phr, TRUE, true)
  293. , m_pPin( pPin )
  294. {
  295. AMTRACE((TEXT("CVPMInputAllocator::Constructor")));
  296. // REVIEW don't overwrite a failure code from CBaseAllocator
  297. return;
  298. }
  299. // destructor
  300. CVPMInputAllocator::~CVPMInputAllocator()
  301. {
  302. AMTRACE((TEXT("CVPMInputAllocator::Destructor")));
  303. }
  304. // Override this to publicise IDirectDrawMediaSampleAllocator
  305. STDMETHODIMP CVPMInputAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  306. {
  307. HRESULT hr = E_NOINTERFACE;
  308. AMTRACE((TEXT("CVPMInputAllocator::NonDelegatingQueryInterface")));
  309. CAutoLock cLock( &m_pPin.GetFilter().GetFilterLock() );
  310. return hr;
  311. }
  312. STDMETHODIMP CVPMInputAllocator::SetProperties(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual)
  313. {
  314. HRESULT hr = NOERROR;
  315. AMTRACE((TEXT("CVPMInputAllocator::SetProperties")));
  316. // call the base class
  317. hr = CBaseAllocator::SetProperties(pRequest, pActual);
  318. if (FAILED(hr))
  319. {
  320. DbgLog((LOG_ERROR, 1, TEXT("CBaseAllocator::SetProperties() failed, hr = 0x%x"), hr));
  321. goto CleanUp;
  322. }
  323. // tell the pin
  324. hr = m_pPin.OnSetProperties(pRequest, pActual);
  325. if (FAILED(hr))
  326. {
  327. DbgLog((LOG_ERROR, 1, TEXT("m_pPin.AllocateSurfaces() failed, hr = 0x%x"), hr));
  328. goto CleanUp;
  329. }
  330. CleanUp:
  331. return hr;
  332. }
  333. // called when we receive a sample
  334. HRESULT CVPMInputAllocator::GetBuffer(IMediaSample **ppSample, REFERENCE_TIME *pStartTime,
  335. REFERENCE_TIME *pEndTime, DWORD dwFlags)
  336. {
  337. HRESULT hr = NOERROR;
  338. AMTRACE((TEXT("CVPMInputAllocator::GetBuffer")));
  339. // call the base class
  340. IMediaSample *pSample = NULL;
  341. hr = CBaseAllocator::GetBuffer(&pSample,pStartTime,pEndTime,0);
  342. if (FAILED(hr))
  343. {
  344. DbgLog((LOG_ERROR, 1, TEXT("CBaseAllocator::GetBuffer() failed, hr = 0x%x"), hr));
  345. goto CleanUp;
  346. }
  347. // tell the pin
  348. hr = m_pPin.OnGetBuffer(&pSample, pStartTime, pEndTime, dwFlags);
  349. if (FAILED(hr))
  350. {
  351. DbgLog((LOG_ERROR, 1, TEXT("m_pPin.OnGetBuffer() failed, hr = 0x%x"), hr));
  352. goto CleanUp;
  353. }
  354. CleanUp:
  355. {
  356. // REVIEW why lock? There are no variables in the allocato
  357. // accessed here
  358. CAutoLock cAllocatorLock(this);
  359. if (FAILED(hr))
  360. {
  361. if (pSample)
  362. {
  363. pSample->Release();
  364. }
  365. *ppSample = NULL;
  366. }
  367. else
  368. {
  369. ASSERT(pSample != NULL);
  370. *ppSample = pSample;
  371. }
  372. }
  373. return hr;
  374. }
  375. // called when the sample is released
  376. HRESULT CVPMInputAllocator::ReleaseBuffer(IMediaSample *pSample)
  377. {
  378. HRESULT hr = NOERROR;
  379. AMTRACE((TEXT("CVPMInputAllocator::ReleaseBuffer")));
  380. // unlock the sample first
  381. hr = ((CDDrawMediaSample*)pSample)->GetSurfaceAndReleaseLock(NULL, NULL);
  382. if (FAILED(hr))
  383. {
  384. DbgLog((LOG_ERROR, 1, TEXT("pSample->GetSurfaceAndReleaseLock() failed, hr = 0x%x"), hr));
  385. // goto CleanUp;
  386. // if this happens we still have to release the sample to the free list, so don't bail out
  387. }
  388. {
  389. CAutoLock cAllocatorLock(this);
  390. // Copy of base class code - put at end of the list
  391. {
  392. CheckPointer(pSample,E_POINTER);
  393. ValidateReadPtr(pSample,sizeof(IMediaSample));
  394. BOOL bRelease = FALSE;
  395. {
  396. CAutoLock cal(this);
  397. /* Put back on the free list */
  398. CMediaSample **ppTail;
  399. for (ppTail = &m_lFree.m_List; *ppTail;
  400. ppTail = &((CDDrawMediaSample *)(*ppTail))->Next()) {
  401. }
  402. *ppTail = (CMediaSample *)pSample;
  403. ((CDDrawMediaSample *)pSample)->Next() = NULL;
  404. m_lFree.m_nOnList++;
  405. if (m_lWaiting != 0) {
  406. NotifySample();
  407. }
  408. // if there is a pending Decommit, then we need to complete it by
  409. // calling Free() when the last buffer is placed on the free list
  410. LONG l1 = m_lFree.GetCount();
  411. if (m_bDecommitInProgress && (l1 == m_lAllocated)) {
  412. Free();
  413. m_bDecommitInProgress = FALSE;
  414. bRelease = TRUE;
  415. }
  416. }
  417. if (m_pNotify) {
  418. m_pNotify->NotifyRelease();
  419. }
  420. // For each buffer there is one AddRef, made in GetBuffer and released
  421. // here. This may cause the allocator and all samples to be deleted
  422. if (bRelease)
  423. {
  424. Release();
  425. }
  426. }
  427. }
  428. return hr;
  429. }
  430. // allocate memory for the sample
  431. HRESULT CVPMInputAllocator::Alloc()
  432. {
  433. HRESULT hr = NOERROR;
  434. CDDrawMediaSample **ppSampleList = NULL;
  435. DWORD i;
  436. LONG lToAllocate;
  437. AMTRACE((TEXT("CVPMInputAllocator::Alloc")));
  438. // call the base class
  439. hr = CBaseAllocator::Alloc();
  440. if (FAILED(hr))
  441. {
  442. DbgLog((LOG_ERROR, 1, TEXT("CBaseAllocator::Alloc() failed, hr = 0x%x"), hr));
  443. goto CleanUp;
  444. }
  445. // allocate memory for pointers
  446. lToAllocate = (m_pPin.m_dwBackBufferCount > 1 &&
  447. !m_pPin.m_bSyncOnFill &&
  448. m_pPin.m_bCanOverAllocateBuffers) ?
  449. m_lCount + 1 : m_lCount;
  450. // allocate memory for an array of pointers
  451. ppSampleList = new CDDrawMediaSample *[lToAllocate];
  452. if (!ppSampleList)
  453. {
  454. DbgLog((LOG_ERROR, 1, TEXT("new BYTE[m_lCount*sizeof(CDDrawMediaSample*)] failed")));
  455. hr = E_OUTOFMEMORY;
  456. goto CleanUp;
  457. }
  458. for (i = 0; i < (DWORD)(lToAllocate); i++)
  459. {
  460. // Create a new sample
  461. ppSampleList[i] = new CDDrawMediaSample(NAME("Sample"), this, (HRESULT *) &hr, NULL, (LONG) 0,
  462. DDKERNELCAPS_LOCK & m_pPin.m_pVPMFilter.KernelCaps() ?
  463. true : false);
  464. // REVIEW - actually hr can't be a failure
  465. // so we don't need to delete ppSampleList[i] here
  466. if (FAILED(hr) || ppSampleList[i] == NULL)
  467. {
  468. if (SUCCEEDED(hr))
  469. hr = E_OUTOFMEMORY;
  470. DbgLog((LOG_ERROR, 1, TEXT("new CDDrawMediaSample failed, hr = 0x%x"), hr));
  471. goto CleanUp;
  472. }
  473. // this cannot fail
  474. m_lFree.Add(ppSampleList[i]);
  475. m_lAllocated++;
  476. }
  477. ASSERT(m_lAllocated == lToAllocate);
  478. // tell the pin
  479. hr = m_pPin.OnAlloc(ppSampleList, lToAllocate);
  480. if (FAILED(hr))
  481. {
  482. DbgLog((LOG_ERROR, 1, TEXT("m_pPin.OnAlloc(), hr = 0x%x"), hr));
  483. goto CleanUp;
  484. }
  485. CleanUp:
  486. delete[] ppSampleList;
  487. return hr;
  488. }
  489. void CVPMInputAllocator::Free(void)
  490. {
  491. CDDrawMediaSample *pSample;
  492. AMTRACE((TEXT("CVPMInputAllocator::Free")));
  493. /* Should never be deleting this unless all buffers are freed */
  494. // REVIEW - might not be true if we failed to allocate a sample
  495. ASSERT(m_lAllocated == m_lFree.GetCount());
  496. /* Free up all the CMediaSamples */
  497. for (;;)
  498. {
  499. pSample = (CDDrawMediaSample *) m_lFree.RemoveHead();
  500. if (pSample != NULL)
  501. {
  502. delete pSample;
  503. }
  504. else
  505. {
  506. break;
  507. }
  508. }
  509. m_lAllocated = 0;
  510. return;
  511. }