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.

2234 lines
63 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. #include <ksmedia.h>
  9. // IVideoPortControl
  10. #include <VPObj.h>
  11. // AMINTERLACE_*
  12. #include <dvdmedia.h>
  13. #include "DRect.h"
  14. extern "C"
  15. const TCHAR szPropPage[] = TEXT("Property Pages");
  16. //
  17. // Flipping surface implementation
  18. //
  19. // To allow decoders to hold on to surfaces for out of order decode
  20. // we flip directly to the surface pass on Receive rather than
  21. // use the default NULL target surface for Flip().
  22. //
  23. // This works in the following way
  24. //
  25. // The COMPinputPin::m_pDirectDrawSurface points to the FRONT buffer
  26. //
  27. // When Receive is called we Flip() the front buffer and because we
  28. // do an explicit Flip() DirectDraw swaps the memory pointers for the
  29. // current Front buffer and the surface passed in which is then attached
  30. // to the front buffer.
  31. //
  32. // The received buffer is then put at the back of the queue so (correctly)
  33. // the previous front buffer is now at the back of the queue to be handed
  34. // to the application
  35. //
  36. // The allocator actually has one more buffer than was actually requested
  37. // so the previous front buffer won't actually be requested until the next
  38. // Receive and hence the previous Flip() has time to complete.
  39. //
  40. // Video accelerator disable interface
  41. //
  42. /////////////////////////////////////
  43. // CLASS CVPMInputPin implemented here
  44. /////////////////////////////////////
  45. // constructor
  46. CVPMInputPin::CVPMInputPin( TCHAR *pObjectName,
  47. CVPMFilter& pFilter,
  48. HRESULT *phr,
  49. LPCWSTR pPinName,
  50. DWORD dwPinNo)
  51. : CBaseInputPin(pObjectName, &pFilter, &pFilter.GetFilterLock(), phr, pPinName)
  52. , CVPMPin( dwPinNo, pFilter )
  53. , m_cOurRef( 0 )
  54. , m_pIVPObject( NULL )
  55. , m_pIVPInfo(NULL)
  56. , m_CategoryGUID( GUID_NULL )
  57. , m_Communication( KSPIN_COMMUNICATION_SOURCE )
  58. , m_bStreamingInKernelMode( FALSE )
  59. , m_dwBackBufferCount( 0 )
  60. , m_dwDirectDrawSurfaceWidth( 0 )
  61. , m_dwMinCKStretchFactor( 0 )
  62. , m_bSyncOnFill( FALSE )
  63. , m_bDontFlip( FALSE )
  64. , m_bDynamicFormatNeeded( TRUE )
  65. , m_bNewPaletteSet( TRUE )
  66. , m_dwInterlaceFlags( 0 )
  67. , m_dwFlipFlag( 0 )
  68. , m_bConnected( FALSE )
  69. , m_bUsingOurAllocator( FALSE )
  70. , m_hMemoryDC( NULL )
  71. , m_bCanOverAllocateBuffers( TRUE )
  72. , m_hEndOfStream( NULL )
  73. , m_bDecimating( FALSE )
  74. , m_lWidth( 0L )
  75. , m_lHeight( 0L )
  76. , m_bRuntimeNegotiationFailed( FALSE)
  77. , m_dwUpdateOverlayFlags( 0 )
  78. , m_dwFlipFlag2( 0 )
  79. , m_trLastFrame( 0 )
  80. , m_lSrcWidth( 0 )
  81. , m_lSrcHeight( 0 )
  82. , m_rtNextSample( 0 )
  83. , m_rtLastRun( 0 )
  84. {
  85. AMTRACE((TEXT("CVPMInputPin::Constructor")));
  86. memset( &m_WinInfo, 0, sizeof(m_WinInfo) );
  87. m_bWinInfoSet = false;
  88. *phr = S_OK;
  89. m_Medium.Set = GUID_NULL;
  90. m_Medium.Id = 0;
  91. m_Medium.Flags = 0;
  92. HRESULT hr = NOERROR;
  93. LPUNKNOWN pUnkOuter;
  94. SetReconnectWhenActive(true);
  95. #ifdef PERF
  96. m_PerfFrameFlipped = MSR_REGISTER(TEXT("Frame Drawn"));
  97. #endif
  98. // See combase.cpp(107) for comments on this
  99. IUnknown* pThisUnknown = reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) );
  100. m_pVideoPortObject = new CVideoPortObj( pThisUnknown, phr, this );
  101. // alias pointer to interfaces (instead of QI'ing)
  102. m_pIVPObject = m_pVideoPortObject;
  103. m_pIVPInfo = m_pVideoPortObject;
  104. hr = m_pIVPObject->SetObjectLock( &m_pVPMFilter.GetFilterLock() );
  105. if (FAILED(hr))
  106. {
  107. *phr = hr;
  108. }
  109. return;
  110. }
  111. // destructor
  112. CVPMInputPin::~CVPMInputPin(void)
  113. {
  114. AMTRACE((TEXT("CVPMInputPin::Destructor")));
  115. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  116. // delete the inner object
  117. delete m_pVideoPortObject;
  118. m_pVideoPortObject = NULL;
  119. }
  120. // overriden to expose IMediaPosition and IMediaSeeking control interfaces
  121. STDMETHODIMP CVPMInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  122. {
  123. HRESULT hr = NOERROR;
  124. AMTRACE((TEXT("CVPMInputPin::NonDelegatingQueryInterface")));
  125. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  126. if (riid == IID_IVPNotify ) {
  127. hr = GetInterface( static_cast<IVPNotify*>(m_pVideoPortObject), ppv);
  128. if (FAILED(hr)) {
  129. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPUnknown->QueryInterface failed, hr = 0x%x"), hr));
  130. }
  131. } else if (riid == IID_IVPNotify2 ) {
  132. hr = GetInterface( static_cast<IVPNotify2*>(m_pVideoPortObject), ppv);
  133. if (FAILED(hr)) {
  134. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPUnknown->QueryInterface failed, hr = 0x%x"), hr));
  135. }
  136. } else if (riid == IID_IKsPin) {
  137. hr = GetInterface(static_cast<IKsPin *>(this), ppv);
  138. if (FAILED(hr)) {
  139. DbgLog((LOG_ERROR, 2, TEXT("GetInterface(IKsPin*) failed, hr = 0x%x"), hr));
  140. }
  141. } else if (riid == IID_IKsPropertySet) {
  142. hr = GetInterface(static_cast<IKsPropertySet *>(this), ppv);
  143. if (FAILED(hr)) {
  144. DbgLog((LOG_ERROR, 2, TEXT("GetInterface(IKsPropertySet*) failed, hr = 0x%x"), hr));
  145. }
  146. } else if (riid == IID_IPinConnection) {
  147. hr = GetInterface(static_cast<IPinConnection*>(this), ppv);
  148. if (FAILED(hr)) {
  149. DbgLog((LOG_ERROR, 2, TEXT("GetInterface(IPinConnection, ppv) failed, hr = 0x%x"), hr));
  150. }
  151. } else if (riid == IID_ISpecifyPropertyPages&& 0 != VPMUtil::GetPropPagesRegistryDword( 0)) {
  152. return GetInterface(static_cast<ISpecifyPropertyPages *>(this), ppv);
  153. } else {
  154. // call the base class
  155. hr = CBaseInputPin::NonDelegatingQueryInterface(riid, ppv);
  156. if (FAILED(hr)) {
  157. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::NonDelegatingQueryInterface failed, hr = 0x%x"), hr));
  158. }
  159. }
  160. return hr;
  161. }
  162. //
  163. // NonDelegatingAddRef/NonDelegatingRelease
  164. //
  165. //
  166. STDMETHODIMP_(ULONG) CVPMInputPin::NonDelegatingAddRef(void)
  167. {
  168. return m_pVPMFilter.AddRef();
  169. } // NonDelegatingAddRef
  170. STDMETHODIMP_(ULONG) CVPMInputPin::NonDelegatingRelease(void)
  171. {
  172. return m_pVPMFilter.Release();
  173. }
  174. // --- ISpecifyPropertyPages ---
  175. STDMETHODIMP CVPMInputPin::GetPages(CAUUID *pPages)
  176. {
  177. #if 0
  178. pPages->cElems = 1;
  179. pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)*1);
  180. if (pPages->pElems == NULL) {
  181. return E_OUTOFMEMORY;
  182. }
  183. pPages->pElems[0] = CLSID_COMPinConfigProperties;
  184. return NOERROR;
  185. #else
  186. return E_NOTIMPL;
  187. #endif
  188. }
  189. // this function just tells whether each sample consists of one or two fields
  190. BOOL DisplayingFields(DWORD dwInterlaceFlags)
  191. {
  192. if ((dwInterlaceFlags & AMINTERLACE_IsInterlaced) &&
  193. (dwInterlaceFlags & AMINTERLACE_1FieldPerSample))
  194. return TRUE;
  195. else
  196. return FALSE;
  197. }
  198. BOOL CheckTypeSpecificFlags(DWORD dwInterlaceFlags, DWORD dwTypeSpecificFlags)
  199. {
  200. // first determine which field do we want to display here
  201. if ((dwInterlaceFlags & AMINTERLACE_1FieldPerSample) &&
  202. ((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_INTERLEAVED_FRAME))
  203. {
  204. return FALSE;
  205. }
  206. if ((!(dwInterlaceFlags & AMINTERLACE_1FieldPerSample)) &&
  207. (((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_FIELD1) ||
  208. ((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_FIELD2)))
  209. {
  210. return FALSE;
  211. }
  212. if (dwTypeSpecificFlags & AM_VIDEO_FLAG_REPEAT_FIELD)
  213. {
  214. return FALSE;
  215. }
  216. return TRUE;
  217. }
  218. // given the interlace flags and the type-specific flags, this function determines whether we
  219. // are supposed to display the sample in bob-mode or not. It also tells us, which direct-draw flag
  220. // are we supposed to use when flipping. When displaying an interleaved frame, it assumes we are
  221. // talking about the field which is supposed to be displayed first.
  222. BOOL NeedToFlipOddEven(DWORD dwInterlaceFlags, DWORD dwTypeSpecificFlags, DWORD *pdwFlipFlag)
  223. {
  224. BOOL bDisplayField1 = TRUE;
  225. BOOL bField1IsOdd = TRUE;
  226. BOOL bNeedToFlipOddEven = FALSE;
  227. DWORD dwFlipFlag = 0;
  228. // if not interlaced content, mode is not bob
  229. if (!(dwInterlaceFlags & AMINTERLACE_IsInterlaced))
  230. {
  231. bNeedToFlipOddEven = FALSE;
  232. goto CleanUp;
  233. }
  234. // if sample have a single field, then check the field pattern
  235. if ((dwInterlaceFlags & AMINTERLACE_1FieldPerSample) &&
  236. (((dwInterlaceFlags & AMINTERLACE_FieldPatternMask) == AMINTERLACE_FieldPatField1Only) ||
  237. ((dwInterlaceFlags & AMINTERLACE_FieldPatternMask) == AMINTERLACE_FieldPatField2Only)))
  238. {
  239. bNeedToFlipOddEven = FALSE;
  240. goto CleanUp;
  241. }
  242. if (((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) == AMINTERLACE_DisplayModeBobOnly) ||
  243. (((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) == AMINTERLACE_DisplayModeBobOrWeave) &&
  244. (!(dwTypeSpecificFlags & AM_VIDEO_FLAG_WEAVE))))
  245. {
  246. // first determine which field do we want to display here
  247. if (dwInterlaceFlags & AMINTERLACE_1FieldPerSample)
  248. {
  249. // if we are in 1FieldPerSample mode, check which field is it
  250. ASSERT(((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_FIELD1) ||
  251. ((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_FIELD2));
  252. bDisplayField1 = ((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_FIELD1);
  253. }
  254. else
  255. {
  256. // ok the sample is an interleaved frame
  257. ASSERT((dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD_MASK) == AM_VIDEO_FLAG_INTERLEAVED_FRAME);
  258. bDisplayField1 = (dwTypeSpecificFlags & AM_VIDEO_FLAG_FIELD1FIRST);
  259. }
  260. bField1IsOdd = (dwInterlaceFlags & AMINTERLACE_Field1First);
  261. // if we displaying field 1 and field 1 is odd or we are displaying field2 and field 2 is odd
  262. // then use DDFLIP_ODD. Exactly the opposite for DDFLIP_EVEN
  263. if ((bDisplayField1 && bField1IsOdd) || (!bDisplayField1 && !bField1IsOdd))
  264. dwFlipFlag = DDFLIP_ODD;
  265. else
  266. dwFlipFlag = DDFLIP_EVEN;
  267. bNeedToFlipOddEven = TRUE;
  268. goto CleanUp;
  269. }
  270. CleanUp:
  271. if (pdwFlipFlag)
  272. *pdwFlipFlag = dwFlipFlag;
  273. return bNeedToFlipOddEven;
  274. }
  275. // given the interlace flags and the type-specific flags, this function determines whether we
  276. // are supposed to display the sample in bob-mode or not. It also tells us, which direct-draw flag
  277. // are we supposed to use when flipping. When displaying an interleaved frame, it assumes we are
  278. // talking about the field which is supposed to be displayed first.
  279. DWORD GetUpdateOverlayFlags(DWORD dwInterlaceFlags, DWORD dwTypeSpecificFlags)
  280. {
  281. DWORD dwFlags = DDOVER_SHOW | DDOVER_KEYDEST;
  282. DWORD dwFlipFlag;
  283. if (NeedToFlipOddEven(dwInterlaceFlags, dwTypeSpecificFlags, &dwFlipFlag))
  284. {
  285. dwFlags |= DDOVER_BOB;
  286. if (!DisplayingFields(dwInterlaceFlags))
  287. dwFlags |= DDOVER_INTERLEAVED;
  288. }
  289. return dwFlags;
  290. }
  291. // this function checks if the InterlaceFlags are suitable or not
  292. HRESULT CVPMInputPin::CheckInterlaceFlags(DWORD dwInterlaceFlags)
  293. {
  294. HRESULT hr = NOERROR;
  295. AMTRACE((TEXT("CVPMInputPin::CheckInterlaceFlags")));
  296. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  297. if (dwInterlaceFlags & AMINTERLACE_UNUSED)
  298. {
  299. hr = VFW_E_TYPE_NOT_ACCEPTED;
  300. goto CleanUp;
  301. }
  302. // check that the display mode is one of the three allowed values
  303. if (((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) != AMINTERLACE_DisplayModeBobOnly) &&
  304. ((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) != AMINTERLACE_DisplayModeWeaveOnly) &&
  305. ((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) != AMINTERLACE_DisplayModeBobOrWeave))
  306. {
  307. hr = VFW_E_TYPE_NOT_ACCEPTED;
  308. goto CleanUp;
  309. }
  310. // if content is not interlaced, other bits are irrelavant, so we are done
  311. if (!(dwInterlaceFlags & AMINTERLACE_IsInterlaced))
  312. {
  313. goto CleanUp;
  314. }
  315. // samples are frames, not fields (so we can handle any display mode)
  316. if (!(dwInterlaceFlags & AMINTERLACE_1FieldPerSample))
  317. {
  318. goto CleanUp;
  319. }
  320. // can handle a stream of just field1 or field2, whatever the display mode
  321. if (((dwInterlaceFlags & AMINTERLACE_FieldPatternMask) == AMINTERLACE_FieldPatField1Only) ||
  322. ((dwInterlaceFlags & AMINTERLACE_FieldPatternMask) == AMINTERLACE_FieldPatField2Only))
  323. {
  324. goto CleanUp;
  325. }
  326. // can handle only bob-mode for field samples
  327. if ((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) == AMINTERLACE_DisplayModeBobOnly)
  328. {
  329. goto CleanUp;
  330. }
  331. // cannot handle only Weave mode or BobOrWeave mode for field samples
  332. if (((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) == AMINTERLACE_DisplayModeWeaveOnly) ||
  333. ((dwInterlaceFlags & AMINTERLACE_DisplayModeMask) == AMINTERLACE_DisplayModeBobOrWeave))
  334. {
  335. hr = VFW_E_TYPE_NOT_ACCEPTED;
  336. goto CleanUp;
  337. }
  338. // we should have covered all possible scenarios by now, so assert here
  339. ASSERT(1);
  340. CleanUp:
  341. // we cannot handle bob mode with an offscreen surface or if the driver can't support it
  342. if (SUCCEEDED(hr))
  343. {
  344. const DDCAPS* pDirectCaps = m_pVPMFilter.GetHardwareCaps();
  345. if ( pDirectCaps )
  346. {
  347. // call NeedToFlipOddEven with dwTypeSpecificFlags=0, to pretend that the
  348. // type-specific-flags is asking us to do bob-mode.
  349. bool bCanBob = false;
  350. if ( !bCanBob && NeedToFlipOddEven(dwInterlaceFlags, 0, NULL) )
  351. {
  352. hr = VFW_E_TYPE_NOT_ACCEPTED;
  353. }
  354. }
  355. }
  356. return hr;
  357. }
  358. // this function check if the mediatype on a dynamic format change is suitable.
  359. // No lock is taken here. It is the callee's responsibility to maintain integrity!
  360. HRESULT CVPMInputPin::DynamicCheckMediaType(const CMediaType* pmt)
  361. {
  362. HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
  363. DWORD dwOldInterlaceFlags = 0, dwNewInterlaceFlags = 0, dwCompareSize = 0;
  364. BOOL bOld1FieldPerSample = FALSE, bNew1FieldPerSample = FALSE;
  365. BOOL b1, b2;
  366. AMTRACE((TEXT("CVPMInputPin::DynamicCheckMediaType")));
  367. // majortype and SubType are not allowed to change dynamically,
  368. // format type can change.
  369. CMediaType mtNew;
  370. hr = m_pIVPObject->CurrentMediaType( &mtNew );
  371. if (FAILED(hr) ||
  372. NULL == pmt ||
  373. (!(IsEqualGUID(pmt->majortype, mtNew.majortype))) ||
  374. (!(IsEqualGUID(pmt->subtype, mtNew.subtype))))
  375. {
  376. goto CleanUp;
  377. }
  378. // get the interlace flags of the new mediatype
  379. hr = VPMUtil::GetInterlaceFlagsFromMediaType( *pmt, &dwNewInterlaceFlags);
  380. if (FAILED(hr))
  381. {
  382. goto CleanUp;
  383. }
  384. // get the interlace flags of the new mediatype
  385. hr = VPMUtil::GetInterlaceFlagsFromMediaType( mtNew, &dwOldInterlaceFlags);
  386. if (FAILED(hr))
  387. {
  388. goto CleanUp;
  389. }
  390. //
  391. // There are several bugs in the following code !!
  392. // We goto CleanUp but hr has not been updated with a valid error code!!
  393. //
  394. bOld1FieldPerSample = (dwOldInterlaceFlags & AMINTERLACE_IsInterlaced) &&
  395. (dwOldInterlaceFlags & AMINTERLACE_1FieldPerSample);
  396. bNew1FieldPerSample = (dwNewInterlaceFlags & AMINTERLACE_IsInterlaced) &&
  397. (dwNewInterlaceFlags & AMINTERLACE_1FieldPerSample);
  398. // we do not allow dynamic format changes where you go from 1FieldsPerSample to
  399. // 2FieldsPerSample or vica-versa since that means reallocating the surfaces.
  400. if (bNew1FieldPerSample != bOld1FieldPerSample)
  401. {
  402. goto CleanUp;
  403. }
  404. const BITMAPINFOHEADER* pNewHeader = VPMUtil::GetbmiHeader(pmt);
  405. if (!pNewHeader)
  406. {
  407. goto CleanUp;
  408. }
  409. const BITMAPINFOHEADER* pOldHeader = VPMUtil::GetbmiHeader(&mtNew);
  410. if (!pNewHeader)
  411. {
  412. goto CleanUp;
  413. }
  414. dwCompareSize = FIELD_OFFSET(BITMAPINFOHEADER, biClrUsed);
  415. ASSERT(dwCompareSize < sizeof(BITMAPINFOHEADER));
  416. if (memcmp(pNewHeader, pOldHeader, dwCompareSize) != 0)
  417. {
  418. goto CleanUp;
  419. }
  420. hr = NOERROR;
  421. CleanUp:
  422. // CVPMInputPin::DynamicCheckMediaType")));
  423. return hr;
  424. }
  425. // check that the mediatype is acceptable. No lock is taken here. It is the callee's
  426. // responsibility to maintain integrity!
  427. HRESULT CVPMInputPin::CheckMediaType(const CMediaType* pmt)
  428. {
  429. AMTRACE((TEXT("CVPMInputPin::CheckMediaType")));
  430. // check if the VP component likes this mediatype
  431. // check if the videoport object likes it
  432. HRESULT hr = m_pIVPObject->CheckMediaType(pmt);
  433. if (FAILED(hr)) {
  434. DbgLog((LOG_ERROR, 2, TEXT("m_pIVPObject->CheckMediaType failed, hr = 0x%x"), hr));
  435. ASSERT( hr == VFW_E_TYPE_NOT_ACCEPTED ); // can't fail with anything else
  436. } else {
  437. DbgLog((LOG_TRACE, 2, TEXT("m_pIVPObject->CheckMediaType succeeded, bAcceptableVPMediatype is TRUE")));
  438. }
  439. return hr;
  440. }
  441. // called after we have agreed a media type to actually set it
  442. HRESULT CVPMInputPin::SetMediaType(const CMediaType* pmt)
  443. {
  444. HRESULT hr = NOERROR;
  445. AMTRACE((TEXT("CVPMInputPin::SetMediaType")));
  446. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  447. // make sure the mediatype is correct
  448. hr = CheckMediaType(pmt);
  449. if (FAILED(hr))
  450. {
  451. DbgLog((LOG_ERROR, 1, TEXT("CheckMediaType failed, hr = 0x%x"), hr));
  452. goto CleanUp;
  453. }
  454. const BITMAPINFOHEADER *pHeader = VPMUtil::GetbmiHeader(pmt);
  455. if (pHeader)
  456. {
  457. // store the interlace flags since we use them again and again
  458. hr = VPMUtil::GetInterlaceFlagsFromMediaType( *pmt, &m_dwInterlaceFlags);
  459. ASSERT(SUCCEEDED(hr));
  460. // store the update overlay flags (give the type specific flag is WEAVE so that for BOB or WEAVE
  461. // mode, we not bob
  462. m_dwUpdateOverlayFlags = GetUpdateOverlayFlags(m_dwInterlaceFlags, AM_VIDEO_FLAG_WEAVE);
  463. }
  464. // Set the base class media type (should always succeed)
  465. hr = CBaseInputPin::SetMediaType(pmt);
  466. if (FAILED(hr))
  467. {
  468. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::SetMediaType failed, hr = 0x%x"), hr));
  469. goto CleanUp;
  470. }
  471. hr = m_pIVPObject->CheckMediaType(pmt);
  472. if (SUCCEEDED(hr))
  473. {
  474. m_pVPMFilter.SetDecimationUsage(DECIMATION_LEGACY);
  475. hr = m_pIVPObject->SetMediaType(pmt);
  476. ASSERT(SUCCEEDED(hr));
  477. }
  478. // tell the proxy not to allocate buffers if it is a videoport or overlay connection
  479. SetStreamingInKernelMode(TRUE);
  480. // tell the owning filter
  481. hr = m_pVPMFilter.SetMediaType(m_dwPinId, pmt);
  482. if (FAILED(hr))
  483. {
  484. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.SetMediaType failed, hr = 0x%x"), hr));
  485. goto CleanUp;
  486. }
  487. CleanUp:
  488. return hr;
  489. }
  490. HRESULT CVPMInputPin::CurrentMediaType(CMediaType *pmt)
  491. {
  492. ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE));
  493. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  494. /* Copy constructor of m_mt allocates the memory */
  495. if (IsConnected())
  496. {
  497. if( m_pIVPObject ) {
  498. return m_pIVPObject->CurrentMediaType( pmt );
  499. } else {
  500. // shouldn't happen, we alloc this in our constructor
  501. pmt->InitMediaType();
  502. return E_FAIL;
  503. }
  504. } else {
  505. pmt->InitMediaType();
  506. return VFW_E_NOT_CONNECTED;
  507. }
  508. }
  509. #ifdef DEBUG
  510. /*****************************Private*Routine******************************\
  511. * VideoFormat2String
  512. *
  513. * Converts a video format block to a string - useful for debugging
  514. *
  515. * History:
  516. * Tue 12/07/1999 - StEstrop - Created
  517. *
  518. \**************************************************************************/
  519. void VideoFormat2String(
  520. LPTSTR szBuffer,
  521. const GUID* pFormatType,
  522. BYTE* pFormat,
  523. ULONG lFormatLength
  524. )
  525. {
  526. if (!pFormat) {
  527. lstrcpy(szBuffer, TEXT("No format data specified"));
  528. return;
  529. }
  530. //
  531. // Video Format
  532. //
  533. if (IsEqualGUID(*pFormatType, FORMAT_VideoInfo) ||
  534. IsEqualGUID(*pFormatType, FORMAT_MPEGVideo)) {
  535. VIDEOINFO * pVideoFormat = (VIDEOINFO *) pFormat;
  536. wsprintf(szBuffer, TEXT("%4.4hs %dx%d, %d bits"),
  537. (pVideoFormat->bmiHeader.biCompression == 0) ? "RGB " :
  538. ((pVideoFormat->bmiHeader.biCompression == BI_BITFIELDS) ? "BITF" :
  539. (LPSTR) &pVideoFormat->bmiHeader.biCompression),
  540. pVideoFormat->bmiHeader.biWidth,
  541. pVideoFormat->bmiHeader.biHeight,
  542. pVideoFormat->bmiHeader.biBitCount);
  543. }
  544. else if (IsEqualGUID(*pFormatType, FORMAT_VideoInfo2) ||
  545. IsEqualGUID(*pFormatType, FORMAT_MPEG2Video)) {
  546. VIDEOINFOHEADER2 * pVideoFormat = (VIDEOINFOHEADER2 *) pFormat;
  547. wsprintf(szBuffer, TEXT("%4.4hs %dx%d, %d bits"),
  548. (pVideoFormat->bmiHeader.biCompression == 0) ? "RGB " :
  549. ((pVideoFormat->bmiHeader.biCompression == BI_BITFIELDS) ? "BITF" :
  550. (LPSTR) &pVideoFormat->bmiHeader.biCompression ),
  551. pVideoFormat->bmiHeader.biWidth,
  552. pVideoFormat->bmiHeader.biHeight,
  553. pVideoFormat->bmiHeader.biBitCount);
  554. }
  555. else {
  556. lstrcpy(szBuffer, TEXT("Unknown format"));
  557. }
  558. }
  559. #endif
  560. // pConnector is the initiating connecting pin
  561. // pmt is the media type we will exchange
  562. // This function is also called while the graph is running when the
  563. // up stream decoder filter wants to change the size of the
  564. // decoded video.
  565. //
  566. // If the up stream decoder wants to change from one transport
  567. // type to another, eg. from MoComp back to IMemInputPin then it
  568. // should perform a dynamic filter reconnect via the IGraphConfig
  569. // Reconnect method.
  570. //
  571. STDMETHODIMP CVPMInputPin::ReceiveConnection(IPin * pConnector, const AM_MEDIA_TYPE *pmt)
  572. {
  573. HRESULT hr = NOERROR;
  574. CVPMInputAllocator * pAlloc = NULL;
  575. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  576. CheckPointer(pmt, E_POINTER);
  577. CMediaType cmt(*pmt);
  578. if (m_Connected != pConnector || pConnector == NULL)
  579. {
  580. hr = CBaseInputPin::ReceiveConnection(pConnector, &cmt);
  581. goto CleanUp;
  582. }
  583. #ifdef DEBUG
  584. DbgLog((LOG_TRACE, 2, TEXT("ReceiveConnection when connected")));
  585. if (pmt)
  586. {
  587. TCHAR szFmt[128];
  588. VideoFormat2String(szFmt, &pmt->formattype, pmt->pbFormat, pmt->cbFormat);
  589. DbgLog((LOG_TRACE, 2, TEXT("Format is: %s"), szFmt));
  590. }
  591. #endif
  592. {
  593. /* Can only do this if the allocator can be reconfigured */
  594. pAlloc = (CVPMInputAllocator *)m_pAllocator;
  595. if (!pAlloc)
  596. {
  597. hr = E_FAIL;
  598. DbgLog((LOG_TRACE, 2, TEXT("ReceiveConnection: Failed because of no allocator")));
  599. goto CleanUp;
  600. }
  601. if (!pAlloc->CanFree())
  602. {
  603. hr = VFW_E_WRONG_STATE;
  604. DbgLog((LOG_TRACE, 2, TEXT("ReceiveConnection: Failed because allocator can't free")));
  605. goto CleanUp;
  606. }
  607. }
  608. m_bConnected = FALSE;
  609. hr = CheckMediaType(&cmt);
  610. if (FAILED(hr))
  611. {
  612. DbgLog((LOG_TRACE, 2, TEXT("ReceiveConnection: CheckMediaType failed")));
  613. goto CleanUp;
  614. }
  615. ALLOCATOR_PROPERTIES Props;
  616. {
  617. pAlloc->Decommit();
  618. pAlloc->GetProperties(&Props);
  619. }
  620. // back buffers are not addref'd so just set them to NULL
  621. m_dwBackBufferCount = 0;
  622. m_dwDirectDrawSurfaceWidth = 0;
  623. SetMediaType(&cmt);
  624. {
  625. ALLOCATOR_PROPERTIES PropsActual;
  626. Props.cbBuffer = pmt->lSampleSize;
  627. hr = pAlloc->SetProperties(&Props, &PropsActual);
  628. if (SUCCEEDED(hr))
  629. {
  630. hr = pAlloc->Commit();
  631. }
  632. }
  633. hr = UpdateMediaType();
  634. ASSERT(SUCCEEDED(hr));
  635. m_bConnected = TRUE;
  636. CleanUp:
  637. return hr;
  638. }
  639. HRESULT CVPMInputPin::CheckConnect(IPin * pReceivePin)
  640. {
  641. HRESULT hr = NOERROR;
  642. PKSMULTIPLE_ITEM pMediumList = NULL;
  643. IKsPin *pIKsPin = NULL;
  644. PKSPIN_MEDIUM pMedium = NULL;
  645. AMTRACE((TEXT("CVPMInputPin::CheckConnect")));
  646. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  647. hr = pReceivePin->QueryInterface(IID_IKsPin, (void **)&pIKsPin);
  648. if (SUCCEEDED(hr))
  649. {
  650. ASSERT(pIKsPin);
  651. hr = pIKsPin->KsQueryMediums(&pMediumList);
  652. }
  653. if( SUCCEEDED( hr )) {
  654. ASSERT(pMediumList);
  655. pMedium = (KSPIN_MEDIUM *)(pMediumList+1);
  656. SetKsMedium((const KSPIN_MEDIUM *)pMedium);
  657. }
  658. // CleanUp:
  659. // call the base class
  660. hr = CBaseInputPin::CheckConnect(pReceivePin);
  661. if (FAILED(hr))
  662. {
  663. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::CheckConnect failed, hr = 0x%x"), hr));
  664. }
  665. RELEASE(pIKsPin);
  666. if (pMediumList)
  667. {
  668. CoTaskMemFree((void*)pMediumList);
  669. pMediumList = NULL;
  670. }
  671. return hr;
  672. }
  673. HRESULT CVPMInputPin::UpdateMediaType()
  674. {
  675. HRESULT hr = NOERROR;
  676. AMTRACE((TEXT("CVPMInputPin::UpdateMediaType")));
  677. return hr;
  678. }
  679. // final connect
  680. HRESULT CVPMInputPin::FinalConnect()
  681. {
  682. HRESULT hr = NOERROR;
  683. AMTRACE((TEXT("CVPMInputPin::FinalConnect")));
  684. if (m_bConnected)
  685. {
  686. hr = E_FAIL;
  687. goto CleanUp;
  688. }
  689. // update the mediatype, tell the filter about the updated dimensions
  690. hr = UpdateMediaType();
  691. if (FAILED(hr))
  692. {
  693. DbgLog((LOG_ERROR, 1, TEXT("UpdateMediaType failed, hr = 0x%x"), hr));
  694. goto CleanUp;
  695. }
  696. // tell the filter (might involve a reconnection with the output pin)
  697. hr = m_pVPMFilter.CompleteConnect(m_dwPinId);
  698. if (FAILED(hr))
  699. {
  700. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.CompleteConnect failed, hr = 0x%x"), hr));
  701. goto CleanUp;
  702. }
  703. m_bConnected = TRUE;
  704. CleanUp:
  705. return hr;
  706. }
  707. // Complete Connect
  708. HRESULT CVPMInputPin::CompleteConnect(IPin *pReceivePin)
  709. {
  710. HRESULT hr = NOERROR;
  711. AMVPDATAINFO amvpDataInfo;
  712. BITMAPINFOHEADER *pHeader = NULL;
  713. AMTRACE((TEXT("CVPMInputPin::CompleteConnect")));
  714. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  715. {
  716. // tell the videoport object
  717. hr = m_pIVPObject->CompleteConnect(pReceivePin);
  718. if (FAILED(hr))
  719. {
  720. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->CompleteConnect failed, hr = 0x%x"), hr));
  721. goto CleanUp;
  722. }
  723. m_bRuntimeNegotiationFailed = FALSE;
  724. }
  725. // call the base class
  726. hr = CBaseInputPin::CompleteConnect(pReceivePin);
  727. if (FAILED(hr))
  728. {
  729. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::CompleteConnect failed, hr = 0x%x"), hr));
  730. goto CleanUp;
  731. }
  732. ASSERT(SUCCEEDED(hr));
  733. {
  734. // tell the proxy not to allocate buffers if it is a videoport or overlay connection
  735. SetStreamingInKernelMode(TRUE);
  736. hr = FinalConnect();
  737. // ASSERT(SUCCEEDED(hr));
  738. if( FAILED(hr) ) {
  739. SetStreamingInKernelMode(FALSE);
  740. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::FinalConnect failed, hr = 0x%x"), hr));
  741. goto CleanUp;
  742. }
  743. }
  744. // the decoders can support a particular property set to tell the ovmixer to not to try to over-allocate
  745. // buffers incase they want complete control over the buffers etc
  746. {
  747. HRESULT hr1 = NOERROR;
  748. IKsPropertySet *pIKsPropertySet = NULL;
  749. DWORD dwVal = 0, dwBytesReturned = 0;
  750. hr1 = pReceivePin->QueryInterface(IID_IKsPropertySet, (void**)&pIKsPropertySet);
  751. if (SUCCEEDED(hr1))
  752. {
  753. ASSERT(pIKsPropertySet);
  754. if (!pIKsPropertySet)
  755. {
  756. DbgLog((LOG_ERROR, 1, TEXT("pIKsPropertySet == NULL, even though QI returned success")));
  757. goto CleanUp;
  758. }
  759. hr1 = pIKsPropertySet->Get( PROPSETID_ALLOCATOR_CONTROL, KSPROPERTY_ALLOCATOR_CONTROL_HONOR_COUNT,
  760. NULL, 0, &dwVal, sizeof(dwVal), &dwBytesReturned);
  761. DbgLog((LOG_TRACE, 2, TEXT("pIKsPropertySet->Get(KSPROPSETID_ALLOCATOR_CONTROL), hr1 = 0x%x, dwVal == %d, dwBytesReturned == %d"),
  762. hr1, dwVal, dwBytesReturned));
  763. // if the decoder supports this property
  764. // and its value is 1 and the decoder supports DDKERNELCAPS_FLIPOVERLAY,
  765. // than we will do exactly honour its request and the
  766. // and not make any attempt to allocate more in order to prevent tearing
  767. //
  768. if ((SUCCEEDED(hr1)) && (dwVal == 1) && (dwBytesReturned == sizeof(dwVal)) &&
  769. (DDKERNELCAPS_FLIPOVERLAY & m_pVPMFilter.KernelCaps()))
  770. {
  771. DbgLog((LOG_TRACE, 2, TEXT("setting m_bCanOverAllocateBuffers == FALSE")));
  772. m_bCanOverAllocateBuffers = FALSE;
  773. }
  774. pIKsPropertySet->Release();
  775. }
  776. }
  777. CleanUp:
  778. return hr;
  779. }
  780. HRESULT CVPMInputPin::OnSetProperties(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual)
  781. {
  782. HRESULT hr = NOERROR;
  783. IPin *pReceivePin = NULL;
  784. DDSURFACEDESC ddSurfaceDesc;
  785. IEnumMediaTypes *pEnumMediaTypes = NULL;
  786. CMediaType cMediaType;
  787. AM_MEDIA_TYPE *pNewMediaType = NULL, *pEnumeratedMediaType = NULL;
  788. ULONG ulFetched = 0;
  789. DWORD dwMaxBufferCount = 0;
  790. BOOL bFoundSuitableSurface = FALSE;
  791. BITMAPINFOHEADER *pHeader = NULL;
  792. LPDDCAPS pDirectCaps = NULL;
  793. AMTRACE((TEXT("CVPMInputPin::OnSetProperties")));
  794. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  795. // this function is only called after the base class CBaseAllocator::SetProperties() has been called
  796. // with the above parameters, so we don't have to do any parameter validation
  797. ASSERT(IsConnected());
  798. pReceivePin = CurrentPeer();
  799. ASSERT(pReceivePin);
  800. // we only care about the number of buffers requested, rest everything is ignored
  801. if (pRequest->cBuffers <= 0)
  802. {
  803. hr = E_FAIL;
  804. goto CleanUp;
  805. }
  806. CleanUp:
  807. return hr;
  808. }
  809. HRESULT CVPMInputPin::BreakConnect(void)
  810. {
  811. HRESULT hr = NOERROR;
  812. AMTRACE((TEXT("CVPMInputPin::BreakConnect")));
  813. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  814. {
  815. // tell the videoport object
  816. ASSERT(m_pIVPObject);
  817. hr = m_pIVPObject->BreakConnect();
  818. if (FAILED(hr))
  819. {
  820. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->BreakConnect failed, hr = 0x%x"), hr));
  821. }
  822. }
  823. {
  824. // back buffers are not addref'd so just set them to NULL
  825. m_dwBackBufferCount = 0;
  826. m_dwDirectDrawSurfaceWidth = 0;
  827. }
  828. // initialize the behaviour to telling the proxy to allocate buffers
  829. SetStreamingInKernelMode(FALSE);
  830. m_bUsingOurAllocator = FALSE;
  831. m_bCanOverAllocateBuffers = TRUE;
  832. if (m_hMemoryDC)
  833. {
  834. EXECUTE_ASSERT(DeleteDC(m_hMemoryDC));
  835. m_hMemoryDC = NULL;
  836. }
  837. // call the base class
  838. hr = CBaseInputPin::BreakConnect();
  839. if (FAILED(hr))
  840. {
  841. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::BreakConnect failed, hr = 0x%x"), hr));
  842. }
  843. // tell the owning filter
  844. hr = m_pVPMFilter.BreakConnect(m_dwPinId);
  845. if (FAILED(hr))
  846. {
  847. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.BreakConnect failed, hr = 0x%x"), hr));
  848. }
  849. m_bConnected = FALSE;
  850. //CleanUp:
  851. return hr;
  852. }
  853. STDMETHODIMP CVPMInputPin::GetState(DWORD dwMSecs,FILTER_STATE *pState)
  854. {
  855. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  856. // if not connected or VideoPort Connection or IOverlay connection, then let the base class handle it
  857. // otherwise (overlay, offcreen, gdi, motion-comp) let the sync object handle it
  858. return E_NOTIMPL;
  859. }
  860. HRESULT CVPMInputPin::CompleteStateChange(FILTER_STATE OldState)
  861. {
  862. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  863. return S_OK;
  864. }
  865. // transition from stop to pause state
  866. HRESULT CVPMInputPin::Active(void)
  867. {
  868. HRESULT hr = NOERROR;
  869. AMTRACE((TEXT("CVPMInputPin::Active")));
  870. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  871. m_hEndOfStream = NULL;
  872. {
  873. // tell the videoport object
  874. hr = m_pIVPObject->Active();
  875. if (FAILED(hr))
  876. {
  877. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->Active failed, hr = 0x%x"), hr));
  878. goto CleanUp;
  879. }
  880. }
  881. // call the base class
  882. hr = CBaseInputPin::Active();
  883. // if it is a VP connection, this error is ok
  884. if (hr == VFW_E_NO_ALLOCATOR)
  885. {
  886. hr = NOERROR;
  887. }
  888. if (FAILED(hr))
  889. {
  890. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::Active failed, hr = 0x%x"), hr));
  891. goto CleanUp;
  892. }
  893. CleanUp:
  894. return hr;
  895. }
  896. // transition from pause to stop state
  897. HRESULT CVPMInputPin::Inactive(void)
  898. {
  899. HRESULT hr = NOERROR;
  900. AMTRACE((TEXT("CVPMInputPin::Inactive")));
  901. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  902. {
  903. // tell the videoport object
  904. hr = m_pIVPObject->Inactive();
  905. if (FAILED(hr))
  906. {
  907. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->Inactive failed, hr = 0x%x"), hr));
  908. goto CleanUp;
  909. }
  910. // make sure that if there is a run time error, stop succeeds
  911. if (m_bRuntimeNegotiationFailed && hr == VFW_E_NOT_CONNECTED)
  912. {
  913. hr = NOERROR;
  914. }
  915. }
  916. // call the base class
  917. hr = CBaseInputPin::Inactive();
  918. // if it is a VP connection, this error is ok
  919. if ( hr == VFW_E_NO_ALLOCATOR)
  920. {
  921. hr = NOERROR;
  922. }
  923. if (FAILED(hr))
  924. {
  925. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::Inactive failed, hr = 0x%x"), hr));
  926. goto CleanUp;
  927. }
  928. CleanUp:
  929. return hr;
  930. }
  931. // transition from pause to run state
  932. HRESULT CVPMInputPin::Run(REFERENCE_TIME tStart)
  933. {
  934. HRESULT hr = NOERROR;
  935. AMTRACE((TEXT("CVPMInputPin::Run")));
  936. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  937. m_bDontFlip = FALSE ; // need to reset it to do the right things in this session
  938. {
  939. // tell the videoport object
  940. hr = m_pIVPObject->Run(tStart);
  941. if (FAILED(hr))
  942. {
  943. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->Run() failed, hr = 0x%x"), hr));
  944. goto CleanUp;
  945. }
  946. }
  947. // call the base class
  948. hr = CBaseInputPin::Run(tStart);
  949. if (FAILED(hr))
  950. {
  951. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::Run failed, hr = 0x%x"), hr));
  952. goto CleanUp;
  953. }
  954. // TBD: figure out ... stream time
  955. m_rtNextSample = 0;
  956. m_rtLastRun = tStart;
  957. // just start the src video running, we'll have an output image when we get a sample
  958. hr = InitVideo();
  959. CleanUp:
  960. m_trLastFrame = -1;
  961. return hr;
  962. }
  963. // transition from run to pause state
  964. HRESULT CVPMInputPin::RunToPause(void)
  965. {
  966. HRESULT hr = NOERROR;
  967. AMTRACE((TEXT("CVPMInputPin::RunToPause")));
  968. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  969. // only if a vp pin
  970. if( m_pIVPObject ) {
  971. // tell the videoport object
  972. hr = m_pIVPObject->RunToPause();
  973. if (FAILED(hr))
  974. {
  975. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->RunToPause() failed, hr = 0x%x"), hr));
  976. goto CleanUp;
  977. }
  978. }
  979. CleanUp:
  980. return hr;
  981. }
  982. // signals start of flushing on the input pin
  983. HRESULT CVPMInputPin::BeginFlush(void)
  984. {
  985. HRESULT hr = NOERROR;
  986. AMTRACE((TEXT("CVPMInputPin::BeginFlush")));
  987. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  988. m_hEndOfStream = 0;
  989. if (m_bFlushing)
  990. {
  991. return E_FAIL;
  992. }
  993. // if the conection is VideoPort or IOverlay, we do not care about flushing
  994. // call the base class
  995. hr = CBaseInputPin::BeginFlush();
  996. if (FAILED(hr))
  997. {
  998. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::BeginFlush() failed, hr = 0x%x"), hr));
  999. goto CleanUp;
  1000. }
  1001. CleanUp:
  1002. return hr;
  1003. }
  1004. // signals end of flushing on the input pin
  1005. HRESULT CVPMInputPin::EndFlush(void)
  1006. {
  1007. HRESULT hr = NOERROR;
  1008. AMTRACE((TEXT("CVPMInputPin::EndFlush")));
  1009. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1010. if (!m_bFlushing)
  1011. {
  1012. return E_FAIL;
  1013. }
  1014. // if the conection is VideoPort or IOverlay, we do not care about flushing
  1015. // call the base class
  1016. hr = CBaseInputPin::EndFlush();
  1017. if (FAILED(hr))
  1018. {
  1019. DbgLog((LOG_ERROR, 1, TEXT("CBaseInputPin::EndFlush() failed, hr = 0x%x"), hr));
  1020. goto CleanUp;
  1021. }
  1022. CleanUp:
  1023. return hr;
  1024. }
  1025. // Send a quality message if required - this is the hack version
  1026. // that just passes the lateness
  1027. void CVPMInputPin::DoQualityMessage()
  1028. {
  1029. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1030. if (m_pVPMFilter.m_State == State_Running &&
  1031. SampleProps()->dwSampleFlags & AM_SAMPLE_TIMEVALID)
  1032. {
  1033. CRefTime CurTime;
  1034. if (S_OK == m_pVPMFilter.StreamTime(CurTime))
  1035. {
  1036. const REFERENCE_TIME tStart = SampleProps()->tStart;
  1037. Quality msg;
  1038. msg.Proportion = 1000;
  1039. msg.Type = CurTime > tStart ? Flood : Famine;
  1040. msg.Late = CurTime - tStart;
  1041. msg.TimeStamp = tStart;
  1042. PassNotify(msg);
  1043. m_trLastFrame = CurTime;
  1044. }
  1045. }
  1046. }
  1047. // called when the upstream pin delivers us a sample
  1048. HRESULT CVPMInputPin::Receive(IMediaSample *pMediaSample)
  1049. {
  1050. HRESULT hr = NOERROR;
  1051. BOOL bNeedToFlipOddEven = FALSE;
  1052. BOOL bDisplayingFields = FALSE;
  1053. DWORD dwTypeSpecificFlags = 0;
  1054. LPDIRECTDRAWSURFACE7 pPrimarySurface = NULL;
  1055. AMTRACE((TEXT("CVPMInputPin::Receive")));
  1056. // a videoport connection does not receive samples so bail out
  1057. {
  1058. hr = VFW_E_NOT_SAMPLE_CONNECTION;
  1059. goto CleanUp;
  1060. }
  1061. CleanUp:
  1062. return hr;
  1063. }
  1064. HRESULT CVPMInputPin::OnReceiveFirstSample(IMediaSample *pMediaSample)
  1065. {
  1066. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1067. ASSERT( !"OnReceiveFirstSample" );
  1068. return NOERROR;
  1069. }
  1070. HRESULT CVPMInputPin::InitVideo()
  1071. {
  1072. HRESULT hr = m_pIVPObject->StartVideo( &m_WinInfo );
  1073. if (FAILED(hr))
  1074. {
  1075. DbgLog((LOG_ERROR, 1, TEXT("m_pIVPObject->StartVideo failed, hr = 0x%x"), hr));
  1076. }
  1077. return hr;
  1078. }
  1079. // this function just tells whether each sample consists of one or two fields
  1080. static HRESULT SetTypeSpecificFlags(IMediaSample *pSample, DWORD dwTypeSpecificFlags )
  1081. {
  1082. IMediaSample2 *pSample2 = NULL;
  1083. /* Check for IMediaSample2 */
  1084. HRESULT hr = pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2);
  1085. if (SUCCEEDED(hr)) {
  1086. AM_SAMPLE2_PROPERTIES SampleProps;
  1087. hr = pSample2->GetProperties(sizeof(SampleProps), (PBYTE)&SampleProps);
  1088. if( SUCCEEDED( hr )) {
  1089. SampleProps.dwTypeSpecificFlags = dwTypeSpecificFlags;
  1090. hr = pSample2->SetProperties(sizeof(SampleProps), (PBYTE)&SampleProps);
  1091. }
  1092. pSample2->Release();
  1093. }
  1094. return hr;
  1095. }
  1096. static REFERENCE_TIME ScaleMicroToRefTime( DWORD dwMicroseconds )
  1097. {
  1098. // Reference time is in 100 ns = 0.1us, so multiply by 10
  1099. ASSERT( 10*1000000 == UNITS );
  1100. switch( dwMicroseconds ) {
  1101. case 16667:
  1102. case 16666: // 60hz
  1103. return 166667;
  1104. case 16683: // 59.94hz
  1105. return 166834;
  1106. case 20000: // 50hz PAL
  1107. return REFERENCE_TIME(dwMicroseconds)*10;
  1108. default:
  1109. ASSERT( !"Missing ref scale" );
  1110. return REFERENCE_TIME(dwMicroseconds)*10;
  1111. }
  1112. }
  1113. HRESULT CVPMInputPin::DoRenderSample(IMediaSample* pSample, LPDIRECTDRAWSURFACE7 pDDDestSurface, const DDVIDEOPORTNOTIFY& notify,
  1114. const VPInfo& vpInfo )
  1115. {
  1116. if( !pDDDestSurface ) {
  1117. return E_INVALIDARG;
  1118. }
  1119. AMTRACE((TEXT("CVPMInputPin::DoRenderSample")));
  1120. CAutoLock cLock(&m_pVPMFilter.GetReceiveLock());
  1121. HRESULT hr = S_OK;
  1122. if( SUCCEEDED( hr )) {
  1123. hr = m_pIVPObject->CallUpdateSurface( notify.dwSurfaceIndex, pDDDestSurface );
  1124. if( SUCCEEDED( hr )) {
  1125. REFERENCE_TIME rtStart = m_rtNextSample; // for debugging, assume continuous
  1126. hr = m_pVPMFilter.GetRefClockTime( &rtStart );
  1127. ASSERT( SUCCEEDED( hr ));
  1128. // make time relative to last run time, i.e. timestamps after run begin at 0
  1129. rtStart -= m_rtLastRun;
  1130. // get the actual time
  1131. REFERENCE_TIME rtInterval = ScaleMicroToRefTime( vpInfo.vpDataInfo.dwMicrosecondsPerField );
  1132. // now set the field info
  1133. DWORD dwTypeFlags=0;
  1134. #ifdef DEBUG
  1135. static bool checked=false;
  1136. #endif
  1137. switch( vpInfo.mode ) {
  1138. case AMVP_MODE_BOBNONINTERLEAVED:
  1139. switch( notify.lField ) {
  1140. case 0:
  1141. dwTypeFlags = AM_VIDEO_FLAG_FIELD1;
  1142. break;
  1143. case 1:
  1144. dwTypeFlags = AM_VIDEO_FLAG_FIELD2;
  1145. break;
  1146. case -1:
  1147. #ifdef DEBUG
  1148. if( !checked ) {
  1149. ASSERT( !"Video driver doesn't known field for sample, VPM assuming Field1" );
  1150. checked=true;
  1151. }
  1152. #endif
  1153. dwTypeFlags = AM_VIDEO_FLAG_FIELD1;
  1154. break;
  1155. default:
  1156. #ifdef DEBUG
  1157. if( !checked ) {
  1158. ASSERT( !"Bogus field value returned by video driver for sample, assuming Field1" );
  1159. checked=true;
  1160. }
  1161. #endif
  1162. dwTypeFlags = AM_VIDEO_FLAG_FIELD1;
  1163. break;
  1164. }
  1165. break;
  1166. case AMVP_MODE_BOBINTERLEAVED:
  1167. if( !vpInfo.vpDataInfo.bFieldPolarityInverted ) { // Device inverts the polarity by default
  1168. dwTypeFlags = AM_VIDEO_FLAG_FIELD1FIRST;
  1169. }
  1170. rtInterval *= 2; // 2 fields
  1171. break;
  1172. case AMVP_MODE_WEAVE:
  1173. dwTypeFlags = AM_VIDEO_FLAG_WEAVE;
  1174. rtInterval *= 2; // 2 fields
  1175. break;
  1176. case AMVP_MODE_SKIPEVEN:
  1177. dwTypeFlags = AM_VIDEO_FLAG_FIELD1;
  1178. break;
  1179. case AMVP_MODE_SKIPODD:
  1180. dwTypeFlags = AM_VIDEO_FLAG_FIELD2;
  1181. break;
  1182. default:
  1183. break;
  1184. }
  1185. REFERENCE_TIME rtStop = rtStart+rtInterval;
  1186. // set flags & timestamps
  1187. hr = SetTypeSpecificFlags( pSample, dwTypeFlags);
  1188. hr = pSample->SetTime(&rtStart, &rtStop);
  1189. // assume next sample comes immediately afterwards
  1190. m_rtNextSample += rtInterval;
  1191. }
  1192. }
  1193. return hr;
  1194. }
  1195. HRESULT CVPMInputPin::StartVideo()
  1196. {
  1197. HRESULT hr = m_pIVPObject->StartVideo( &m_WinInfo );
  1198. ASSERT( SUCCEEDED( hr ));
  1199. if (FAILED(hr))
  1200. {
  1201. DbgLog((LOG_ERROR, 0, TEXT("InPin::StartVideo() failed, hr = %d"), hr & 0xffff));
  1202. } else {
  1203. // hack for now, force a new dest recalc
  1204. SetRect( &m_WinInfo.DestRect, 0,0,0,0);
  1205. }
  1206. return hr;
  1207. }
  1208. // signals end of data stream on the input pin
  1209. STDMETHODIMP CVPMInputPin::EndOfStream(void)
  1210. {
  1211. HRESULT hr = NOERROR;
  1212. AMTRACE((TEXT("CVPMInputPin::EndOfStream")));
  1213. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1214. if (m_hEndOfStream) {
  1215. EXECUTE_ASSERT(SetEvent(m_hEndOfStream));
  1216. return S_OK;
  1217. }
  1218. // Make sure we're streaming ok
  1219. hr = CheckStreaming();
  1220. if (FAILED(hr))
  1221. {
  1222. DbgLog((LOG_ERROR, 1, TEXT("CheckStreaming() failed, hr = 0x%x"), hr));
  1223. goto CleanUp;
  1224. }
  1225. {
  1226. // Pass EOS to the filter graph
  1227. hr = m_pVPMFilter.EventNotify(m_dwPinId, EC_COMPLETE, S_OK, 0);
  1228. if (FAILED(hr))
  1229. {
  1230. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.EventNotify failed, hr = 0x%x"), hr));
  1231. }
  1232. }
  1233. CleanUp:
  1234. return hr;
  1235. }
  1236. // signals end of data stream on the input pin
  1237. HRESULT CVPMInputPin::EventNotify(long lEventCode, DWORD_PTR lEventParam1, DWORD_PTR lEventParam2)
  1238. {
  1239. HRESULT hr = NOERROR;
  1240. AMTRACE((TEXT("CVPMInputPin::EventNotify")));
  1241. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1242. // if (lEventCode == EC_OVMIXER_REDRAW_ALL || lEventCode == EC_REPAINT)
  1243. // {
  1244. // m_pVPMFilter.EventNotify(m_dwPinId, lEventCode, lEventParam1, lEventParam2);
  1245. // goto CleanUp;
  1246. // }
  1247. // WARNING : we are assuming here that the input pin will be the first pin to be created
  1248. if (lEventCode == EC_COMPLETE && m_dwPinId == 0)
  1249. {
  1250. m_pVPMFilter.EventNotify(m_dwPinId, lEventCode, lEventParam1, lEventParam2);
  1251. goto CleanUp;
  1252. }
  1253. if (lEventCode == EC_ERRORABORT)
  1254. {
  1255. m_pVPMFilter.EventNotify(m_dwPinId, lEventCode, lEventParam1, lEventParam2);
  1256. m_bRuntimeNegotiationFailed = TRUE;
  1257. goto CleanUp;
  1258. }
  1259. if (lEventCode == EC_STEP_COMPLETE) {
  1260. m_pVPMFilter.EventNotify(m_dwPinId, lEventCode, lEventParam1, lEventParam2);
  1261. goto CleanUp;
  1262. }
  1263. CleanUp:
  1264. return hr;
  1265. }
  1266. /******************************Public*Routine******************************\
  1267. * GetCaptureInfo
  1268. *
  1269. *
  1270. *
  1271. * History:
  1272. * 3/12/1999 - StEstrop - Created
  1273. *
  1274. \**************************************************************************/
  1275. HRESULT
  1276. CVPMInputPin::GetCaptureInfo(
  1277. BOOL *lpCapturing,
  1278. DWORD *lpdwWidth,
  1279. DWORD *lpdwHeight,
  1280. BOOL *lpInterleave
  1281. )
  1282. {
  1283. AMTRACE((TEXT("CVPMInputPin::GetCaptureInfo")));
  1284. HRESULT hr = NOERROR;
  1285. IKsPropertySet *pIKsPropertySet = NULL;
  1286. DWORD dwVal[2], dwBytesReturned = 0;
  1287. *lpCapturing = FALSE;
  1288. if (!m_Connected) {
  1289. DbgLog((LOG_TRACE, 1, TEXT("Input pin not connected!!")));
  1290. hr = E_FAIL;
  1291. goto CleanUp;
  1292. }
  1293. #if defined(DEBUG)
  1294. else {
  1295. PIN_INFO PinInfo;
  1296. hr = m_Connected->QueryPinInfo(&PinInfo);
  1297. if (SUCCEEDED(hr)) {
  1298. DbgLog((LOG_TRACE, 1, TEXT("Up stream pin name %ls"), PinInfo.achName));
  1299. PinInfo.pFilter->Release();
  1300. }
  1301. }
  1302. #endif
  1303. hr = m_Connected->QueryInterface(IID_IKsPropertySet,
  1304. (void**)&pIKsPropertySet);
  1305. if (SUCCEEDED(hr))
  1306. {
  1307. ASSERT(pIKsPropertySet);
  1308. hr = pIKsPropertySet->Set(
  1309. PROPSETID_ALLOCATOR_CONTROL,
  1310. AM_KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_CAPS,
  1311. NULL, 0,
  1312. lpInterleave, sizeof(*lpInterleave));
  1313. if (SUCCEEDED(hr)) {
  1314. hr = pIKsPropertySet->Get(
  1315. PROPSETID_ALLOCATOR_CONTROL,
  1316. AM_KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_INTERLEAVE,
  1317. NULL, 0,
  1318. lpInterleave, sizeof(*lpInterleave), &dwBytesReturned);
  1319. if (FAILED(hr) || dwBytesReturned != sizeof(*lpInterleave)) {
  1320. *lpInterleave = FALSE;
  1321. }
  1322. }
  1323. else {
  1324. *lpInterleave = FALSE;
  1325. }
  1326. hr = pIKsPropertySet->Get(
  1327. PROPSETID_ALLOCATOR_CONTROL,
  1328. KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE,
  1329. NULL, 0, dwVal, sizeof(dwVal), &dwBytesReturned);
  1330. DbgLog((LOG_TRACE, 2,
  1331. TEXT("pIKsPropertySet->Get(")
  1332. TEXT("PROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE),\n")
  1333. TEXT("\thr = 0x%x, dwVal[0] == %d, dwVal[1] == %d, ")
  1334. TEXT("dwBytesReturned == %d"),
  1335. hr, dwVal[0], dwVal[1], dwBytesReturned));
  1336. // if the decoder supports this property then we are capturing
  1337. // and the intended capturing is size is given by
  1338. // dwVal[0] and dwVal[1]
  1339. //
  1340. if (SUCCEEDED(hr) && dwBytesReturned == sizeof(dwVal))
  1341. {
  1342. *lpCapturing = TRUE;
  1343. *lpdwWidth = dwVal[0];
  1344. *lpdwHeight = dwVal[1];
  1345. DbgLog((LOG_TRACE, 1,
  1346. TEXT("We are CAPTURING, intended size (%d, %d) interleave = %d"),
  1347. dwVal[0], dwVal[1], *lpInterleave));
  1348. }
  1349. pIKsPropertySet->Release();
  1350. }
  1351. CleanUp:
  1352. return hr;
  1353. }
  1354. /******************************Public*Routine******************************\
  1355. * GetDecimationUsage
  1356. *
  1357. *
  1358. *
  1359. * History:
  1360. * Thu 07/15/1999 - StEstrop - Created
  1361. *
  1362. \**************************************************************************/
  1363. HRESULT
  1364. CVPMInputPin::GetDecimationUsage(
  1365. DECIMATION_USAGE *lpdwUsage
  1366. )
  1367. {
  1368. return m_pVPMFilter.QueryDecimationUsage(lpdwUsage);
  1369. }
  1370. // This overrides the CBaseInputPin virtual method to return our allocator
  1371. HRESULT CVPMInputPin::GetAllocator(IMemAllocator **ppAllocator)
  1372. {
  1373. HRESULT hr = NOERROR;
  1374. AMTRACE((TEXT("CVPMInputPin::GetAllocator")));
  1375. if (!ppAllocator)
  1376. {
  1377. DbgLog((LOG_ERROR, 1, TEXT("ppAllocator is NULL")));
  1378. hr = E_POINTER;
  1379. goto CleanUp;
  1380. }
  1381. {
  1382. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1383. // if vp connection, don't return any allocator
  1384. {
  1385. *ppAllocator = NULL;
  1386. hr = VFW_E_NO_ALLOCATOR;
  1387. goto CleanUp;
  1388. }
  1389. }
  1390. CleanUp:
  1391. return hr;
  1392. } // GetAllocator
  1393. // This overrides the CBaseInputPin virtual method to return our allocator
  1394. HRESULT CVPMInputPin::NotifyAllocator(IMemAllocator *pAllocator,BOOL bReadOnly)
  1395. {
  1396. HRESULT hr = NOERROR;
  1397. AMTRACE((TEXT("CVPMInputPin::NotifyAllocator")));
  1398. if (!pAllocator)
  1399. {
  1400. DbgLog((LOG_ERROR, 1, TEXT("ppAllocator is NULL")));
  1401. hr = E_INVALIDARG;
  1402. goto CleanUp;
  1403. }
  1404. {
  1405. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1406. // if vp connection, don't care
  1407. {
  1408. goto CleanUp;
  1409. }
  1410. }
  1411. CleanUp:
  1412. return hr;
  1413. } // NotifyAllocator
  1414. HRESULT CVPMInputPin::OnAlloc(CDDrawMediaSample **ppSampleList, DWORD dwSampleCount)
  1415. {
  1416. HRESULT hr = NOERROR;
  1417. DWORD i;
  1418. LPDIRECTDRAWSURFACE7 pDDrawSurface = NULL, pBackBuffer = NULL;
  1419. DDSCAPS ddSurfaceCaps;
  1420. DWORD dwDDrawSampleSize = 0;
  1421. BITMAPINFOHEADER *pHeader = NULL;
  1422. DIBDATA DibData;
  1423. AMTRACE((TEXT("CVPMInputPin::OnAlloc")));
  1424. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1425. ASSERT(IsConnected());
  1426. // get the image size
  1427. {
  1428. CMediaType mtNew;
  1429. hr = m_pIVPObject->CurrentMediaType( &mtNew );
  1430. if( FAILED( hr )) {
  1431. goto CleanUp;
  1432. }
  1433. pHeader = VPMUtil::GetbmiHeader(&mtNew);
  1434. if ( ! pHeader )
  1435. {
  1436. hr = E_FAIL;
  1437. goto CleanUp;
  1438. }
  1439. dwDDrawSampleSize = pHeader->biSizeImage;
  1440. }
  1441. ASSERT(dwDDrawSampleSize > 0);
  1442. if (!ppSampleList)
  1443. {
  1444. DbgLog((LOG_ERROR, 1, TEXT("ppSampleList is NULL")));
  1445. hr = E_INVALIDARG;
  1446. goto CleanUp;
  1447. }
  1448. for (i = 0; i < dwSampleCount; i++)
  1449. {
  1450. if (!ppSampleList[i])
  1451. {
  1452. DbgLog((LOG_ERROR, 1, TEXT("ppSampleList[%d] is NULL"), i));
  1453. hr = E_INVALIDARG;
  1454. goto CleanUp;
  1455. }
  1456. hr = ppSampleList[i]->SetDDrawSampleSize(dwDDrawSampleSize);
  1457. if (FAILED(hr))
  1458. {
  1459. DbgLog((LOG_ERROR, 0, TEXT("ppSampleList[%d]->SetSampleSize failed, hr = 0x%x"), i, hr));
  1460. goto CleanUp;
  1461. }
  1462. } // end of for (i < dwSampleCount) loop
  1463. CleanUp:
  1464. return hr;
  1465. }
  1466. // sets the pointer to directdraw
  1467. HRESULT CVPMInputPin::OnGetBuffer(IMediaSample **ppSample, REFERENCE_TIME *pStartTime,
  1468. REFERENCE_TIME *pEndTime, DWORD dwFlags)
  1469. {
  1470. HRESULT hr = NOERROR;
  1471. CDDrawMediaSample *pCDDrawMediaSample = NULL;
  1472. LPDIRECTDRAWSURFACE7 pBackBuffer = NULL;
  1473. DDSURFACEDESC ddSurfaceDesc;
  1474. BOOL bWaitForDraw = FALSE;
  1475. BOOL bPalettised = FALSE;
  1476. AMTRACE((TEXT("CVPMInputPin::OnGetBuffer")));
  1477. // not valid for videoport
  1478. ASSERT( FALSE ) ;
  1479. return hr;
  1480. }
  1481. // In case of flipping surfaces, gets the back buffer
  1482. HRESULT CVPMInputPin::OnReleaseBuffer(IMediaSample *pMediaSample)
  1483. {
  1484. HRESULT hr = NOERROR;
  1485. AMTRACE((TEXT("CVPMInputPin::OnReleaseBuffer")));
  1486. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1487. return hr;
  1488. }
  1489. #if 0
  1490. /*****************************Private*Routine******************************\
  1491. * GetUpstreamFilterName
  1492. *
  1493. *
  1494. *
  1495. * History:
  1496. * Tue 11/30/1999 - StEstrop - Created
  1497. *
  1498. \**************************************************************************/
  1499. HRESULT
  1500. CVPMInputPin::GetUpstreamFilterName(
  1501. TCHAR* FilterName
  1502. )
  1503. {
  1504. PIN_INFO PinInfo;
  1505. if (!m_Connected)
  1506. {
  1507. return VFW_E_NOT_CONNECTED;
  1508. }
  1509. HRESULT hr = m_Connected->QueryPinInfo(&PinInfo);
  1510. if (SUCCEEDED(hr))
  1511. {
  1512. FILTER_INFO FilterInfo;
  1513. hr = PinInfo.pFilter->QueryFilterInfo(&FilterInfo);
  1514. if (SUCCEEDED(hr))
  1515. {
  1516. #ifdef UNICODE
  1517. wcscpy( FilterName, FilterInfo.achName );
  1518. #else
  1519. wsprintf(FilterName, TEXT("%ls"), FilterInfo.achName);
  1520. #endif
  1521. if (FilterInfo.pGraph)
  1522. {
  1523. FilterInfo.pGraph->Release();
  1524. }
  1525. }
  1526. PinInfo.pFilter->Release();
  1527. }
  1528. return hr;
  1529. }
  1530. #endif
  1531. HRESULT CVPMInputPin::CreateDDrawSurface(CMediaType *pMediaType, DWORD *pdwMaxBufferCount, LPDIRECTDRAWSURFACE7 *ppDDrawSurface)
  1532. {
  1533. HRESULT hr = NOERROR;
  1534. DDSURFACEDESC2 SurfaceDesc;
  1535. DWORD dwInterlaceFlags = 0, dwTotalBufferCount = 0, dwMinBufferCount = 0;
  1536. DDSCAPS ddSurfaceCaps;
  1537. BITMAPINFOHEADER *pHeader;
  1538. FOURCCMap amFourCCMap(pMediaType->Subtype());
  1539. AMTRACE((TEXT("CVPMInputPin::CreateDDrawSurface")));
  1540. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1541. LPDIRECTDRAW7 pDirectDraw = m_pVPMFilter.GetDirectDraw();
  1542. ASSERT(pDirectDraw);
  1543. if (!pMediaType)
  1544. {
  1545. DbgLog((LOG_ERROR, 1, TEXT("pMediaType is NULL")));
  1546. hr = E_INVALIDARG;
  1547. goto CleanUp;
  1548. }
  1549. if (!ppDDrawSurface)
  1550. {
  1551. DbgLog((LOG_ERROR, 1, TEXT("ppDDrawSurface is NULL")));
  1552. hr = E_INVALIDARG;
  1553. goto CleanUp;
  1554. }
  1555. {
  1556. hr = E_INVALIDARG;
  1557. goto CleanUp;
  1558. }
  1559. CleanUp:
  1560. return hr;
  1561. }
  1562. // this function is used to restore the ddraw surface. In the videoport case, we just recreate
  1563. // the whole thing from scratch.
  1564. HRESULT CVPMInputPin::RestoreDDrawSurface()
  1565. {
  1566. HRESULT hr = NOERROR;
  1567. {
  1568. // stop the video
  1569. m_pIVPObject->Inactive();
  1570. // don't have to give up the IVPConfig interface here
  1571. m_pIVPObject->BreakConnect(TRUE);
  1572. // redo the connection process
  1573. hr = m_pIVPObject->CompleteConnect(NULL, TRUE);
  1574. }
  1575. return hr;
  1576. }
  1577. HRESULT CVPMInputPin::GetSourceAndDest(RECT *prcSource, RECT *prcDest, DWORD *dwWidth, DWORD *dwHeight)
  1578. {
  1579. {
  1580. m_pIVPObject->GetRectangles(prcSource, prcDest);
  1581. }
  1582. CMediaType mt;
  1583. HRESULT hr = CurrentMediaType(&mt);
  1584. if (SUCCEEDED(hr))
  1585. {
  1586. BITMAPINFOHEADER *pHeader = VPMUtil::GetbmiHeader(&mt);
  1587. if ( ! pHeader )
  1588. {
  1589. hr = E_FAIL;
  1590. }
  1591. else
  1592. {
  1593. *dwWidth = abs(pHeader->biWidth);
  1594. *dwHeight = abs(pHeader->biHeight);
  1595. }
  1596. }
  1597. return hr;
  1598. }
  1599. STDMETHODIMP CVPMInputPin::Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData,
  1600. LPVOID pPropData, DWORD cbPropData)
  1601. {
  1602. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1603. return E_PROP_SET_UNSUPPORTED ;
  1604. }
  1605. STDMETHODIMP CVPMInputPin::Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData,
  1606. LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned)
  1607. {
  1608. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1609. return E_PROP_SET_UNSUPPORTED;
  1610. }
  1611. STDMETHODIMP CVPMInputPin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
  1612. {
  1613. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1614. if (AMPROPSETID_Pin == guidPropSet)
  1615. {
  1616. if (AMPROPERTY_PIN_CATEGORY != dwPropID && AMPROPERTY_PIN_MEDIUM != dwPropID )
  1617. return E_PROP_ID_UNSUPPORTED ;
  1618. if (pTypeSupport)
  1619. *pTypeSupport = KSPROPERTY_SUPPORT_GET ;
  1620. return S_OK;
  1621. }
  1622. return E_PROP_SET_UNSUPPORTED ;
  1623. }
  1624. STDMETHODIMP CVPMInputPin::KsQueryMediums(PKSMULTIPLE_ITEM* pMediumList)
  1625. {
  1626. PKSPIN_MEDIUM pMedium;
  1627. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1628. *pMediumList = reinterpret_cast<PKSMULTIPLE_ITEM>(CoTaskMemAlloc(sizeof(**pMediumList) + sizeof(*pMedium)));
  1629. if (!*pMediumList)
  1630. {
  1631. return E_OUTOFMEMORY;
  1632. }
  1633. (*pMediumList)->Count = 1;
  1634. (*pMediumList)->Size = sizeof(**pMediumList) + sizeof(*pMedium);
  1635. pMedium = reinterpret_cast<PKSPIN_MEDIUM>(*pMediumList + 1);
  1636. pMedium->Set = m_Medium.Set;
  1637. pMedium->Id = m_Medium.Id;
  1638. pMedium->Flags = m_Medium.Flags;
  1639. // The following special return code notifies the proxy that this pin is
  1640. // not available as a kernel mode connection
  1641. return S_FALSE;
  1642. }
  1643. STDMETHODIMP CVPMInputPin::KsQueryInterfaces(PKSMULTIPLE_ITEM* pInterfaceList)
  1644. {
  1645. PKSPIN_INTERFACE pInterface;
  1646. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1647. *pInterfaceList = reinterpret_cast<PKSMULTIPLE_ITEM>(CoTaskMemAlloc(sizeof(**pInterfaceList) + sizeof(*pInterface)));
  1648. if (!*pInterfaceList)
  1649. {
  1650. return E_OUTOFMEMORY;
  1651. }
  1652. (*pInterfaceList)->Count = 1;
  1653. (*pInterfaceList)->Size = sizeof(**pInterfaceList) + sizeof(*pInterface);
  1654. pInterface = reinterpret_cast<PKSPIN_INTERFACE>(*pInterfaceList + 1);
  1655. pInterface->Set = KSINTERFACESETID_Standard;
  1656. pInterface->Id = KSINTERFACE_STANDARD_STREAMING;
  1657. pInterface->Flags = 0;
  1658. return NOERROR;
  1659. }
  1660. STDMETHODIMP CVPMInputPin::KsGetCurrentCommunication(KSPIN_COMMUNICATION* pCommunication, KSPIN_INTERFACE* pInterface, KSPIN_MEDIUM* pMedium)
  1661. {
  1662. HRESULT hr = NOERROR;
  1663. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1664. if (!m_bStreamingInKernelMode)
  1665. hr = S_FALSE;
  1666. if (pCommunication != NULL)
  1667. {
  1668. *pCommunication = m_Communication;
  1669. }
  1670. if (pInterface != NULL)
  1671. {
  1672. pInterface->Set = KSINTERFACESETID_Standard;
  1673. pInterface->Id = KSINTERFACE_STANDARD_STREAMING;
  1674. pInterface->Flags = 0;
  1675. }
  1676. if (pMedium != NULL)
  1677. {
  1678. *pMedium = m_Medium;
  1679. }
  1680. return hr;
  1681. }
  1682. /******************************Public*Routine******************************\
  1683. * DynamicQueryAccept
  1684. *
  1685. * Do you accept this type change in your current state?
  1686. *
  1687. * History:
  1688. * Wed 12/22/1999 - StEstrop - Created
  1689. *
  1690. \**************************************************************************/
  1691. STDMETHODIMP
  1692. CVPMInputPin::DynamicQueryAccept(
  1693. const AM_MEDIA_TYPE *pmt
  1694. )
  1695. {
  1696. AMTRACE((TEXT("CVPMInputPin::DynamicQueryAccept")));
  1697. CheckPointer(pmt, E_POINTER);
  1698. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1699. //
  1700. // I want CheckMedia type to behave as though we aren't connected to
  1701. // anything yet - hence the messing about with m_bConnected.
  1702. //
  1703. CMediaType cmt(*pmt);
  1704. BOOL bConnected = m_bConnected;
  1705. m_bConnected = FALSE;
  1706. HRESULT hr = CheckMediaType(&cmt);
  1707. m_bConnected = bConnected;
  1708. return hr;
  1709. }
  1710. /******************************Public*Routine******************************\
  1711. * NotifyEndOfStream
  1712. *
  1713. *
  1714. * Set event when EndOfStream receive - do NOT pass it on
  1715. * This condition is cancelled by a flush or Stop
  1716. *
  1717. * History:
  1718. * Wed 12/22/1999 - StEstrop - Created
  1719. *
  1720. \**************************************************************************/
  1721. STDMETHODIMP
  1722. CVPMInputPin::NotifyEndOfStream(
  1723. HANDLE hNotifyEvent
  1724. )
  1725. {
  1726. AMTRACE((TEXT("CVPMInputPin::NotifyEndOfStream")));
  1727. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  1728. m_hEndOfStream = hNotifyEvent;
  1729. return S_OK;
  1730. }
  1731. /******************************Public*Routine******************************\
  1732. * IsEndPin
  1733. *
  1734. * Are you an 'end pin'
  1735. *
  1736. * History:
  1737. * Wed 12/22/1999 - StEstrop - Created
  1738. *
  1739. \**************************************************************************/
  1740. STDMETHODIMP
  1741. CVPMInputPin::IsEndPin()
  1742. {
  1743. AMTRACE((TEXT("CVPMInputPin::IsEndPin")));
  1744. return S_OK;
  1745. }
  1746. /******************************Public*Routine******************************\
  1747. * DynamicDisconnect
  1748. *
  1749. * Disconnect while running
  1750. *
  1751. * History:
  1752. * Wed 2/7/1999 - SyonB - Created
  1753. *
  1754. \**************************************************************************/
  1755. STDMETHODIMP
  1756. CVPMInputPin::DynamicDisconnect()
  1757. {
  1758. AMTRACE((TEXT("CVPMInputPin::DynamicDisconnect")));
  1759. CAutoLock l(m_pLock);
  1760. return CBaseInputPin::DisconnectInternal();
  1761. }
  1762. HRESULT CVPMInputPin::GetAllOutputFormats( const PixelFormatList** ppList )
  1763. {
  1764. HRESULT hr;
  1765. CAutoLock l(m_pLock);
  1766. if (IsConnected() ) {
  1767. hr = m_pIVPObject->GetAllOutputFormats( ppList );
  1768. } else {
  1769. hr = VFW_E_NOT_CONNECTED;
  1770. }
  1771. return hr;
  1772. }
  1773. HRESULT CVPMInputPin::GetOutputFormat( DDPIXELFORMAT* pFormat )
  1774. {
  1775. HRESULT hr;
  1776. CAutoLock l(m_pLock);
  1777. if (IsConnected() ) {
  1778. hr = m_pIVPObject->GetOutputFormat( pFormat );
  1779. } else {
  1780. hr = VFW_E_NOT_CONNECTED;
  1781. }
  1782. return hr;
  1783. }
  1784. HRESULT CVPMInputPin::SetVideoPortID( DWORD dwIndex )
  1785. {
  1786. HRESULT hr = S_OK;
  1787. CAutoLock l(m_pLock);
  1788. if (m_pIVPObject ) {
  1789. hr = m_pIVPObject->SetVideoPortID( dwIndex );
  1790. }
  1791. return hr;
  1792. }
  1793. HRESULT CVPMInputPin::InPin_GetVPInfo( VPInfo* pVPInfo )
  1794. {
  1795. HRESULT hr = E_FAIL;
  1796. // Private: must hold streaming lock
  1797. CAutoLock l(&m_pVPMFilter.GetReceiveLock());
  1798. if (m_pIVPInfo ) {
  1799. hr = m_pIVPInfo->GetVPDataInfo( &pVPInfo->vpDataInfo );
  1800. if( SUCCEEDED( hr )) {
  1801. hr = m_pIVPInfo->GetVPInfo( &pVPInfo->vpInfo );
  1802. }
  1803. if( SUCCEEDED( hr )) {
  1804. hr = m_pIVPObject->GetMode( &pVPInfo->mode );
  1805. }
  1806. }
  1807. return hr;
  1808. }
  1809. LPDIRECTDRAW7 CVPMInputPin::GetDirectDraw()
  1810. {
  1811. return m_pVPMFilter.GetDirectDraw();
  1812. }
  1813. const DDCAPS* CVPMInputPin::GetHardwareCaps()
  1814. {
  1815. return m_pVPMFilter.GetHardwareCaps();
  1816. }
  1817. HRESULT CVPMInputPin::SignalNewVP( LPDIRECTDRAWVIDEOPORT pVP )
  1818. {
  1819. return m_pVPMFilter.SignalNewVP( pVP );
  1820. }
  1821. //==========================================================================
  1822. HRESULT CVPMInputPin::GetMediaType(int iPosition, CMediaType *pmt)
  1823. {
  1824. CAutoLock cLock( &m_pVPMFilter.GetFilterLock() );
  1825. AMTRACE((TEXT("Entering CVBIInputPin::GetMediaType")));
  1826. HRESULT hr = m_pIVPObject->GetMediaType(iPosition, pmt);
  1827. return hr;
  1828. }