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.

802 lines
22 KiB

  1. // !!! Paint black in window when not running, please
  2. // Copyright (c) 1994 - 1999 Microsoft Corporation. All Rights Reserved.
  3. /*
  4. Methods for CCapOverlay, CCapOverlayNotify
  5. */
  6. #include <streams.h>
  7. #include "driver.h"
  8. CCapOverlay * CreateOverlayPin(CVfwCapture * pCapture, HRESULT * phr)
  9. {
  10. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay::CreateOverlayPin(%08lX,%08lX)"),
  11. pCapture, phr));
  12. WCHAR wszPinName[16];
  13. lstrcpyW(wszPinName, L"Preview");
  14. CCapOverlay * pOverlay = new CCapOverlay(NAME("Video Overlay Stream"),
  15. pCapture, phr, wszPinName);
  16. if (!pOverlay)
  17. *phr = E_OUTOFMEMORY;
  18. // if initialization failed, delete the stream array
  19. // and return the error
  20. //
  21. if (FAILED(*phr) && pOverlay)
  22. delete pOverlay, pOverlay = NULL;
  23. return pOverlay;
  24. }
  25. //#pragma warning(disable:4355)
  26. // CCapOverlay constructor
  27. //
  28. CCapOverlay::CCapOverlay(TCHAR *pObjectName, CVfwCapture *pCapture,
  29. HRESULT * phr, LPCWSTR pName)
  30. :
  31. CBaseOutputPin(pObjectName, pCapture, &pCapture->m_lock, phr, pName),
  32. m_OverlayNotify(NAME("Overlay notification interface"), pCapture, NULL, phr),
  33. m_pCap(pCapture),
  34. m_fRunning(FALSE)
  35. #ifdef OVERLAY_SC
  36. ,m_hThread(NULL),
  37. m_tid(0),
  38. m_dwAdvise(0),
  39. m_rtStart(0),
  40. m_rtEnd(0),
  41. m_fHaveThread(FALSE)
  42. #endif
  43. {
  44. DbgLog((LOG_TRACE,1,TEXT("CCapOverlay constructor")));
  45. ASSERT(pCapture);
  46. }
  47. CCapOverlay::~CCapOverlay()
  48. {
  49. DbgLog((LOG_TRACE,1,TEXT("*Destroying the Overlay pin")));
  50. };
  51. // Say if we're prepared to connect to a given input pin from
  52. // this output pin
  53. //
  54. STDMETHODIMP CCapOverlay::Connect(IPin *pReceivePin,
  55. const AM_MEDIA_TYPE *pmt)
  56. {
  57. DbgLog((LOG_TRACE,3,TEXT("CCapOverlay::Connect")));
  58. /* Call the base class to make sure the directions match! */
  59. HRESULT hr = CBaseOutputPin::Connect(pReceivePin,pmt);
  60. if (FAILED(hr)) {
  61. return hr;
  62. }
  63. /* We're happy if we can get an IOverlay interface */
  64. hr = pReceivePin->QueryInterface(IID_IOverlay,
  65. (void **)&m_pOverlay);
  66. // we were promised this would work
  67. ASSERT(SUCCEEDED(hr));
  68. /* Because we're not going to get called again - except to
  69. propose a media type - we set up a callback here.
  70. There's only one overlay pin so we don't need any context.
  71. */
  72. hr = m_pOverlay->Advise(&m_OverlayNotify,
  73. ADVISE_CLIPPING | ADVISE_POSITION);
  74. /*
  75. We don't need to hold on to the IOverlay pointer
  76. because BreakConnect will be called before the receiving
  77. pin goes away.
  78. */
  79. if (FAILED(hr)) {
  80. // !!! Shouldn't happen, but this isn't quite right
  81. Disconnect();
  82. pReceivePin->Disconnect();
  83. return hr;
  84. } else {
  85. m_bAdvise = TRUE;
  86. }
  87. return hr;
  88. }
  89. STDMETHODIMP CCapOverlay::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
  90. {
  91. DbgLog((LOG_TRACE,99,TEXT("CCapOverlay::NonDelegatingQueryInterface")));
  92. if (ppv)
  93. *ppv = NULL;
  94. /* Do we have this interface */
  95. if (riid == IID_IKsPropertySet) {
  96. return GetInterface((LPUNKNOWN) (IKsPropertySet *) this, ppv);
  97. #ifdef OVERLAY_SC
  98. } else if (riid == IID_IAMStreamControl) {
  99. return GetInterface((LPUNKNOWN) (IAMStreamControl *) this, ppv);
  100. #endif
  101. } else {
  102. return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
  103. }
  104. }
  105. #ifdef OVERLAY_SC
  106. // overidden because we aren't an IMemInputPin... we have no delivering
  107. // to do to notice when to start and stop. We need a thread. Ick. Fun.
  108. STDMETHODIMP CCapOverlay::StopAt(const REFERENCE_TIME * ptStop, BOOL bBlockData, DWORD dwCookie)
  109. {
  110. REFERENCE_TIME rt;
  111. CAutoLock cObjectLock(m_pCap->m_pLock);
  112. // we must be connected and running
  113. if (!IsConnected() || m_pCap->m_State != State_Running)
  114. return E_UNEXPECTED;
  115. // we are stopped!
  116. if (!m_fRunning)
  117. return NOERROR;
  118. // Stop now. That's easy enough
  119. if (ptStop == NULL) {
  120. ActivePause();
  121. return CBaseStreamControl::StopAt(ptStop, bBlockData, dwCookie);
  122. }
  123. // can't do this without a clock
  124. if (m_pCap->m_pClock == NULL)
  125. return E_FAIL;
  126. // cancel the stop
  127. if (*ptStop == MAX_TIME) {
  128. if (m_rtEnd > 0) {
  129. m_rtEnd = 0;
  130. if (m_dwAdvise) {
  131. m_pCap->m_pClock->Unadvise(m_dwAdvise);
  132. m_EventAdvise.Set();
  133. }
  134. }
  135. return CBaseStreamControl::StopAt(ptStop, bBlockData, dwCookie);
  136. }
  137. m_pCap->m_pClock->GetTime(&rt);
  138. // Stop in the past. That's easy enough. Stop now.
  139. if (*ptStop <= rt) {
  140. ActivePause();
  141. return CBaseStreamControl::StopAt(ptStop, bBlockData, dwCookie);
  142. }
  143. // stop in the future. That's tricky. We need a thread to notice
  144. // "when's later, Daddy?"
  145. m_rtEnd = *ptStop; // DO THIS BEFORE m_fHaveThread test or thread
  146. // could die after we think it's staying around
  147. m_dwCookieStop = dwCookie;
  148. // we need a new thread
  149. if (m_fHaveThread == FALSE) {
  150. // we made one before that we haven't closed
  151. if (m_hThread) {
  152. WaitForSingleObject(m_hThread, INFINITE);
  153. CloseHandle(m_hThread);
  154. m_hThread = NULL;
  155. m_tid = 0;
  156. }
  157. m_EventAdvise.Reset();
  158. m_fHaveThread = TRUE;
  159. m_hThread = CreateThread(NULL, 0, CCapOverlay::ThreadProcInit, this,
  160. 0, &m_tid);
  161. if (!m_hThread) {
  162. DbgLog((LOG_ERROR,1,TEXT("Can't create Overlay thread")));
  163. return E_OUTOFMEMORY;
  164. }
  165. }
  166. return CBaseStreamControl::StopAt(ptStop, bBlockData, dwCookie);
  167. }
  168. STDMETHODIMP CCapOverlay::StartAt(const REFERENCE_TIME * ptStart, DWORD dwCookie)
  169. {
  170. REFERENCE_TIME rt;
  171. CAutoLock cObjectLock(m_pCap->m_pLock);
  172. // we must be connected and running
  173. if (!IsConnected() || m_pCap->m_State != State_Running)
  174. return E_UNEXPECTED;
  175. // we are running!
  176. if (m_fRunning)
  177. return NOERROR;
  178. // Start now. That's easy enough
  179. if (ptStart == NULL) {
  180. ActiveRun(0);
  181. return CBaseStreamControl::StartAt(ptStart, dwCookie);
  182. }
  183. // can't do this without a clock
  184. if (m_pCap->m_pClock == NULL)
  185. return E_FAIL;
  186. // cancel the start
  187. if (*ptStart == MAX_TIME) {
  188. if (m_rtStart > 0) {
  189. m_rtStart = 0;
  190. if (m_dwAdvise) {
  191. m_pCap->m_pClock->Unadvise(m_dwAdvise);
  192. m_EventAdvise.Set();
  193. }
  194. }
  195. return CBaseStreamControl::StartAt(ptStart, dwCookie);
  196. }
  197. m_pCap->m_pClock->GetTime(&rt);
  198. // Start in the past. That's easy enough. Start now.
  199. if (*ptStart <= rt) {
  200. ActiveRun(0);
  201. return CBaseStreamControl::StartAt(ptStart, dwCookie);
  202. }
  203. // start in the future. That's tricky. We need a thread to notice
  204. // "when's later, Daddy?"
  205. m_rtStart = *ptStart;// DO THIS BEFORE m_fHaveThread test or thread
  206. // could die after we think it's staying around
  207. m_dwCookieStart = dwCookie;
  208. // we need a new thread
  209. if (m_fHaveThread == FALSE) {
  210. // we made one before that we haven't closed
  211. if (m_hThread) {
  212. WaitForSingleObject(m_hThread, INFINITE);
  213. CloseHandle(m_hThread);
  214. m_hThread = NULL;
  215. m_tid = 0;
  216. }
  217. m_EventAdvise.Reset();
  218. m_fHaveThread = TRUE;
  219. m_hThread = CreateThread(NULL, 0, CCapOverlay::ThreadProcInit, this,
  220. 0, &m_tid);
  221. if (!m_hThread) {
  222. DbgLog((LOG_ERROR,1,TEXT("Can't create Overlay thread")));
  223. return E_OUTOFMEMORY;
  224. }
  225. }
  226. return CBaseStreamControl::StartAt(ptStart, dwCookie);
  227. }
  228. #endif // OVERLAY_SC
  229. // !!! The base classes change all the time and I won't pick up their bug fixes!
  230. //
  231. HRESULT CCapOverlay::BreakConnect()
  232. {
  233. DbgLog((LOG_TRACE,3,TEXT("CCapOverlay::BreakConnect")));
  234. if (m_pOverlay != NULL) {
  235. if (m_bAdvise) {
  236. m_pOverlay->Unadvise();
  237. m_bAdvise = FALSE;
  238. }
  239. m_pOverlay->Release();
  240. m_pOverlay = NULL;
  241. }
  242. #if 0
  243. // we've broken our connection, so next time we reconnect don't allow
  244. // repainting until we've actually drawn something in the first place
  245. m_pFilter->m_fOKToRepaint = FALSE;
  246. #endif
  247. return CBaseOutputPin::BreakConnect();
  248. }
  249. // Override this because we don't want any allocator!
  250. //
  251. HRESULT CCapOverlay::DecideAllocator(IMemInputPin * pPin,
  252. IMemAllocator ** pAlloc) {
  253. /* We just don't want one so everything's OK as it is */
  254. return S_OK;
  255. }
  256. HRESULT CCapOverlay::GetMediaType(int iPosition, CMediaType *pmt)
  257. {
  258. DbgLog((LOG_TRACE,3,TEXT("CCapOverlay::GetMediaType #%d"), iPosition));
  259. if (pmt == NULL) {
  260. DbgLog((LOG_TRACE,3,TEXT("NULL format, no can do")));
  261. return E_INVALIDARG;
  262. }
  263. if (iPosition < 0) {
  264. return E_INVALIDARG;
  265. }
  266. if (iPosition > 0) {
  267. return VFW_S_NO_MORE_ITEMS;
  268. }
  269. // We provide a media type of OVERLAY with an 8 bit format (silly
  270. // renderer won't accept it if we don't set up an 8 bit format)
  271. BYTE aFormat[sizeof(VIDEOINFOHEADER) + SIZE_PALETTE];
  272. VIDEOINFOHEADER *pFormat = (VIDEOINFOHEADER *)aFormat;
  273. ZeroMemory(pFormat, sizeof(VIDEOINFOHEADER) + SIZE_PALETTE);
  274. pFormat->bmiHeader.biWidth =
  275. m_pCap->m_pStream->m_user.pvi->bmiHeader.biWidth;
  276. pFormat->bmiHeader.biHeight =
  277. m_pCap->m_pStream->m_user.pvi->bmiHeader.biHeight;
  278. // we don't work with funny rectangles. Sorry
  279. #if 0
  280. // I bet the renderer ignores these rectangles and I'll need to call
  281. // IBasicVideo::put_Source* and ::put_Destination* instead
  282. // The idea is to make OnClipChange's source and target match these numbers
  283. pFormat->rcSource = m_pCap->m_pStream->m_user.pvi->rcSource;
  284. pFormat->rcTarget = m_pCap->m_pStream->m_user.pvi->rcTarget;
  285. #endif
  286. pFormat->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  287. pFormat->bmiHeader.biPlanes = 1;
  288. pFormat->bmiHeader.biBitCount = 8;
  289. pmt->SetFormat((PBYTE)pFormat, sizeof(VIDEOINFOHEADER) + SIZE_PALETTE);
  290. pmt->SetFormatType(&FORMAT_VideoInfo);
  291. if (pmt->pbFormat == NULL) {
  292. return E_OUTOFMEMORY;
  293. }
  294. pmt->majortype = MEDIATYPE_Video;
  295. pmt->subtype = MEDIASUBTYPE_Overlay;
  296. pmt->bFixedSizeSamples = FALSE;
  297. pmt->bTemporalCompression = FALSE;
  298. pmt->lSampleSize = 0;
  299. return NOERROR;
  300. }
  301. // We accept overlay connections only
  302. //
  303. HRESULT CCapOverlay::CheckMediaType(const CMediaType *pMediaType)
  304. {
  305. DbgLog((LOG_TRACE,3,TEXT("CCapOverlay::CheckMediaType")));
  306. if (pMediaType->subtype == MEDIASUBTYPE_Overlay)
  307. return NOERROR;
  308. else
  309. return E_FAIL;
  310. }
  311. // Don't insist on IMemInputPin
  312. //
  313. HRESULT CCapOverlay::CheckConnect(IPin *pPin)
  314. {
  315. // we don't connect to anyone who doesn't support IOverlay.
  316. // after all, we're an overlay pin
  317. HRESULT hr = pPin->QueryInterface(IID_IOverlay, (void **)&m_pOverlay);
  318. if (FAILED(hr)) {
  319. return E_NOINTERFACE;
  320. } else {
  321. m_pOverlay->Release();
  322. m_pOverlay = NULL;
  323. }
  324. return CBasePin::CheckConnect(pPin);
  325. }
  326. HRESULT CCapOverlay::Active()
  327. {
  328. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay Stop->Pause")));
  329. videoStreamInit(m_pCap->m_pStream->m_cs.hVideoExtOut, 0, 0, 0, 0);
  330. // don't let the base class Active() get called for non-IMemInput pins
  331. return NOERROR;
  332. }
  333. HRESULT CCapOverlay::Inactive()
  334. {
  335. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay Pause->Stop")));
  336. // turn off overlay
  337. videoStreamFini(m_pCap->m_pStream->m_cs.hVideoExtOut);
  338. #ifdef OVERLAY_SC
  339. CAutoLock cObjectLock(m_pCap->m_pLock);
  340. // kill our thread
  341. m_rtStart = 0;
  342. m_rtEnd = 0;
  343. if (m_pCap->m_pClock && m_dwAdvise) {
  344. m_pCap->m_pClock->Unadvise(m_dwAdvise);
  345. m_EventAdvise.Set();
  346. }
  347. // we haven't properly shut down our thread yet
  348. if (m_hThread) {
  349. WaitForSingleObject(m_hThread, INFINITE);
  350. CloseHandle(m_hThread);
  351. m_tid = 0;
  352. m_hThread = NULL;
  353. }
  354. #endif
  355. return NOERROR;
  356. }
  357. HRESULT CCapOverlay::ActiveRun(REFERENCE_TIME tStart)
  358. {
  359. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay Pause->Run")));
  360. ASSERT(m_pCap->m_pOverlayPin->IsConnected());
  361. m_fRunning = TRUE;
  362. HVIDEO hVideoExtOut = m_pCap->m_pStream->m_cs.hVideoExtOut;
  363. if (hVideoExtOut == NULL || m_pOverlay == NULL)
  364. return NOERROR;
  365. HWND hwnd;
  366. HDC hdc;
  367. m_pOverlay->GetWindowHandle(&hwnd);
  368. if (hwnd)
  369. hdc = GetDC(hwnd);
  370. if (hwnd == NULL || hdc == NULL)
  371. return NOERROR;
  372. RECT rcSrc, rcDst;
  373. rcSrc.left = 0; rcSrc.top = 0;
  374. rcSrc.right = HEADER(m_mt.Format())->biWidth;
  375. rcSrc.bottom = HEADER(m_mt.Format())->biHeight;
  376. GetClientRect (hwnd, &rcDst);
  377. ClientToScreen(hwnd, (LPPOINT)&rcDst);
  378. ClientToScreen(hwnd, (LPPOINT)&rcDst + 1);
  379. DbgLog((LOG_TRACE,2,TEXT("Starting overlay (%d,%d) to (%d,%d)"),
  380. rcSrc.right, rcSrc.bottom, rcDst.right - rcDst.left,
  381. rcDst.bottom - rcDst.top));
  382. // turn overlay on
  383. vidxSetRect(m_pCap->m_pStream->m_cs.hVideoExtOut, DVM_SRC_RECT,
  384. rcSrc.left, rcSrc.top, rcSrc.right, rcSrc.bottom);
  385. vidxSetRect(m_pCap->m_pStream->m_cs.hVideoExtOut, DVM_DST_RECT,
  386. rcDst.left, rcDst.top, rcDst.right, rcDst.bottom);
  387. // INIT now done in PAUSE
  388. videoUpdate(m_pCap->m_pStream->m_cs.hVideoExtOut, hwnd, hdc);
  389. ReleaseDC(hwnd, hdc);
  390. return NOERROR;
  391. }
  392. HRESULT CCapOverlay::ActivePause()
  393. {
  394. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay Run->Pause")));
  395. DbgLog((LOG_TRACE,2,TEXT("Turning OVERLAY off")));
  396. m_fRunning = FALSE;
  397. return NOERROR;
  398. }
  399. #if 0
  400. // Return the IOverlay interface we are using (AddRef'd)
  401. //
  402. IOverlay *CCapOverlay::GetOverlayInterface()
  403. {
  404. if (m_pOverlay) {
  405. m_pOverlay->AddRef();
  406. }
  407. return m_pOverlay;
  408. }
  409. #endif
  410. #ifdef OVERLAY_SC
  411. DWORD WINAPI CCapOverlay::ThreadProcInit(void *pv)
  412. {
  413. CCapOverlay *pThis = (CCapOverlay *)pv;
  414. return pThis->ThreadProc();
  415. }
  416. DWORD CCapOverlay::ThreadProc()
  417. {
  418. DbgLog((LOG_TRACE,2,TEXT("Starting CCapOverlay ThreadProc")));
  419. REFERENCE_TIME rt;
  420. HRESULT hr;
  421. // protect from other people dicking with m_rtStart and m_rtEnd
  422. m_pCap->m_pLock->Lock();
  423. while (m_rtStart > 0 || m_rtEnd > 0) {
  424. rt = m_rtStart;
  425. if (m_rtEnd < rt)
  426. rt = m_rtEnd;
  427. hr = m_pCap->m_pClock->AdviseTime(
  428. // this was the reference time when our stream started playing
  429. (REFERENCE_TIME) m_pCap->m_tStart,
  430. // this is the offset from our start time when we want to
  431. // wake up.
  432. (REFERENCE_TIME) rt,
  433. (HEVENT)(HANDLE) m_EventAdvise, // event to fire
  434. &m_dwAdvise); // Advise cookie
  435. m_pCap->m_pLock->Unlock();
  436. if (SUCCEEDED(hr)) {
  437. m_EventAdvise.Wait();
  438. } else {
  439. DbgLog((LOG_TRACE,1,TEXT("AdviseTime ERROR, doing it now")));
  440. }
  441. m_pCap->m_pLock->Lock();
  442. m_dwAdvise = 0;
  443. m_pCap->m_pClock->GetTime(&rt);
  444. if (m_rtStart < rt) {
  445. m_rtStart = 0;
  446. ActiveRun(0);
  447. }
  448. if (m_rtEnd < rt) {
  449. m_rtEnd = 0;
  450. ActivePause();
  451. }
  452. }
  453. DbgLog((LOG_TRACE,2,TEXT("CCapOverlay ThreadProc is dead")));
  454. // somebody needs to kill me officially later
  455. m_fHaveThread = FALSE;
  456. m_pCap->m_pLock->Unlock();
  457. return 0;
  458. }
  459. #endif // OVERLAY_SC
  460. //=========================================================================//
  461. //*** I N T E R M I S S I O N ***//
  462. //=========================================================================//
  463. /*
  464. IOverlayNotify
  465. */
  466. CCapOverlayNotify::CCapOverlayNotify(TCHAR * pName,
  467. CVfwCapture * pFilter,
  468. LPUNKNOWN pUnk,
  469. HRESULT * phr) :
  470. CUnknown(pName, pUnk)
  471. {
  472. DbgLog((LOG_TRACE,1,TEXT("*Instantiating CCapOverlayNotify")));
  473. m_pFilter = pFilter;
  474. }
  475. CCapOverlayNotify::~CCapOverlayNotify()
  476. {
  477. DbgLog((LOG_TRACE,1,TEXT("*Destroying CCapOverlayNotify")));
  478. }
  479. STDMETHODIMP CCapOverlayNotify::NonDelegatingQueryInterface(REFIID riid,
  480. void ** ppv)
  481. {
  482. DbgLog((LOG_TRACE,99,TEXT("CCapOverlayNotify::QueryInterface")));
  483. if (ppv)
  484. *ppv = NULL;
  485. /* Do we have this interface */
  486. if (riid == IID_IOverlayNotify) {
  487. return GetInterface((LPUNKNOWN) (IOverlayNotify *) this, ppv);
  488. } else {
  489. return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  490. }
  491. }
  492. STDMETHODIMP_(ULONG) CCapOverlayNotify::NonDelegatingRelease()
  493. {
  494. return m_pFilter->Release();
  495. }
  496. STDMETHODIMP_(ULONG) CCapOverlayNotify::NonDelegatingAddRef()
  497. {
  498. return m_pFilter->AddRef();
  499. }
  500. STDMETHODIMP CCapOverlayNotify::OnColorKeyChange(
  501. const COLORKEY *pColorKey) // Defines new colour key
  502. {
  503. DbgLog((LOG_TRACE,3,TEXT("CCapOverlayNotify::OnColorKeyChange")));
  504. // We expect the hardware to handle colour key stuff, so I'm really
  505. // hoping that the renderer will never draw the colour key itself.
  506. return NOERROR;
  507. }
  508. // The calls to OnClipChange happen in sync with the window. So it's called
  509. // with an empty clip list before the window moves to freeze the video, and
  510. // then when the window has stabilised it is called again with the new clip
  511. // list. The OnPositionChange callback is for overlay cards that don't want
  512. // the expense of synchronous clipping updates and just want to know when
  513. // the source or destination video positions change. They will NOT be called
  514. // in sync with the window but at some point after the window has changed
  515. // (basicly in time with WM_SIZE etc messages received). This is therefore
  516. // suitable for overlay cards that don't inlay their data to the framebuffer
  517. STDMETHODIMP CCapOverlayNotify::OnClipChange(
  518. const RECT * pSourceRect, // Area of source video to use
  519. const RECT * pDestinationRect, // screen co-ords of window
  520. const RGNDATA * pRegionData) // Header describing clipping
  521. {
  522. if (!m_pFilter->m_pOverlayPin)
  523. return NOERROR;
  524. if (!m_pFilter->m_pOverlayPin->IsConnected())
  525. return NOERROR;
  526. if (IsRectEmpty(pSourceRect) && IsRectEmpty(pDestinationRect))
  527. return NOERROR;
  528. HWND hwnd = NULL;
  529. HDC hdc;
  530. if (m_pFilter->m_pOverlayPin->m_pOverlay)
  531. m_pFilter->m_pOverlayPin->m_pOverlay->GetWindowHandle(&hwnd);
  532. if (hwnd == NULL || !IsWindowVisible(hwnd))
  533. return NOERROR;
  534. if (hwnd)
  535. hdc = GetDC(hwnd);
  536. if (hdc == NULL)
  537. return NOERROR;
  538. DbgLog((LOG_TRACE,3,TEXT("OnClip/PositionChange (%d,%d) (%d,%d)"),
  539. pSourceRect->right - pSourceRect->left,
  540. pSourceRect->bottom - pSourceRect->top,
  541. pDestinationRect->right - pDestinationRect->left,
  542. pDestinationRect->bottom - pDestinationRect->top));
  543. // It's up to us to keep garbage out of the window by painting it if
  544. // we're not running, and the hardware has nothing to draw
  545. if (!m_pFilter->m_pOverlayPin->m_fRunning) {
  546. RECT rcC;
  547. GetClientRect(hwnd, &rcC);
  548. HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, GetStockObject(BLACK_BRUSH));
  549. PatBlt(hdc, 0, 0, rcC.right, rcC.bottom, PATCOPY);
  550. SelectObject(hdc, hbrOld);
  551. ReleaseDC(hwnd, hdc);
  552. return NOERROR;
  553. }
  554. vidxSetRect(m_pFilter->m_pStream->m_cs.hVideoExtOut, DVM_SRC_RECT,
  555. pSourceRect->left, pSourceRect->top,
  556. pSourceRect->right, pSourceRect->bottom);
  557. vidxSetRect(m_pFilter->m_pStream->m_cs.hVideoExtOut, DVM_DST_RECT,
  558. pDestinationRect->left, pDestinationRect->top,
  559. pDestinationRect->right, pDestinationRect->bottom);
  560. videoStreamInit(m_pFilter->m_pStream->m_cs.hVideoExtOut, 0, 0, 0, 0);
  561. videoUpdate(m_pFilter->m_pStream->m_cs.hVideoExtOut, hwnd, hdc);
  562. ReleaseDC(hwnd, hdc);
  563. return NOERROR;
  564. }
  565. STDMETHODIMP CCapOverlayNotify::OnPaletteChange(
  566. DWORD dwColors, // Number of colours present
  567. const PALETTEENTRY *pPalette) // Array of palette colours
  568. {
  569. DbgLog((LOG_TRACE,3,TEXT("CCapOverlayNotify::OnPaletteChange")));
  570. return NOERROR;
  571. }
  572. STDMETHODIMP CCapOverlayNotify::OnPositionChange(
  573. const RECT *pSourceRect, // Area of video to play with
  574. const RECT *pDestinationRect) // Area video goes
  575. {
  576. return OnClipChange(pSourceRect, pDestinationRect, NULL);
  577. }
  578. //
  579. // PIN CATEGORIES - let the world know that we are a PREVIEW pin
  580. //
  581. HRESULT CCapOverlay::Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
  582. {
  583. return E_NOTIMPL;
  584. }
  585. // To get a property, the caller allocates a buffer which the called
  586. // function fills in. To determine necessary buffer size, call Get with
  587. // pPropData=NULL and cbPropData=0.
  588. HRESULT CCapOverlay::Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned)
  589. {
  590. if (guidPropSet != AMPROPSETID_Pin)
  591. return E_PROP_SET_UNSUPPORTED;
  592. if (dwPropID != AMPROPERTY_PIN_CATEGORY)
  593. return E_PROP_ID_UNSUPPORTED;
  594. if (pPropData == NULL && pcbReturned == NULL)
  595. return E_POINTER;
  596. if (pcbReturned)
  597. *pcbReturned = sizeof(GUID);
  598. if (pPropData == NULL)
  599. return S_OK;
  600. if (cbPropData < sizeof(GUID))
  601. return E_UNEXPECTED;
  602. *(GUID *)pPropData = PIN_CATEGORY_PREVIEW;
  603. return S_OK;
  604. }
  605. // QuerySupported must either return E_NOTIMPL or correctly indicate
  606. // if getting or setting the property set and property is supported.
  607. // S_OK indicates the property set and property ID combination is
  608. HRESULT CCapOverlay::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
  609. {
  610. if (guidPropSet != AMPROPSETID_Pin)
  611. return E_PROP_SET_UNSUPPORTED;
  612. if (dwPropID != AMPROPERTY_PIN_CATEGORY)
  613. return E_PROP_ID_UNSUPPORTED;
  614. if (pTypeSupport)
  615. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  616. return S_OK;
  617. }